View Javadoc

1   /**
2    * Copyright 2005-2013 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.krad.datadictionary;
17  
18  import org.apache.commons.lang.ClassUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.kuali.rice.core.api.uif.DataType;
22  import org.kuali.rice.core.api.util.ClassLoaderUtils;
23  import org.kuali.rice.core.web.format.Formatter;
24  import org.kuali.rice.krad.datadictionary.control.ControlDefinition;
25  import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException;
26  import org.kuali.rice.krad.datadictionary.exception.ClassValidationException;
27  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
28  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
29  import org.kuali.rice.krad.datadictionary.validation.ValidationPattern;
30  import org.kuali.rice.krad.datadictionary.validation.capability.CaseConstrainable;
31  import org.kuali.rice.krad.datadictionary.validation.capability.Formatable;
32  import org.kuali.rice.krad.datadictionary.validation.capability.HierarchicallyConstrainable;
33  import org.kuali.rice.krad.datadictionary.validation.capability.MustOccurConstrainable;
34  import org.kuali.rice.krad.datadictionary.validation.capability.PrerequisiteConstrainable;
35  import org.kuali.rice.krad.datadictionary.validation.capability.ValidCharactersConstrainable;
36  import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
37  import org.kuali.rice.krad.datadictionary.validation.constraint.LookupConstraint;
38  import org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint;
39  import org.kuali.rice.krad.datadictionary.validation.constraint.PrerequisiteConstraint;
40  import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
41  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
42  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
43  import org.kuali.rice.krad.uif.control.Control;
44  import org.kuali.rice.krad.util.ObjectUtils;
45  
46  import java.beans.PropertyEditor;
47  import java.util.List;
48  
49  /**
50   * A single attribute definition in the DataDictionary, which contains
51   * information relating to the display, validation, and general maintenance of a
52   * specific attribute of an entry.
53   *
54   * @author Kuali Rice Team (rice.collab@kuali.org)
55   */
56  @BeanTag(name = "attributeDefinition-bean")
57  public class AttributeDefinition extends AttributeDefinitionBase implements CaseConstrainable, PrerequisiteConstrainable, Formatable, HierarchicallyConstrainable, MustOccurConstrainable, ValidCharactersConstrainable {
58      private static final long serialVersionUID = -2490613377818442742L;
59  
60      protected Boolean forceUppercase = Boolean.FALSE;
61  
62      protected DataType dataType;
63  
64      protected Boolean unique;
65  
66      //These are deprecated DO NOT USE with new KRAD implementations
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      protected PropertyEditor propertyEditor;
77  
78      protected AttributeSecurity attributeSecurity;
79  
80      protected Boolean dynamic;
81  
82      // KRAD constraints
83      protected String customValidatorClass;
84      protected ValidCharactersConstraint validCharactersConstraint;
85      protected CaseConstraint caseConstraint;
86      protected List<PrerequisiteConstraint> dependencyConstraints;
87      protected List<MustOccurConstraint> mustOccurConstraints;
88      // if the user wants to match against two searches, that search must be defined as well
89      protected LookupConstraint lookupDefinition;
90      protected String lookupContextPath;
91  
92      //TODO: This may not be required since we now use ComplexAttributeDefinition
93      protected String childEntryName;
94  
95      private KeyValuesFinder optionsFinder;
96  
97      protected String alternateDisplayAttributeName;
98      protected String additionalDisplayAttributeName;
99  
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 }