001/**
002 * Copyright 2005-2016 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
035public 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}