001/** 002 * Copyright 2005-2015 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 */ 016package org.kuali.rice.kns.datadictionary; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.CoreApiServiceLocator; 020import org.kuali.rice.core.api.config.property.ConfigurationService; 021import org.kuali.rice.krad.datadictionary.DataDictionaryDefinitionBase; 022import org.kuali.rice.krad.datadictionary.HelpDefinition; 023import org.kuali.rice.krad.datadictionary.SortDefinition; 024import org.kuali.rice.krad.datadictionary.exception.DuplicateEntryException; 025import org.kuali.rice.krad.util.KRADConstants; 026 027import java.util.ArrayList; 028import java.util.LinkedHashMap; 029import java.util.List; 030import java.util.Map; 031 032/** 033 * Contains lookup-related information relating to the parent BusinessObject. 034 * <p/> 035 * The lookup element is used to specify the rules for "looking up" 036 * a business object. These specifications define the following: 037 * How to specify the search criteria used to locate a set of business objects 038 * How to display the search results 039 * <p/> 040 * DD: See LookupDefinition.java 041 * <p/> 042 * JSTL: The lookup element is a Map which is accessed using 043 * a key of "lookup". This map contains the following keys: 044 * lookupableID (String, optional) 045 * title (String) 046 * menubar (String, optional) 047 * defaultSort (Map, optional) 048 * lookupFields (Map) 049 * resultFields (Map) 050 * resultSetLimit (String, optional) 051 * <p/> 052 * See LookupMapBuilder.java 053 * <p/> 054 * Note: the setters do copious amounts of validation, to facilitate generating errors during the parsing process. 055 * 056 * @deprecated Use {@link org.kuali.rice.krad.lookup.LookupView}. 057 */ 058@Deprecated 059public class LookupDefinition extends DataDictionaryDefinitionBase { 060 private static final long serialVersionUID = 6733008572890721359L; 061 062 protected String lookupableID; 063 protected String title; 064 protected String menubar; 065 protected SortDefinition defaultSort; 066 067 protected List<FieldDefinition> lookupFields = new ArrayList<FieldDefinition>(); 068 protected Map<String, FieldDefinition> lookupFieldMap = new LinkedHashMap<String, FieldDefinition>(); 069 protected List<FieldDefinition> resultFields = new ArrayList<FieldDefinition>(); 070 protected Map<String, FieldDefinition> resultFieldMap = new LinkedHashMap<String, FieldDefinition>(); 071 072 protected Integer resultSetLimit = null; 073 protected Integer multipleValuesResultSetLimit = null; 074 075 protected String extraButtonSource; 076 protected String extraButtonParams; 077 078 protected String searchIconOverride; 079 080 protected int numOfColumns; 081 082 protected HelpDefinition helpDefinition; 083 protected String helpUrl; 084 085 protected boolean translateCodes = false; 086 protected boolean disableSearchButtons = false; 087 088 public LookupDefinition() { 089 } 090 091 /** 092 * The lookupableID element identifies the name of the Spring bean which 093 * will be used to obtain the lookupable helper service for the business object. 094 * For example, the Balance.xml file has a lookupableId = "glBalanceLookupable". 095 * The KualiSpringBeansGL.xml file determines that the helper service will be an 096 * instance of BalanceLookupableHelperServiceImpl. 097 * <p/> 098 * If this field is omitted, the default bean id used will be kualiLookupable which uses 099 * the KualiLookupableHelperServiceImpl helper service. 100 */ 101 public void setLookupableID(String lookupableID) { 102 if (lookupableID == null) { 103 throw new IllegalArgumentException("invalid (null) lookupableID"); 104 } 105 106 this.lookupableID = lookupableID; 107 } 108 109 /** 110 * @return custom lookupable id 111 */ 112 public String getLookupableID() { 113 return this.lookupableID; 114 } 115 116 /** 117 * @return title 118 */ 119 public String getTitle() { 120 return title; 121 } 122 123 /** 124 * Sets title to the given value. 125 * 126 * @param title 127 * @throws IllegalArgumentException if the given title is blank 128 */ 129 public void setTitle(String title) { 130 if (StringUtils.isBlank(title)) { 131 throw new IllegalArgumentException("invalid (blank) title"); 132 } 133 this.title = title; 134 } 135 136 /** 137 * @return true if this instance has a menubar 138 */ 139 public boolean hasMenubar() { 140 return (menubar != null); 141 } 142 143 /** 144 * @return menubar 145 */ 146 public String getMenubar() { 147 return menubar; 148 } 149 150 /** 151 * The menubar element is used to add additional html code 152 * to the header line on the lookup screen. 153 * <p/> 154 * For example, Account.xml uses this element to 155 * add the "create new global" button to the Account Lookup header. 156 * 157 * @throws IllegalArgumentException if the given menubar is blank 158 */ 159 public void setMenubar(String menubar) { 160 if (StringUtils.isBlank(menubar)) { 161 throw new IllegalArgumentException("invalid (blank) menubar"); 162 } 163 // TODO: catch exception if service locator call fails 164 ConfigurationService kualiConfigurationservice = CoreApiServiceLocator.getKualiConfigurationService(); 165 this.menubar = menubar.replace("${kr.externalizable.images.url}", 166 kualiConfigurationservice.getPropertyValueAsString(KRADConstants.EXTERNALIZABLE_IMAGES_URL_KEY)).replace("${externalizable.images.url}", 167 kualiConfigurationservice.getPropertyValueAsString( 168 KRADConstants.APPLICATION_EXTERNALIZABLE_IMAGES_URL_KEY)); 169 this.menubar = this.menubar.replace("${application.url}", kualiConfigurationservice.getPropertyValueAsString( 170 KRADConstants.APPLICATION_URL_KEY)); 171 } 172 173 174 /** 175 * @return true if this instance has a default sort defined 176 */ 177 public boolean hasDefaultSort() { 178 return (defaultSort != null); 179 } 180 181 /** 182 * @return defaultSort 183 */ 184 public SortDefinition getDefaultSort() { 185 return defaultSort; 186 } 187 188 /** 189 * The defaultSort element specifies the sequence in which the 190 * lookup search results should be displayed. It contains an 191 * ascending/descending indicator and a list of attribute names. 192 * <p/> 193 * DD: See SortDefinition.java 194 * <p/> 195 * JSTL: defaultSort is a Map with the following keys: 196 * sortAscending (boolean String) 197 * sortAttributes (Map) 198 * <p/> 199 * By the time JSTL export occurs, the optional attributeName from the defaultSort 200 * tag will have been converted into the first contained sortAttribute 201 * <p/> 202 * See LookupMapBuilder.java 203 * 204 * @throws IllegalArgumentException if the given defaultSort is blank 205 */ 206 public void setDefaultSort(SortDefinition defaultSort) { 207 if (defaultSort == null) { 208 throw new IllegalArgumentException("invalid (null) defaultSort"); 209 } 210 this.defaultSort = defaultSort; 211 } 212 213 /** 214 * @return List of attributeNames of all lookupField FieldDefinitions associated with this LookupDefinition, in the order in 215 * which they were added 216 */ 217 public List getLookupFieldNames() { 218 List fieldNames = new ArrayList(); 219 fieldNames.addAll(this.lookupFieldMap.keySet()); 220 221 return fieldNames; 222 } 223 224 /** 225 * @return Collection of all lookupField FieldDefinitions associated with this LookupDefinition, in the order in which they were 226 * added 227 */ 228 public List<FieldDefinition> getLookupFields() { 229 return lookupFields; 230 } 231 232 /** 233 * @param fieldName 234 * @return FieldDefinition associated with the named lookup field, or null if there is none 235 */ 236 public FieldDefinition getLookupField(String attributeName) { 237 return lookupFieldMap.get(attributeName); 238 } 239 240 /** 241 * @return List of attributeNames of all resultField FieldDefinitions associated with this LookupDefinition, in the order in 242 * which they were added 243 */ 244 public List<String> getResultFieldNames() { 245 List<String> fieldNames = new ArrayList<String>(); 246 fieldNames.addAll(resultFieldMap.keySet()); 247 248 return fieldNames; 249 } 250 251 /** 252 * @return Collection of all resultField FieldDefinitions associated with this LookupDefinition, in the order in which they were 253 * added 254 */ 255 public List<FieldDefinition> getResultFields() { 256 return resultFields; 257 } 258 259 260 /** 261 * @param fieldName 262 * @return FieldDefinition associated with the named result field, or null if there is none 263 */ 264 public FieldDefinition getResultField(String attributeName) { 265 return resultFieldMap.get(attributeName); 266 } 267 268 /** 269 * The resultSetLimit element specifies the maximum number of records that will be listed 270 * as a result of the lookup search. 271 */ 272 public void setResultSetLimit(Integer resultSetLimit) { 273 this.resultSetLimit = resultSetLimit; 274 } 275 276 /** 277 * @return true if this instance has a result set limit 278 */ 279 public boolean hasResultSetLimit() { 280 return (resultSetLimit != null); 281 } 282 283 284 /** 285 * The resultSetLimit element specifies the maximum number of records that will be listed 286 * as a result of the lookup search. 287 */ 288 public Integer getResultSetLimit() { 289 return resultSetLimit; 290 } 291 292 /** 293 * The multipleValuesResultSetLimit element specifies the maximum number of records that will be listed 294 * as a result of a multiple values lookup search. 295 */ 296 public void setMultipleValuesResultSetLimit(Integer multipleValuesResultSetLimit) { 297 this.multipleValuesResultSetLimit = multipleValuesResultSetLimit; 298 } 299 300 /** 301 * @return true if this instance has a multiple values result set limit 302 */ 303 public boolean hasMultipleValuesResultSetLimit() { 304 return (multipleValuesResultSetLimit != null); 305 } 306 307 308 /** 309 * The multipleValuesResultSetLimit element specifies the maximum number of records that will be listed 310 * as a result of a multiple values lookup search. 311 */ 312 public Integer getMultipleValuesResultSetLimit() { 313 return multipleValuesResultSetLimit; 314 } 315 316 /** 317 * Directly validate simple fields, call completeValidation on Definition fields. 318 * 319 * @see org.kuali.rice.krad.datadictionary.DataDictionaryDefinition#completeValidation(java.lang.Class, java.lang.Object) 320 */ 321 public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) { 322 if (hasDefaultSort()) { 323 defaultSort.completeValidation(rootBusinessObjectClass, null); 324 } 325 326 for (FieldDefinition lookupField : lookupFields) { 327 lookupField.completeValidation(rootBusinessObjectClass, null); 328 } 329 330 for (FieldDefinition resultField : resultFields) { 331 resultField.completeValidation(rootBusinessObjectClass, null); 332 } 333 } 334 335 /** 336 * @return true if this instance has extraButtonSource 337 */ 338 public boolean hasExtraButtonSource() { 339 return extraButtonSource != null; 340 } 341 342 /** 343 * @return extraButtonSource 344 */ 345 public String getExtraButtonSource() { 346 return extraButtonSource; 347 } 348 349 /** 350 * The extraButton element is used to define additional buttons which will 351 * appear on the lookup screen next to the Search and Clear buttons. 352 * You can define the image source and additional html parameters for 353 * each button. 354 * <p/> 355 * The extraButtonSource element defines the location of an image file 356 * to use for the extra button. 357 * 358 * @throws IllegalArgumentException if the given source is blank 359 */ 360 public void setExtraButtonSource(String extraButtonSource) { 361 if (StringUtils.isBlank(extraButtonSource)) { 362 throw new IllegalArgumentException("invalid (blank) button source"); 363 } 364 this.extraButtonSource = extraButtonSource; 365 } 366 367 /** 368 * @return true if this instance has extraButtonParams 369 */ 370 public boolean hasExtraButtonParams() { 371 return extraButtonParams != null; 372 } 373 374 /** 375 * @return extraButtonParams 376 */ 377 public String getExtraButtonParams() { 378 return extraButtonParams; 379 } 380 381 /** 382 * The extraButton element is used to define additional buttons which will 383 * appear on the lookup screen next to the Search and Clear buttons. 384 * You can define the image source and additional html parameters for 385 * each button. 386 * <p/> 387 * The extraButtonParams contains extra HTML parameters that be associated 388 * with the button. 389 */ 390 public void setExtraButtonParams(String extraButtonParams) { 391 this.extraButtonParams = extraButtonParams; 392 } 393 394 395 /** 396 * @return true if this instance has an alternate icon to use for lookup icon 397 */ 398 public boolean hasSearchIconOverride() { 399 return searchIconOverride != null; 400 } 401 402 /** 403 * @return search icon override url 404 */ 405 public String getSearchIconOverride() { 406 return searchIconOverride; 407 } 408 409 /** 410 * The searchIconOverride element is used to define alternative icons 411 * appear on the lookup screen next to the Search and Clear buttons. 412 * You can define the image source. 413 * 414 * @throws IllegalArgumentException if the given source is blank 415 */ 416 public void setSearchIconOverride(String searchIconOverride) { 417 if (StringUtils.isBlank(searchIconOverride)) { 418 throw new IllegalArgumentException("invalid (blank) search icon override"); 419 } 420 this.searchIconOverride = searchIconOverride; 421 } 422 423 424 public String toString() { 425 return "LookupDefinition '" + getTitle() + "'"; 426 } 427 428 /** 429 * The lookupFields element defines the set of fields in which the user 430 * can enter values representing search selection criteria. A search result 431 * record will be returned only if the criteria entered in all the 432 * lookup fields are met. 433 * <p/> 434 * DD: See LookupDefinition.java 435 * <p/> 436 * JSTL: lookupFields is a Map which is accessed using a key of "lookupFields". 437 * This map contains the following keys: 438 * attributeName of first lookup field 439 * attributeName of second lookup field 440 * etc. 441 * The corresponding values are lookupField Export Maps. 442 * See LookupMapBuilder.java. 443 * <p/> 444 * The lookupField element defines one lookup search 445 * criterion field. 446 * DD: See LookupDefinition.java. 447 * <p/> 448 * JSTL: lookupField is a Map which is accessed by a key 449 * which is the attributeName of a lookup field. This map contains 450 * entries with the following keys: 451 * "attributeName" (String) 452 * "required" (boolean String) 453 * <p/> 454 * lookupField attribute definitions: 455 * <p/> 456 * required = true means that the user must enter something 457 * into the search criterion lookup field 458 * forceLookup = this attribute is not used 459 * noLookup = true means that field should not include magnifying glass (i.e. quickfinder) 460 */ 461 public void setLookupFields(List<FieldDefinition> lookupFields) { 462 lookupFieldMap.clear(); 463 for (FieldDefinition lookupField : lookupFields) { 464 if (lookupField == null) { 465 throw new IllegalArgumentException("invalid (null) lookupField"); 466 } 467 String keyName = lookupField.getAttributeName(); 468 if (lookupFieldMap.containsKey(keyName)) { 469 throw new DuplicateEntryException("duplicate lookupField entry for attribute '" + keyName + "'"); 470 } 471 472 lookupFieldMap.put(keyName, lookupField); 473 } 474 this.lookupFields = lookupFields; 475 } 476 477 /** 478 * The resultFields element specifies the list of fields that are shown as a result 479 * of the lookup search. 480 * <p/> 481 * JSTL: resultFields is a Map which is accesseed by a key of "resultFields". 482 * This map contains entries with the following keys: 483 * attributeName of first result field 484 * attributeName of second result field 485 * etc. 486 * The corresponding values are ExportMap's 487 * <p/> 488 * The ExportMaps are accessed using a key of attributeName. 489 * Each ExportMap contains a single entry as follows: 490 * "attributeName" 491 * The corresponding value is the attributeName of the field. 492 * <p/> 493 * See LookupMapBuilder.java. 494 */ 495 public void setResultFields(List<FieldDefinition> resultFields) { 496 resultFieldMap.clear(); 497 for (FieldDefinition resultField : resultFields) { 498 if (resultField == null) { 499 throw new IllegalArgumentException("invalid (null) resultField"); 500 } 501 502 String keyName = resultField.getAttributeName(); 503 if (resultFieldMap.containsKey(keyName)) { 504 throw new DuplicateEntryException("duplicate resultField entry for attribute '" + keyName + "'"); 505 } 506 507 resultFieldMap.put(keyName, resultField); 508 } 509 this.resultFields = resultFields; 510 } 511 512 /** 513 * @return the numOfColumns 514 */ 515 public int getNumOfColumns() { 516 return this.numOfColumns; 517 } 518 519 /** 520 * @param numOfColumns the numOfColumns to set 521 */ 522 public void setNumOfColumns(int numOfColumns) { 523 this.numOfColumns = numOfColumns; 524 } 525 526 /** 527 * @return the helpDefinition 528 */ 529 public HelpDefinition getHelpDefinition() { 530 return this.helpDefinition; 531 } 532 533 /** 534 * @param helpDefinition the helpDefinition to set 535 */ 536 public void setHelpDefinition(HelpDefinition helpDefinition) { 537 this.helpDefinition = helpDefinition; 538 } 539 540 /** 541 * @return the helpUrl 542 */ 543 public String getHelpUrl() { 544 return this.helpUrl; 545 } 546 547 /** 548 * @param helpUrl the helpUrl to set 549 */ 550 public void setHelpUrl(String helpUrl) { 551 this.helpUrl = helpUrl; 552 } 553 554 public boolean isTranslateCodes() { 555 return this.translateCodes; 556 } 557 558 public void setTranslateCodes(boolean translateCodes) { 559 this.translateCodes = translateCodes; 560 } 561 562 public boolean isDisableSearchButtons() { 563 return this.disableSearchButtons; 564 } 565 566 public void setDisableSearchButtons(boolean disableSearchButtons) { 567 this.disableSearchButtons = disableSearchButtons; 568 } 569 570}