1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.config;
19
20 import org.apache.commons.beanutils.ConvertUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 import java.lang.reflect.Array;
25 import java.lang.reflect.InvocationTargetException;
26
27 /***
28 * <p>A JavaBean representing the configuration information of a
29 * <code><form-property></code> element in a Struts configuration
30 * file.<p>
31 *
32 * @version $Rev: 421119 $ $Date: 2005-11-12 11:52:08 -0500 (Sat, 12 Nov 2005)
33 * $
34 * @since Struts 1.1
35 */
36 public class FormPropertyConfig extends BaseConfig {
37 /***
38 * The logging instance
39 */
40 private static final Log log = LogFactory.getLog(FormPropertyConfig.class);
41
42
43
44
45 /***
46 * String representation of the initial value for this property.
47 */
48 protected String initial = null;
49
50 /***
51 * The JavaBean property name of the property described by this element.
52 */
53 protected String name = null;
54
55 /***
56 * <p>The conditions under which the property described by this element
57 * should be reset to its <code>initial</code> value when the form's
58 * <code>reset</code> method is called.</p> <p>This may be set to true (to
59 * always reset the property) or a comma-separated list of HTTP request
60 * methods.</p>
61 *
62 * @since Struts 1.3
63 */
64 protected String reset = null;
65
66 /***
67 * <p>The size of the array to be created if this property is an array
68 * type and there is no specified <code>initial</code> value. This value
69 * must be non-negative.</p>
70 *
71 * @since Struts 1.1
72 */
73 protected int size = 0;
74
75 /***
76 * The fully qualified Java class name of the implementation class of this
77 * bean property, optionally followed by <code>[]</code> to indicate that
78 * the property is indexed.
79 */
80 protected String type = null;
81
82
83
84 /***
85 * Standard no-arguments constructor for dynamic instantiation.
86 */
87 public FormPropertyConfig() {
88 super();
89 }
90
91 /***
92 * Constructor that preconfigures the relevant properties.
93 *
94 * @param name Name of this property
95 * @param type Fully qualified class name of this property
96 * @param initial Initial value of this property (if any)
97 */
98 public FormPropertyConfig(String name, String type, String initial) {
99 this(name, type, initial, 0);
100 }
101
102 /***
103 * Constructor that preconfigures the relevant properties.
104 *
105 * @param name Name of this property
106 * @param type Fully qualified class name of this property
107 * @param initial Initial value of this property (if any)
108 * @param reset The conditions under which this property will be reset
109 * to its initial value.
110 */
111 public FormPropertyConfig(String name, String type, String initial,
112 String reset) {
113 this(name, type, initial, reset, 0);
114 }
115
116 /***
117 * Constructor that preconfigures the relevant properties.
118 *
119 * @param name Name of this property
120 * @param type Fully qualified class name of this property
121 * @param initial Initial value of this property (if any)
122 * @param size Size of the array to be created if this property is an
123 * array with no defined initial value
124 */
125 public FormPropertyConfig(String name, String type, String initial, int size) {
126 this(name, type, initial, null, size);
127 }
128
129 /***
130 * Constructor that preconfigures the relevant properties.
131 *
132 * @param name Name of this property
133 * @param type Fully qualified class name of this property
134 * @param initial Initial value of this property (if any)
135 * @param size Size of the array to be created if this property is an
136 * array with no defined initial value
137 * @param reset The conditions under which this property will be reset
138 * to its initial value.
139 */
140 public FormPropertyConfig(String name, String type, String initial,
141 String reset, int size) {
142 super();
143 setName(name);
144 setType(type);
145 setInitial(initial);
146 setReset(reset);
147 setSize(size);
148 }
149
150 public String getInitial() {
151 return (this.initial);
152 }
153
154 public void setInitial(String initial) {
155 if (configured) {
156 throw new IllegalStateException("Configuration is frozen");
157 }
158
159 this.initial = initial;
160 }
161
162 public String getName() {
163 return (this.name);
164 }
165
166 public void setName(String name) {
167 if (configured) {
168 throw new IllegalStateException("Configuration is frozen");
169 }
170
171 this.name = name;
172 }
173
174 public String getReset() {
175 return (this.reset);
176 }
177
178 public void setReset(String reset) {
179 if (configured) {
180 throw new IllegalStateException("Configuration is frozen");
181 }
182
183 this.reset = reset;
184 }
185
186 public int getSize() {
187 return (this.size);
188 }
189
190 public void setSize(int size) {
191 if (configured) {
192 throw new IllegalStateException("Configuration is frozen");
193 }
194
195 if (size < 0) {
196 throw new IllegalArgumentException("size < 0");
197 }
198
199 this.size = size;
200 }
201
202 public String getType() {
203 return (this.type);
204 }
205
206 public void setType(String type) {
207 if (configured) {
208 throw new IllegalStateException("Configuration is frozen");
209 }
210
211 this.type = type;
212 }
213
214 /***
215 * Return a Class corresponds to the value specified for the
216 * <code>type</code> property, taking into account the trailing "[]" for
217 * arrays (as well as the ability to specify primitive Java types).
218 */
219 public Class getTypeClass() {
220
221 String baseType = getType();
222 boolean indexed = false;
223
224 if (baseType.endsWith("[]")) {
225 baseType = baseType.substring(0, baseType.length() - 2);
226 indexed = true;
227 }
228
229
230 Class baseClass = null;
231
232 if ("boolean".equals(baseType)) {
233 baseClass = Boolean.TYPE;
234 } else if ("byte".equals(baseType)) {
235 baseClass = Byte.TYPE;
236 } else if ("char".equals(baseType)) {
237 baseClass = Character.TYPE;
238 } else if ("double".equals(baseType)) {
239 baseClass = Double.TYPE;
240 } else if ("float".equals(baseType)) {
241 baseClass = Float.TYPE;
242 } else if ("int".equals(baseType)) {
243 baseClass = Integer.TYPE;
244 } else if ("long".equals(baseType)) {
245 baseClass = Long.TYPE;
246 } else if ("short".equals(baseType)) {
247 baseClass = Short.TYPE;
248 } else {
249 ClassLoader classLoader =
250 Thread.currentThread().getContextClassLoader();
251
252 if (classLoader == null) {
253 classLoader = this.getClass().getClassLoader();
254 }
255
256 try {
257 baseClass = classLoader.loadClass(baseType);
258 } catch (Throwable t) {
259 baseClass = null;
260 }
261 }
262
263
264 if (indexed) {
265 return (Array.newInstance(baseClass, 0).getClass());
266 } else {
267 return (baseClass);
268 }
269 }
270
271
272
273 /***
274 * <p>Return an object representing the initial value of this property.
275 * This is calculated according to the following algorithm:</p>
276 *
277 * <ul>
278 *
279 * <li>If the value you have specified for the <code>type</code> property
280 * represents an array (i.e. it ends with "[]"):
281 *
282 * <ul>
283 *
284 * <li>If you have specified a value for the <code>initial</code>
285 * property, <code>ConvertUtils.convert</code> will be called to convert
286 * it into an instance of the specified array type.</li>
287 *
288 * <li>If you have not specified a value for the <code>initial</code>
289 * property, an array of the length specified by the <code>size</code>
290 * property will be created. Each element of the array will be
291 * instantiated via the zero-args constructor on the specified class (if
292 * any). Otherwise, <code>null</code> will be returned.</li>
293 *
294 * </ul></li>
295 *
296 * <li>If the value you have specified for the <code>type</code> property
297 * does not represent an array:
298 *
299 * <ul>
300 *
301 * <li>If you have specified a value for the <code>initial</code>
302 * property, <code>ConvertUtils.convert</code> will be called to convert
303 * it into an object instance.</li>
304 *
305 * <li>If you have not specified a value for the <code>initial</code>
306 * attribute, Struts will instantiate an instance via the zero-args
307 * constructor on the specified class (if any). Otherwise,
308 * <code>null</code> will be returned.</li>
309 *
310 * </ul></li>
311 *
312 * </ul>
313 */
314 public Object initial() {
315 Object initialValue = null;
316
317 try {
318 Class clazz = getTypeClass();
319
320 if (clazz.isArray()) {
321 if (initial != null) {
322 initialValue = ConvertUtils.convert(initial, clazz);
323 } else {
324 initialValue =
325 Array.newInstance(clazz.getComponentType(), size);
326
327 if (!(clazz.getComponentType().isPrimitive())) {
328 for (int i = 0; i < size; i++) {
329 try {
330 Array.set(initialValue, i,
331 clazz.getComponentType().newInstance());
332 } catch (Throwable t) {
333 log.error("Unable to create instance of "
334 + clazz.getName() + " for property=" + name
335 + ", type=" + type + ", initial=" + initial
336 + ", size=" + size + ".");
337
338
339 }
340 }
341 }
342 }
343 } else {
344 if (initial != null) {
345 initialValue = ConvertUtils.convert(initial, clazz);
346 } else {
347 initialValue = clazz.newInstance();
348 }
349 }
350 } catch (Throwable t) {
351 initialValue = null;
352 }
353
354 return (initialValue);
355 }
356
357 /***
358 * <p>Inherit values that have not been overridden from the provided
359 * config object. Subclasses overriding this method should verify that
360 * the given parameter is of a class that contains a property it is trying
361 * to inherit:</p>
362 * <pre>
363 * if (config instanceof MyCustomFormPropertyConfig) {
364 * MyCustomFormPropertyConfig myConfig =
365 * (MyCustomFormPropertyConfig) config;
366 *
367 * if (getMyCustomProp() == null) {
368 * setMyCustomProp(myConfig.getMyCustomProp());
369 * }
370 * }
371 * </pre>
372 *
373 * @param config The object that this instance will be inheriting its
374 * values from.
375 */
376 public void inheritFrom(FormPropertyConfig config)
377 throws IllegalAccessException, InvocationTargetException,
378 InstantiationException, ClassNotFoundException {
379 if (configured) {
380 throw new IllegalStateException("Configuration is frozen");
381 }
382
383 if (getInitial() == null) {
384 setInitial(config.getInitial());
385 }
386
387 if (getName() == null) {
388 setName(config.getName());
389 }
390
391 if (getSize() == 0) {
392 setSize(config.getSize());
393 }
394
395 if (getType() == null) {
396 setType(config.getType());
397 }
398
399 inheritProperties(config);
400 }
401
402 /***
403 * Return a String representation of this object.
404 */
405 public String toString() {
406 StringBuffer sb = new StringBuffer("FormPropertyConfig[");
407
408 sb.append("name=");
409 sb.append(this.name);
410 sb.append(",type=");
411 sb.append(this.type);
412 sb.append(",initial=");
413 sb.append(this.initial);
414 sb.append(",reset=");
415 sb.append(this.reset);
416 sb.append("]");
417
418 return (sb.toString());
419 }
420 }