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