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 }