Coverage Report - org.kuali.rice.krad.datadictionary.DataDictionaryEntryBase
 
Classes in this File Line Coverage Branch Coverage Complexity
DataDictionaryEntryBase
29%
36/122
22%
15/68
3.75
 
 1  
 /**
 2  
  * Copyright 2005-2011 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  
 package org.kuali.rice.krad.datadictionary;
 17  
 
 18  
 import java.io.Serializable;
 19  
 import java.util.ArrayList;
 20  
 import java.util.LinkedHashMap;
 21  
 import java.util.List;
 22  
 import java.util.Map;
 23  
 import java.util.Set;
 24  
 
 25  
 import org.apache.commons.lang.StringUtils;
 26  
 import org.kuali.rice.krad.datadictionary.exception.DuplicateEntryException;
 27  
 import org.kuali.rice.krad.exception.ValidationException;
 28  
 import org.springframework.beans.BeanUtils;
 29  
 import org.springframework.beans.factory.InitializingBean;
 30  
 
 31  
 /**
 32  
  * Contains common properties and methods for data dictionary entries.
 33  
  * 
 34  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 35  
  */
 36  
 abstract public class DataDictionaryEntryBase implements DataDictionaryEntry, Serializable, InitializingBean {
 37  
     protected List<AttributeDefinition> attributes;
 38  
     protected List<ComplexAttributeDefinition> complexAttributes;
 39  
     protected List<CollectionDefinition> collections;
 40  
     protected List<RelationshipDefinition> relationships;
 41  
     protected Map<String, AttributeDefinition> attributeMap;
 42  
     protected Map<String, ComplexAttributeDefinition> complexAttributeMap;
 43  
     protected Map<String, CollectionDefinition> collectionMap;
 44  
     protected Map<String, RelationshipDefinition> relationshipMap;
 45  
     
 46  100
     public DataDictionaryEntryBase() {
 47  100
         this.attributes = new ArrayList<AttributeDefinition>();
 48  100
         this.complexAttributes = new ArrayList<ComplexAttributeDefinition>();
 49  100
         this.collections = new ArrayList<CollectionDefinition>();
 50  100
         this.relationships = new ArrayList<RelationshipDefinition>();
 51  100
         this.attributeMap = new LinkedHashMap<String, AttributeDefinition>();
 52  100
         this.complexAttributeMap = new LinkedHashMap<String, ComplexAttributeDefinition>();
 53  100
         this.collectionMap = new LinkedHashMap<String, CollectionDefinition>();
 54  100
         this.relationshipMap = new LinkedHashMap<String, RelationshipDefinition>();
 55  100
     }
 56  
     
 57  
     /* Returns the given entry class (bo class or document class) */
 58  
     public abstract Class<?> getEntryClass();
 59  
     
 60  
     /**
 61  
      * @param attributeName
 62  
      * @return AttributeDefinition with the given name, or null if none with that name exists
 63  
      */
 64  
     public AttributeDefinition getAttributeDefinition(String attributeName) {
 65  78
         if (StringUtils.isBlank(attributeName)) {
 66  0
             throw new IllegalArgumentException("invalid (blank) attributeName");
 67  
         }
 68  78
         return attributeMap.get(attributeName);
 69  
     }
 70  
 
 71  
     /**
 72  
      * @return a Map containing all AttributeDefinitions associated with this BusinessObjectEntry, indexed by attributeName
 73  
      */
 74  
     public List<AttributeDefinition> getAttributes() {
 75  0
         return this.attributes;
 76  
     }
 77  
     
 78  
     /**
 79  
          * @return the complexAttributes
 80  
          */
 81  
         public List<ComplexAttributeDefinition> getComplexAttributes() {
 82  0
                 return this.complexAttributes;
 83  
         }
 84  
 
 85  
         /**
 86  
          * @param complexAttributes the complexAttributes to set
 87  
          */
 88  
         public void setComplexAttributes(
 89  
                         List<ComplexAttributeDefinition> complexAttributes) {
 90  0
         complexAttributeMap.clear();
 91  0
         for ( ComplexAttributeDefinition complexAttribute : complexAttributes ) {
 92  0
             if (complexAttribute == null) {
 93  0
                 throw new IllegalArgumentException("invalid (null) complexAttributeDefinition");
 94  
             }
 95  0
             String complexAttributeName = complexAttribute.getName();
 96  0
             if (StringUtils.isBlank(complexAttributeName)) {
 97  0
                 throw new ValidationException("invalid (blank) collectionName");
 98  
             }
 99  
 
 100  0
             if (complexAttributeMap.containsKey(complexAttribute)){
 101  0
                 throw new DuplicateEntryException("complex attribute '" + complexAttribute + "' already defined as an complex attribute for class '" + getEntryClass().getName() + "'");
 102  0
             } else if (collectionMap.containsKey(complexAttributeName)) {
 103  0
                 throw new DuplicateEntryException("complex attribute '" + complexAttributeName + "' already defined as a Collection for class '" + getEntryClass().getName() + "'");
 104  0
             } else if (attributeMap.containsKey(complexAttributeName)) {
 105  0
                 throw new DuplicateEntryException("complex attribute '" + complexAttributeName + "' already defined as an Attribute for class '" + getEntryClass().getName() + "'");
 106  
             } 
 107  
 
 108  0
             complexAttributeMap.put(complexAttributeName, complexAttribute);
 109  
             
 110  0
         }
 111  
 
 112  0
             this.complexAttributes = complexAttributes;
 113  0
         }
 114  
 
 115  
     /**
 116  
      * @param collectionName
 117  
      * @return CollectionDefinition with the given name, or null if none with that name exists
 118  
      */
 119  
     public CollectionDefinition getCollectionDefinition(String collectionName) {
 120  0
         if (StringUtils.isBlank(collectionName)) {
 121  0
             throw new IllegalArgumentException("invalid (blank) collectionName");
 122  
         }
 123  0
         return collectionMap.get(collectionName);
 124  
     }
 125  
 
 126  
     /**
 127  
      * @return a Map containing all CollectionDefinitions associated with this BusinessObjectEntry, indexed by collectionName
 128  
      */
 129  
     public List<CollectionDefinition> getCollections() {
 130  0
         return this.collections;
 131  
     }
 132  
 
 133  
     /**
 134  
      * @param relationshipName
 135  
      * @return RelationshipDefinition with the given name, or null if none with that name exists
 136  
      */
 137  
     public RelationshipDefinition getRelationshipDefinition(String relationshipName) {
 138  0
         if (StringUtils.isBlank(relationshipName)) {
 139  0
             throw new IllegalArgumentException("invalid (blank) relationshipName");
 140  
         }
 141  0
         return relationshipMap.get(relationshipName);
 142  
     }
 143  
 
 144  
     /**
 145  
      * @return a Map containing all RelationshipDefinitions associated with this BusinessObjectEntry, indexed by relationshipName
 146  
      */
 147  
     public List<RelationshipDefinition> getRelationships() {
 148  0
         return this.relationships;
 149  
     }
 150  
 
 151  
 
 152  
     /**
 153  
      * Directly validate simple fields, call completeValidation on Definition fields.
 154  
      */
 155  
     public void completeValidation() {
 156  
         
 157  0
         for ( AttributeDefinition attributeDefinition : attributes ) {
 158  0
             attributeDefinition.completeValidation(getEntryClass(), null);
 159  
         }
 160  
 
 161  0
         for ( CollectionDefinition collectionDefinition : collections ) {
 162  0
             collectionDefinition.completeValidation(getEntryClass(), null);
 163  
         }
 164  
 
 165  0
         for ( RelationshipDefinition relationshipDefinition : relationships ) {
 166  0
             relationshipDefinition.completeValidation(getEntryClass(), null);
 167  
         }
 168  0
     }
 169  
 
 170  
     /**
 171  
             The attributes element contains attribute 
 172  
             elements.  These define the specifications for business object fields.
 173  
 
 174  
             JSTL: attributes is a Map which is accessed by a key of "attributes".
 175  
             This map contains entries with the following keys:
 176  
                 * attributeName of first attribute
 177  
                 * attributeName of second attribute
 178  
                 etc.
 179  
 
 180  
             The corresponding value for each entry is an attribute ExportMap.
 181  
             By the time the JSTL export happens, all attributeReferences will be
 182  
             indistinguishable from attributes.
 183  
 
 184  
             See AttributesMapBuilder.java
 185  
 
 186  
                 The attribute element specifies the way in which a business object
 187  
                 field appears on a screen for data entry or display purposes.  These
 188  
                 specifications include the following:
 189  
                 * The title and formatting of the field
 190  
                 * Descriptive information about the field
 191  
                 * The edits used at time of data-entry
 192  
 
 193  
                 DD: See AttributeDefinition.java
 194  
 
 195  
                 JSTL: attribute is a Map which is accessed using a key which is the attributeName
 196  
                 of an attribute.  Each entry contains the following keys:
 197  
                     * name (String)
 198  
                     * forceUppercase (boolean String)
 199  
                     * label (String)
 200  
                     * shortLabel (String, copied from label if not present)
 201  
                     * maxLength (String)
 202  
                     * exclusiveMin (bigdecimal String)
 203  
                     * exclusiveMax (bigdecimal String)
 204  
                     * validationPattern (Map, optional)
 205  
                     * required (boolean String)
 206  
                     * control (Map)
 207  
                     * summary (String)
 208  
                     * description (String)
 209  
                     * formatterClass (String, optional)
 210  
                     * fullClassName (String)
 211  
                     * displayWorkgroup(String, optional)
 212  
                     * displayMaskClass(String, optional)
 213  
 
 214  
                 See AttributesMapBuilder.java
 215  
                 Note: exclusiveMax is mapped from the inclusiveMax element!
 216  
                 The validation logic seems to be assuming inclusiveMax.
 217  
      *
 218  
      */
 219  
     public void setAttributes(List<AttributeDefinition> attributes) {
 220  94
         attributeMap.clear();
 221  94
         for ( AttributeDefinition attribute : attributes ) {
 222  252
             if (attribute == null) {
 223  0
                 throw new IllegalArgumentException("invalid (null) attributeDefinition");
 224  
             }
 225  252
             String attributeName = attribute.getName();
 226  252
             if (StringUtils.isBlank(attributeName)) {
 227  0
                 throw new ValidationException("invalid (blank) attributeName");
 228  
             }
 229  
 
 230  252
             if (attributeMap.containsKey(attributeName)) {
 231  0
                 throw new DuplicateEntryException("attribute '" + attributeName + "' already defined as an Attribute for class '" + getEntryClass().getName() + "'");
 232  252
             } else if (collectionMap.containsKey(attributeName)) {
 233  0
                 throw new DuplicateEntryException("attribute '" + attributeName + "' already defined as a Collection for class '" + getEntryClass().getName() + "'");
 234  252
             } else if (complexAttributeMap.containsKey(attributeName)){
 235  0
                 throw new DuplicateEntryException("attribute '" + attributeName + "' already defined as an Complex Attribute for class '" + getEntryClass().getName() + "'");
 236  
             }
 237  252
             attributeMap.put(attributeName, attribute);            
 238  252
         }
 239  94
         this.attributes = attributes;
 240  94
     }
 241  
 
 242  
     /**
 243  
             The collections element contains collection elements.  These define
 244  
             the lists of other business objects which are related to and
 245  
             defined in the business objects.
 246  
 
 247  
             JSTL: collections is a Map which is accessed by a key of "collections".
 248  
             This map contains entries with the following keys:
 249  
                 * name of first collection
 250  
                 * name of second collection
 251  
                 etc.
 252  
             The corresponding value for each entry is a collection ExportMap.
 253  
 
 254  
             The collection element defines the name and description a
 255  
             list of objects related to the business object.
 256  
 
 257  
             DD: See CollectionDefinition.java.
 258  
 
 259  
             JSTL: collection is a Map which is accessed using a key which is the
 260  
             name of the collection.  Each entry contains the following keys:
 261  
                 * name (String)
 262  
                 * label (String)
 263  
                 * shortLabel (String, copied from label if missing)
 264  
                 * elementLabel (String, copied from contained class if missing)
 265  
                 * summary (String)
 266  
                 * description (String)
 267  
 
 268  
             See CollectionsMapBuilder.java.
 269  
      */
 270  
     public void setCollections(List<CollectionDefinition> collections) {
 271  6
         collectionMap.clear();
 272  6
         for ( CollectionDefinition collection : collections ) {
 273  6
             if (collection == null) {
 274  0
                 throw new IllegalArgumentException("invalid (null) collectionDefinition");
 275  
             }
 276  6
             String collectionName = collection.getName();
 277  6
             if (StringUtils.isBlank(collectionName)) {
 278  0
                 throw new ValidationException("invalid (blank) collectionName");
 279  
             }
 280  
 
 281  6
             if (collectionMap.containsKey(collectionName)) {
 282  0
                 throw new DuplicateEntryException("collection '" + collectionName + "' already defined for class '" + getEntryClass().getName() + "'");
 283  6
             } else if (attributeMap.containsKey(collectionName)) {
 284  0
                 throw new DuplicateEntryException("collection '" + collectionName + "' already defined as an Attribute for class '" + getEntryClass().getName() + "'");
 285  6
             } else if (complexAttributeMap.containsKey(collectionName)){
 286  0
                 throw new DuplicateEntryException("collection '" + collectionName + "' already defined as Complex Attribute for class '" + getEntryClass().getName() + "'");
 287  
             }
 288  
 
 289  6
             collectionMap.put(collectionName, collection);
 290  
             
 291  6
         }
 292  6
         this.collections = collections;
 293  6
     }
 294  
 
 295  
     /**
 296  
             The relationships element contains relationship elements.
 297  
             These are used to map attribute names to fields in a reference object.
 298  
 
 299  
             JSTL: relationships is a Map which is accessed by a key of "relationships".
 300  
             This map contains entries with the following keys:
 301  
                 * objectAttributeName of first relationship
 302  
                 * objectAttributeName of second relationship
 303  
                 etc.
 304  
             The corresponding value for each entry is a relationship ExportMap.
 305  
 
 306  
             The relationship element defines how primitive attributes of this
 307  
             class can be used to retrieve an instance of some related Object instance
 308  
             DD: See RelationshipDefinition.java.
 309  
 
 310  
             JSTL: relationship is a Map which is accessed using a key which is the
 311  
             objectAttributeName of a relationship.  The map contains a single entry
 312  
             with a key of "primitiveAttributes" and value which is an attributesMap ExportMap.
 313  
 
 314  
             The attributesMap ExportMap contains the following keys:
 315  
                 * 0   (for first primitiveAttribute)
 316  
                 * 1   (for second primitiveAttribute)
 317  
                 etc.
 318  
             The corresponding value for each entry is an primitiveAttribute ExportMap
 319  
             which contains the following keys:
 320  
                 * "sourceName"
 321  
                 * "targetName"
 322  
 
 323  
             See RelationshipsMapBuilder.java.
 324  
             
 325  
      */
 326  
     public void setRelationships(List<RelationshipDefinition> relationships) {
 327  0
         this.relationships = relationships;
 328  0
     }
 329  
 
 330  
     public Set<String> getCollectionNames() {
 331  0
         return collectionMap.keySet();
 332  
     }
 333  
     
 334  
     public Set<String> getAttributeNames() {
 335  0
         return attributeMap.keySet();
 336  
     }
 337  
 
 338  
     public Set<String> getRelationshipNames() {
 339  0
         return relationshipMap.keySet();
 340  
     }
 341  
     
 342  
     /**
 343  
      * This overridden method ...
 344  
      * 
 345  
      * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
 346  
      */
 347  
     public void afterPropertiesSet() throws Exception {
 348  0
             if ( relationships != null ) {
 349  0
             relationshipMap.clear();
 350  0
             for ( RelationshipDefinition relationship : relationships ) {            
 351  0
                 if (relationship == null) {
 352  0
                     throw new IllegalArgumentException("invalid (null) relationshipDefinition");
 353  
                 }
 354  0
                 String relationshipName = relationship.getObjectAttributeName();
 355  0
                 if (StringUtils.isBlank(relationshipName)) {
 356  0
                     throw new ValidationException("invalid (blank) relationshipName");
 357  
                 }
 358  0
                 relationship.setSourceClass(getEntryClass());
 359  0
                 relationshipMap.put(relationshipName, relationship);
 360  0
             }
 361  
             }
 362  
             
 363  
             //Populate attributes with nested attribute definitions
 364  0
             if (complexAttributes != null){
 365  0
                     for (ComplexAttributeDefinition complexAttribute:complexAttributes){
 366  0
                             addNestedAttributes(complexAttribute, complexAttribute.getName());
 367  
                     }
 368  
             }
 369  0
            }
 370  
     
 371  
     private void addNestedAttributes(ComplexAttributeDefinition complexAttribute, String attrPath){
 372  0
             DataDictionaryEntryBase dataDictionaryEntry = (DataDictionaryEntryBase)complexAttribute.getDataObjectEntry();
 373  
             
 374  
             //Add attributes for the complex attibutes
 375  0
             for (AttributeDefinition attribute:dataDictionaryEntry.getAttributes()){
 376  0
                     String nestedAttributeName = attrPath + "." + attribute.getName();
 377  0
                     AttributeDefinition nestedAttribute = copyAttributeDefinition(attribute);
 378  0
                     nestedAttribute.setName(nestedAttributeName);
 379  
                     
 380  0
                     if (!attributeMap.containsKey(nestedAttributeName)){
 381  0
                             this.attributes.add(nestedAttribute);
 382  0
                             this.attributeMap.put(nestedAttributeName, nestedAttribute);
 383  
                     }
 384  0
             }            
 385  
             
 386  
             //Recursively add complex attributes
 387  0
             List<ComplexAttributeDefinition> nestedComplexAttributes = dataDictionaryEntry.getComplexAttributes();
 388  0
             if (nestedComplexAttributes != null){
 389  0
                     for (ComplexAttributeDefinition nestedComplexAttribute:nestedComplexAttributes){
 390  0
                             addNestedAttributes(nestedComplexAttribute, attrPath + "." + nestedComplexAttribute.getName());
 391  
                     }
 392  
             }
 393  0
     }
 394  
     
 395  
     private AttributeDefinition copyAttributeDefinition(AttributeDefinition attrDefToCopy){
 396  0
             AttributeDefinition attrDefCopy = new AttributeDefinition();
 397  
             
 398  
             try {                    
 399  0
                         BeanUtils.copyProperties(attrDefToCopy, attrDefCopy, new String[] { "formatterClass" });
 400  
                         
 401  
                         //BeanUtils doesn't copy properties w/o "get" read methods, manually copy those here
 402  0
                         attrDefCopy.setRequired(attrDefToCopy.isRequired());
 403  
                         
 404  0
                 } catch (Exception e) {
 405  0
                         e.printStackTrace();
 406  0
                 }
 407  
                 
 408  0
                 return attrDefCopy;
 409  
     }
 410  
 }