View Javadoc

1   /*
2    * $Id: LazyValidatorForm.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts.validator;
19  
20  import org.apache.commons.beanutils.DynaBean;
21  import org.apache.commons.beanutils.LazyDynaBean;
22  
23  import java.util.List;
24  import java.util.Map;
25  
26  /***
27   * <p>Struts <i>Lazy</i> <code>ActionForm</code> which <i>wraps</i> a
28   * <code>LazyDynaBean</code>.</p>
29   *
30   * <p>There isn't really that much to this implementation as most of the
31   * <i>lazy</i> behaviour is in <code>LazyDynaBean</code> and <i>wrapping</i>
32   * the <code>LazyDynaBean<code> is handled in the parent
33   * <code>BeanValidatorForm</code>. The only thing it really does is populate
34   * <i>indexed</i> properties which are a <code>List<code> type with a
35   * <code>LazyDynaBean<code> in the <code>get(name, index)</code> method.</p>
36   *
37   * <p><i>Lazy</i> DynaBeans provide several types of <i>lazy</i>
38   * behaviour:</p>
39   *
40   * <ul>
41   *
42   * <li><b><i>lazy</i> property addition</b> - properties which do not exist
43   * are automatically added.</li>
44   *
45   * <li><b><i>lazy</i> List facilities</b> - automatically <i>grows</i> a
46   * <code>List</code> or <code>Array</code> to accomodate the index value being
47   * set.</li>
48   *
49   * <li><b><i>lazy</i> List creation</b> - automatic creation of a
50   * <code>List</code> or <code>Array</code> for <i>indexed</i> properties, if
51   * it doesn't exist.</li> <li><b><i>lazy</i> Map creation</b> - automatic
52   * creation of a <code>Map</code> for <i>mapped</i> properties, if it doesn't
53   * exist.</li>
54   *
55   * </ul>
56   *
57   * <p>Using this <i>lazy</i> <code>ActionForm</code> means that you don't have
58   * to define the ActionForm's properties in the <code>struts-config.xml</code>.
59   * However, a word of warning, everything in the Request gets populated into
60   * this <code>ActionForm</code> circumventing the normal <i>firewall</i>
61   * function of Struts forms. Therefore you should only <i>take out</i> of this
62   * form properties you expect to be there rather than blindly populating all
63   * the properties into the business tier.</p>
64   *
65   * <p>Having said that it is not necessary to pre-define properties in the
66   * <code>struts-config.xml</code>, it is useful to sometimes do so for
67   * <i>mapped</i> or <i>indexed</i> properties. For example, if you want to use
68   * a different <code>Map<code> implementation from the default
69   * <code>HashMap</code> or an array for indexed properties, rather than the
70   * default <code>List</code> type:</p>
71   *
72   * <pre><code>
73   *   &lt;form-bean name="myForm" type="org.apache.struts.validator.LazyValidatorForm"&gt;
74   *     &lt;form-property name="myMap" type="java.util.TreeMap" /&gt;
75   *     &lt;form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]"
76   * /&gt;
77   *   &lt;/form-bean&gt;
78   * </code></pre>
79   *
80   * <p>Another reason for defining <i>indexed</i> properties in the
81   * <code>struts-config.xml</code> is that if you are validating indexed
82   * properties using the Validator and none are submitted then the indexed
83   * property will be <code>null</code> which causes validator to fail.
84   * Pre-defining them in the <code>struts-config.xml</code> will result in a
85   * zero-length indexed property (array or List) being instantiated, avoiding
86   * an issue with validator in that circumstance.</p>
87   *
88   * <p>This implementation validates using the ActionForm <i>name</i>. If you
89   * require a version that validates according to the <i>path</i> then it can
90   * be easily created in the following manner:</p>
91   *
92   * <pre><code>
93   *    public class MyLazyForm extends LazyValidatorForm {
94   *
95   *        public MyLazyForm () {
96   *            super();
97   *            setPathValidation(true);
98   *        }
99   *
100  *    }
101  * </code></pre>
102  *
103  * <p>Rather than using this class, another alternative is to either use a
104  * <code>LazyDynaBean</code> or custom version of <code>LazyDynaBean</code>
105  * directly. Struts now automatically <i>wraps</i> objects which are not
106  * <code>ActionForms</code> in a <code>BeanValidatorForm</code>. For
107  * example:</p>
108  *
109  * <pre><code>
110  *   &lt;form-bean name="myForm" type="org.apache.commons.beanutils.LazyDynaBean"&gt;
111  *     &lt;form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]"
112  * /&gt;
113  *   &lt;/form-bean&gt;
114  * </code></pre>
115  *
116  * @version $Rev: 421119 $ $Date: 2005-05-07 12:11:38 -0400 (Sat, 07 May 2005)
117  *          $
118  * @see <a href="http://jakarta.apache.org/commons/beanutils/apidocs/org/apache/commons/beanutils/package-summary.html#dynamic.lazy">Commons
119  *      BeanUtils JavaDoc</a>
120  * @since Struts 1.2.6
121  */
122 public class LazyValidatorForm extends BeanValidatorForm {
123     // ------------------- Constructors ----------------------------------
124 
125     /***
126      * Default Constructor which creates a <code>LazyDynaBean</code> to
127      * <i>back</i> this form.
128      */
129     public LazyValidatorForm() {
130         super(new LazyDynaBean());
131     }
132 
133     /***
134      */
135     public LazyValidatorForm(DynaBean bean) {
136         super(bean);
137     }
138 
139     // ------------------- DynaBean methods ----------------------------------
140 
141     /***
142      * <p>Return an indexed property value.</p>
143      *
144      * <p>If the "indexed" property is a <code>List</code> type then any
145      * missing values are populated with a bean (created in the
146      * <code>newIndexedBean(name)</code> method - in this implementation this
147      * is a <code>LazyDynaBean</code> type.</p>
148      */
149     public Object get(String name, int index) {
150         int size = size(name);
151 
152         // Get the indexed property
153         Object value = dynaBean.get(name, index);
154 
155         // Create missing beans for Lists
156         if (value == null) {
157             Object indexedValue = dynaBean.get(name);
158 
159             if (List.class.isAssignableFrom(indexedValue.getClass())) {
160                 for (int i = size; i <= index; i++) {
161                     value = newIndexedBean(name);
162                     set(name, i, value);
163                 }
164             }
165         }
166 
167         return value;
168     }
169 
170     // ------------------- Public methods ----------------------------------
171 
172     /***
173      * <p>Return the <code>Map</code> containing the property values.</p>
174      *
175      * <p>Provided so that properties can be access using JSTL.</p>
176      */
177     public Map getMap() {
178         return ((LazyDynaBean) dynaBean).getMap();
179     }
180 
181     // ------------------- Protected methods ----------------------------------
182 
183     /***
184      * <p>Creates new <code>DynaBean</code> instances to populate an 'indexed'
185      * property of beans - defaults to <code>LazyDynaBean</code> type.</p>
186      *
187      * <p>Override this method if you require a different type of
188      * <code>DynaBean</code>.</p>
189      */
190     protected DynaBean newIndexedBean(String name) {
191         return new LazyDynaBean();
192     }
193 }