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