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