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