View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    * 
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    * http://www.opensource.org/licenses/ecl2.php
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.kuali.rice.krad.datadictionary;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.kuali.rice.core.api.util.ClassLoaderUtils;
23  import org.kuali.rice.krad.bo.BusinessObject;
24  import org.kuali.rice.krad.bo.PersistableBusinessObjectExtension;
25  import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
26  import org.kuali.rice.krad.datadictionary.exception.CompletionException;
27  import org.kuali.rice.krad.datadictionary.parse.StringListConverter;
28  import org.kuali.rice.krad.datadictionary.parse.StringMapConverter;
29  import org.kuali.rice.krad.service.KRADServiceLocator;
30  import org.kuali.rice.krad.service.PersistenceStructureService;
31  import org.kuali.rice.krad.uif.container.View;
32  import org.kuali.rice.krad.uif.util.ComponentBeanPostProcessor;
33  import org.kuali.rice.krad.uif.util.UifBeanFactoryPostProcessor;
34  import org.kuali.rice.krad.util.ObjectUtils;
35  import org.springframework.beans.factory.config.BeanPostProcessor;
36  import org.springframework.beans.factory.support.DefaultListableBeanFactory;
37  import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
38  import org.springframework.context.expression.StandardBeanExpressionResolver;
39  import org.springframework.core.convert.support.GenericConversionService;
40  import org.springframework.core.io.DefaultResourceLoader;
41  import org.springframework.core.io.Resource;
42  
43  import java.beans.IntrospectionException;
44  import java.beans.PropertyDescriptor;
45  import java.io.File;
46  import java.io.IOException;
47  import java.util.ArrayList;
48  import java.util.Collection;
49  import java.util.HashMap;
50  import java.util.List;
51  import java.util.Map;
52  import java.util.Set;
53  import java.util.TreeMap;
54  
55  /**
56   * Collection of named BusinessObjectEntry objects, each of which contains
57   * information relating to the display, validation, and general maintenance of a
58   * BusinessObject.
59   */
60  public class DataDictionary  {
61  
62  	protected DefaultListableBeanFactory ddBeans = new DefaultListableBeanFactory();
63      protected XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ddBeans);
64  
65  	// logger
66  	private static final Log LOG = LogFactory.getLog(DataDictionary.class);
67  
68  	/**
69  	 * The encapsulation of DataDictionary indices
70  	 */
71  	protected DataDictionaryIndex ddIndex = new DataDictionaryIndex(ddBeans);
72  	
73  	// View indices
74  	protected UifDictionaryIndex uifIndex = new UifDictionaryIndex(ddBeans);
75  
76  	/**
77  	 * The DataDictionaryMapper
78  	 * The default mapper simply consults the initialized indices
79  	 * on workflow document type
80  	 */
81  	protected DataDictionaryMapper ddMapper = new DataDictionaryIndexMapper();
82  
83  	protected List<String> configFileLocations = new ArrayList<String>();
84  	
85  
86  	public List<String> getConfigFileLocations() {
87          return this.configFileLocations;
88      }
89  
90      public void setConfigFileLocations(List<String> configFileLocations) {
91          this.configFileLocations = configFileLocations;
92      }
93      
94      public void addConfigFileLocation( String location ) throws IOException {
95          indexSource( location );
96      }
97  
98      /**
99       * Sets the DataDictionaryMapper
100      * @param mapper the datadictionary mapper
101      */
102     public void setDataDictionaryMapper(DataDictionaryMapper mapper) {
103     	this.ddMapper = mapper;
104     }
105     
106     private void indexSource(String sourceName) throws IOException {        
107         if (sourceName == null) {
108             throw new DataDictionaryException("Source Name given is null");
109         }
110 
111         if (!sourceName.endsWith(".xml") ) {
112             Resource resource = getFileResource(sourceName);
113             if (resource.exists()) {
114                 indexSource(resource.getFile());
115             } else {
116                 LOG.warn("Could not find " + sourceName);
117                 throw new DataDictionaryException("DD Resource " + sourceName + " not found");
118             }
119         } else {
120             if ( LOG.isDebugEnabled() ) {
121                 LOG.debug("adding sourceName " + sourceName + " ");
122             }
123             Resource resource = getFileResource(sourceName);
124             if (! resource.exists()) {
125                 throw new DataDictionaryException("DD Resource " + sourceName + " not found");  
126             }
127             
128             String indexName = sourceName.substring(sourceName.lastIndexOf("/") + 1, sourceName.indexOf(".xml"));
129             configFileLocations.add( sourceName );
130         }
131     }    
132 
133     protected Resource getFileResource(String sourceName) {
134         DefaultResourceLoader resourceLoader = new DefaultResourceLoader(ClassLoaderUtils.getDefaultClassLoader());
135         return resourceLoader.getResource(sourceName);
136     }
137 
138     private void indexSource(File dir) {
139         for (File file : dir.listFiles()) {
140             if (file.isDirectory()) {
141                 indexSource(file);
142             } else if (file.getName().endsWith(".xml") ) {
143                 configFileLocations.add( "file:" + file.getAbsolutePath());
144             } else {
145                 if ( LOG.isDebugEnabled() ) {
146                     LOG.debug("Skipping non xml file " + file.getAbsolutePath() + " in DD load");
147                 }
148             }
149         }
150     }
151     
152     public void parseDataDictionaryConfigurationFiles( boolean allowConcurrentValidation ) {
153 		// configure the bean factory, setup component decorator post processor
154 		// and allow Spring EL
155         try {
156             BeanPostProcessor idPostProcessor = ComponentBeanPostProcessor.class.newInstance();
157             ddBeans.addBeanPostProcessor(idPostProcessor);
158             ddBeans.setBeanExpressionResolver(new StandardBeanExpressionResolver());
159 
160             GenericConversionService conversionService = new GenericConversionService();
161             conversionService.addConverter(new StringMapConverter());
162             conversionService.addConverter(new StringListConverter());
163             ddBeans.setConversionService(conversionService);
164         } catch (Exception e1) {
165             LOG.error("Cannot create component decorator post processor: " + e1.getMessage(), e1);
166             throw new RuntimeException("Cannot create component decorator post processor: " + e1.getMessage(), e1);
167         }
168 
169         // expand configuration locations into files
170         LOG.info("Starting DD XML File Load");
171 
172         String[] configFileLocationsArray = new String[configFileLocations.size()];
173         configFileLocationsArray = configFileLocations.toArray(configFileLocationsArray);
174         configFileLocations.clear(); // empty the list out so other items can be added
175         try {
176             xmlReader.loadBeanDefinitions(configFileLocationsArray);
177         } catch (Exception e) {
178             LOG.error("Error loading bean definitions", e);
179             throw new DataDictionaryException("Error loading bean definitions: " + e.getLocalizedMessage());
180         }
181         LOG.info("Completed DD XML File Load");
182 
183         UifBeanFactoryPostProcessor factoryPostProcessor = new UifBeanFactoryPostProcessor();
184         factoryPostProcessor.postProcessBeanFactory(ddBeans);
185 
186         // indexing
187         if (allowConcurrentValidation) {
188             Thread t = new Thread(ddIndex);
189             t.start();
190 
191             Thread t2 = new Thread(uifIndex);
192             t2.start();
193         } else {
194             ddIndex.run();
195             uifIndex.run();
196         }
197     }
198 
199 	static boolean validateEBOs = true;
200     
201     public void validateDD( boolean validateEbos ) {
202     	DataDictionary.validateEBOs = validateEbos;
203     	Map<String,DataObjectEntry> doBeans = ddBeans.getBeansOfType(DataObjectEntry.class);
204         for ( DataObjectEntry entry : doBeans.values() ) {
205             entry.completeValidation();
206         }
207         Map<String,DocumentEntry> docBeans = ddBeans.getBeansOfType(DocumentEntry.class);
208         for ( DocumentEntry entry : docBeans.values() ) {
209             entry.completeValidation();
210         }
211     }
212     
213     public void validateDD() {
214     	validateDD(true);
215     }
216 
217 	/**
218 	 * @param className
219 	 * @return BusinessObjectEntry for the named class, or null if none exists
220 	 */
221     @Deprecated
222 	public BusinessObjectEntry getBusinessObjectEntry(String className ) {
223 		return ddMapper.getBusinessObjectEntry(ddIndex, className);
224 	}
225 
226 	/**
227      * @param className
228      * @return BusinessObjectEntry for the named class, or null if none exists
229      */
230     public DataObjectEntry getDataObjectEntry(String className ) {
231         return ddMapper.getDataObjectEntry(ddIndex, className);
232     }
233 
234 	/**
235 	 * This method gets the business object entry for a concrete class
236 	 * 
237 	 * @param className
238 	 * @return
239 	 */
240 	public BusinessObjectEntry getBusinessObjectEntryForConcreteClass(String className){
241 		return ddMapper.getBusinessObjectEntryForConcreteClass(ddIndex, className);
242 	}
243 	
244 	/**
245 	 * @return List of businessObject classnames
246 	 */
247 	public List<String> getBusinessObjectClassNames() {
248 		return ddMapper.getBusinessObjectClassNames(ddIndex);
249 	}
250 
251 	/**
252 	 * @return Map of (classname, BusinessObjectEntry) pairs
253 	 */
254 	public Map<String, BusinessObjectEntry> getBusinessObjectEntries() {
255 		return ddMapper.getBusinessObjectEntries(ddIndex);
256 	}
257 
258 	/**
259 	 * @param className
260 	 * @return DataDictionaryEntryBase for the named class, or null if none
261 	 *         exists
262 	 */
263 	public DataDictionaryEntry getDictionaryObjectEntry(String className) {
264 		return ddMapper.getDictionaryObjectEntry(ddIndex, className);
265 	}
266 
267 	/**
268 	 * Returns the KNS document entry for the given lookup key.  The documentTypeDDKey is interpreted
269 	 * successively in the following ways until a mapping is found (or none if found):
270 	 * <ol>
271 	 * <li>KEW/workflow document type</li>
272 	 * <li>business object class name</li>
273 	 * <li>maintainable class name</li>
274 	 * </ol>
275 	 * This mapping is compiled when DataDictionary files are parsed on startup (or demand).  Currently this
276 	 * means the mapping is static, and one-to-one (one KNS document maps directly to one and only
277 	 * one key).
278 	 * 
279 	 * @param documentTypeDDKey the KEW/workflow document type name
280 	 * @return the KNS DocumentEntry if it exists
281 	 */
282 	public DocumentEntry getDocumentEntry(String documentTypeDDKey ) {
283 		return ddMapper.getDocumentEntry(ddIndex, documentTypeDDKey);
284 	}
285 
286 	/**
287 	 * Note: only MaintenanceDocuments are indexed by businessObject Class
288 	 * 
289 	 * This is a special case that is referenced in one location. Do we need
290 	 * another map for this stuff??
291 	 * 
292 	 * @param businessObjectClass
293 	 * @return DocumentEntry associated with the given Class, or null if there
294 	 *         is none
295 	 */
296 	public MaintenanceDocumentEntry getMaintenanceDocumentEntryForBusinessObjectClass(Class<?> businessObjectClass) {
297 		return ddMapper.getMaintenanceDocumentEntryForBusinessObjectClass(ddIndex, businessObjectClass);
298 	}
299 
300 	public Map<String, DocumentEntry> getDocumentEntries() {
301 		return ddMapper.getDocumentEntries(ddIndex);
302 	}
303 	
304 	/**
305 	 * Returns the View entry identified by the given id
306 	 * 
307 	 * @param viewId - unique id for view
308 	 * @return View instance associated with the id
309 	 */
310 	public View getViewById(String viewId) {
311 		return ddMapper.getViewById(uifIndex, viewId);
312 	}
313 	
314 	/**
315 	 * Returns View instance identified by the view type name and index
316 	 * 
317 	 * @param viewTypeName
318 	 *            - type name for the view
319 	 * @param indexKey
320 	 *            - Map of index key parameters, these are the parameters the
321 	 *            indexer used to index the view initially and needs to identify
322 	 *            an unique view instance
323 	 * @return View instance that matches the given index
324 	 */
325 	public View getViewByTypeIndex(String viewTypeName, Map<String, String> indexKey) {
326 		return ddMapper.getViewByTypeIndex(uifIndex, viewTypeName, indexKey);
327 	}
328 	
329 	/**
330 	 * Gets all <code>View</code> prototypes configured for the given view type
331 	 * name
332 	 * 
333 	 * @param viewTypeName
334 	 *            - view type name to retrieve
335 	 * @return List<View> view prototypes with the given type name, or empty
336 	 *         list
337 	 */
338 	public List<View> getViewsForType(String viewTypeName) {
339 		return ddMapper.getViewsForType(uifIndex, viewTypeName);
340 	}
341 
342     /**
343      * @param clazz
344      * @param propertyName
345      * @return true if the given propertyName names a property of the given class
346      * @throws CompletionException if there is a problem accessing the named property on the given class
347      */
348     public static boolean isPropertyOf(Class targetClass, String propertyName) {
349         if (targetClass == null) {
350             throw new IllegalArgumentException("invalid (null) targetClass");
351         }
352         if (StringUtils.isBlank(propertyName)) {
353             throw new IllegalArgumentException("invalid (blank) propertyName");
354         }
355 
356         PropertyDescriptor propertyDescriptor = buildReadDescriptor(targetClass, propertyName);
357 
358         boolean isPropertyOf = (propertyDescriptor != null);
359         return isPropertyOf;
360     }
361 
362     /**
363      * @param clazz
364      * @param propertyName
365      * @return true if the given propertyName names a Collection property of the given class
366      * @throws CompletionException if there is a problem accessing the named property on the given class
367      */
368     public static boolean isCollectionPropertyOf(Class targetClass, String propertyName) {
369         boolean isCollectionPropertyOf = false;
370 
371         PropertyDescriptor propertyDescriptor = buildReadDescriptor(targetClass, propertyName);
372         if (propertyDescriptor != null) {
373             Class clazz = propertyDescriptor.getPropertyType();
374 
375             if ((clazz != null) && Collection.class.isAssignableFrom(clazz)) {
376                 isCollectionPropertyOf = true;
377             }
378         }
379 
380         return isCollectionPropertyOf;
381     }
382 
383     public static PersistenceStructureService persistenceStructureService;
384     
385     /**
386      * @return the persistenceStructureService
387      */
388     public static PersistenceStructureService getPersistenceStructureService() {
389         if ( persistenceStructureService == null ) {
390             persistenceStructureService = KRADServiceLocator.getPersistenceStructureService();
391         }
392         return persistenceStructureService;
393     }
394     
395     /**
396      * This method determines the Class of the attributeName passed in. Null will be returned if the member is not available, or if
397      * a reflection exception is thrown.
398      * 
399      * @param rootClass - Class that the attributeName property exists in.
400      * @param attributeName - Name of the attribute you want a class for.
401      * @return The Class of the attributeName, if the attribute exists on the rootClass. Null otherwise.
402      */
403     public static Class getAttributeClass(Class boClass, String attributeName) {
404 
405         // fail loudly if the attributeName isnt a member of rootClass
406         if (!isPropertyOf(boClass, attributeName)) {
407             throw new AttributeValidationException("unable to find attribute '" + attributeName + "' in rootClass '" + boClass.getName() + "'");
408         }
409 
410     	//Implementing Externalizable Business Object Services...
411         //The boClass can be an interface, hence handling this separately, 
412         //since the original method was throwing exception if the class could not be instantiated.
413         if(boClass.isInterface())
414         	return getAttributeClassWhenBOIsInterface(boClass, attributeName);
415         else
416         	return getAttributeClassWhenBOIsClass(boClass, attributeName);        	
417 
418     }
419 
420     /**
421      * 
422      * This method gets the property type of the given attributeName when the bo class is a concrete class
423      * 
424      * @param boClass
425      * @param attributeName
426      * @return
427      */
428     private static Class getAttributeClassWhenBOIsClass(Class boClass, String attributeName){
429     	BusinessObject boInstance;
430         try {
431             boInstance = (BusinessObject) boClass.newInstance();
432         } catch (Exception e) {
433         	throw new RuntimeException("Unable to instantiate BO: " + boClass, e);
434         }
435 
436         // attempt to retrieve the class of the property
437         try {
438             return ObjectUtils.getPropertyType(boInstance, attributeName, getPersistenceStructureService());
439         } catch (Exception e) {
440             throw new RuntimeException("Unable to determine property type for: " + boClass.getName() + "." + attributeName, e);
441         }
442     }
443 
444     /**
445      * 
446      * This method gets the property type of the given attributeName when the bo class is an interface
447      * This method will also work if the bo class is not an interface, 
448      * but that case requires special handling, hence a separate method getAttributeClassWhenBOIsClass 
449      * 
450      * @param boClass
451      * @param attributeName
452      * @return
453      */
454     private static Class getAttributeClassWhenBOIsInterface(Class boClass, String attributeName){
455         if (boClass == null) {
456             throw new IllegalArgumentException("invalid (null) boClass");
457         }
458         if (StringUtils.isBlank(attributeName)) {
459             throw new IllegalArgumentException("invalid (blank) attributeName");
460         }
461 
462         PropertyDescriptor propertyDescriptor = null;
463 
464         String[] intermediateProperties = attributeName.split("\\.");
465         int lastLevel = intermediateProperties.length - 1;
466         Class currentClass = boClass;
467 
468         for (int i = 0; i <= lastLevel; ++i) {
469 
470             String currentPropertyName = intermediateProperties[i];
471             propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
472 
473             if (propertyDescriptor != null) {
474 
475                 Class propertyType = propertyDescriptor.getPropertyType();
476                 if ( propertyType.equals( PersistableBusinessObjectExtension.class ) ) {
477                     propertyType = getPersistenceStructureService().getBusinessObjectAttributeClass( currentClass, currentPropertyName );                    
478                 }
479                 if (Collection.class.isAssignableFrom(propertyType)) {
480                 	// TODO: determine property type using generics type definition
481                 	throw new AttributeValidationException("Can't determine the Class of Collection elements because when the business object is an (possibly ExternalizableBusinessObject) interface.");
482                 }
483                 else {
484                     currentClass = propertyType;
485                 }
486             }
487             else {
488             	throw new AttributeValidationException("Can't find getter method of " + boClass.getName() + " for property " + attributeName);
489             }
490         }
491         return currentClass;
492     }
493     
494     /**
495      * This method determines the Class of the elements in the collectionName passed in.
496      * 
497      * @param boClass Class that the collectionName collection exists in.
498      * @param collectionName the name of the collection you want the element class for
499      * @return
500      */
501     public static Class getCollectionElementClass(Class boClass, String collectionName) {
502         if (boClass == null) {
503             throw new IllegalArgumentException("invalid (null) boClass");
504         }
505         if (StringUtils.isBlank(collectionName)) {
506             throw new IllegalArgumentException("invalid (blank) collectionName");
507         }
508 
509         PropertyDescriptor propertyDescriptor = null;
510 
511         String[] intermediateProperties = collectionName.split("\\.");
512         Class currentClass = boClass;
513 
514         for (int i = 0; i <intermediateProperties.length; ++i) {
515 
516             String currentPropertyName = intermediateProperties[i];
517             propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
518 
519 
520                 if (propertyDescriptor != null) {
521 
522                     Class type = propertyDescriptor.getPropertyType();
523                     if (Collection.class.isAssignableFrom(type)) {
524 
525                         if (getPersistenceStructureService().isPersistable(currentClass)) {
526 
527                             Map<String, Class> collectionClasses = new HashMap<String, Class>();
528                             collectionClasses = getPersistenceStructureService().listCollectionObjectTypes(currentClass);
529                             currentClass = collectionClasses.get(currentPropertyName);
530 
531                         }
532                         else {
533                             throw new RuntimeException("Can't determine the Class of Collection elements because persistenceStructureService.isPersistable(" + currentClass.getName() + ") returns false.");
534                         }
535 
536                     }
537                     else {
538 
539                         currentClass = propertyDescriptor.getPropertyType();
540 
541                     }
542                 }
543             }
544 
545         return currentClass;
546     }
547 
548     static private Map<String, Map<String, PropertyDescriptor>> cache = new TreeMap<String, Map<String, PropertyDescriptor>>();
549 
550     /**
551      * @param propertyClass
552      * @param propertyName
553      * @return PropertyDescriptor for the getter for the named property of the given class, if one exists.
554      */
555     public static PropertyDescriptor buildReadDescriptor(Class propertyClass, String propertyName) {
556         if (propertyClass == null) {
557             throw new IllegalArgumentException("invalid (null) propertyClass");
558         }
559         if (StringUtils.isBlank(propertyName)) {
560             throw new IllegalArgumentException("invalid (blank) propertyName");
561         }
562 
563         PropertyDescriptor propertyDescriptor = null;
564 
565         String[] intermediateProperties = propertyName.split("\\.");
566         int lastLevel = intermediateProperties.length - 1;
567         Class currentClass = propertyClass;
568 
569         for (int i = 0; i <= lastLevel; ++i) {
570 
571             String currentPropertyName = intermediateProperties[i];
572             propertyDescriptor = buildSimpleReadDescriptor(currentClass, currentPropertyName);
573 
574             if (i < lastLevel) {
575 
576                 if (propertyDescriptor != null) {
577 
578                     Class propertyType = propertyDescriptor.getPropertyType();
579                     if ( propertyType.equals( PersistableBusinessObjectExtension.class ) ) {
580                         propertyType = getPersistenceStructureService().getBusinessObjectAttributeClass( currentClass, currentPropertyName );                    
581                     }
582                     if (Collection.class.isAssignableFrom(propertyType)) {
583 
584                         if (getPersistenceStructureService().isPersistable(currentClass)) {
585 
586                             Map<String, Class> collectionClasses = new HashMap<String, Class>();
587                             collectionClasses = getPersistenceStructureService().listCollectionObjectTypes(currentClass);
588                             currentClass = collectionClasses.get(currentPropertyName);
589 
590                         }
591                         else {
592 
593                             throw new RuntimeException("Can't determine the Class of Collection elements because persistenceStructureService.isPersistable(" + currentClass.getName() + ") returns false.");
594 
595                         }
596 
597                     }
598                     else {
599 
600                         currentClass = propertyType;
601 
602                     }
603 
604                 }
605 
606             }
607 
608         }
609 
610         return propertyDescriptor;
611     }
612 
613     /**
614      * @param propertyClass
615      * @param propertyName
616      * @return PropertyDescriptor for the getter for the named property of the given class, if one exists.
617      */
618     public static PropertyDescriptor buildSimpleReadDescriptor(Class propertyClass, String propertyName) {
619         if (propertyClass == null) {
620             throw new IllegalArgumentException("invalid (null) propertyClass");
621         }
622         if (StringUtils.isBlank(propertyName)) {
623             throw new IllegalArgumentException("invalid (blank) propertyName");
624         }
625 
626         PropertyDescriptor p = null;
627 
628         // check to see if we've cached this descriptor already. if yes, return true.
629         String propertyClassName = propertyClass.getName();
630         Map<String, PropertyDescriptor> m = cache.get(propertyClassName);
631         if (null != m) {
632             p = m.get(propertyName);
633             if (null != p) {
634                 return p;
635             }
636         }
637 
638         String prefix = StringUtils.capitalize(propertyName);
639         String getName = "get" + prefix;
640         String isName = "is" + prefix;
641 
642         try {
643 
644             p = new PropertyDescriptor(propertyName, propertyClass, getName, null);
645 
646         }
647         catch (IntrospectionException e) {
648             try {
649 
650                 p = new PropertyDescriptor(propertyName, propertyClass, isName, null);
651 
652             }
653             catch (IntrospectionException f) {
654                 // ignore it
655             }
656         }
657 
658         // cache the property descriptor if we found it.
659         if (null != p) {
660 
661             if (null == m) {
662 
663                 m = new TreeMap<String, PropertyDescriptor>();
664                 cache.put(propertyClassName, m);
665 
666             }
667 
668             m.put(propertyName, p);
669 
670         }
671 
672         return p;
673     }
674 
675     public Set<InactivationBlockingMetadata> getAllInactivationBlockingMetadatas(Class blockedClass) {
676     	return ddMapper.getAllInactivationBlockingMetadatas(ddIndex, blockedClass);
677     }
678     
679     /**
680      * This method gathers beans of type BeanOverride and invokes each one's performOverride() method.
681      */
682     // KULRICE-4513
683     public void performBeanOverrides()
684     {
685     	Collection<BeanOverride> beanOverrides = ddBeans.getBeansOfType(BeanOverride.class).values();
686     	
687     	if (beanOverrides.isEmpty()){
688     		LOG.info("DataDictionary.performOverrides(): No beans to override");
689     	}
690 		for (BeanOverride beanOverride : beanOverrides) {
691 			
692 			Object bean = ddBeans.getBean(beanOverride.getBeanName());
693 			beanOverride.performOverride(bean);
694 			LOG.info("DataDictionary.performOverrides(): Performing override on bean: " + bean.toString());
695 		}
696     }
697 
698 }