| 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 | } |