001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.krad.datadictionary;
017
018 import org.apache.commons.lang.ClassUtils;
019 import org.apache.commons.lang.StringUtils;
020 import org.apache.log4j.Logger;
021 import org.kuali.rice.core.api.uif.DataType;
022 import org.kuali.rice.core.api.util.ClassLoaderUtils;
023 import org.kuali.rice.core.web.format.Formatter;
024 import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
025 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
026 import org.kuali.rice.krad.datadictionary.exception.ClassValidationException;
027 import org.kuali.rice.krad.datadictionary.parse.BeanTag;
028 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
029 import org.kuali.rice.krad.datadictionary.validation.ValidationPattern;
030 import org.kuali.rice.krad.datadictionary.validation.capability.CaseConstrainable;
031 import org.kuali.rice.krad.datadictionary.validation.capability.Formatable;
032 import org.kuali.rice.krad.datadictionary.validation.capability.HierarchicallyConstrainable;
033 import org.kuali.rice.krad.datadictionary.validation.capability.MustOccurConstrainable;
034 import org.kuali.rice.krad.datadictionary.validation.capability.PrerequisiteConstrainable;
035 import org.kuali.rice.krad.datadictionary.validation.capability.ValidCharactersConstrainable;
036 import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
037 import org.kuali.rice.krad.datadictionary.validation.constraint.LookupConstraint;
038 import org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint;
039 import org.kuali.rice.krad.datadictionary.validation.constraint.PrerequisiteConstraint;
040 import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
041 import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
042 import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
043 import org.kuali.rice.krad.uif.control.Control;
044 import org.kuali.rice.krad.util.ObjectUtils;
045
046 import java.beans.PropertyEditor;
047 import java.util.List;
048
049 /**
050 * A single attribute definition in the DataDictionary, which contains
051 * information relating to the display, validation, and general maintenance of a
052 * specific attribute of an entry.
053 *
054 * @author Kuali Rice Team (rice.collab@kuali.org)
055 */
056 @BeanTag(name = "attributeDefinition-bean")
057 public class AttributeDefinition extends AttributeDefinitionBase implements CaseConstrainable, PrerequisiteConstrainable, Formatable, HierarchicallyConstrainable, MustOccurConstrainable, ValidCharactersConstrainable {
058 private static final long serialVersionUID = -2490613377818442742L;
059
060 protected Boolean forceUppercase = Boolean.FALSE;
061
062 protected DataType dataType;
063
064 protected Boolean unique;
065
066 //These are deprecated DO NOT USE with new KRAD implementations
067 @Deprecated
068 protected ValidationPattern validationPattern;
069
070 protected ControlDefinition control;
071
072 // TODO: rename to control once ControlDefinition is removed
073 protected Control controlField;
074
075 protected String formatterClass;
076 protected PropertyEditor propertyEditor;
077
078 protected AttributeSecurity attributeSecurity;
079
080 protected Boolean dynamic;
081
082 // KRAD constraints
083 protected String customValidatorClass;
084 protected ValidCharactersConstraint validCharactersConstraint;
085 protected CaseConstraint caseConstraint;
086 protected List<PrerequisiteConstraint> dependencyConstraints;
087 protected List<MustOccurConstraint> mustOccurConstraints;
088 // if the user wants to match against two searches, that search must be defined as well
089 protected LookupConstraint lookupDefinition;
090 protected String lookupContextPath;
091
092 //TODO: This may not be required since we now use ComplexAttributeDefinition
093 protected String childEntryName;
094
095 private KeyValuesFinder optionsFinder;
096
097 protected String alternateDisplayAttributeName;
098 protected String additionalDisplayAttributeName;
099
100 public AttributeDefinition() {
101 super();
102 }
103
104 /**
105 * Setter for force upper case
106 *
107 * @param forceUppercase
108 */
109 public void setForceUppercase(Boolean forceUppercase) {
110 this.forceUppercase = forceUppercase;
111 }
112
113 /**
114 * Indicates whether user entry should be converted to upper case
115 *
116 * <p>
117 * If set all user input will be changed to uppercase. Values from the database will also be forced to display
118 * as upper case and thus be persisted as upper case.
119 * </p>
120 *
121 * @return boolean true if force upper case is set
122 */
123 @BeanTagAttribute(name = "forceUppercase")
124 public Boolean getForceUppercase() {
125 return this.forceUppercase;
126 }
127
128 /**
129 * @see org.kuali.rice.krad.datadictionary.validation.constraint.LengthConstraint#getMaxLength()
130 */
131 @BeanTagAttribute(name = "maxLength")
132 public Integer getMaxLength() {
133 return this.getSimpleConstraint().getMaxLength();
134 }
135
136 /**
137 * Setter for maximum length
138 *
139 * @param maxLength
140 */
141 public void setMaxLength(Integer maxLength) {
142 this.getSimpleConstraint().setMaxLength(maxLength);
143 }
144
145 /**
146 * @see org.kuali.rice.krad.datadictionary.validation.constraint.RangeConstraint#getExclusiveMin()
147 */
148 @BeanTagAttribute(name = "exclusiveMin")
149 public String getExclusiveMin() {
150 return this.getSimpleConstraint().getExclusiveMin();
151 }
152
153 /**
154 * Setter for minimum value
155 *
156 * @param exclusiveMin - minimum allowed value
157 */
158 public void setExclusiveMin(String exclusiveMin) {
159 this.getSimpleConstraint().setExclusiveMin(exclusiveMin);
160 }
161
162 /**
163 * @see org.kuali.rice.krad.datadictionary.validation.constraint.RangeConstraint#getInclusiveMax()
164 */
165 @BeanTagAttribute(name = "inclusiveMax")
166 public String getInclusiveMax() {
167 return this.getSimpleConstraint().getInclusiveMax();
168 }
169
170 /**
171 * Setter for maximum value
172 *
173 * @param inclusiveMax - max allowed value
174 */
175 public void setInclusiveMax(String inclusiveMax) {
176 this.getSimpleConstraint().setInclusiveMax(inclusiveMax);
177 }
178
179 /**
180 * The validationPattern element defines the allowable character-level or
181 * field-level values for an attribute.
182 *
183 * JSTL: validationPattern is a Map which is accessed using a key of
184 * "validationPattern". Each entry may contain some of the keys listed
185 * below. The keys that may be present for a given attribute are dependent
186 * upon the type of validationPattern.
187 *
188 * maxLength (String) exactLength type allowWhitespace allowUnderscore
189 * allowPeriod validChars precision scale allowNegative
190 *
191 * The allowable keys (in addition to type) for each type are: Type****
192 * ***Keys*** alphanumeric exactLength maxLength allowWhitespace
193 * allowUnderscore allowPeriod
194 *
195 * alpha exactLength maxLength allowWhitespace
196 *
197 * anyCharacter exactLength maxLength allowWhitespace
198 *
199 * charset validChars
200 *
201 * numeric exactLength maxLength
202 *
203 * fixedPoint allowNegative precision scale
204 *
205 * floatingPoint allowNegative
206 *
207 * date n/a emailAddress n/a javaClass n/a month n/a phoneNumber n/a
208 * timestamp n/a year n/a zipcode n/a
209 *
210 * Note: maxLength and exactLength are mutually exclusive. If one is
211 * entered, the other may not be entered.
212 *
213 * Note: See ApplicationResources.properties for exact regex patterns. e.g.
214 * validationPatternRegex.date for regex used in date validation.
215 */
216 public void setValidationPattern(ValidationPattern validationPattern) {
217 this.validationPattern = validationPattern;
218 }
219
220 /**
221 * Indicates whether a validation pattern has been set
222 * @return boolean
223 */
224 public boolean hasValidationPattern() {
225 return (validationPattern != null);
226 }
227
228 /**
229 * Defines the allowable character-level or
230 * field-level values for an attribute
231 *
232 * <p>
233 * ValidationPattern is a Map which is accessed using a key of "validationPattern". Each entry may contain
234 * some of the keys listed below. The keys that may be present for a given attribute are dependent
235 * upon the type of validationPattern.
236 *
237 * maxLength (String) exactLength type allowWhitespace allowUnderscore
238 * allowPeriod validChars precision scale allowNegative
239 *
240 * The allowable keys (in addition to type) for each type are: Type****
241 * ***Keys*** alphanumeric exactLength maxLength allowWhitespace
242 * allowUnderscore allowPeriod
243 *
244 * alpha exactLength maxLength allowWhitespace
245 *
246 * anyCharacter exactLength maxLength allowWhitespace
247 *
248 * charset validChars
249 *
250 * numeric exactLength maxLength
251 *
252 * fixedPoint allowNegative precision scale
253 *
254 * floatingPoint allowNegative
255 *
256 * date n/a emailAddress n/a javaClass n/a month n/a phoneNumber n/a
257 * timestamp n/a year n/a zipcode n/a
258 *
259 * Note: maxLength and exactLength are mutually exclusive. If one is
260 * entered, the other may not be entered.
261 *
262 * Note: See ApplicationResources.properties for exact regex patterns. e.g.
263 * validationPatternRegex.date for regex used in date validation.
264 * </p>
265 *
266 * @return ValidationPattern
267 */
268 public ValidationPattern getValidationPattern() {
269 return this.validationPattern;
270 }
271
272 /**
273 * @return control
274 */
275 @BeanTagAttribute(name = "oldControl", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
276 public ControlDefinition getControl() {
277 return control;
278 }
279
280 /**
281 * The control element defines the manner in which an attribute is displayed
282 * and the manner in which the attribute value is entered.
283 *
284 * JSTL: control is a Map representing an HTML control. It is accessed using
285 * a key of "control". The table below shows the types of entries associated
286 * with each type of control.
287 *
288 * * Control Type** **Key** **Value** checkbox checkbox boolean String
289 *
290 * hidden hidden boolean String
291 *
292 * radio radio boolean String valuesFinder valuesFinder class name
293 * dataObjectClass String keyAttribute String labelAttribute String
294 * includeKeyInLabel boolean String
295 *
296 * select select boolean String valuesFinder valuesFinder class name
297 * dataObjectClass String keyAttribute String labelAttribute String
298 * includeBlankRow boolean String includeKeyInLabel boolean String
299 *
300 * apcSelect apcSelect boolean String paramNamespace String
301 * parameterDetailType String parameterName String
302 *
303 * text text boolean String size String
304 *
305 * textarea textarea boolean String rows cols
306 *
307 * currency currency boolean String size String formattedMaxLength String
308 *
309 * kualiUser kualiUser boolean String universalIdAttributeName String
310 * userIdAttributeName String personNameAttributeName String
311 *
312 * lookupHidden lookupHidden boolean String
313 *
314 * lookupReadonly lookupReadonly boolean String
315 *
316 * @param control
317 * @throws IllegalArgumentException if the given control is null
318 */
319 public void setControl(ControlDefinition control) {
320 if (control == null) {
321 throw new IllegalArgumentException("invalid (null) control");
322 }
323 this.control = control;
324 }
325
326 public boolean hasFormatterClass() {
327 return (formatterClass != null);
328 }
329
330 @Override
331 @BeanTagAttribute(name = "formatterClass")
332 public String getFormatterClass() {
333 return formatterClass;
334 }
335
336 /**
337 * The formatterClass element is used when custom formatting is required for
338 * display of the field value. This field specifies the name of the java
339 * class to be used for the formatting. About 15 different classes are
340 * available including BooleanFormatter, CurrencyFormatter, DateFormatter,
341 * etc.
342 */
343 public void setFormatterClass(String formatterClass) {
344 if (formatterClass == null) {
345 throw new IllegalArgumentException("invalid (null) formatterClass");
346 }
347 this.formatterClass = formatterClass;
348 }
349
350 /**
351 * Performs formatting of the field value for display and then converting the value back to its
352 * expected type from a string
353 *
354 * <p>
355 * Note property editors exist and are already registered for the basic Java types and the
356 * common Kuali types such as [@link KualiDecimal}. Registration with this property is only
357 * needed for custom property editors
358 * </p>
359 *
360 * @return PropertyEditor property editor instance to use for this field
361 */
362 @BeanTagAttribute(name = "propertyEditor", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
363 public PropertyEditor getPropertyEditor() {
364 return propertyEditor;
365 }
366
367 /**
368 * Setter for the custom property editor to use for the field
369 *
370 * @param propertyEditor
371 */
372 public void setPropertyEditor(PropertyEditor propertyEditor) {
373 this.propertyEditor = propertyEditor;
374 }
375
376 /**
377 * Convenience setter for configuring a property editor by class
378 *
379 * @param propertyEditorClass
380 */
381 public void setPropertyEditorClass(Class<? extends PropertyEditor> propertyEditorClass) {
382 this.propertyEditor = ObjectUtils.newInstance(propertyEditorClass);
383 }
384
385 /**
386 * Directly validate simple fields, call completeValidation on Definition
387 * fields.
388 *
389 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#completeValidation()
390 */
391 @Override
392 @Deprecated
393 public void completeValidation(Class<?> rootObjectClass, Class<?> otherObjectClass) {
394 try {
395 if (!DataDictionary.isPropertyOf(rootObjectClass, getName())) {
396 throw new AttributeValidationException("property '"
397 + getName()
398 + "' is not a property of class '"
399 + rootObjectClass.getName()
400 + "' ("
401 + ""
402 + ")");
403 }
404
405 //TODO currently requiring a control or controlField, but this should not be case (AttrField should probably do the check)
406 if (getControl() == null && getControlField() == null) {
407 throw new AttributeValidationException("property '"
408 + getName()
409 + "' in class '"
410 + rootObjectClass.getName()
411 + " does not have a control defined");
412 }
413
414 if (getControl() != null) {
415 getControl().completeValidation(rootObjectClass, otherObjectClass);
416 }
417
418 if (attributeSecurity != null) {
419 attributeSecurity.completeValidation(rootObjectClass, otherObjectClass);
420 }
421
422 if (validationPattern != null) {
423 validationPattern.completeValidation();
424 }
425
426 if (formatterClass != null) {
427 try {
428 Class formatterClassObject = ClassUtils.getClass(ClassLoaderUtils.getDefaultClassLoader(),
429 getFormatterClass());
430 if (!Formatter.class.isAssignableFrom(formatterClassObject)) {
431 throw new ClassValidationException("formatterClass is not a valid instance of "
432 + Formatter.class.getName()
433 + " instead was: "
434 + formatterClassObject.getName());
435 }
436 } catch (ClassNotFoundException e) {
437 throw new ClassValidationException("formatterClass could not be found: " + getFormatterClass(), e);
438 }
439 }
440 } catch (RuntimeException ex) {
441 Logger.getLogger(getClass()).error(
442 "Unable to validate attribute " + rootObjectClass + "." + getName() + ": " + ex.getMessage(), ex);
443 throw ex;
444 }
445 }
446
447 /**
448 * Directly validate simple fields, call completeValidation on Definition
449 * fields.
450 *
451 * @see org.kuali.rice.krad.datadictionary.DataDictionaryEntry#completeValidation(org.kuali.rice.krad.datadictionary.validator.ValidationTrace)
452 */
453 public void completeValidation(Class rootObjectClass, Class otherObjectClass, ValidationTrace tracer) {
454 tracer.addBean(this.getClass().getSimpleName(), "Attribute: " + getName());
455 try {
456 if (!DataDictionary.isPropertyOf(rootObjectClass, getName())) {
457 String currentValues[] = {"property = " + getName(), "class = " + rootObjectClass.getName()};
458 tracer.createError("Property is not found in class", currentValues);
459 }
460
461 //TODO currently requiring a control or controlField, but this should not be case (AttrField should probably do the check)
462 if (getControl() == null && getControlField() == null) {
463 String currentValues[] = {"property = " + getName(), "class = " + rootObjectClass.getName()};
464 tracer.createError("Property does not have a control defined in the class", currentValues);
465 }
466
467 if (getControl() != null) {
468 //getControl().completeValidation(rootObjectClass, otherObjectClass, tracer.getCopy());
469 }
470
471 if (attributeSecurity != null) {
472 attributeSecurity.completeValidation(rootObjectClass, otherObjectClass, tracer.getCopy());
473 }
474
475 if (validationPattern != null) {
476 // validationPattern.completeValidation(tracer.getCopy());
477 }
478
479 if (formatterClass != null) {
480 try {
481 Class formatterClassObject = ClassUtils.getClass(ClassLoaderUtils.getDefaultClassLoader(),
482 getFormatterClass());
483 if (!Formatter.class.isAssignableFrom(formatterClassObject)) {
484 String currentValues[] = {"formatterClassObject = " + formatterClassObject.getName()};
485 tracer.createError("FormatterClass is not a valid instance", currentValues);
486 }
487 } catch (ClassNotFoundException e) {
488 String currentValues[] = {"class = " + getFormatterClass()};
489 tracer.createError("FormatterClass could not be found", currentValues);
490 }
491 }
492 } catch (RuntimeException ex) {
493 String currentValues[] =
494 {"attribute = " + rootObjectClass + "." + getName(), "Exception = " + ex.getMessage()};
495 tracer.createError("Unable to validate attribute", currentValues);
496 }
497 }
498
499 /**
500 * @see java.lang.Object#toString()
501 */
502 @Override
503 public String toString() {
504 return "AttributeDefinition for attribute " + getName();
505 }
506
507 /**
508 * @return the attributeSecurity
509 */
510 @BeanTagAttribute(name = "attributeSecurity", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
511 public AttributeSecurity getAttributeSecurity() {
512 return this.attributeSecurity;
513 }
514
515 /**
516 * @param attributeSecurity the attributeSecurity to set
517 */
518 public void setAttributeSecurity(AttributeSecurity attributeSecurity) {
519 this.attributeSecurity = attributeSecurity;
520 }
521
522 public boolean hasAttributeSecurity() {
523 return (attributeSecurity != null);
524 }
525
526 /**
527 * This overridden method ...
528 *
529 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
530 */
531 @Override
532 public void afterPropertiesSet() throws Exception {
533 if (StringUtils.isEmpty(name)) {
534 throw new RuntimeException("blank name for bean: " + id);
535 }
536 }
537
538 /**
539 * @return the unique
540 */
541 public Boolean getUnique() {
542 return this.unique;
543 }
544
545 /**
546 * @param unique the unique to set
547 */
548 public void setUnique(Boolean unique) {
549 this.unique = unique;
550 }
551
552 /**
553 * Default {@code Control} to use when the attribute is to be rendered
554 * for the UI. Used by the UIF when a control is not defined for an
555 * {@code InputField}
556 *
557 * @return Control instance
558 */
559 @BeanTagAttribute(name = "control", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
560 public Control getControlField() {
561 return this.controlField;
562 }
563
564 /**
565 * Setter for the default control
566 *
567 * @param controlField
568 */
569 public void setControlField(Control controlField) {
570 this.controlField = controlField;
571 }
572
573 /**
574 * @see org.kuali.rice.krad.datadictionary.validation.constraint.LengthConstraint#getMinLength()
575 */
576 @BeanTagAttribute(name = "minLength")
577 public Integer getMinLength() {
578 return this.getSimpleConstraint().getMinLength();
579 }
580
581 /**
582 * Setter for minumum length
583 *
584 * @param minLength
585 */
586 public void setMinLength(Integer minLength) {
587 this.getSimpleConstraint().setMinLength(minLength);
588 }
589
590 /**
591 * @return the dataType
592 */
593 @BeanTagAttribute(name = "dataType", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
594 public DataType getDataType() {
595 return simpleConstraint.getDataType();
596 }
597
598 /**
599 * @param dataType the dataType to set
600 */
601 public void setDataType(DataType dataType) {
602 simpleConstraint.setDataType(dataType);
603 }
604
605 public void setDataType(String dataType) {
606 simpleConstraint.setDataType(DataType.valueOf(dataType));
607 }
608
609 /**
610 * @return the customValidatorClass
611 */
612 @BeanTagAttribute(name = "customValidatorClass")
613 public String getCustomValidatorClass() {
614 return this.customValidatorClass;
615 }
616
617 /**
618 * @param customValidatorClass the customValidatorClass to set
619 */
620 public void setCustomValidatorClass(String customValidatorClass) {
621 this.customValidatorClass = customValidatorClass;
622 }
623
624 /**
625 * @return the validChars
626 */
627 @Override
628 @BeanTagAttribute(name = "validChractersConstraint", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
629 public ValidCharactersConstraint getValidCharactersConstraint() {
630 return this.validCharactersConstraint;
631 }
632
633 /**
634 * @param validCharactersConstraint the validChars to set
635 */
636 public void setValidCharactersConstraint(ValidCharactersConstraint validCharactersConstraint) {
637 this.validCharactersConstraint = validCharactersConstraint;
638 }
639
640 /**
641 * @return the caseConstraint
642 */
643 @Override
644 @BeanTagAttribute(name = "caseConstraint", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
645 public CaseConstraint getCaseConstraint() {
646 return this.caseConstraint;
647 }
648
649 /**
650 * @param caseConstraint the caseConstraint to set
651 */
652 public void setCaseConstraint(CaseConstraint caseConstraint) {
653 this.caseConstraint = caseConstraint;
654 }
655
656 /**
657 * @return the requireConstraint
658 */
659 @Override
660 @BeanTagAttribute(name = "prerequisteConstraint", type = BeanTagAttribute.AttributeType.LISTBEAN)
661 public List<PrerequisiteConstraint> getPrerequisiteConstraints() {
662 return this.dependencyConstraints;
663 }
664
665 /**
666 * @param dependencyConstraints the requireConstraint to set
667 */
668 public void setPrerequisiteConstraints(List<PrerequisiteConstraint> dependencyConstraints) {
669 this.dependencyConstraints = dependencyConstraints;
670 }
671
672 /**
673 * @return the occursConstraint
674 */
675 @Override
676 @BeanTagAttribute(name = "mustOccurConstraints", type = BeanTagAttribute.AttributeType.LISTBEAN)
677 public List<MustOccurConstraint> getMustOccurConstraints() {
678 return this.mustOccurConstraints;
679 }
680
681 /**
682 * @param mustOccurConstraints the occursConstraint to set
683 */
684 public void setMustOccurConstraints(List<MustOccurConstraint> mustOccurConstraints) {
685 this.mustOccurConstraints = mustOccurConstraints;
686 }
687
688 /**
689 * @return the lookupDefinition
690 */
691 public LookupConstraint getLookupDefinition() {
692 return this.lookupDefinition;
693 }
694
695 /**
696 * @param lookupDefinition the lookupDefinition to set
697 */
698 public void setLookupDefinition(LookupConstraint lookupDefinition) {
699 this.lookupDefinition = lookupDefinition;
700 }
701
702 /**
703 * @return the lookupContextPath
704 */
705 public String getLookupContextPath() {
706 return this.lookupContextPath;
707 }
708
709 /**
710 * @param lookupContextPath the lookupContextPath to set
711 */
712 public void setLookupContextPath(String lookupContextPath) {
713 this.lookupContextPath = lookupContextPath;
714 }
715
716 /**
717 * @return the childEntryName
718 */
719 @BeanTagAttribute(name = "childEntryName")
720 public String getChildEntryName() {
721 return this.childEntryName;
722 }
723
724 /**
725 * @param childEntryName the childEntryName to set
726 */
727 public void setChildEntryName(String childEntryName) {
728 this.childEntryName = childEntryName;
729 }
730
731 /**
732 * Instance of {@code KeyValluesFinder} that should be invoked to
733 * provide a List of values the field can have. Generally used to provide
734 * the options for a multi-value control or to validate the submitted field
735 * value
736 *
737 * @return KeyValuesFinder instance
738 */
739 @BeanTagAttribute(name = "optionFinder", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
740 public KeyValuesFinder getOptionsFinder() {
741 return this.optionsFinder;
742 }
743
744 /**
745 * Setter for the field's KeyValuesFinder instance
746 *
747 * @param optionsFinder
748 */
749 public void setOptionsFinder(KeyValuesFinder optionsFinder) {
750 this.optionsFinder = optionsFinder;
751 }
752
753 /**
754 * Setter that takes in the class name for the options finder and creates a
755 * new instance to use as the finder for the attribute field
756 *
757 * @param optionsFinderClass
758 */
759 public void setOptionsFinderClass(Class<? extends KeyValuesFinder> optionsFinderClass) {
760 this.optionsFinder = ObjectUtils.newInstance(optionsFinderClass);
761 }
762
763 public void setAdditionalDisplayAttributeName(String additionalDisplayAttributeName) {
764 this.additionalDisplayAttributeName = additionalDisplayAttributeName;
765 }
766
767 @BeanTagAttribute(name = "additionalDisplayAttributeName")
768 public String getAdditionalDisplayAttributeName() {
769 return this.additionalDisplayAttributeName;
770 }
771
772 public void setAlternateDisplayAttributeName(String alternateDisplayAttributeName) {
773 this.alternateDisplayAttributeName = alternateDisplayAttributeName;
774 }
775
776 @BeanTagAttribute(name = "alternateDisplayAttributeName")
777 public String getAlternateDisplayAttributeName() {
778 return this.alternateDisplayAttributeName;
779 }
780
781 /**
782 * Gets dependency constraints for this AttributeDefinition. Same as getPrerequisiteConstraints.
783 *
784 * @return dependency constraints
785 */
786 public List<PrerequisiteConstraint> getDependencyConstraints() {
787 return dependencyConstraints;
788 }
789
790 /**
791 * Sets dependency constraints for this AttributeDefinition. Same as setPrerequisiteConstraints.
792 *
793 * @param dependencyConstraints dependency constraints
794 */
795 public void setDependencyConstraints(List<PrerequisiteConstraint> dependencyConstraints) {
796 this.dependencyConstraints = dependencyConstraints;
797 }
798
799 }