View Javadoc

1   /**
2    * Copyright 2005-2012 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.web.bind;
17  
18  import org.kuali.rice.core.web.format.Formatter;
19  import org.kuali.rice.krad.uif.field.DataField;
20  import org.kuali.rice.krad.uif.view.ViewModel;
21  import org.springframework.beans.BeanWrapperImpl;
22  import org.springframework.beans.BeansException;
23  import org.springframework.beans.InvalidPropertyException;
24  import org.springframework.beans.PropertyValue;
25  
26  import java.beans.PropertyDescriptor;
27  import java.beans.PropertyEditor;
28  import java.util.HashSet;
29  import java.util.Set;
30  
31  /**
32   * Class is a top level BeanWrapper for a UIF View Model
33   *
34   * <p>
35   * Registers custom property editors configured on the field associated with the property name for which
36   * we are getting or setting a value. In addition determines if the field requires encryption and if so applies
37   * the {@link UifEncryptionPropertyEditorWrapper}
38   * </p>
39   *
40   * @author Kuali Rice Team (rice.collab@kuali.org)
41   */
42  public class UifViewBeanWrapper extends BeanWrapperImpl {
43      private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(UifViewBeanWrapper.class);
44  
45      // this is a handle to the target object so we don't have to cast so often
46      private ViewModel model;
47  
48      // this stores all properties this wrapper has already checked
49      // with the view so the service isn't called again
50      private Set<String> processedProperties;
51  
52      public UifViewBeanWrapper(ViewModel model) {
53          super(model);
54  
55          this.model = model;
56          this.processedProperties = new HashSet<String>();
57      }
58  
59      /**
60       * Attempts to find a corresponding data field for the given property name in the current view or previous view,
61       * then if the field has a property editor configured it is registered with the property editor registry to use
62       * for this property
63       *
64       * @param propertyName - name of the property to find field and editor for
65       */
66      protected void registerEditorFromView(String propertyName) {
67          if (LOG.isDebugEnabled()) {
68              LOG.debug("Attempting to find property editor for property '" + propertyName + "'");
69          }
70  
71          PropertyEditor propertyEditor = null;
72  
73          // viewId should be determined in UifAnnotationMethodHandlerAdapter so
74          // nothing we can do without one here
75          if (model.getView() == null) {
76              return;
77          }
78  
79          // check if we already processed this property for this BeanWrapper instance
80          if (processedProperties.contains(propertyName)) {
81              return;
82          }
83  
84          DataField dataField = null;
85          if (model.getView().getViewIndex() != null) {
86              dataField = model.getView().getViewIndex().getDataFieldByPath(propertyName);
87          }
88  
89          if ((dataField == null) && (model.getPreviousView() != null) && (model.getPreviousView().getViewIndex()
90                  != null)) {
91              dataField = model.getPreviousView().getViewIndex().getDataFieldByPath(propertyName);
92          }
93  
94          // determine if the field value should be secured
95          boolean requiresEncryption = false;
96          if (dataField != null) {
97              if (dataField.hasSecureValue()) {
98                  requiresEncryption = true;
99              }
100 
101             propertyEditor = dataField.getPropertyEditor();
102         }
103 
104         if (propertyEditor != null) {
105             if (LOG.isDebugEnabled()) {
106                 LOG.debug("Registering custom editor for property path '"
107                         + propertyName
108                         + "' and property editor class '"
109                         + propertyEditor.getClass().getName()
110                         + "'");
111             }
112 
113             if (requiresEncryption) {
114                 if (LOG.isDebugEnabled()) {
115                     LOG.debug("Enabling encryption for custom editor '"
116                             + propertyName
117                             + "' and property editor class '"
118                             + propertyEditor.getClass().getName()
119                             + "'");
120                 }
121                 this.registerCustomEditor(null, propertyName, new UifEncryptionPropertyEditorWrapper(propertyEditor));
122             } else {
123                 this.registerCustomEditor(null, propertyName, propertyEditor);
124             }
125         } else if (requiresEncryption) {
126             if (LOG.isDebugEnabled()) {
127                 LOG.debug("No custom formatter for property path '"
128                         + propertyName
129                         + "' but property does require encryption");
130             }
131 
132             this.registerCustomEditor(null, propertyName, new UifEncryptionPropertyEditorWrapper(
133                     findEditorForPropertyName(propertyName)));
134         }
135 
136         processedProperties.add(propertyName);
137     }
138 
139     protected PropertyEditor findEditorForPropertyName(String propertyName) {
140         Class<?> clazz = getPropertyType(propertyName);
141         if (LOG.isDebugEnabled()) {
142             LOG.debug("Attempting retrieval of property editor using class '"
143                     + clazz
144                     + "' and property path '"
145                     + propertyName
146                     + "'");
147         }
148 
149         PropertyEditor editor = findCustomEditor(clazz, propertyName);
150         if (editor == null) {
151             if (LOG.isDebugEnabled()) {
152                 LOG.debug("No custom property editor found using class '"
153                         + clazz
154                         + "' and property path '"
155                         + propertyName
156                         + "'. Attempting to find default property editor class.");
157             }
158             editor = getDefaultEditor(clazz);
159         }
160 
161         return editor;
162     }
163 
164     @Override
165     public Class<?> getPropertyType(String propertyName) throws BeansException {
166         try {
167             PropertyDescriptor pd = getPropertyDescriptorInternal(propertyName);
168             if (pd != null) {
169                 return pd.getPropertyType();
170             }
171 
172             // Maybe an indexed/mapped property...
173             Object value = super.getPropertyValue(propertyName);
174             if (value != null) {
175                 return value.getClass();
176             }
177 
178             // Check to see if there is a custom editor,
179             // which might give an indication on the desired target type.
180             Class<?> editorType = guessPropertyTypeFromEditors(propertyName);
181             if (editorType != null) {
182                 return editorType;
183             }
184         } catch (InvalidPropertyException ex) {
185             // Consider as not determinable.
186         }
187 
188         return null;
189     }
190 
191     @Override
192     public Object getPropertyValue(String propertyName) throws BeansException {
193         registerEditorFromView(propertyName);
194         return super.getPropertyValue(propertyName);
195     }
196 
197     @Override
198     public void setPropertyValue(PropertyValue pv) throws BeansException {
199         registerEditorFromView(pv.getName());
200         super.setPropertyValue(pv);
201     }
202 
203     @Override
204     public void setPropertyValue(String propertyName, Object value) throws BeansException {
205         registerEditorFromView(propertyName);
206         super.setPropertyValue(propertyName, value);
207     }
208 
209     @Override
210     public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
211         //TODO clear cache?
212         model = (ViewModel) object;
213         super.setWrappedInstance(object, nestedPath, rootObject);
214     }
215 
216     @Override
217     public void setWrappedInstance(Object object) {
218         //TODO clear cache?
219         model = (ViewModel) object;
220         super.setWrappedInstance(object);
221     }
222 }