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