Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
AttributeDefinition |
|
| 1.46;1.46 |
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.util.List; | |
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.core.web.format.Formatter; | |
26 | import org.kuali.rice.kns.datadictionary.control.ControlDefinition; | |
27 | import org.kuali.rice.kns.datadictionary.exception.AttributeValidationException; | |
28 | import org.kuali.rice.kns.datadictionary.exception.ClassValidationException; | |
29 | import org.kuali.rice.kns.datadictionary.validation.DataType; | |
30 | import org.kuali.rice.kns.datadictionary.validation.ValidationPattern; | |
31 | import org.kuali.rice.kns.datadictionary.validation.capability.CaseConstrainable; | |
32 | import org.kuali.rice.kns.datadictionary.validation.capability.Formatable; | |
33 | import org.kuali.rice.kns.datadictionary.validation.capability.HierarchicallyConstrainable; | |
34 | import org.kuali.rice.kns.datadictionary.validation.capability.LengthConstrainable; | |
35 | import org.kuali.rice.kns.datadictionary.validation.capability.MustOccurConstrainable; | |
36 | import org.kuali.rice.kns.datadictionary.validation.capability.PrerequisiteConstrainable; | |
37 | import org.kuali.rice.kns.datadictionary.validation.capability.RangeConstrainable; | |
38 | import org.kuali.rice.kns.datadictionary.validation.capability.ValidCharactersConstrainable; | |
39 | import org.kuali.rice.kns.datadictionary.validation.constraint.CaseConstraint; | |
40 | import org.kuali.rice.kns.datadictionary.validation.constraint.LookupConstraint; | |
41 | import org.kuali.rice.kns.datadictionary.validation.constraint.MustOccurConstraint; | |
42 | import org.kuali.rice.kns.datadictionary.validation.constraint.PrerequisiteConstraint; | |
43 | import org.kuali.rice.kns.datadictionary.validation.constraint.ValidCharactersConstraint; | |
44 | import org.kuali.rice.kns.uif.control.Control; | |
45 | ||
46 | /** | |
47 | * A single attribute definition in the DataDictionary, which contains | |
48 | * information relating to the display, validation, and general maintenance of a | |
49 | * specific attribute of an entry. | |
50 | * | |
51 | * | |
52 | */ | |
53 | public class AttributeDefinition extends AttributeDefinitionBase implements CaseConstrainable, PrerequisiteConstrainable, Formatable, HierarchicallyConstrainable, MustOccurConstrainable, LengthConstrainable, RangeConstrainable, ValidCharactersConstrainable { | |
54 | private static final long serialVersionUID = -2490613377818442742L; | |
55 | ||
56 | 0 | protected Boolean forceUppercase = Boolean.FALSE; |
57 | ||
58 | protected DataType dataType; | |
59 | ||
60 | protected Integer minLength; | |
61 | protected Integer maxLength; | |
62 | protected Boolean unique; | |
63 | ||
64 | protected String exclusiveMin; | |
65 | protected String inclusiveMax; | |
66 | ||
67 | @Deprecated | |
68 | protected ValidationPattern validationPattern; | |
69 | ||
70 | protected ControlDefinition control; | |
71 | ||
72 | // TODO: rename to control once ControlDefinition is removed | |
73 | protected Control controlField; | |
74 | ||
75 | protected String formatterClass; | |
76 | ||
77 | protected AttributeSecurity attributeSecurity; | |
78 | // protected Constraint constraint; | |
79 | ||
80 | protected Boolean dynamic; | |
81 | ||
82 | // KS-style constraints | |
83 | protected String customValidatorClass; | |
84 | protected ValidCharactersConstraint validCharactersConstraint; | |
85 | protected CaseConstraint caseConstraint; | |
86 | protected List<PrerequisiteConstraint> dependencyConstraints; | |
87 | protected List<MustOccurConstraint> mustOccurConstraints; | |
88 | protected LookupConstraint lookupDefinition;// If the user wants to match | |
89 | // against two searches, that search must be defined as well | |
90 | protected String lookupContextPath; | |
91 | ||
92 | //TODO: This may not be required since we now use ComplexAttributeDefinition | |
93 | protected String childEntryName; | |
94 | ||
95 | ||
96 | 0 | public AttributeDefinition() { |
97 | // Empty | |
98 | 0 | } |
99 | ||
100 | /** | |
101 | * forceUppercase = convert user entry to uppercase and always display | |
102 | * database value as uppercase. | |
103 | */ | |
104 | public void setForceUppercase(Boolean forceUppercase) { | |
105 | 0 | this.forceUppercase = forceUppercase; |
106 | 0 | } |
107 | ||
108 | public Boolean getForceUppercase() { | |
109 | 0 | return this.forceUppercase; |
110 | } | |
111 | ||
112 | @Override | |
113 | public Integer getMaxLength() { | |
114 | 0 | return maxLength; |
115 | } | |
116 | ||
117 | /** | |
118 | * The maxLength element determines the maximum size of the field for data | |
119 | * entry edit purposes and for display purposes. | |
120 | */ | |
121 | public void setMaxLength(Integer maxLength) { | |
122 | 0 | this.maxLength = maxLength; |
123 | 0 | } |
124 | ||
125 | @Override | |
126 | public String getExclusiveMin() { | |
127 | 0 | return exclusiveMin; |
128 | } | |
129 | ||
130 | /** | |
131 | * The exclusiveMin element determines the minimum allowable value for data | |
132 | * entry editing purposes. Value can be an integer or decimal value such as | |
133 | * -.001 or 99. | |
134 | */ | |
135 | public void setExclusiveMin(String exclusiveMin) { | |
136 | 0 | this.exclusiveMin = exclusiveMin; |
137 | 0 | } |
138 | ||
139 | /** | |
140 | * The inclusiveMax element determines the maximum allowable value for data | |
141 | * entry editing purposes. Value can be an integer or decimal value such as | |
142 | * -.001 or 99. | |
143 | * | |
144 | * JSTL: This field is mapped into the field named "exclusiveMax". | |
145 | */ | |
146 | @Override | |
147 | public String getInclusiveMax() { | |
148 | 0 | return inclusiveMax; |
149 | } | |
150 | ||
151 | /** | |
152 | * The inclusiveMax element determines the maximum allowable value for data | |
153 | * entry editing purposes. Value can be an integer or decimal value such as | |
154 | * -.001 or 99. | |
155 | * | |
156 | * JSTL: This field is mapped into the field named "exclusiveMax". | |
157 | */ | |
158 | public void setInclusiveMax(String inclusiveMax) { | |
159 | 0 | this.inclusiveMax = inclusiveMax; |
160 | 0 | } |
161 | ||
162 | /** | |
163 | * @return true if a validationPattern has been set | |
164 | */ | |
165 | public boolean hasValidationPattern() { | |
166 | 0 | return (validationPattern != null); |
167 | } | |
168 | ||
169 | public ValidationPattern getValidationPattern() { | |
170 | 0 | return this.validationPattern; |
171 | } | |
172 | ||
173 | /** | |
174 | * The validationPattern element defines the allowable character-level or | |
175 | * field-level values for an attribute. | |
176 | * | |
177 | * JSTL: validationPattern is a Map which is accessed using a key of | |
178 | * "validationPattern". Each entry may contain some of the keys listed | |
179 | * below. The keys that may be present for a given attribute are dependent | |
180 | * upon the type of validationPattern. | |
181 | * | |
182 | * maxLength (String) exactLength type allowWhitespace allowUnderscore | |
183 | * allowPeriod validChars precision scale allowNegative | |
184 | * | |
185 | * The allowable keys (in addition to type) for each type are: Type**** | |
186 | * ***Keys*** alphanumeric exactLength maxLength allowWhitespace | |
187 | * allowUnderscore allowPeriod | |
188 | * | |
189 | * alpha exactLength maxLength allowWhitespace | |
190 | * | |
191 | * anyCharacter exactLength maxLength allowWhitespace | |
192 | * | |
193 | * charset validChars | |
194 | * | |
195 | * numeric exactLength maxLength | |
196 | * | |
197 | * fixedPoint allowNegative precision scale | |
198 | * | |
199 | * floatingPoint allowNegative | |
200 | * | |
201 | * date n/a emailAddress n/a javaClass n/a month n/a phoneNumber n/a | |
202 | * timestamp n/a year n/a zipcode n/a | |
203 | * | |
204 | * Note: maxLength and exactLength are mutually exclusive. If one is | |
205 | * entered, the other may not be entered. | |
206 | * | |
207 | * Note: See ApplicationResources.properties for exact regex patterns. e.g. | |
208 | * validationPatternRegex.date for regex used in date validation. | |
209 | */ | |
210 | public void setValidationPattern(ValidationPattern validationPattern) { | |
211 | 0 | this.validationPattern = validationPattern; |
212 | ||
213 | // FIXME: JLR - need to recreate this functionality using the ValidCharsConstraint logic | |
214 | 0 | } |
215 | ||
216 | ||
217 | /** | |
218 | * @return control | |
219 | */ | |
220 | public ControlDefinition getControl() { | |
221 | 0 | return control; |
222 | } | |
223 | ||
224 | /** | |
225 | * The control element defines the manner in which an attribute is displayed | |
226 | * and the manner in which the attribute value is entered. | |
227 | * | |
228 | * JSTL: control is a Map representing an HTML control. It is accessed using | |
229 | * a key of "control". The table below shows the types of entries associated | |
230 | * with each type of control. | |
231 | * | |
232 | ** Control Type** **Key** **Value** checkbox checkbox boolean String | |
233 | * | |
234 | * hidden hidden boolean String | |
235 | * | |
236 | * radio radio boolean String valuesFinder valuesFinder class name | |
237 | * businessObjectClass String keyAttribute String labelAttribute String | |
238 | * includeKeyInLabel boolean String | |
239 | * | |
240 | * select select boolean String valuesFinder valuesFinder class name | |
241 | * businessObjectClass String keyAttribute String labelAttribute String | |
242 | * includeBlankRow boolean String includeKeyInLabel boolean String | |
243 | * | |
244 | * apcSelect apcSelect boolean String paramNamespace String | |
245 | * parameterDetailType String parameterName String | |
246 | * | |
247 | * text text boolean String size String | |
248 | * | |
249 | * textarea textarea boolean String rows cols | |
250 | * | |
251 | * currency currency boolean String size String formattedMaxLength String | |
252 | * | |
253 | * kualiUser kualiUser boolean String universalIdAttributeName String | |
254 | * userIdAttributeName String personNameAttributeName String | |
255 | * | |
256 | * lookupHidden lookupHidden boolean String | |
257 | * | |
258 | * lookupReadonly lookupReadonly boolean String | |
259 | * | |
260 | * @param control | |
261 | * @throws IllegalArgumentException | |
262 | * if the given control is null | |
263 | */ | |
264 | public void setControl(ControlDefinition control) { | |
265 | 0 | if (control == null) { |
266 | 0 | throw new IllegalArgumentException("invalid (null) control"); |
267 | } | |
268 | 0 | this.control = control; |
269 | 0 | } |
270 | ||
271 | public boolean hasFormatterClass() { | |
272 | 0 | return (formatterClass != null); |
273 | } | |
274 | ||
275 | @Override | |
276 | public String getFormatterClass() { | |
277 | 0 | return formatterClass; |
278 | } | |
279 | ||
280 | /** | |
281 | * The formatterClass element is used when custom formatting is required for | |
282 | * display of the field value. This field specifies the name of the java | |
283 | * class to be used for the formatting. About 15 different classes are | |
284 | * available including BooleanFormatter, CurrencyFormatter, DateFormatter, | |
285 | * etc. | |
286 | */ | |
287 | public void setFormatterClass(String formatterClass) { | |
288 | 0 | if (formatterClass == null) { |
289 | 0 | throw new IllegalArgumentException("invalid (null) formatterClass"); |
290 | } | |
291 | 0 | this.formatterClass = formatterClass; |
292 | 0 | } |
293 | ||
294 | /** | |
295 | * Directly validate simple fields, call completeValidation on Definition | |
296 | * fields. | |
297 | * | |
298 | * @see org.kuali.rice.kns.datadictionary.DataDictionaryEntry#completeValidation() | |
299 | */ | |
300 | @Override | |
301 | public void completeValidation(Class<?> rootObjectClass, Class<?> otherObjectClass) { | |
302 | try { | |
303 | 0 | if (!DataDictionary.isPropertyOf(rootObjectClass, getName())) { |
304 | 0 | throw new AttributeValidationException("property '" + getName() + "' is not a property of class '" |
305 | + rootObjectClass.getName() + "' (" + "" + ")"); | |
306 | } | |
307 | ||
308 | //TODO currently requiring a control or controlField, but this should not be case (AttrField should probably do the check) | |
309 | 0 | if (getControl() == null && getControlField() == null) { |
310 | 0 | throw new AttributeValidationException("property '" + getName() + "' in class '" |
311 | + rootObjectClass.getName() + " does not have a control defined"); | |
312 | } | |
313 | ||
314 | 0 | if(getControl() != null) { |
315 | 0 | getControl().completeValidation(rootObjectClass, otherObjectClass); |
316 | } | |
317 | ||
318 | 0 | if (attributeSecurity != null) { |
319 | 0 | attributeSecurity.completeValidation(rootObjectClass, otherObjectClass); |
320 | } | |
321 | ||
322 | 0 | if (validationPattern != null) { |
323 | 0 | validationPattern.completeValidation(); |
324 | } | |
325 | ||
326 | 0 | if (formatterClass != null) { |
327 | try { | |
328 | 0 | Class formatterClassObject = ClassUtils.getClass(ClassLoaderUtils.getDefaultClassLoader(), |
329 | getFormatterClass()); | |
330 | 0 | if (!Formatter.class.isAssignableFrom(formatterClassObject)) { |
331 | 0 | throw new ClassValidationException("formatterClass is not a valid instance of " |
332 | + Formatter.class.getName() + " instead was: " + formatterClassObject.getName()); | |
333 | } | |
334 | } | |
335 | 0 | catch (ClassNotFoundException e) { |
336 | 0 | throw new ClassValidationException("formatterClass could not be found: " + getFormatterClass(), e); |
337 | 0 | } |
338 | } | |
339 | } | |
340 | 0 | catch (RuntimeException ex) { |
341 | 0 | Logger.getLogger(getClass()).error( |
342 | "Unable to validate attribute " + rootObjectClass + "." + getName() + ": " + ex.getMessage(), ex); | |
343 | 0 | throw ex; |
344 | 0 | } |
345 | 0 | } |
346 | ||
347 | /** | |
348 | * @see java.lang.Object#toString() | |
349 | */ | |
350 | @Override | |
351 | public String toString() { | |
352 | 0 | return "AttributeDefinition for attribute " + getName(); |
353 | } | |
354 | ||
355 | /** | |
356 | * @return the attributeSecurity | |
357 | */ | |
358 | public AttributeSecurity getAttributeSecurity() { | |
359 | 0 | return this.attributeSecurity; |
360 | } | |
361 | ||
362 | /** | |
363 | * @param attributeSecurity | |
364 | * the attributeSecurity to set | |
365 | */ | |
366 | public void setAttributeSecurity(AttributeSecurity attributeSecurity) { | |
367 | 0 | this.attributeSecurity = attributeSecurity; |
368 | 0 | } |
369 | ||
370 | public boolean hasAttributeSecurity() { | |
371 | 0 | return (attributeSecurity != null); |
372 | } | |
373 | ||
374 | /** | |
375 | * This overridden method ... | |
376 | * | |
377 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() | |
378 | */ | |
379 | @Override | |
380 | public void afterPropertiesSet() throws Exception { | |
381 | 0 | if (StringUtils.isEmpty(name)) { |
382 | 0 | throw new RuntimeException("blank name for bean: " + id); |
383 | } | |
384 | ||
385 | 0 | if (validationPattern != null) { |
386 | 0 | if (validCharactersConstraint == null) { |
387 | 0 | validCharactersConstraint = new ValidCharactersConstraint(); |
388 | } | |
389 | ||
390 | 0 | validCharactersConstraint.setValue(new StringBuilder().append("regex:").append(validationPattern.getRegexPattern()).toString()); |
391 | } | |
392 | 0 | } |
393 | ||
394 | /** | |
395 | * @return the unique | |
396 | */ | |
397 | public Boolean getUnique() { | |
398 | 0 | return this.unique; |
399 | } | |
400 | ||
401 | /** | |
402 | * @param unique | |
403 | * the unique to set | |
404 | */ | |
405 | public void setUnique(Boolean unique) { | |
406 | 0 | this.unique = unique; |
407 | 0 | } |
408 | ||
409 | /** | |
410 | * Default <code>Control</code> to use when the attribute is to be rendered | |
411 | * for the UI. Used by the UIF when a control is not defined for an | |
412 | * <code>AttributeField</code> | |
413 | * | |
414 | * @return Control instance | |
415 | */ | |
416 | public Control getControlField() { | |
417 | 0 | return this.controlField; |
418 | } | |
419 | ||
420 | /** | |
421 | * Setter for the default control | |
422 | * | |
423 | * @param controlField | |
424 | */ | |
425 | public void setControlField(Control controlField) { | |
426 | 0 | this.controlField = controlField; |
427 | 0 | } |
428 | ||
429 | /** | |
430 | * @return the minLength | |
431 | */ | |
432 | public Integer getMinLength() { | |
433 | 0 | return this.minLength; |
434 | } | |
435 | ||
436 | /** | |
437 | * @param minLength the minLength to set | |
438 | */ | |
439 | public void setMinLength(Integer minLength) { | |
440 | 0 | this.minLength = minLength; |
441 | 0 | } |
442 | ||
443 | /** | |
444 | * @return the dataType | |
445 | */ | |
446 | @Override | |
447 | public DataType getDataType() { | |
448 | 0 | return this.dataType; |
449 | } | |
450 | ||
451 | /** | |
452 | * @param dataType the dataType to set | |
453 | */ | |
454 | public void setDataType(DataType dataType) { | |
455 | 0 | this.dataType = dataType; |
456 | 0 | } |
457 | ||
458 | public void setDataType(String dataType) { | |
459 | 0 | this.dataType = DataType.valueOf(dataType); |
460 | 0 | } |
461 | ||
462 | /** | |
463 | * @return the customValidatorClass | |
464 | */ | |
465 | public String getCustomValidatorClass() { | |
466 | 0 | return this.customValidatorClass; |
467 | } | |
468 | ||
469 | /** | |
470 | * @param customValidatorClass the customValidatorClass to set | |
471 | */ | |
472 | public void setCustomValidatorClass(String customValidatorClass) { | |
473 | 0 | this.customValidatorClass = customValidatorClass; |
474 | 0 | } |
475 | ||
476 | /** | |
477 | * @return the validChars | |
478 | */ | |
479 | @Override | |
480 | public ValidCharactersConstraint getValidCharactersConstraint() { | |
481 | 0 | return this.validCharactersConstraint; |
482 | } | |
483 | ||
484 | /** | |
485 | * @param validCharactersConstraint the validChars to set | |
486 | */ | |
487 | public void setValidCharactersConstraint(ValidCharactersConstraint validCharactersConstraint) { | |
488 | 0 | this.validCharactersConstraint = validCharactersConstraint; |
489 | 0 | } |
490 | ||
491 | /** | |
492 | * @return the caseConstraint | |
493 | */ | |
494 | @Override | |
495 | public CaseConstraint getCaseConstraint() { | |
496 | 0 | return this.caseConstraint; |
497 | } | |
498 | ||
499 | /** | |
500 | * @param caseConstraint the caseConstraint to set | |
501 | */ | |
502 | public void setCaseConstraint(CaseConstraint caseConstraint) { | |
503 | 0 | this.caseConstraint = caseConstraint; |
504 | 0 | } |
505 | ||
506 | /** | |
507 | * @return the requireConstraint | |
508 | */ | |
509 | @Override | |
510 | public List<PrerequisiteConstraint> getPrerequisiteConstraints() { | |
511 | 0 | return this.dependencyConstraints; |
512 | } | |
513 | ||
514 | /** | |
515 | * @param dependencyConstraints the requireConstraint to set | |
516 | */ | |
517 | public void setPrerequisiteConstraints(List<PrerequisiteConstraint> dependencyConstraints) { | |
518 | 0 | this.dependencyConstraints = dependencyConstraints; |
519 | 0 | } |
520 | ||
521 | /** | |
522 | * @return the occursConstraint | |
523 | */ | |
524 | @Override | |
525 | public List<MustOccurConstraint> getMustOccurConstraints() { | |
526 | 0 | return this.mustOccurConstraints; |
527 | } | |
528 | ||
529 | /** | |
530 | * @param mustOccurConstraints the occursConstraint to set | |
531 | */ | |
532 | public void setMustOccurConstraints(List<MustOccurConstraint> mustOccurConstraints) { | |
533 | 0 | this.mustOccurConstraints = mustOccurConstraints; |
534 | 0 | } |
535 | ||
536 | /** | |
537 | * @return the lookupDefinition | |
538 | */ | |
539 | public LookupConstraint getLookupDefinition() { | |
540 | 0 | return this.lookupDefinition; |
541 | } | |
542 | ||
543 | /** | |
544 | * @param lookupDefinition the lookupDefinition to set | |
545 | */ | |
546 | public void setLookupDefinition(LookupConstraint lookupDefinition) { | |
547 | 0 | this.lookupDefinition = lookupDefinition; |
548 | 0 | } |
549 | ||
550 | /** | |
551 | * @return the lookupContextPath | |
552 | */ | |
553 | public String getLookupContextPath() { | |
554 | 0 | return this.lookupContextPath; |
555 | } | |
556 | ||
557 | /** | |
558 | * @param lookupContextPath the lookupContextPath to set | |
559 | */ | |
560 | public void setLookupContextPath(String lookupContextPath) { | |
561 | 0 | this.lookupContextPath = lookupContextPath; |
562 | 0 | } |
563 | ||
564 | /** | |
565 | * @return the childEntryName | |
566 | */ | |
567 | public String getChildEntryName() { | |
568 | 0 | return this.childEntryName; |
569 | } | |
570 | ||
571 | /** | |
572 | * @param childEntryName the childEntryName to set | |
573 | */ | |
574 | public void setChildEntryName(String childEntryName) { | |
575 | 0 | this.childEntryName = childEntryName; |
576 | 0 | } |
577 | ||
578 | /** | |
579 | * @return the constraintMessage | |
580 | */ | |
581 | public String getConstraint() { | |
582 | 0 | return this.constraint; |
583 | } | |
584 | ||
585 | /** | |
586 | * @param constraintMessage the constraintMessage to set | |
587 | */ | |
588 | public void setConstraint(String constraint) { | |
589 | 0 | this.constraint = constraint; |
590 | 0 | } |
591 | ||
592 | // /** | |
593 | // * @return the constraint | |
594 | // */ | |
595 | // public Constraint getConstraint() { | |
596 | // return this.constraint; | |
597 | // } | |
598 | // | |
599 | // /** | |
600 | // * @param constraint the constraint to set | |
601 | // */ | |
602 | // public void setConstraint(Constraint constraint) { | |
603 | // this.constraint = constraint; | |
604 | // } | |
605 | ||
606 | } |