View Javadoc

1   /*
2    * Copyright 2004-2005 The Apache Software Foundation.
3    *
4    * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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.apache.struts.validator;
17  
18  import org.apache.commons.beanutils.ConvertUtils;
19  import org.apache.commons.beanutils.DynaBean;
20  import org.apache.commons.beanutils.DynaClass;
21  import org.apache.commons.beanutils.WrapDynaBean;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.struts.action.ActionMapping;
25  
26  import javax.servlet.http.HttpServletRequest;
27  
28  import java.io.Serializable;
29  
30  import java.lang.reflect.Array;
31  
32  import java.util.List;
33  import java.util.Map;
34  
35  /***
36   * <p>Struts <i>validator</i> <code>ActionForm</code> backed by either a
37   * <code>DynaBean</code> or POJO JavaBean.</p>
38   *
39   * <p>Passing a POJO JavaBean to the constructor will automatically create an
40   * associated <code>WrapDynaBean</code>. One use for this would be to migrate
41   * <i>view</i> objects from an existing system which, for the usual reasons,
42   * can't be changed to extend <ActionForm</code>.</p>
43   *
44   * <p>This form is based on the standard struts <code>ValidatorForm</code> for
45   * use with the <i>Validator</i> framework and validates either using the
46   * <i>name</i> from the Struts <code>ActionMapping</code> or the
47   * <code>ActionMapping</code>'s path depending on whether
48   * <code>pathValidation</code> is <code>true</code> or
49   * <code>false</code>.</p>
50   *
51   * <p><b>Note</b>: WrapDynaBean is NOT serializable.  If you use this class
52   * with a WrapDynaBean (as described above), you should not store your form in
53   * session scope.</p>
54   */
55  public class BeanValidatorForm extends ValidatorForm implements DynaBean,
56      Serializable {
57      /***
58       * Commons Logging
59       */
60      protected static Log logger = LogFactory.getLog(BeanValidatorForm.class);
61  
62      /***
63       * The <code>DynaBean</code> that this ActionForm is backed by.
64       */
65      protected DynaBean dynaBean;
66  
67      /***
68       * Indicates whether the ActionMapping's path should be used for the
69       * validation key.
70       */
71      protected boolean pathValidation = false;
72  
73      // ------------------- Constructor ----------------------------------
74  
75      /***
76       * Construct a new <code>BeanValidatorForm</code> with the specified
77       * bean.
78       */
79      public BeanValidatorForm(Object bean) {
80          if (bean instanceof DynaBean) {
81              dynaBean = (DynaBean) bean;
82          } else {
83              dynaBean = new WrapDynaBean(bean);
84          }
85      }
86  
87      // ------------------- Protected Methods ----------------------------------
88  
89      /***
90       * <p>Set whether this form should validate based on the
91       * <code>ActionMapping</code>'s path.</p>
92       */
93      protected void setPathValidation(boolean pathValidation) {
94          this.pathValidation = pathValidation;
95      }
96  
97      /***
98       * <p>Indicates whether this form should validate based on the
99       * <code>ActionMapping</code>'s path.</p>
100      */
101     protected boolean isPathValidation() {
102         return pathValidation;
103     }
104 
105     // ------------------- Public Methods ----------------------------------
106 
107     /***
108      * <p>Return the <code>DynaBean</code> that this <code>ActionForm</code>
109      * is backed by.</p>
110      */
111     public DynaBean getDynaBean() {
112         return dynaBean;
113     }
114 
115     /***
116      * <p>Return the <code>Bean</code> that this <code>ActionForm</code> is
117      * backed by.</p>
118      *
119      * <p>If the <code>DynaBean</code> is a <code>WrapDynaBean</code> type
120      * then this method returns the 'Wrapped' POJO bean associated with it. If
121      * you require the actual <code>WrapDynaBean</code> then use the
122      * <code>getDynaBean()</code> method.</p>
123      */
124     public Object getInstance() {
125         if (dynaBean instanceof WrapDynaBean) {
126             return ((WrapDynaBean) dynaBean).getInstance();
127         }
128 
129         return dynaBean;
130     }
131 
132     /***
133      * <p>Return the size of an indexed or mapped property.</p>
134      */
135     public int size(String name) {
136         Object value = dynaBean.get(name);
137 
138         if (value == null) {
139             return 0;
140         }
141 
142         if (value instanceof Map) {
143             return ((Map) value).size();
144         }
145 
146         if (value instanceof List) {
147             return ((List) value).size();
148         }
149 
150         if ((value.getClass().isArray())) {
151             return Array.getLength(value);
152         }
153 
154         return 0;
155     }
156 
157     // ------------------- ValidatorForm Methods ----------------------------------
158 
159     /***
160      * Returns the Validation key
161      *
162      * @param mapping The mapping used to select this instance
163      * @param request The servlet request we are processing
164      * @return validation key to use
165      */
166     public String getValidationKey(ActionMapping mapping,
167         HttpServletRequest request) {
168         String validationKey = null;
169 
170         if (isPathValidation()) {
171             // Get the path replacing any slashes by underscore
172             validationKey = mapping.getPath();
173 
174             // Remove any leading slash
175             if (validationKey.charAt(0) == '/') {
176                 validationKey = validationKey.substring(1);
177             }
178 
179             // Replace any slashes by underscore
180             if (validationKey.indexOf("/") > 0) {
181                 validationKey = validationKey.replace('/', '_');
182             }
183         } else {
184             validationKey = mapping.getAttribute();
185         }
186 
187         if (logger.isDebugEnabled()) {
188             logger.debug("Validating ActionForm '" + mapping.getName()
189                 + "' using key '" + validationKey + "' for mapping '"
190                 + mapping.getPath() + "'");
191         }
192 
193         return validationKey;
194     }
195 
196     // ------------------- DynaBean Methods ----------------------------------
197 
198     /***
199      * Return the <code>DynaClass</code> instance that describes the set of
200      * properties available for this DynaBean.
201      */
202     public DynaClass getDynaClass() {
203         return dynaBean.getDynaClass();
204     }
205 
206     /***
207      * Return the value of a simple property with the specified name.
208      *
209      * @param name Name of the property whose value is to be retrieved
210      */
211     public Object get(String name) {
212         return dynaBean.get(name);
213     }
214 
215     /***
216      * Return the value of an indexed property with the specified name.
217      *
218      * @param name  Name of the property whose value is to be retrieved
219      * @param index Index of the value to be retrieved
220      */
221     public Object get(String name, int index) {
222         return dynaBean.get(name, index);
223     }
224 
225     /***
226      * Return the value of a mapped property with the specified name, or
227      * <code>null</code> if there is no value for the specified key.
228      *
229      * @param name Name of the property whose value is to be retrieved
230      * @param key  Key of the value to be retrieved
231      */
232     public Object get(String name, String key) {
233         return dynaBean.get(name, key);
234     }
235 
236     /***
237      * Set the value of a simple property with the specified name.
238      *
239      * @param name  Name of the property whose value is to be set
240      * @param value Value to which this property is to be set
241      */
242     public void set(String name, Object value) {
243         // Set the page number (for validator)
244         if ("page".equals(name)) {
245             if (value == null) {
246                 page = 0;
247             } else if (value instanceof Integer) {
248                 page = ((Integer) value).intValue();
249             } else {
250                 try {
251                     page =
252                         ((Integer) ConvertUtils.convert(value.toString(),
253                             Integer.class)).intValue();
254                 } catch (Exception ignore) {
255                     page = 0;
256                 }
257             }
258         }
259 
260         dynaBean.set(name, value);
261     }
262 
263     /***
264      * Set the value of an indexed property with the specified name.
265      *
266      * @param name  Name of the property whose value is to be set
267      * @param index Index of the property to be set
268      * @param value Value to which this property is to be set
269      */
270     public void set(String name, int index, Object value) {
271         dynaBean.set(name, index, value);
272     }
273 
274     /***
275      * Set the value of a mapped property with the specified name.
276      *
277      * @param name  Name of the property whose value is to be set
278      * @param key   Key of the property to be set
279      * @param value Value to which this property is to be set
280      */
281     public void set(String name, String key, Object value) {
282         dynaBean.set(name, key, value);
283     }
284 
285     /***
286      * Does the specified mapped property contain a value for the specified
287      * key value?
288      *
289      * @param name Name of the property to check
290      * @param key  Name of the key to check
291      */
292     public boolean contains(String name, String key) {
293         return dynaBean.contains(name, key);
294     }
295 
296     /***
297      * Remove any existing value for the specified key on the specified mapped
298      * property.
299      *
300      * @param name Name of the property for which a value is to be removed
301      * @param key  Key of the value to be removed
302      */
303     public void remove(String name, String key) {
304         dynaBean.remove(name, key);
305     }
306 }