1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 * <form-bean name="myForm" type="org.apache.struts.validator.LazyValidatorForm">
74 * <form-property name="myMap" type="java.util.TreeMap" />
75 * <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]"
76 * />
77 * </form-bean>
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 * <form-bean name="myForm" type="org.apache.commons.beanutils.LazyDynaBean">
111 * <form-property name="myBeans" type="org.apache.commons.beanutils.LazyDynaBean[]"
112 * />
113 * </form-bean>
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
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
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
153 Object value = dynaBean.get(name, index);
154
155
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
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
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 }