Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
AttributeDefinition |
|
| 1.65;1.65 |
1 | /* | |
2 | * Copyright 2005-2008 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.math.BigDecimal; | |
20 | ||
21 | import org.apache.commons.lang.ClassUtils; | |
22 | import org.apache.commons.lang.StringUtils; | |
23 | import org.apache.log4j.Logger; | |
24 | import org.kuali.rice.core.util.ClassLoaderUtils; | |
25 | import org.kuali.rice.kns.datadictionary.control.ControlDefinition; | |
26 | import org.kuali.rice.kns.datadictionary.exception.AttributeValidationException; | |
27 | import org.kuali.rice.kns.datadictionary.exception.ClassValidationException; | |
28 | import org.kuali.rice.kns.datadictionary.validation.ValidationPattern; | |
29 | import org.kuali.rice.kns.web.format.Formatter; | |
30 | import org.springframework.beans.factory.InitializingBean; | |
31 | ||
32 | ||
33 | /** | |
34 | * A single attribute definition in the DataDictionary, which contains information relating to the display, validation, and general | |
35 | * maintenance of a specific attribute of an entry. | |
36 | * | |
37 | * | |
38 | */ | |
39 | public class AttributeDefinition extends DataDictionaryDefinitionBase implements InitializingBean { | |
40 | private static final long serialVersionUID = -2490613377818442742L; | |
41 | ||
42 | 0 | protected Boolean forceUppercase = Boolean.FALSE; |
43 | ||
44 | protected String name; | |
45 | protected String label; | |
46 | protected String shortLabel; | |
47 | protected String displayLabelAttribute; | |
48 | ||
49 | protected Integer maxLength; | |
50 | protected Boolean unique; | |
51 | ||
52 | protected BigDecimal exclusiveMin; | |
53 | protected BigDecimal inclusiveMax; | |
54 | ||
55 | protected ValidationPattern validationPattern; | |
56 | 0 | protected Boolean required = Boolean.FALSE; |
57 | ||
58 | protected ControlDefinition control; | |
59 | ||
60 | protected String summary; | |
61 | protected String description; | |
62 | ||
63 | protected String formatterClass; | |
64 | ||
65 | protected AttributeSecurity attributeSecurity; | |
66 | ||
67 | 0 | public AttributeDefinition() {} |
68 | ||
69 | ||
70 | /** | |
71 | * forceUppercase = convert user entry to uppercase and always display | |
72 | database value as uppercase. | |
73 | */ | |
74 | public void setForceUppercase(Boolean forceUppercase) { | |
75 | 0 | this.forceUppercase = forceUppercase; |
76 | 0 | } |
77 | ||
78 | public Boolean getForceUppercase() { | |
79 | 0 | return this.forceUppercase; |
80 | } | |
81 | ||
82 | public String getName() { | |
83 | 0 | return name; |
84 | } | |
85 | ||
86 | /* | |
87 | * name = name of attribute | |
88 | */ | |
89 | public void setName(String name) { | |
90 | 0 | if (StringUtils.isBlank(name)) { |
91 | 0 | throw new IllegalArgumentException("invalid (blank) name"); |
92 | } | |
93 | 0 | this.name = name; |
94 | 0 | } |
95 | ||
96 | public String getLabel() { | |
97 | 0 | return label; |
98 | } | |
99 | ||
100 | /** | |
101 | The label element is the field or collection name that will be shown on inquiry and | |
102 | maintenance screens. | |
103 | This will be overridden by presence of displayLabelAttribute element. | |
104 | */ | |
105 | public void setLabel(String label) { | |
106 | 0 | if (StringUtils.isBlank(label)) { |
107 | 0 | throw new IllegalArgumentException("invalid (blank) label"); |
108 | } | |
109 | 0 | this.label = label; |
110 | 0 | } |
111 | ||
112 | /** | |
113 | * @return the shortLabel, or the label if no shortLabel has been set | |
114 | */ | |
115 | public String getShortLabel() { | |
116 | 0 | return (shortLabel != null) ? shortLabel : getLabel(); |
117 | } | |
118 | ||
119 | /** | |
120 | * @return the shortLabel directly, without substituting in the label | |
121 | */ | |
122 | protected String getDirectShortLabel() { | |
123 | 0 | return shortLabel; |
124 | } | |
125 | ||
126 | /** | |
127 | The shortLabel element is the field or collection name that will be used | |
128 | in applications when a shorter name (than the label element) is required. | |
129 | This will be overridden by presence of displayLabelAttribute element. | |
130 | */ | |
131 | public void setShortLabel(String shortLabel) { | |
132 | 0 | if (StringUtils.isBlank(shortLabel)) { |
133 | 0 | throw new IllegalArgumentException("invalid (blank) shortLabel"); |
134 | } | |
135 | 0 | this.shortLabel = shortLabel; |
136 | 0 | } |
137 | ||
138 | public Integer getMaxLength() { | |
139 | 0 | return maxLength; |
140 | } | |
141 | ||
142 | /** | |
143 | The maxLength element determines the maximum size of the field | |
144 | for data entry edit purposes and for display purposes. | |
145 | */ | |
146 | public void setMaxLength(Integer maxLength) { | |
147 | 0 | this.maxLength = maxLength; |
148 | 0 | } |
149 | ||
150 | public BigDecimal getExclusiveMin() { | |
151 | 0 | return exclusiveMin; |
152 | } | |
153 | ||
154 | /** | |
155 | The exclusiveMin element determines the minimum allowable value | |
156 | for data entry editing purposes. Value can be an integer or decimal | |
157 | value such as -.001 or 99. | |
158 | */ | |
159 | public void setExclusiveMin(BigDecimal exclusiveMin) { | |
160 | 0 | this.exclusiveMin = exclusiveMin; |
161 | 0 | } |
162 | ||
163 | /** | |
164 | The inclusiveMax element determines the maximum allowable value | |
165 | for data entry editing purposes. Value can be an integer or decimal | |
166 | value such as -.001 or 99. | |
167 | ||
168 | JSTL: This field is mapped into the field named "exclusiveMax". | |
169 | */ | |
170 | public BigDecimal getInclusiveMax() { | |
171 | 0 | return inclusiveMax; |
172 | } | |
173 | ||
174 | /** | |
175 | The inclusiveMax element determines the maximum allowable value | |
176 | for data entry editing purposes. Value can be an integer or decimal | |
177 | value such as -.001 or 99. | |
178 | ||
179 | JSTL: This field is mapped into the field named "exclusiveMax". | |
180 | */ | |
181 | public void setInclusiveMax(BigDecimal inclusiveMax) { | |
182 | 0 | this.inclusiveMax = inclusiveMax; |
183 | 0 | } |
184 | ||
185 | /** | |
186 | * @return true if a validationPattern has been set | |
187 | */ | |
188 | public boolean hasValidationPattern() { | |
189 | 0 | return (validationPattern != null); |
190 | } | |
191 | ||
192 | public ValidationPattern getValidationPattern() { | |
193 | 0 | return this.validationPattern; |
194 | } | |
195 | ||
196 | /** | |
197 | The validationPattern element defines the allowable character-level | |
198 | or field-level values for an attribute. | |
199 | ||
200 | JSTL: validationPattern is a Map which is accessed using a key | |
201 | of "validationPattern". Each entry may contain some of the keys | |
202 | listed below. The keys that may be present for a given attribute | |
203 | are dependent upon the type of validationPattern. | |
204 | ||
205 | * maxLength (String) | |
206 | * exactLength | |
207 | * type | |
208 | * allowWhitespace | |
209 | * allowUnderscore | |
210 | * allowPeriod | |
211 | * validChars | |
212 | * precision | |
213 | * scale | |
214 | * allowNegative | |
215 | ||
216 | The allowable keys (in addition to type) for each type are: | |
217 | ****Type**** ***Keys*** | |
218 | alphanumeric exactLength | |
219 | maxLength | |
220 | allowWhitespace | |
221 | allowUnderscore | |
222 | allowPeriod | |
223 | ||
224 | alpha exactLength | |
225 | maxLength | |
226 | allowWhitespace | |
227 | ||
228 | anyCharacter exactLength | |
229 | maxLength | |
230 | allowWhitespace | |
231 | ||
232 | charset validChars | |
233 | ||
234 | numeric exactLength | |
235 | maxLength | |
236 | ||
237 | fixedPoint allowNegative | |
238 | precision | |
239 | scale | |
240 | ||
241 | floatingPoint allowNegative | |
242 | ||
243 | date n/a | |
244 | emailAddress n/a | |
245 | javaClass n/a | |
246 | month n/a | |
247 | phoneNumber n/a | |
248 | timestamp n/a | |
249 | year n/a | |
250 | zipcode n/a | |
251 | ||
252 | Note: maxLength and exactLength are mutually exclusive. | |
253 | If one is entered, the other may not be entered. | |
254 | ||
255 | Note: See ApplicationResources.properties for | |
256 | exact regex patterns. | |
257 | e.g. validationPatternRegex.date for regex used in date validation. | |
258 | */ | |
259 | public void setValidationPattern(ValidationPattern validationPattern) { | |
260 | 0 | this.validationPattern = validationPattern; |
261 | 0 | } |
262 | ||
263 | ||
264 | /** | |
265 | The required element allows values of "true" or "false". | |
266 | A value of "true" indicates that a value must be entered for this | |
267 | business object when creating or editing a new business object. | |
268 | */ | |
269 | public void setRequired(Boolean required) { | |
270 | 0 | this.required = required; |
271 | 0 | } |
272 | ||
273 | public Boolean isRequired() { | |
274 | 0 | return this.required; |
275 | } | |
276 | ||
277 | ||
278 | /** | |
279 | * @return control | |
280 | */ | |
281 | public ControlDefinition getControl() { | |
282 | 0 | return control; |
283 | } | |
284 | ||
285 | /** | |
286 | * The control element defines the manner in which an attribute is | |
287 | displayed and the manner in which the attribute value is entered. | |
288 | ||
289 | JSTL: control is a Map representing an HTML control. It is accessed | |
290 | using a key of "control". The table below shows the types of entries | |
291 | associated with each type of control. | |
292 | ||
293 | **Control Type** **Key** **Value** | |
294 | checkbox checkbox boolean String | |
295 | ||
296 | hidden hidden boolean String | |
297 | ||
298 | radio radio boolean String | |
299 | valuesFinder valuesFinder class name | |
300 | businessObjectClass String | |
301 | keyAttribute String | |
302 | labelAttribute String | |
303 | includeKeyInLabel boolean String | |
304 | ||
305 | select select boolean String | |
306 | valuesFinder valuesFinder class name | |
307 | businessObjectClass String | |
308 | keyAttribute String | |
309 | labelAttribute String | |
310 | includeBlankRow boolean String | |
311 | includeKeyInLabel boolean String | |
312 | ||
313 | apcSelect apcSelect boolean String | |
314 | paramNamespace String | |
315 | parameterDetailType String | |
316 | parameterName String | |
317 | ||
318 | text text boolean String | |
319 | size String | |
320 | ||
321 | textarea textarea boolean String | |
322 | rows | |
323 | cols | |
324 | ||
325 | currency currency boolean String | |
326 | size String | |
327 | formattedMaxLength String | |
328 | ||
329 | kualiUser kualiUser boolean String | |
330 | universalIdAttributeName String | |
331 | userIdAttributeName String | |
332 | personNameAttributeName String | |
333 | ||
334 | lookupHidden lookupHidden boolean String | |
335 | ||
336 | lookupReadonly lookupReadonly boolean String | |
337 | ||
338 | * @param control | |
339 | * @throws IllegalArgumentException if the given control is null | |
340 | */ | |
341 | public void setControl(ControlDefinition control) { | |
342 | 0 | if (control == null) { |
343 | 0 | throw new IllegalArgumentException("invalid (null) control"); |
344 | } | |
345 | 0 | this.control = control; |
346 | 0 | } |
347 | ||
348 | public String getSummary() { | |
349 | 0 | return summary; |
350 | } | |
351 | ||
352 | /** | |
353 | The summary element is used to provide a short description of the | |
354 | attribute or collection. This is designed to be used for help purposes. | |
355 | */ | |
356 | public void setSummary(String summary) { | |
357 | 0 | this.summary = summary; |
358 | 0 | } |
359 | ||
360 | public String getDescription() { | |
361 | 0 | return description; |
362 | } | |
363 | ||
364 | /** | |
365 | * The description element is used to provide a long description of the | |
366 | attribute or collection. This is designed to be used for help purposes. | |
367 | */ | |
368 | public void setDescription(String description) { | |
369 | 0 | this.description = description; |
370 | 0 | } |
371 | ||
372 | public boolean hasFormatterClass() { | |
373 | 0 | return (formatterClass != null); |
374 | } | |
375 | ||
376 | public String getFormatterClass() { | |
377 | 0 | return formatterClass; |
378 | } | |
379 | ||
380 | /** | |
381 | The formatterClass element is used when custom formatting is | |
382 | required for display of the field value. This field specifies | |
383 | the name of the java class to be used for the formatting. About | |
384 | 15 different classes are available including BooleanFormatter, | |
385 | CurrencyFormatter, DateFormatter, etc. | |
386 | */ | |
387 | public void setFormatterClass(String formatterClass) { | |
388 | 0 | if (formatterClass == null) { |
389 | 0 | throw new IllegalArgumentException("invalid (null) formatterClass"); |
390 | } | |
391 | 0 | this.formatterClass = formatterClass; |
392 | 0 | } |
393 | ||
394 | /** | |
395 | * Directly validate simple fields, call completeValidation on Definition fields. | |
396 | * | |
397 | * @see org.kuali.rice.kns.datadictionary.DataDictionaryEntry#completeValidation() | |
398 | */ | |
399 | public void completeValidation(Class rootObjectClass, Class otherObjectClass) { | |
400 | try { | |
401 | 0 | if (!DataDictionary.isPropertyOf(rootObjectClass, getName())) { |
402 | 0 | throw new AttributeValidationException("property '" + getName() + "' is not a property of class '" + rootObjectClass.getName() + "' (" + "" + ")"); |
403 | } | |
404 | ||
405 | 0 | if ( getControl() == null ) { |
406 | 0 | throw new AttributeValidationException( "property '" + getName() + "' in class '" + rootObjectClass.getName() + " does not have a control defined" ); |
407 | } | |
408 | ||
409 | 0 | getControl().completeValidation(rootObjectClass, otherObjectClass); |
410 | ||
411 | 0 | if(attributeSecurity != null){ |
412 | 0 | attributeSecurity.completeValidation(rootObjectClass, otherObjectClass); |
413 | } | |
414 | ||
415 | 0 | if (validationPattern != null) { |
416 | 0 | validationPattern.completeValidation(); |
417 | } | |
418 | ||
419 | 0 | if (formatterClass != null) { |
420 | try { | |
421 | 0 | Class formatterClassObject = ClassUtils.getClass(ClassLoaderUtils.getDefaultClassLoader(), getFormatterClass()); |
422 | 0 | if (!Formatter.class.isAssignableFrom(formatterClassObject)) { |
423 | 0 | throw new ClassValidationException("formatterClass is not a valid instance of " + Formatter.class.getName() + " instead was: " + formatterClassObject.getName()); |
424 | } | |
425 | 0 | } catch (ClassNotFoundException e) { |
426 | 0 | throw new ClassValidationException("formatterClass could not be found: " + getFormatterClass(), e); |
427 | 0 | } |
428 | } | |
429 | 0 | } catch ( RuntimeException ex ) { |
430 | 0 | Logger.getLogger(getClass()).error("Unable to validate attribute " + rootObjectClass + "." + getName() + ": " + ex.getMessage(), ex ); |
431 | 0 | throw ex; |
432 | 0 | } |
433 | 0 | } |
434 | ||
435 | ||
436 | /** | |
437 | * @see java.lang.Object#toString() | |
438 | */ | |
439 | @Override | |
440 | public String toString() { | |
441 | 0 | return "AttributeDefinition for attribute " + getName(); |
442 | } | |
443 | ||
444 | ||
445 | public String getDisplayLabelAttribute() { | |
446 | 0 | return displayLabelAttribute; |
447 | } | |
448 | ||
449 | ||
450 | /** | |
451 | The displayLabelAttribute element is used to indicate that the | |
452 | label and short label should be obtained from another attribute. | |
453 | ||
454 | The label element and short label element defined for this attribute | |
455 | will be overridden. Instead, the label and short label values | |
456 | will be obtained by referencing the corresponding values from the | |
457 | attribute indicated by this element. | |
458 | */ | |
459 | public void setDisplayLabelAttribute(String displayLabelAttribute) { | |
460 | 0 | this.displayLabelAttribute = displayLabelAttribute; |
461 | 0 | } |
462 | ||
463 | ||
464 | /** | |
465 | * @return the attributeSecurity | |
466 | */ | |
467 | public AttributeSecurity getAttributeSecurity() { | |
468 | 0 | return this.attributeSecurity; |
469 | } | |
470 | ||
471 | ||
472 | /** | |
473 | * @param attributeSecurity the attributeSecurity to set | |
474 | */ | |
475 | public void setAttributeSecurity(AttributeSecurity attributeSecurity) { | |
476 | 0 | this.attributeSecurity = attributeSecurity; |
477 | 0 | } |
478 | ||
479 | public boolean hasAttributeSecurity() { | |
480 | 0 | return (attributeSecurity != null); |
481 | } | |
482 | ||
483 | ||
484 | /** | |
485 | * This overridden method ... | |
486 | * | |
487 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() | |
488 | */ | |
489 | public void afterPropertiesSet() throws Exception { | |
490 | 0 | if ( StringUtils.isEmpty(name) ) { |
491 | 0 | throw new RuntimeException( "blank name for bean: " + id ); |
492 | } | |
493 | ||
494 | 0 | } |
495 | ||
496 | ||
497 | /** | |
498 | * @return the unique | |
499 | */ | |
500 | public Boolean getUnique() { | |
501 | 0 | return this.unique; |
502 | } | |
503 | ||
504 | ||
505 | /** | |
506 | * @param unique the unique to set | |
507 | */ | |
508 | public void setUnique(Boolean unique) { | |
509 | 0 | this.unique = unique; |
510 | 0 | } |
511 | } |