001 /** 002 * Copyright 2005-2013 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.kns.datadictionary; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.kuali.rice.kns.service.BusinessObjectMetaDataService; 020 import org.kuali.rice.kns.service.KNSServiceLocator; 021 import org.kuali.rice.krad.datadictionary.DataDictionary; 022 import org.kuali.rice.krad.datadictionary.DataDictionaryDefinitionBase; 023 import org.kuali.rice.krad.datadictionary.RelationshipDefinition; 024 import org.kuali.rice.krad.datadictionary.exception.AttributeValidationException; 025 import org.kuali.rice.krad.datadictionary.exception.ClassValidationException; 026 import org.kuali.rice.krad.datadictionary.mask.Mask; 027 import org.kuali.rice.krad.valuefinder.ValueFinder; 028 029 /** 030 * Contains field-related information for DataDictionary entries. Used by lookups and inquiries. 031 * 032 * Note: the setters do copious amounts of validation, to facilitate generating errors during the parsing process. 033 */ 034 @Deprecated 035 public class FieldDefinition extends DataDictionaryDefinitionBase implements FieldDefinitionI { 036 private static final long serialVersionUID = -3426603523049661524L; 037 038 protected String attributeName; 039 protected boolean required = false; 040 protected boolean forceInquiry = false; 041 protected boolean noInquiry = false; 042 protected boolean noDirectInquiry = false; 043 protected boolean forceLookup = false; 044 protected boolean noLookup = false; 045 protected boolean useShortLabel = false; 046 protected String defaultValue; 047 protected Class<? extends ValueFinder> defaultValueFinderClass; 048 protected String quickfinderParameterString; 049 protected Class<? extends ValueFinder> quickfinderParameterStringBuilderClass; 050 051 protected Integer maxLength = null; 052 053 protected String displayEditMode; 054 protected Mask displayMask; 055 056 protected boolean hidden = false; 057 protected boolean readOnly = false; 058 059 protected boolean treatWildcardsAndOperatorsAsLiteral = false; 060 061 protected String alternateDisplayAttributeName; 062 protected String additionalDisplayAttributeName; 063 064 protected boolean triggerOnChange; 065 protected boolean total = false; 066 067 public FieldDefinition() { 068 } 069 070 071 /** 072 * @return attributeName 073 */ 074 public String getAttributeName() { 075 return attributeName; 076 } 077 078 /** 079 * Sets attributeName to the given value. 080 * 081 * @param attributeName 082 * @throws IllegalArgumentException if the given attributeName is blank 083 */ 084 public void setAttributeName(String attributeName) { 085 if (StringUtils.isBlank(attributeName)) { 086 throw new IllegalArgumentException("invalid (blank) attributeName"); 087 } 088 this.attributeName = attributeName; 089 } 090 091 092 /** 093 * @return true if this attribute is required 094 */ 095 public boolean isRequired() { 096 return required; 097 } 098 099 100 /** 101 required = true means that the user must enter something 102 into the search criterion lookup field 103 */ 104 public void setRequired(boolean required) { 105 this.required = required; 106 } 107 108 109 /** 110 * @return Returns the forceInquiry. 111 */ 112 public boolean isForceInquiry() { 113 return forceInquiry; 114 } 115 116 117 /** 118 * forceInquiry = true means that the displayed field value will 119 always be made inquirable (this attribute is not used within the code). 120 */ 121 public void setForceInquiry(boolean forceInquiry) { 122 this.forceInquiry = forceInquiry; 123 } 124 125 /** 126 * @return Returns the forceLookup. 127 */ 128 public boolean isForceLookup() { 129 return forceLookup; 130 } 131 132 /** 133 * forceLookup = this attribute is not used 134 */ 135 public void setForceLookup(boolean forceLookup) { 136 this.forceLookup = forceLookup; 137 } 138 139 /** 140 * @return Returns the noInquiry. 141 */ 142 public boolean isNoInquiry() { 143 return noInquiry; 144 } 145 146 /** 147 * @return Returns a boolean value indicating whether or not to provide 148 * a direct inquiry for the lookup field 149 */ 150 public boolean isNoDirectInquiry() 151 { 152 return noDirectInquiry; 153 } 154 155 /** 156 * noInquiry = true means that the displayed field will never be made inquirable. 157 */ 158 public void setNoInquiry(boolean noInquiry) { 159 this.noInquiry = noInquiry; 160 } 161 162 /** 163 * @param noInquiry If true, the displayed field will not have a direct 164 * inquiry facility 165 */ 166 public void setNoDirectInquiry(boolean noDirectInquiry) { 167 this.noDirectInquiry = noDirectInquiry; 168 } 169 170 /** 171 * @return Returns the noLookup. 172 */ 173 public boolean isNoLookup() { 174 return noLookup; 175 } 176 177 /** 178 * noLookup = true means that field should not include magnifying glass (i.e. quickfinder) 179 */ 180 public void setNoLookup(boolean noLookup) { 181 this.noLookup = noLookup; 182 } 183 184 185 /** 186 * @return the useShortLabel 187 */ 188 public boolean isUseShortLabel() { 189 return this.useShortLabel; 190 } 191 192 193 /** 194 * @param useShortLabel the useShortLabel to set 195 */ 196 public void setUseShortLabel(boolean useShortLabel) { 197 this.useShortLabel = useShortLabel; 198 } 199 200 201 /** 202 * @return Returns the defaultValue. 203 */ 204 public String getDefaultValue() { 205 return defaultValue; 206 } 207 208 209 /** 210 The defaultValue element will pre-load the specified value 211 into the field. 212 */ 213 public void setDefaultValue(String defaultValue) { 214 this.defaultValue = defaultValue; 215 } 216 217 /** 218 * the quickfinderParameterString is a comma separated list of parameter/value pairs, of the format 219 * "param1=value1,param2=value2", where the parameters correspond to attributes of the target class 220 * for the quickfinder, and the values to literals that those attributes will default to when the 221 * quickfinder is used. 222 * @return the quickfinderParameterString 223 */ 224 public String getQuickfinderParameterString() { 225 return this.quickfinderParameterString; 226 } 227 228 /** 229 * @param quickfinderParameterString the quickfinderParameterString to set. See {@link #getQuickfinderParameterString()} 230 */ 231 public void setQuickfinderParameterString(String quickfinderParameterString) { 232 this.quickfinderParameterString = quickfinderParameterString; 233 } 234 235 236 /** 237 * the quickfinderParameterStringBuilderClass specifies the java class that will be used 238 * to determine the default value(s) for field(s) on the target lookup when the quickfinder 239 * is used. The classname specified in this field must implement 240 * {@link org.kuali.rice.krad.valuefinder.ValueFinder}. See {@link #getQuickfinderParameterString()} 241 * for the result string format. 242 * @return the quickfinderParameterStringBuilderClass 243 */ 244 public Class<? extends ValueFinder> getQuickfinderParameterStringBuilderClass() { 245 return this.quickfinderParameterStringBuilderClass; 246 } 247 248 /** 249 * See {@link #getQuickfinderParameterStringBuilderClass()} 250 * @param quickfinderParameterStringBuilderClass the quickfinderParameterStringBuilderClass to set 251 */ 252 public void setQuickfinderParameterStringBuilderClass( 253 Class<? extends ValueFinder> quickfinderParameterStringBuilderClass) { 254 if (quickfinderParameterStringBuilderClass == null) { 255 throw new IllegalArgumentException("invalid (null) quickfinderParameterStringBuilderClass"); 256 } 257 this.quickfinderParameterStringBuilderClass = quickfinderParameterStringBuilderClass; 258 } 259 260 /** 261 * Directly validate simple fields. 262 * 263 * @see org.kuali.rice.krad.datadictionary.DataDictionaryDefinition#completeValidation(java.lang.Class, java.lang.Object) 264 */ 265 public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) { 266 BusinessObjectMetaDataService boMetadataService = KNSServiceLocator.getBusinessObjectMetaDataService(); 267 268 if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, getAttributeName())) { 269 throw new AttributeValidationException("unable to find attribute '" + attributeName + "' in rootBusinessObjectClass '" + rootBusinessObjectClass.getName() + "' (" + "" + ")"); 270 } 271 272 if (StringUtils.isNotBlank(getAlternateDisplayAttributeName())) { 273 if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, getAlternateDisplayAttributeName())) { 274 throw new AttributeValidationException("unable to find attribute named '" + getName() + "' in rootBusinessObjectClass '" + rootBusinessObjectClass.getName() + "' (" + "" + ")"); 275 } 276 } 277 278 if (StringUtils.isNotBlank(getAdditionalDisplayAttributeName())) { 279 if (!DataDictionary.isPropertyOf(rootBusinessObjectClass, getAdditionalDisplayAttributeName())) { 280 throw new AttributeValidationException("unable to find attribute named '" + getName() + "' in rootBusinessObjectClass '" + rootBusinessObjectClass.getName() + "' (" + "" + ")"); 281 } 282 } 283 284 if (defaultValueFinderClass != null && defaultValue != null) { 285 throw new AttributeValidationException("Both defaultValue and defaultValueFinderClass can not be specified on attribute " + getAttributeName() + " in rootBusinessObjectClass " + rootBusinessObjectClass.getName()); 286 } 287 288 validateQuickfinderParameters(rootBusinessObjectClass, boMetadataService); 289 290 if (forceInquiry == true && noInquiry == true) { 291 throw new AttributeValidationException("Both forceInquiry and noInquiry can not be set to true on attribute " + getAttributeName() + " in rootBusinessObjectClass " + rootBusinessObjectClass.getName()); 292 } 293 if (forceLookup == true && noLookup == true) { 294 throw new AttributeValidationException("Both forceLookup and noLookup can not be set to true on attribute " + getAttributeName() + " in rootBusinessObjectClass " + rootBusinessObjectClass.getName()); 295 } 296 } 297 298 299 /** 300 * This method does validation on the quickfinderParameterString and quickfinderParameterStringBuilderClass members 301 * 302 * @param rootBusinessObjectClass 303 * @param boMetadataService 304 */ 305 private void validateQuickfinderParameters(Class rootBusinessObjectClass, 306 BusinessObjectMetaDataService boMetadataService) { 307 if (quickfinderParameterStringBuilderClass != null && quickfinderParameterString != null) { 308 throw new AttributeValidationException("Both quickfinderParameterString and quickfinderParameterStringBuilderClass can not be specified on attribute " + getAttributeName() + " in rootBusinessObjectClass " + rootBusinessObjectClass.getName()); 309 } 310 311 // String used for building exception messages 312 String quickfinderParameterStringSource = "quickfinderParameterString"; 313 314 if (quickfinderParameterStringBuilderClass != null) { 315 try { 316 quickfinderParameterStringSource = "quickfinderParameterStringBuilderClass " + quickfinderParameterStringBuilderClass.getCanonicalName(); 317 quickfinderParameterString = quickfinderParameterStringBuilderClass.newInstance().getValue(); 318 } catch (InstantiationException e) { 319 throw new ClassValidationException("unable to create new instance of "+ quickfinderParameterStringSource +" while validating rootBusinessObjectClass '"+ rootBusinessObjectClass.getName() +"'", e); 320 } catch (IllegalAccessException e) { 321 throw new ClassValidationException("unable to create new instance of "+ quickfinderParameterStringSource +" while validating rootBusinessObjectClass '"+ rootBusinessObjectClass.getName() +"'", e); 322 } 323 } 324 325 if (!StringUtils.isEmpty(quickfinderParameterString)) { 326 // quickfinderParameterString will look something like "campusTypeCode=P,active=Y" 327 for (String quickfinderParam : quickfinderParameterString.split(",")) { // this is guaranteed to return at least one 328 if (quickfinderParam.contains("=")) { 329 String propertyName = quickfinderParam.split("=")[0]; 330 RelationshipDefinition relationship = boMetadataService.getBusinessObjectRelationshipDefinition(rootBusinessObjectClass, attributeName); 331 Class targetClass = relationship.getTargetClass(); 332 333 // This is insufficient to ensure the property is valid for a lookup default, but it's better than nothing. 334 if (!DataDictionary.isPropertyOf(targetClass, propertyName)) { 335 throw new ClassValidationException("malformed parameter string '"+ quickfinderParameterString +"' from "+ quickfinderParameterStringSource + 336 ", '"+ propertyName +"' is not a property of "+ targetClass +"' for rootBusinessObjectClass '"+ rootBusinessObjectClass.getName() +"'"); 337 } 338 339 } else { 340 throw new ClassValidationException("malformed parameter string '"+ quickfinderParameterString +"' from "+ quickfinderParameterStringSource + 341 " for rootBusinessObjectClass '"+ rootBusinessObjectClass.getName() +"'"); 342 } 343 } 344 } 345 } 346 347 348 /** 349 * @see java.lang.Object#toString() 350 */ 351 public String toString() { 352 return "FieldDefinition for attribute " + getAttributeName(); 353 } 354 355 356 public String getName() { 357 return attributeName; 358 } 359 360 361 public String getDisplayEditMode() { 362 return displayEditMode; 363 } 364 365 366 /* 367 The document authorizer classes have a method getEditMode, which is a map of edit mode to 368 value mappings. Depending on the context, the value of the mapping may be relevant, and the logic determining 369 whether the value is relevant is often implemented in the JSP/tag layer. 370 371 Fields on a document (particularily maintenance documents) may be associated with 372 an edit mode. If the edit mode is mapped to a relevant value, then the all fields associated with the edit mode 373 will be rendered unhidden. 374 375 The displayEditMode element is used to specify the edit mode that will be associated with the field. 376 If the document authorizer returns a map with this edit mode mapped to a proper value, then the field will be unhidden to the user. 377 */ 378 public void setDisplayEditMode(String displayEditMode) { 379 this.displayEditMode = displayEditMode; 380 } 381 382 383 public Mask getDisplayMask() { 384 return displayMask; 385 } 386 387 /** 388 * The displayMask element specifies the type of masking to 389 be used to hide the value from un-authorized users. 390 There are three types of masking. 391 */ 392 public void setDisplayMask(Mask displayMask) { 393 this.displayMask = displayMask; 394 } 395 396 397 398 public boolean isReadOnlyAfterAdd() { 399 return false; 400 } 401 402 403 /** 404 * Gets the maxLength attribute. 405 * @return Returns the maxLength. 406 */ 407 public Integer getMaxLength() { 408 return maxLength; 409 } 410 411 412 /** 413 * maxLength = the maximum allowable length of the field in the lookup result fields. In other contexts, 414 like inquiries, this field has no effect. 415 */ 416 public void setMaxLength(Integer maxLength) { 417 this.maxLength = maxLength; 418 } 419 420 /** 421 * @return custom defaultValue class 422 */ 423 public Class<? extends ValueFinder> getDefaultValueFinderClass() { 424 return this.defaultValueFinderClass; 425 } 426 427 /** 428 The defaultValueFinderClass specifies the java class that will be 429 used to determine the default value of a field. The classname 430 specified in this field must implement ValueFinder 431 */ 432 public void setDefaultValueFinderClass(Class<? extends ValueFinder> defaultValueFinderClass) { 433 if (defaultValueFinderClass == null) { 434 throw new IllegalArgumentException("invalid (null) defaultValueFinderClass"); 435 } 436 this.defaultValueFinderClass = defaultValueFinderClass; 437 } 438 439 /** 440 * @return the hidden 441 */ 442 public boolean isHidden() { 443 return this.hidden; 444 } 445 446 /** 447 * @param hidden 448 * If the ControlDefinition.isHidden == true then a corresponding LookupDefinition would 449 * automatically be removed from the search criteria. In some cases you might want the 450 * hidden field to be used as a search criteria. For example, in PersonImpl.xml a client 451 * might want to have the campus code hidden and preset to Bloomington. So when the search 452 * is run, only people from the bloomington campus are returned. 453 * 454 * So, if you want to have a hidden search criteria, set this variable to true. Defaults to 455 * false. 456 */ 457 public void setHidden(boolean hidden) { 458 this.hidden = hidden; 459 } 460 461 /** 462 * @return the readOnly 463 */ 464 public boolean isReadOnly() { 465 return this.readOnly; 466 } 467 468 /** 469 * @param readOnly the readOnly to set 470 */ 471 public void setReadOnly(boolean readOnly) { 472 this.readOnly = readOnly; 473 } 474 475 public boolean isTriggerOnChange() { 476 return this.triggerOnChange; 477 } 478 479 public void setTriggerOnChange(boolean triggerOnChange) { 480 this.triggerOnChange = triggerOnChange; 481 } 482 483 /** 484 * @return the treatWildcardsAndOperatorsAsLiteralOnLookups 485 */ 486 public boolean isTreatWildcardsAndOperatorsAsLiteral() { 487 return this.treatWildcardsAndOperatorsAsLiteral; 488 } 489 490 491 /** 492 * @param treatWildcardsAndOperatorsAsLiteralOnLookups the treatWildcardsAndOperatorsAsLiteralOnLookups to set 493 */ 494 public void setTreatWildcardsAndOperatorsAsLiteral( 495 boolean treatWildcardsAndOperatorsAsLiteralOnLookups) { 496 this.treatWildcardsAndOperatorsAsLiteral = treatWildcardsAndOperatorsAsLiteralOnLookups; 497 } 498 499 500 public String getAlternateDisplayAttributeName() { 501 return this.alternateDisplayAttributeName; 502 } 503 504 505 public void setAlternateDisplayAttributeName(String alternateDisplayAttributeName) { 506 this.alternateDisplayAttributeName = alternateDisplayAttributeName; 507 } 508 509 510 public String getAdditionalDisplayAttributeName() { 511 return this.additionalDisplayAttributeName; 512 } 513 514 515 public void setAdditionalDisplayAttributeName(String additionalDisplayAttributeName) { 516 this.additionalDisplayAttributeName = additionalDisplayAttributeName; 517 } 518 519 520 public boolean isTotal() { 521 return this.total; 522 } 523 524 525 public void setTotal(boolean total) { 526 this.total = total; 527 } 528 529 }