View Javadoc
1   /**
2    * Copyright 2005-2014 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  package org.kuali.rice.krad.uif.field;
17  
18  import java.beans.PropertyEditor;
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  
23  import org.apache.commons.lang.StringEscapeUtils;
24  import org.apache.commons.lang.StringUtils;
25  import org.kuali.rice.core.api.exception.RiceRuntimeException;
26  import org.kuali.rice.core.api.util.type.TypeUtils;
27  import org.kuali.rice.krad.bo.DataObjectRelationship;
28  import org.kuali.rice.krad.bo.KualiCode;
29  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
30  import org.kuali.rice.krad.datadictionary.mask.MaskFormatter;
31  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
32  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
33  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
34  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
35  import org.kuali.rice.krad.datadictionary.validator.Validator;
36  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
37  import org.kuali.rice.krad.uif.UifConstants;
38  import org.kuali.rice.krad.uif.component.BindingInfo;
39  import org.kuali.rice.krad.uif.component.ComponentSecurity;
40  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
41  import org.kuali.rice.krad.uif.lifecycle.ViewPostMetadata;
42  import org.kuali.rice.krad.uif.util.ComponentFactory;
43  import org.kuali.rice.krad.uif.util.LifecycleAwareList;
44  import org.kuali.rice.krad.uif.util.LifecycleElement;
45  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
46  import org.kuali.rice.krad.uif.util.ViewModelUtils;
47  import org.kuali.rice.krad.uif.view.View;
48  import org.kuali.rice.krad.uif.view.ViewModel;
49  import org.kuali.rice.krad.uif.widget.Help;
50  import org.kuali.rice.krad.uif.widget.Inquiry;
51  import org.kuali.rice.krad.uif.widget.Tooltip;
52  import org.kuali.rice.krad.util.KRADPropertyConstants;
53  import org.kuali.rice.krad.util.KRADUtils;
54  import org.kuali.rice.krad.valuefinder.ValueFinder;
55  import org.kuali.rice.krad.web.form.InquiryForm;
56  
57  /**
58   * Field that renders data from the application, such as the value of a data object property
59   *
60   * @author Kuali Rice Team (rice.collab@kuali.org)
61   */
62  @BeanTags({@BeanTag(name = "data", parent = "Uif-DataField"),
63          @BeanTag(name = "dataLabelTop", parent = "Uif-DataField-LabelTop"),
64          @BeanTag(name = "dataLabelRight", parent = "Uif-DataField-LabelRight"),
65          @BeanTag(name = "dataNoLabel", parent = "Uif-DataField-withoutLabel")})
66  public class DataFieldBase extends FieldBase implements DataField {
67      private static final long serialVersionUID = -4129678891948564724L;
68  
69      // binding
70      private String propertyName;
71      private BindingInfo bindingInfo;
72  
73      private String dictionaryAttributeName;
74      private String dictionaryObjectEntry;
75  
76      // value props
77      private Object defaultValue;
78      private Class<? extends ValueFinder> defaultValueFinderClass;
79      private List<Object> defaultValues;
80      private String forcedValue;
81  
82      private PropertyEditor propertyEditor;
83  
84      private boolean addHiddenWhenReadOnly;
85  
86      // read only display properties
87      protected String readOnlyDisplayReplacementPropertyName;
88      protected String readOnlyDisplaySuffixPropertyName;
89  
90      private String readOnlyDisplayReplacement;
91      private String readOnlyDisplaySuffix;
92  
93      private String readOnlyListDisplayType;
94      private String readOnlyListDelimiter;
95  
96      private boolean applyMask;
97      private MaskFormatter maskFormatter;
98  
99      private List<String> additionalHiddenPropertyNames;
100     private List<String> propertyNamesForAdditionalDisplay;
101 
102     private boolean escapeHtmlInPropertyValue;
103     private boolean multiLineReadOnlyDisplay;
104 
105     // widgets
106     private Inquiry inquiry;
107     private boolean enableAutoInquiry;
108 
109     private Help help;
110 
111     // Optional span render flags
112     private boolean renderInfoMessageSpan;
113     private boolean renderMarkerIconSpan;
114 
115     private String sortAs;
116 
117     public DataFieldBase() {
118         super();
119 
120         enableAutoInquiry = true;
121         escapeHtmlInPropertyValue = true;
122 
123         additionalHiddenPropertyNames = Collections.emptyList();
124         propertyNamesForAdditionalDisplay = Collections.emptyList();
125     }
126 
127     /**
128      * {@inheritDoc}
129      */
130     @Override
131     public void performInitialization(Object model) {
132         super.performInitialization(model);
133 
134         if (bindingInfo != null) {
135             bindingInfo.setDefaults(ViewLifecycle.getView(), getPropertyName());
136         }
137     }
138     
139     /**
140      * {@inheritDoc}
141      */
142     @Override
143     public void afterEvaluateExpression() {
144         // set to true before calling super.
145         if (getReadOnly() == null) {
146             setReadOnly(true);
147         }
148         
149         super.afterEvaluateExpression();
150     }
151 
152     /**
153      * {@inheritDoc}
154      */
155     @Override
156     public void performApplyModel(Object model, LifecycleElement parent) {
157         super.performApplyModel(model, parent);
158 
159         if (enableAutoInquiry && this.inquiry == null && Boolean.TRUE.equals(getReadOnly()) && hasAutoInquiryRelationship()) {
160             this.inquiry = ComponentFactory.getInquiry();
161         }
162 
163         if (isAddHiddenWhenReadOnly()) {
164             setReadOnly(true);
165             getAdditionalHiddenPropertyNames().add(getPropertyName());
166         }
167     }
168 
169     /**
170      * {@inheritDoc}
171      */
172     @Override
173     public void performFinalize(Object model, LifecycleElement parent) {
174         super.performFinalize(model, parent);
175 
176         // adjust the path for hidden fields and add as accessible paths
177         List<String> hiddenPropertyPaths = new ArrayList<String>();
178         for (String hiddenPropertyName : getAdditionalHiddenPropertyNames()) {
179             String hiddenPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(hiddenPropertyName);
180             hiddenPropertyPaths.add(hiddenPropertyPath);
181 
182             if (isRender() || StringUtils.isNotBlank(getProgressiveRender())) {
183                 ViewLifecycle.getViewPostMetadata().addAccessibleBindingPath(hiddenPropertyPath);
184             }
185         }
186         this.additionalHiddenPropertyNames = hiddenPropertyPaths;
187 
188         // adjust paths on informational property names
189         List<String> informationalPropertyPaths = new ArrayList<String>();
190         for (String infoPropertyName : getPropertyNamesForAdditionalDisplay()) {
191             String infoPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(infoPropertyName);
192             informationalPropertyPaths.add(infoPropertyPath);
193         }
194         this.propertyNamesForAdditionalDisplay = informationalPropertyPaths;
195 
196         // process read-only lists and additional and alternate display values
197         boolean hasPropertyEditor = getPropertyEditor() != null;
198         boolean hasReadOnlyDisplayReplacement = StringUtils.isNotBlank(getReadOnlyDisplayReplacement());
199         boolean hasReadOnlyDisplayReplacementPropertyName = StringUtils.isNotBlank(
200                 getReadOnlyDisplayReplacementPropertyName());
201         String bindingPath = getBindingInfo().getBindingPath();
202         Class<?> type = StringUtils.isNotEmpty(bindingPath) ? ObjectPropertyUtils.getPropertyType(model, bindingPath) : null;
203         boolean isReadOnlyList = Boolean.TRUE.equals(getReadOnly()) && type != null && List.class.isAssignableFrom(type);
204 
205         if (!hasPropertyEditor && !hasReadOnlyDisplayReplacement && !hasReadOnlyDisplayReplacementPropertyName && isReadOnlyList) {
206             Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, bindingPath);
207             List<?> list = fieldValue != null ? (List<?>) fieldValue : Collections.emptyList();
208 
209             processReadOnlyListDisplay(model, list);
210         } else {
211             setAlternateAndAdditionalDisplayValue(ViewLifecycle.getView(), model);
212         }
213 
214         if (this.getFieldLabel() != null && StringUtils.isNotBlank(this.getId())) {
215             this.getFieldLabel().setLabelForComponentId(this.getId() + UifConstants.IdSuffixes.CONTROL);
216         }
217 
218         if (model instanceof ViewModel) {
219             View view = ViewLifecycle.getView();
220             if(((ViewModel) model).isApplyDefaultValues()) {
221 
222                 // apply default field values to view
223                 view.getViewHelperService().populateDefaultValueForField(model, this,
224                         this.getBindingInfo().getBindingPath());
225 
226                 // ensure default values are only applied once
227                 ((ViewModel) model).setApplyDefaultValues(false);
228             }
229         }
230         
231         ViewPostMetadata viewPostMetadata = ViewLifecycle.getViewPostMetadata();
232         if (isRender() && viewPostMetadata != null) {
233             viewPostMetadata.addRenderedPropertyPath(getBindingInfo().getBindingPath());
234         }
235     }
236 
237     /**
238      * This method is called when the list is readOnly as determined in DataField's performFinalize method.  This
239      * method
240      * should be overridden to perform any additional processing to the values before calling
241      * generateReadOnlyListDisplayReplacement.  The default implementation calls it directly with the originalList.
242      *
243      * @param model the model
244      * @param originalList originalList of values
245      */
246     protected void processReadOnlyListDisplay(Object model, List<?> originalList) {
247         this.setReadOnlyDisplayReplacement(generateReadOnlyListDisplayReplacement(originalList));
248     }
249 
250     /**
251      * Generates the html to be used and sets the readOnlyDisplayReplacement for DataFields that contain lists and
252      * do not have their own readOnlyDisplayReplacement defined.  The type of html generated is based on the options
253      * set on readOnlyListDisplayType and readOnlyListDelimiter.
254      *
255      * @param list the list to be converted to readOnly html
256      */
257     protected String generateReadOnlyListDisplayReplacement(List<?> list) {
258         //Default to delimited if nothing is set
259         if (getReadOnlyListDisplayType() == null) {
260             this.setReadOnlyListDisplayType(UifConstants.ReadOnlyListTypes.DELIMITED.name());
261         }
262 
263         String generatedHtml = "";
264 
265         //begin generation setup
266         if (!list.isEmpty()) {
267             if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name())) {
268                 generatedHtml = "<ul class='uif-readOnlyStringList'>";
269             } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) {
270                 generatedHtml = "<ol class='uif-readOnlyStringList'>";
271             } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.BREAK.name())) {
272                 setReadOnlyListDelimiter("<br/>");
273             } else if (this.getReadOnlyListDelimiter() == null) {
274                 setReadOnlyListDelimiter(", ");
275             }
276         }
277 
278         //iterate through each value
279         for (Object value : list) {
280             //if blank skip
281             if (!TypeUtils.isSimpleType(value.getClass()) || StringUtils.isBlank(value.toString())) {
282                 continue;
283             }
284 
285             //handle mask if any
286             if (isApplyMask()) {
287                 value = getMaskFormatter().maskValue(value);
288             }
289 
290             //TODO the value should use the formatted text property value we would expect to see instead of toString
291             //two types - delimited and html list
292             if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name())
293                     || getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) {
294                 generatedHtml = generatedHtml + "<li>" + StringEscapeUtils.escapeHtml(value.toString()) + "</li>";
295             } else {
296                 //no matching needed - delimited is always the fallback and break uses same logic
297                 generatedHtml = generatedHtml + StringEscapeUtils.escapeHtml(value.toString())
298                         + this.getReadOnlyListDelimiter();
299             }
300         }
301 
302         //end the generation
303         if (!list.isEmpty()) {
304             if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.UL.name())) {
305                 generatedHtml = generatedHtml + "</ul>";
306             } else if (getReadOnlyListDisplayType().equalsIgnoreCase(UifConstants.ReadOnlyListTypes.OL.name())) {
307                 generatedHtml = generatedHtml + "</ol>";
308             } else {
309                 generatedHtml = StringUtils.removeEnd(generatedHtml, this.getReadOnlyListDelimiter());
310             }
311         }
312 
313         if (StringUtils.isBlank(generatedHtml)) {
314             generatedHtml = "&nbsp;";
315         }
316 
317         return generatedHtml;
318     }
319 
320     /**
321      * Sets alternate and additional property value for this field.
322      *
323      * <p>
324      * If <code>AttributeSecurity</code> present in this field, make sure the current user has permission to view the
325      * field value. If user doesn't have permission to view the value, mask the value as configured and set it
326      * as alternate value for display. If security doesn't exists for this field but
327      * <code>alternateDisplayPropertyName</code> present, get its value and format it based on that
328      * fields formatting and set for display.
329      * </p>
330      *
331      * <p>
332      * For additional display value, if <code>AttributeSecurity</code> not present, sets the value if
333      * <code>additionalDisplayPropertyName</code> present. If not present, check whether this field is a
334      * <code>KualiCode</code> and get the relationship configured in the datadictionary file and set the name
335      * additional display value which will be displayed along with the code. If additional display property not
336      * present, check whether this field is has <code>MultiValueControlBase</code>. If yes, get the Label
337      * for the value and set it as additional display value.
338      * </p>
339      *
340      * @param view the current view instance
341      * @param model model instance
342      */
343     protected void setAlternateAndAdditionalDisplayValue(View view, Object model) {
344         // if alternate or additional display values set don't use property names
345         if (StringUtils.isNotBlank(readOnlyDisplayReplacement) || StringUtils.isNotBlank(readOnlyDisplaySuffix)) {
346             return;
347         }
348 
349         // check whether field value needs to be masked, and if so apply masking as alternateDisplayValue
350         if (isApplyMask()) {
351             Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath());
352             if (getMaskFormatter() != null) {
353                 readOnlyDisplayReplacement = getMaskFormatter().maskValue(fieldValue);
354             }
355 
356             return;
357         }
358 
359         // if not read only, return without trying to set alternate and additional values
360         if (!Boolean.TRUE.equals(getReadOnly())) {
361             return;
362         }
363 
364         // if field is not secure, check for alternate and additional display properties
365         if (StringUtils.isNotBlank(getReadOnlyDisplayReplacementPropertyName())) {
366             String alternateDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(
367                     getReadOnlyDisplayReplacementPropertyName());
368 
369             Object alternateFieldValue = ObjectPropertyUtils.getPropertyValue(model, alternateDisplayPropertyPath);
370             if (alternateFieldValue != null) {
371                 // TODO: format by type
372                 readOnlyDisplayReplacement = alternateFieldValue.toString();
373             }
374         }
375 
376         // perform automatic translation for code references if enabled on view
377         if (StringUtils.isBlank(getReadOnlyDisplaySuffixPropertyName()) && view.isTranslateCodesOnReadOnlyDisplay()) {
378             // check for any relationship present for this field and it's of type KualiCode
379             Class<?> parentObjectClass = ViewModelUtils.getParentObjectClassForMetadata(view, model, this);
380             DataObjectRelationship relationship =
381                     KRADServiceLocatorWeb.getLegacyDataAdapter().getDataObjectRelationship(null,
382                             parentObjectClass, getBindingInfo().getBindingName(), "", true, false, false);
383 
384             if (relationship != null
385                     && getPropertyName().startsWith(relationship.getParentAttributeName())
386                     && KualiCode.class.isAssignableFrom(relationship.getRelatedClass())) {
387                 readOnlyDisplaySuffixPropertyName =
388                         relationship.getParentAttributeName() + "." + KRADPropertyConstants.NAME;
389             }
390         }
391 
392         // now check for an additional display property and if set get the value
393         if (StringUtils.isNotBlank(getReadOnlyDisplaySuffixPropertyName())) {
394             String additionalDisplayPropertyPath = getBindingInfo().getPropertyAdjustedBindingPath(
395                     getReadOnlyDisplaySuffixPropertyName());
396 
397             Object additionalFieldValue = ObjectPropertyUtils.getPropertyValue(model, additionalDisplayPropertyPath);
398             if (additionalFieldValue != null) {
399                 // TODO: format by type
400                 readOnlyDisplaySuffix = additionalFieldValue.toString();
401             }
402         }
403     }
404 
405     /**
406      * {@inheritDoc}
407      */
408     @Override
409     public void copyFromAttributeDefinition(AttributeDefinition attributeDefinition) {
410         // label
411         if (StringUtils.isEmpty(getLabel())) {
412             setLabel(attributeDefinition.getLabel());
413         }
414 
415         // short label
416         if (StringUtils.isEmpty(getShortLabel())) {
417             setShortLabel(attributeDefinition.getShortLabel());
418         }
419 
420         // security
421         if ((attributeDefinition.getAttributeSecurity() != null) && ((getDataFieldSecurity() == null) || (
422                 getDataFieldSecurity().getAttributeSecurity() == null))) {
423             initializeComponentSecurity();
424 
425             getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity());
426         }
427 
428         // alternate property name
429         if (getReadOnlyDisplayReplacementPropertyName() == null && StringUtils.isNotBlank(
430                 attributeDefinition.getAlternateDisplayAttributeName())) {
431             setReadOnlyDisplayReplacementPropertyName(attributeDefinition.getAlternateDisplayAttributeName());
432         }
433 
434         // additional property display name
435         if (getReadOnlyDisplaySuffixPropertyName() == null && StringUtils.isNotBlank(
436                 attributeDefinition.getAdditionalDisplayAttributeName())) {
437             setReadOnlyDisplaySuffixPropertyName(attributeDefinition.getAdditionalDisplayAttributeName());
438         }
439 
440         // property editor
441         if (getPropertyEditor() == null) {
442             setPropertyEditor(attributeDefinition.getPropertyEditor());
443         }
444     }
445 
446     /**
447      * {@inheritDoc}
448      */
449     @Override
450     public boolean isInputAllowed() {
451         return false;
452     }
453 
454     /**
455      * {@inheritDoc}
456      */
457     @Override
458     @BeanTagAttribute
459     public String getPropertyName() {
460         return this.propertyName;
461     }
462 
463     /**
464      * {@inheritDoc}
465      */
466     @Override
467     public void setPropertyName(String propertyName) {
468         this.propertyName = propertyName;
469     }
470 
471     /**
472      * {@inheritDoc}
473      */
474     @Override
475     @BeanTagAttribute
476     public PropertyEditor getPropertyEditor() {
477         return propertyEditor;
478     }
479 
480     /**
481      * {@inheritDoc}
482      */
483     @Override
484     public void setPropertyEditor(PropertyEditor propertyEditor) {
485         this.propertyEditor = propertyEditor;
486     }
487 
488     /**
489      * {@inheritDoc}
490      */
491     @Override
492     public void setPropertyEditorClass(Class<? extends PropertyEditor> propertyEditorClass) {
493         this.propertyEditor = KRADUtils.createNewObjectFromClass(propertyEditorClass);
494     }
495 
496     /**
497      * {@inheritDoc}
498      */
499     @Override
500     @BeanTagAttribute
501     public BindingInfo getBindingInfo() {
502         return this.bindingInfo;
503     }
504 
505     /**
506      * {@inheritDoc}
507      */
508     @Override
509     public void setBindingInfo(BindingInfo bindingInfo) {
510         this.bindingInfo = bindingInfo;
511     }
512 
513     /**
514      * {@inheritDoc}
515      */
516     @Override
517     public String getName() {
518         return this.getBindingInfo().getBindingPath();
519     }
520 
521     /**
522      * {@inheritDoc}
523      */
524     @Override
525     @BeanTagAttribute
526     public String getDictionaryAttributeName() {
527         return this.dictionaryAttributeName;
528     }
529 
530     /**
531      * {@inheritDoc}
532      */
533     @Override
534     public void setDictionaryAttributeName(String dictionaryAttributeName) {
535         this.dictionaryAttributeName = dictionaryAttributeName;
536     }
537 
538     /**
539      * {@inheritDoc}
540      */
541     @Override
542     @BeanTagAttribute
543     public String getDictionaryObjectEntry() {
544         return this.dictionaryObjectEntry;
545     }
546 
547     /**
548      * {@inheritDoc}
549      */
550     @Override
551     public void setDictionaryObjectEntry(String dictionaryObjectEntry) {
552         this.dictionaryObjectEntry = dictionaryObjectEntry;
553     }
554 
555     /**
556      * {@inheritDoc}
557      */
558     @Override
559     @BeanTagAttribute
560     public Object getDefaultValue() {
561         return this.defaultValue;
562     }
563 
564     /**
565      * {@inheritDoc}
566      */
567     @Override
568     public void setDefaultValue(Object defaultValue) {
569         this.defaultValue = defaultValue;
570     }
571 
572     /**
573      * {@inheritDoc}
574      */
575     @Override
576     @BeanTagAttribute
577     public Class<? extends ValueFinder> getDefaultValueFinderClass() {
578         return this.defaultValueFinderClass;
579     }
580 
581     /**
582      * {@inheritDoc}
583      */
584     @Override
585     public void setDefaultValueFinderClass(Class<? extends ValueFinder> defaultValueFinderClass) {
586         this.defaultValueFinderClass = defaultValueFinderClass;
587     }
588 
589     /**
590      * {@inheritDoc}
591      */
592     @Override
593     @BeanTagAttribute
594     public List<Object> getDefaultValues() {
595         return this.defaultValues;
596     }
597 
598     /**
599      * {@inheritDoc}
600      */
601     public void setDefaultValues(List<Object> defaultValues) {
602         this.defaultValues = defaultValues;
603     }
604 
605     /**
606      * {@inheritDoc}
607      */
608     @Override
609     public String getForcedValue() {
610         return forcedValue;
611     }
612 
613     /**
614      * {@inheritDoc}
615      */
616     @Override
617     public void setForcedValue(String forcedValue) {
618         this.forcedValue = forcedValue;
619     }
620 
621     /**
622      * {@inheritDoc}
623      */
624     @Override
625     @BeanTagAttribute
626     public String getHelpSummary() {
627         return this.help.getTooltipHelpContent();
628     }
629 
630     /**
631      * {@inheritDoc}
632      */
633     @Override
634     public void setHelpSummary(String helpSummary) {
635         this.help.setTooltipHelpContent(helpSummary);
636     }
637 
638     /**
639      * {@inheritDoc}
640      */
641     @Override
642     public DataFieldSecurity getDataFieldSecurity() {
643         return (DataFieldSecurity) super.getComponentSecurity();
644     }
645 
646     /**
647      * {@inheritDoc}
648      */
649     @Override
650     public void setComponentSecurity(ComponentSecurity componentSecurity) {
651         if ((componentSecurity != null) && !(componentSecurity instanceof DataFieldSecurity)) {
652             throw new RiceRuntimeException("Component security for DataField should be instance of DataFieldSecurity");
653         }
654 
655         super.setComponentSecurity(componentSecurity);
656     }
657 
658     /**
659      * @see org.kuali.rice.krad.uif.component.ComponentBase#initializeComponentSecurity()
660      */
661     @Override
662     protected void initializeComponentSecurity() {
663         if (getComponentSecurity() == null) {
664             setComponentSecurity(KRADUtils.createNewObjectFromClass(DataFieldSecurity.class));
665         }
666     }
667 
668     /**
669      * {@inheritDoc}
670      */
671     @Override
672     @BeanTagAttribute
673     public boolean isAddHiddenWhenReadOnly() {
674         return addHiddenWhenReadOnly;
675     }
676 
677     /**
678      * {@inheritDoc}
679      */
680     @Override
681     public void setAddHiddenWhenReadOnly(boolean addHiddenWhenReadOnly) {
682         this.addHiddenWhenReadOnly = addHiddenWhenReadOnly;
683     }
684 
685     /**
686      * {@inheritDoc}
687      */
688     @Override
689     @BeanTagAttribute(type = BeanTagAttribute.AttributeType.DIRECTORBYTYPE)
690     public Inquiry getInquiry() {
691         return this.inquiry;
692     }
693 
694     /**
695      * {@inheritDoc}
696      */
697     @Override
698     public void setInquiry(Inquiry inquiry) {
699         this.inquiry = inquiry;
700     }
701 
702     /**
703      * {@inheritDoc}
704      */
705     @Override
706     public boolean isEnableAutoInquiry() {
707         return enableAutoInquiry;
708     }
709 
710     /**
711      * {@inheritDoc}
712      */
713     @Override
714     public void setEnableAutoInquiry(boolean enableAutoInquiry) {
715         this.enableAutoInquiry = enableAutoInquiry;
716     }
717 
718     /**
719      * {@inheritDoc}
720      */
721     @Override
722     @BeanTagAttribute(type = BeanTagAttribute.AttributeType.DIRECTORBYTYPE)
723     public Help getHelp() {
724         return this.help;
725     }
726 
727     /**
728      * {@inheritDoc}
729      */
730     @Override
731     public void setHelp(Help help) {
732         this.help = help;
733     }
734 
735     /**
736      * {@inheritDoc}
737      */
738     @Override
739     @BeanTagAttribute
740     public boolean isRenderInfoMessageSpan() {
741         return renderInfoMessageSpan;
742     }
743 
744     /**
745      * {@inheritDoc}
746      */
747     @Override
748     public void setRenderInfoMessageSpan(boolean renderInfoMessageSpan) {
749         this.renderInfoMessageSpan = renderInfoMessageSpan;
750     }
751 
752     /**
753      * {@inheritDoc}
754      */
755     @Override
756     @BeanTagAttribute
757     public boolean isRenderMarkerIconSpan() {
758         return renderMarkerIconSpan;
759     }
760 
761     /**
762      * {@inheritDoc}
763      */
764     @Override
765     public void setRenderMarkerIconSpan(boolean renderMarkerIconSpan) {
766         this.renderMarkerIconSpan = renderMarkerIconSpan;
767     }
768 
769     /**
770      * {@inheritDoc}
771      */
772     @Override
773     public void setTooltipOfComponent(Tooltip tooltip) {
774         getFieldLabel().setToolTip(tooltip);
775     }
776 
777     /**
778      * {@inheritDoc}
779      */
780     @Override
781     public String getHelpTitle() {
782         return this.getLabel();
783     }
784 
785     /**
786      * {@inheritDoc}
787      */
788     @Override
789     @BeanTagAttribute
790     public String getReadOnlyDisplaySuffixPropertyName() {
791         return this.readOnlyDisplaySuffixPropertyName;
792     }
793 
794     /**
795      * {@inheritDoc}
796      */
797     @Override
798     public void setReadOnlyDisplaySuffixPropertyName(String readOnlyDisplaySuffixPropertyName) {
799         this.readOnlyDisplaySuffixPropertyName = readOnlyDisplaySuffixPropertyName;
800     }
801 
802     /**
803      * {@inheritDoc}
804      */
805     @Override
806     @BeanTagAttribute
807     public String getReadOnlyDisplayReplacementPropertyName() {
808         return this.readOnlyDisplayReplacementPropertyName;
809     }
810 
811     /**
812      * {@inheritDoc}
813      */
814     @Override
815     public void setReadOnlyDisplayReplacementPropertyName(String readOnlyDisplayReplacementPropertyName) {
816         this.readOnlyDisplayReplacementPropertyName = readOnlyDisplayReplacementPropertyName;
817     }
818 
819     /**
820      * {@inheritDoc}
821      */
822     @Override
823     @BeanTagAttribute
824     public String getReadOnlyDisplayReplacement() {
825         return readOnlyDisplayReplacement;
826     }
827 
828     /**
829      * {@inheritDoc}
830      */
831     @Override
832     public void setReadOnlyDisplayReplacement(String value) {
833         this.readOnlyDisplayReplacement = value;
834     }
835 
836     /**
837      * {@inheritDoc}
838      */
839     @Override
840     @BeanTagAttribute
841     public String getReadOnlyDisplaySuffix() {
842         return readOnlyDisplaySuffix;
843     }
844 
845     /**
846      * {@inheritDoc}
847      */
848     @Override
849     public void setReadOnlyDisplaySuffix(String value) {
850         this.readOnlyDisplaySuffix = value;
851     }
852 
853     /**
854      * {@inheritDoc}
855      */
856     @Override
857     @BeanTagAttribute
858     public String getReadOnlyListDisplayType() {
859         return readOnlyListDisplayType;
860     }
861 
862     /**
863      * {@inheritDoc}
864      */
865     @Override
866     public void setReadOnlyListDisplayType(String readOnlyListDisplayType) {
867         this.readOnlyListDisplayType = readOnlyListDisplayType;
868     }
869 
870     /**
871      * {@inheritDoc}
872      */
873     @Override
874     @BeanTagAttribute
875     public String getReadOnlyListDelimiter() {
876         return readOnlyListDelimiter;
877     }
878 
879     /**
880      * {@inheritDoc}
881      */
882     @Override
883     public void setReadOnlyListDelimiter(String readOnlyListDelimiter) {
884         this.readOnlyListDelimiter = readOnlyListDelimiter;
885     }
886 
887     /**
888      * {@inheritDoc}
889      */
890     @Override
891     @BeanTagAttribute
892     public boolean isApplyMask() {
893         return applyMask;
894     }
895 
896     /**
897      * {@inheritDoc}
898      */
899     @Override
900     public void setApplyMask(boolean applyMask) {
901         this.applyMask = applyMask;
902     }
903 
904     /**
905      * {@inheritDoc}
906      */
907     @Override
908     @BeanTagAttribute
909     public MaskFormatter getMaskFormatter() {
910         return maskFormatter;
911     }
912 
913     /**
914      * {@inheritDoc}
915      */
916     @Override
917     public void setMaskFormatter(MaskFormatter maskFormatter) {
918         this.maskFormatter = maskFormatter;
919     }
920 
921     /**
922      * {@inheritDoc}
923      */
924     @Override
925     @BeanTagAttribute
926     public List<String> getAdditionalHiddenPropertyNames() {
927         if (additionalHiddenPropertyNames == Collections.EMPTY_LIST && isMutable(true)) {
928             additionalHiddenPropertyNames = new LifecycleAwareList<String>(this);
929         }
930         
931         return additionalHiddenPropertyNames;
932     }
933 
934     /**
935      * {@inheritDoc}
936      */
937     @Override
938     public void setAdditionalHiddenPropertyNames(List<String> additionalHiddenPropertyNames) {
939         if (additionalHiddenPropertyNames == null) {
940             this.additionalHiddenPropertyNames = Collections.emptyList();
941         } else {
942             this.additionalHiddenPropertyNames =
943                     new LifecycleAwareList<String>(this, additionalHiddenPropertyNames);
944         }
945     }
946 
947     /**
948      * {@inheritDoc}
949      */
950     @Override
951     @BeanTagAttribute
952     public List<String> getPropertyNamesForAdditionalDisplay() {
953         if (propertyNamesForAdditionalDisplay == Collections.EMPTY_LIST && isMutable(true)) {
954             propertyNamesForAdditionalDisplay = new LifecycleAwareList<String>(this);
955         }
956         
957         return propertyNamesForAdditionalDisplay;
958     }
959 
960     /**
961      * {@inheritDoc}
962      */
963     @Override
964     public void setPropertyNamesForAdditionalDisplay(List<String> propertyNamesForAdditionalDisplay) {
965         if (propertyNamesForAdditionalDisplay == null) {
966             this.propertyNamesForAdditionalDisplay = Collections.emptyList();
967         } else {
968             this.propertyNamesForAdditionalDisplay =
969                     new LifecycleAwareList<String>(this, propertyNamesForAdditionalDisplay);
970         }
971     }
972     
973     /**
974      * {@inheritDoc}
975      */
976     @Override
977     @BeanTagAttribute
978     public boolean isEscapeHtmlInPropertyValue() {
979         return this.escapeHtmlInPropertyValue;
980     }
981 
982     /**
983      * {@inheritDoc}
984      */
985     @Override
986     public void setEscapeHtmlInPropertyValue(boolean escapeHtmlInPropertyValue) {
987         this.escapeHtmlInPropertyValue = escapeHtmlInPropertyValue;
988     }
989 
990     /**
991      * {@inheritDoc}
992      */
993     @Override
994     @BeanTagAttribute
995     public boolean isMultiLineReadOnlyDisplay() {
996         return multiLineReadOnlyDisplay;
997     }
998 
999     /**
1000      * {@inheritDoc}
1001      */
1002     @Override
1003     public void setMultiLineReadOnlyDisplay(boolean multiLineReadOnlyDisplay) {
1004         this.multiLineReadOnlyDisplay = multiLineReadOnlyDisplay;
1005     }
1006 
1007     /**
1008      * {@inheritDoc}
1009      */
1010     @Override
1011     public boolean hasSecureValue() {
1012         boolean hasHideAuthz = false;
1013 
1014         if (getDataFieldSecurity() != null) {
1015             boolean isViewAuthz = false;
1016             boolean isViewInLineAuthz = false;
1017             boolean isHide = false;
1018 
1019             if (getDataFieldSecurity().isViewAuthz() != null) {
1020                 isViewAuthz = getDataFieldSecurity().isViewAuthz().booleanValue();
1021             }
1022 
1023             if (getDataFieldSecurity().isViewInLineAuthz() != null) {
1024                 isViewInLineAuthz = getDataFieldSecurity().isViewInLineAuthz().booleanValue();
1025             }
1026 
1027             if (getDataFieldSecurity().getAttributeSecurity() != null) {
1028                 isHide = getDataFieldSecurity().getAttributeSecurity().isHide();
1029             }
1030 
1031             hasHideAuthz = isViewAuthz || isViewInLineAuthz || isHide;
1032         }
1033 
1034         return isApplyMask() || (hasHideAuthz && isHidden());
1035     }
1036 
1037     /**
1038      * {@inheritDoc}
1039      */
1040     @Override
1041     public boolean isRenderFieldset() {
1042         return (!Boolean.TRUE.equals(this.getReadOnly())
1043                 && inquiry != null
1044                 && inquiry.isRender()
1045                 && inquiry.getInquiryLink() != null
1046                 && inquiry.getInquiryLink().isRender()) || (help != null
1047                 && help.isRender()
1048                 && help.getHelpAction() != null
1049                 && help.getHelpAction().isRender());
1050     }
1051 
1052     /**
1053      * {@inheritDoc}
1054      */
1055     @Override
1056     @BeanTagAttribute(name = "sortAs")
1057     public String getSortAs() {
1058         return sortAs;
1059     }
1060 
1061     /**
1062      * {@inheritDoc}
1063      */
1064     @Override
1065     public void setSortAs(String sortAs) {
1066         if (!(sortAs.equals(UifConstants.TableToolsValues.CURRENCY) || sortAs.equals(UifConstants.TableToolsValues.DATE) || sortAs.equals(UifConstants.TableToolsValues.NUMERIC) || sortAs.equals(UifConstants.TableToolsValues.STRING))) {
1067             throw new IllegalArgumentException("invalid sortAs value of " + sortAs + ", allowed: " + UifConstants.TableToolsValues.CURRENCY + "|" + UifConstants.TableToolsValues.DATE + "|" + UifConstants.TableToolsValues.NUMERIC + "|" + UifConstants.TableToolsValues.STRING);
1068         }
1069         this.sortAs = sortAs;
1070     }
1071 
1072     /**
1073      * {@inheritDoc}
1074      */
1075     @Override
1076     public void completeValidation(ValidationTrace tracer) {
1077         tracer.addBean(this);
1078 
1079         // Checks that the property is connected to the field
1080         if (getPropertyName() == null) {
1081             if (!Validator.checkExpressions(this, "propertyName")) {
1082                 String currentValues[] = {"propertyName = " + getPropertyName()};
1083                 tracer.createError("Property name not set", currentValues);
1084             }
1085         }
1086 
1087         // Checks that the default values  present
1088 /*        if (getDefaultValue() != null && getDefaultValues() != null) {
1089             String currentValues[] =
1090                     {"defaultValue =" + getDefaultValue(), "defaultValues Size =" + getDefaultValues().length};
1091             tracer.createWarning("Both Default Value and Default Values set", currentValues);
1092         }*/
1093 
1094         // Checks that a mask formatter is set if the data field is to be masked
1095         if (isApplyMask()) {
1096             if (maskFormatter == null) {
1097                 String currentValues[] = {"applyMask =" + isApplyMask(), "maskFormatter =" + maskFormatter};
1098                 tracer.createWarning("Apply mask is true, but no value is set for maskFormatter", currentValues);
1099             }
1100         }
1101 
1102         super.completeValidation(tracer.getCopy());
1103     }
1104 
1105     /**
1106      * Determines wheter or not to create an automatic inqury widget for this field within the current lifecycle.
1107      * 
1108      * @return True if an automatic inquiry widget should be created for this field on the current lifecycle.
1109      */
1110     protected boolean hasAutoInquiryRelationship() {
1111         if (getBindingInfo() == null) {
1112             return false;
1113         }
1114 
1115         View view = ViewLifecycle.getView();
1116         Object model = ViewLifecycle.getModel();
1117 
1118         // Do checks for inquiry when read only
1119         if (Boolean.TRUE.equals(getReadOnly())) {
1120 
1121             String bindingPath = getBindingInfo().getBindingPath();
1122             if (StringUtils.isBlank(bindingPath) || bindingPath.equals("null")) {
1123                 return false;
1124             }
1125 
1126             // check if field value is null, if so no inquiry
1127             try {
1128                 Object propertyValue = ObjectPropertyUtils.getPropertyValue(model, bindingPath);
1129 
1130                 if ((propertyValue == null) || StringUtils.isBlank(propertyValue.toString())) {
1131                     return false;
1132                 }
1133             } catch (Exception e) {
1134                 // if we can't get the value just swallow the exception and don't set an inquiry
1135                 return false;
1136             }
1137 
1138             // skips creating inquiry link if same as parent
1139             if (view.getViewTypeName() == UifConstants.ViewType.INQUIRY) {
1140                 InquiryForm inquiryForm = (InquiryForm) model;
1141                 String propertyName = getPropertyName();
1142 
1143                 // value of field
1144                 Object fieldValue = ObjectPropertyUtils.getPropertyValue(ViewModelUtils.getParentObjectForMetadata(
1145                         view, model, this), propertyName);
1146 
1147                 // value of field in request parameter
1148                 Object parameterValue = inquiryForm.getInitialRequestParameters().get(propertyName);
1149 
1150                 // if data classes and field values are equal
1151                 if (inquiryForm.getDataObjectClassName().equals(getDictionaryObjectEntry())
1152                         && parameterValue != null && fieldValue.equals(parameterValue)) {
1153                     return false;
1154                 }
1155             }
1156         }
1157 
1158         // get parent object for inquiry metadata
1159         Object parentObject = ViewModelUtils.getParentObjectForMetadata(view, model, this);
1160         return parentObject == null ? false : KRADServiceLocatorWeb.getViewDictionaryService().isInquirable(
1161                 parentObject.getClass());
1162     }
1163 
1164 }