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    }