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