View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.kuali.rice.kns.datadictionary;
18  
19  import java.util.ArrayList;
20  import java.util.LinkedHashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.rice.kns.datadictionary.exception.DuplicateEntryException;
26  import org.kuali.rice.kns.service.KNSServiceLocator;
27  import org.kuali.rice.kns.util.KNSConstants;
28  
29  /**
30   * Contains lookup-related information relating to the parent BusinessObject.
31  
32   *            The lookup element is used to specify the rules for "looking up"
33              a business object.  These specifications define the following:
34              * How to specify the search criteria used to locate a set of business objects
35              * How to display the search results
36  
37              DD: See LookupDefinition.java
38  
39              JSTL: The lookup element is a Map which is accessed using
40              a key of "lookup".  This map contains the following keys:
41              * lookupableID (String, optional)
42              * title (String)
43              * menubar (String, optional)
44              * defaultSort (Map, optional)
45              * lookupFields (Map)
46              * resultFields (Map)
47              * resultSetLimit (String, optional)
48  
49              See LookupMapBuilder.java
50  
51   * Note: the setters do copious amounts of validation, to facilitate generating errors during the parsing process.
52   *
53   *
54   */
55  public class LookupDefinition extends DataDictionaryDefinitionBase {
56      private static final long serialVersionUID = 6733008572890721359L;
57  
58  	protected String lookupableID;
59      protected String title;
60      protected String menubar;
61      protected SortDefinition defaultSort;
62  
63      protected List<FieldDefinition> lookupFields = new ArrayList<FieldDefinition>();
64      protected Map<String,FieldDefinition> lookupFieldMap = new LinkedHashMap<String, FieldDefinition>();
65      protected List<FieldDefinition> resultFields = new ArrayList<FieldDefinition>();
66      protected Map<String,FieldDefinition> resultFieldMap = new LinkedHashMap<String, FieldDefinition>();
67  
68      protected Integer resultSetLimit = null;
69  
70      protected String extraButtonSource;
71      protected String extraButtonParams;
72      
73      protected String searchIconOverride;
74  
75      protected int numOfColumns;
76      
77      protected HelpDefinition helpDefinition;
78      protected String helpUrl;
79      
80      protected boolean translateCodes = false;
81      protected boolean disableSearchButtons = false;
82  
83      public LookupDefinition() {}
84  
85      /**
86  
87                  The lookupableID element identifies the name of the Spring bean which
88                  will be used to obtain the lookupable helper service for the business object.
89                  For example, the Balance.xml file has a lookupableId = "glBalanceLookupable".
90                  The KualiSpringBeansGL.xml file determines that the helper service will be an
91                  instance of BalanceLookupableHelperServiceImpl.
92  
93                  If this field is omitted, the default bean id used will be kualiLookupable which uses
94                  the KualiLookupableHelperServiceImpl helper service.
95       */
96      public void setLookupableID(String lookupableID) {
97          if (lookupableID == null) {
98              throw new IllegalArgumentException("invalid (null) lookupableID");
99          }
100 
101         this.lookupableID = lookupableID;
102     }
103 
104     /**
105      * @return custom lookupable id
106      */
107     public String getLookupableID() {
108         return this.lookupableID;
109     }
110 
111     /**
112      * @return title
113      */
114     public String getTitle() {
115         return title;
116     }
117 
118     /**
119      * Sets title to the given value.
120      *
121      * @param title
122      * @throws IllegalArgumentException if the given title is blank
123      */
124     public void setTitle(String title) {
125         if (StringUtils.isBlank(title)) {
126             throw new IllegalArgumentException("invalid (blank) title");
127         }
128         this.title = title;
129     }
130 
131     /**
132      * @return true if this instance has a menubar
133      */
134     public boolean hasMenubar() {
135         return (menubar != null);
136     }
137 
138     /**
139      * @return menubar
140      */
141     public String getMenubar() {
142         return menubar;
143     }
144 
145     /**
146 
147                 The menubar element is used to add additional html code
148                 to the header line on the lookup screen.
149 
150                 For example, Account.xml uses this element to
151                 add the "create new global" button to the Account Lookup header.
152      * @throws IllegalArgumentException if the given menubar is blank
153      */
154     public void setMenubar(String menubar) {
155         if (StringUtils.isBlank(menubar)) {
156             throw new IllegalArgumentException("invalid (blank) menubar");
157         }
158         // TODO: catch exception if service locator call fails
159         this.menubar = menubar.replace("${kr.externalizable.images.url}", KNSServiceLocator.getKualiConfigurationService().getPropertyString(KNSConstants.EXTERNALIZABLE_IMAGES_URL_KEY)).replace("${externalizable.images.url}", KNSServiceLocator.getKualiConfigurationService().getPropertyString(KNSConstants.APPLICATION_EXTERNALIZABLE_IMAGES_URL_KEY));
160         this.menubar = this.menubar.replace("${application.url}", KNSServiceLocator.getKualiConfigurationService().getPropertyString(KNSConstants.APPLICATION_URL_KEY));
161     }
162 
163 
164     /**
165      * @return true if this instance has a default sort defined
166      */
167     public boolean hasDefaultSort() {
168         return (defaultSort != null);
169     }
170 
171     /**
172      * @return defaultSort
173      */
174     public SortDefinition getDefaultSort() {
175         return defaultSort;
176     }
177 
178     /**
179                 The defaultSort element specifies the sequence in which the
180                 lookup search results should be displayed.  It contains an
181                 ascending/descending indicator and a list of attribute names.
182 
183                 DD: See SortDefinition.java
184 
185                 JSTL: defaultSort is a Map with the following keys:
186                 * sortAscending (boolean String)
187                 * sortAttributes (Map)
188 
189                 By the time JSTL export occurs, the optional attributeName from the defaultSort
190                 tag will have been converted into the first contained sortAttribute
191 
192                 See LookupMapBuilder.java
193      * @throws IllegalArgumentException if the given defaultSort is blank
194      */
195     public void setDefaultSort(SortDefinition defaultSort) {
196         if (defaultSort == null) {
197             throw new IllegalArgumentException("invalid (null) defaultSort");
198         }
199         this.defaultSort = defaultSort;
200     }
201 
202     /**
203      * @return List of attributeNames of all lookupField FieldDefinitions associated with this LookupDefinition, in the order in
204      *         which they were added
205      */
206     public List getLookupFieldNames() {
207         List fieldNames = new ArrayList();
208         fieldNames.addAll(this.lookupFieldMap.keySet());
209 
210         return fieldNames;
211     }
212 
213     /**
214      * @return Collection of all lookupField FieldDefinitions associated with this LookupDefinition, in the order in which they were
215      *         added
216      */
217     public List<FieldDefinition> getLookupFields() {
218         return lookupFields;
219     }
220 
221     /**
222      * @return FieldDefinition associated with the named lookup field, or null if there is none
223      * @param fieldName
224      */
225     public FieldDefinition getLookupField(String attributeName) {
226         return lookupFieldMap.get(attributeName);
227     }
228 
229     /**
230      * @return List of attributeNames of all resultField FieldDefinitions associated with this LookupDefinition, in the order in
231      *         which they were added
232      */
233     public List<String> getResultFieldNames() {
234         List<String> fieldNames = new ArrayList<String>();
235         fieldNames.addAll(resultFieldMap.keySet());
236 
237         return fieldNames;
238     }
239 
240     /**
241      * @return Collection of all resultField FieldDefinitions associated with this LookupDefinition, in the order in which they were
242      *         added
243      */
244     public List<FieldDefinition> getResultFields() {
245         return resultFields;
246     }
247 
248 
249     /**
250      * @return FieldDefinition associated with the named result field, or null if there is none
251      * @param fieldName
252      */
253     public FieldDefinition getResultField(String attributeName) {
254         return resultFieldMap.get(attributeName);
255     }
256 
257     /**
258         The resultSetLimit element specifies the maximum number of records that will be listed
259         as a result of the lookup search.
260      */
261     public void setResultSetLimit(Integer resultSetLimit) {
262         this.resultSetLimit = resultSetLimit;
263     }
264 
265     /**
266      * @return true if this instance has a result set limit
267      */
268     public boolean hasResultSetLimit() {
269         return (resultSetLimit != null);
270     }
271 
272 
273     /**
274                 The resultSetLimit element specifies the maximum number of records that will be listed
275                 as a result of the lookup search.
276      */
277     public Integer getResultSetLimit() {
278         return resultSetLimit;
279     }
280 
281     /**
282      * Directly validate simple fields, call completeValidation on Definition fields.
283      *
284      * @see org.kuali.rice.kns.datadictionary.DataDictionaryDefinition#completeValidation(java.lang.Class, java.lang.Object)
285      */
286     public void completeValidation(Class rootBusinessObjectClass, Class otherBusinessObjectClass) {
287         if (hasDefaultSort()) {
288             defaultSort.completeValidation(rootBusinessObjectClass, null);
289         }
290 
291         for ( FieldDefinition lookupField : lookupFields ) {
292             lookupField.completeValidation(rootBusinessObjectClass, null);
293         }
294 
295         for ( FieldDefinition resultField : resultFields ) {
296             resultField.completeValidation(rootBusinessObjectClass, null);
297         }
298     }
299 
300     /**
301      * @return true if this instance has extraButtonSource
302      */
303     public boolean hasExtraButtonSource() {
304         return extraButtonSource != null;
305     }
306 
307     /**
308      * @return extraButtonSource
309      */
310     public String getExtraButtonSource() {
311         return extraButtonSource;
312     }
313 
314     /**
315                 The extraButton element is used to define additional buttons which will
316                 appear on the lookup screen next to the Search and Clear buttons.
317                 You can define the image source and additional html parameters for
318                 each button.
319 
320                The extraButtonSource element defines the location of an image file
321                to use for the extra button.
322 
323 
324      * @throws IllegalArgumentException if the given source is blank
325      */
326     public void setExtraButtonSource(String extraButtonSource) {
327         if (StringUtils.isBlank(extraButtonSource)) {
328             throw new IllegalArgumentException("invalid (blank) button source");
329         }
330         this.extraButtonSource = extraButtonSource;
331     }
332 
333     /**
334      * @return true if this instance has extraButtonParams
335      */
336     public boolean hasExtraButtonParams() {
337         return extraButtonParams != null;
338     }
339 
340     /**
341      * @return extraButtonParams
342      */
343     public String getExtraButtonParams() {
344         return extraButtonParams;
345     }
346 
347     /**
348                 The extraButton element is used to define additional buttons which will
349                 appear on the lookup screen next to the Search and Clear buttons.
350                 You can define the image source and additional html parameters for
351                 each button.
352 
353                 The extraButtonParams contains extra HTML parameters that be associated
354                 with the button.
355 
356      */
357     public void setExtraButtonParams(String extraButtonParams) {
358         this.extraButtonParams = extraButtonParams;
359     }
360 
361     
362     /**
363      * @return true if this instance has an alternate icon to use for lookup icon
364      */
365     public boolean hasSearchIconOverride() {
366         return searchIconOverride != null;
367     }
368 
369     /**
370      * @return search icon override url
371      */
372     public String getSearchIconOverride() {
373         return searchIconOverride;
374     }
375 
376     /**
377                 The searchIconOverride element is used to define alternative icons
378                 appear on the lookup screen next to the Search and Clear buttons.
379                 You can define the image source.
380      * @throws IllegalArgumentException if the given source is blank
381      */
382     public void setSearchIconOverride(String searchIconOverride) {
383         if (StringUtils.isBlank(searchIconOverride)) {
384             throw new IllegalArgumentException("invalid (blank) search icon override");
385         }
386         this.searchIconOverride = searchIconOverride;
387     }
388 
389     
390     public String toString() {
391         return "LookupDefinition '" + getTitle() + "'";
392     }
393 
394     /**
395                 The lookupFields element defines the set of fields in which the user
396                 can enter values representing search selection criteria.  A search result
397                 record will be returned only if the criteria entered in all the
398                 lookup fields are met.
399 
400                 DD:  See LookupDefinition.java
401 
402                 JSTL: lookupFields is a Map which is accessed using a key of "lookupFields".
403                 This map contains the following keys:
404                     * attributeName of first lookup field
405                     * attributeName of second lookup field
406                     etc.
407                 The corresponding values are lookupField Export Maps.
408                 See LookupMapBuilder.java.
409 
410                     The lookupField element defines one lookup search
411                     criterion field.
412                     DD: See LookupDefinition.java.
413 
414                     JSTL: lookupField is a Map which is accessed by a key
415                     which is the attributeName of a lookup field.  This map contains
416                     entries with the following keys:
417                     * "attributeName" (String)
418                     * "required" (boolean String)
419 
420                 lookupField attribute definitions:
421 
422                     * required = true means that the user must enter something
423                         into the search criterion lookup field
424                     * forceLookup = this attribute is not used
425                     * noLookup = true means that field should not include magnifying glass (i.e. quickfinder)
426 
427      */
428     public void setLookupFields(List<FieldDefinition> lookupFields) {
429         lookupFieldMap.clear();
430         for ( FieldDefinition lookupField : lookupFields ) {
431             if (lookupField == null) {
432                 throw new IllegalArgumentException("invalid (null) lookupField");
433             }
434             String keyName = lookupField.getAttributeName();
435             if (lookupFieldMap.containsKey(keyName)) {
436                 throw new DuplicateEntryException("duplicate lookupField entry for attribute '" + keyName + "'");
437             }
438 
439             lookupFieldMap.put(keyName, lookupField);
440         }
441         this.lookupFields = lookupFields;
442     }
443 
444     /**
445                 The resultFields element specifies the list of fields that are shown as a result
446                 of the lookup search.
447 
448                 JSTL: resultFields is a Map which is accesseed by a key of "resultFields".
449                 This map contains entries with the following keys:
450                     * attributeName of first result field
451                     * attributeName of second result field
452                     etc.
453                 The corresponding values are ExportMap's
454 
455                 The ExportMaps are accessed using a key of attributeName.
456                 Each ExportMap contains a single entry as follows:
457                     * "attributeName"
458                 The corresponding value is the attributeName of the field.
459 
460                 See LookupMapBuilder.java.
461      */
462     public void setResultFields(List<FieldDefinition> resultFields) {
463         resultFieldMap.clear();
464         for ( FieldDefinition resultField : resultFields ) {
465             if (resultField == null) {
466                 throw new IllegalArgumentException("invalid (null) resultField");
467             }
468 
469             String keyName = resultField.getAttributeName();
470             if (resultFieldMap.containsKey(keyName)) {
471                 throw new DuplicateEntryException("duplicate resultField entry for attribute '" + keyName + "'");
472             }
473 
474             resultFieldMap.put(keyName, resultField);
475         }
476         this.resultFields = resultFields;
477     }
478 
479 	/**
480 	 * @return the numOfColumns
481 	 */
482 	public int getNumOfColumns() {
483 		return this.numOfColumns;
484 	}
485 
486 	/**
487 	 * @param numOfColumns the numOfColumns to set
488 	 */
489 	public void setNumOfColumns(int numOfColumns) {
490 		this.numOfColumns = numOfColumns;
491 	}
492 
493 	/**
494 	 * @return the helpDefinition
495 	 */
496 	public HelpDefinition getHelpDefinition() {
497 		return this.helpDefinition;
498 	}
499 
500 	/**
501 	 * @param helpDefinition the helpDefinition to set
502 	 */
503 	public void setHelpDefinition(HelpDefinition helpDefinition) {
504 		this.helpDefinition = helpDefinition;
505 	}
506 
507 	/**
508 	 * @return the helpUrl
509 	 */
510 	public String getHelpUrl() {
511 		return this.helpUrl;
512 	}
513 
514 	/**
515 	 * @param helpUrl the helpUrl to set
516 	 */
517 	public void setHelpUrl(String helpUrl) {
518 		this.helpUrl = helpUrl;
519 	}
520 
521 	public boolean isTranslateCodes() {
522 		return this.translateCodes;
523 	}
524 
525 	public void setTranslateCodes(boolean translateCodes) {
526 		this.translateCodes = translateCodes;
527 	}
528 
529 	public boolean isDisableSearchButtons() {
530 		return this.disableSearchButtons;
531 	}
532 
533 	public void setDisableSearchButtons(boolean disableSearchButtons) {
534 		this.disableSearchButtons = disableSearchButtons;
535 	}
536 	
537 }