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