001: /*
002: * $Id: FormPropertyConfig.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.config;
022:
023: import org.apache.commons.beanutils.ConvertUtils;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import java.lang.reflect.Array;
028: import java.lang.reflect.InvocationTargetException;
029:
030: /**
031: * <p>A JavaBean representing the configuration information of a
032: * <code><form-property></code> element in a Struts configuration
033: * file.<p>
034: *
035: * @version $Rev: 471754 $ $Date: 2005-11-12 11:52:08 -0500 (Sat, 12 Nov 2005)$
036: * @since Struts 1.1
037: */
038: public class FormPropertyConfig extends BaseConfig {
039: /**
040: * The logging instance
041: */
042: private static final Log log = LogFactory
043: .getLog(FormPropertyConfig.class);
044:
045: // ----------------------------------------------------- Instance Variables
046: // ------------------------------------------------------------- Properties
047:
048: /**
049: * String representation of the initial value for this property.
050: */
051: protected String initial = null;
052:
053: /**
054: * The JavaBean property name of the property described by this element.
055: */
056: protected String name = null;
057:
058: /**
059: * <p>The conditions under which the property described by this element
060: * should be reset to its <code>initial</code> value when the form's
061: * <code>reset</code> method is called.</p> <p>This may be set to true (to
062: * always reset the property) or a comma-separated list of HTTP request
063: * methods.</p>
064: *
065: * @since Struts 1.3
066: */
067: protected String reset = null;
068:
069: /**
070: * <p>The size of the array to be created if this property is an array
071: * type and there is no specified <code>initial</code> value. This value
072: * must be non-negative.</p>
073: *
074: * @since Struts 1.1
075: */
076: protected int size = 0;
077:
078: /**
079: * The fully qualified Java class name of the implementation class of this
080: * bean property, optionally followed by <code>[]</code> to indicate that
081: * the property is indexed.
082: */
083: protected String type = null;
084:
085: // ----------------------------------------------------------- Constructors
086:
087: /**
088: * Standard no-arguments constructor for dynamic instantiation.
089: */
090: public FormPropertyConfig() {
091: super ();
092: }
093:
094: /**
095: * Constructor that preconfigures the relevant properties.
096: *
097: * @param name Name of this property
098: * @param type Fully qualified class name of this property
099: * @param initial Initial value of this property (if any)
100: */
101: public FormPropertyConfig(String name, String type, String initial) {
102: this (name, type, initial, 0);
103: }
104:
105: /**
106: * Constructor that preconfigures the relevant properties.
107: *
108: * @param name Name of this property
109: * @param type Fully qualified class name of this property
110: * @param initial Initial value of this property (if any)
111: * @param reset The conditions under which this property will be reset
112: * to its initial value.
113: */
114: public FormPropertyConfig(String name, String type, String initial,
115: String reset) {
116: this (name, type, initial, reset, 0);
117: }
118:
119: /**
120: * Constructor that preconfigures the relevant properties.
121: *
122: * @param name Name of this property
123: * @param type Fully qualified class name of this property
124: * @param initial Initial value of this property (if any)
125: * @param size Size of the array to be created if this property is an
126: * array with no defined initial value
127: */
128: public FormPropertyConfig(String name, String type, String initial,
129: int size) {
130: this (name, type, initial, null, size);
131: }
132:
133: /**
134: * Constructor that preconfigures the relevant properties.
135: *
136: * @param name Name of this property
137: * @param type Fully qualified class name of this property
138: * @param initial Initial value of this property (if any)
139: * @param size Size of the array to be created if this property is an
140: * array with no defined initial value
141: * @param reset The conditions under which this property will be reset
142: * to its initial value.
143: */
144: public FormPropertyConfig(String name, String type, String initial,
145: String reset, int size) {
146: super ();
147: setName(name);
148: setType(type);
149: setInitial(initial);
150: setReset(reset);
151: setSize(size);
152: }
153:
154: public String getInitial() {
155: return (this .initial);
156: }
157:
158: public void setInitial(String initial) {
159: if (configured) {
160: throw new IllegalStateException("Configuration is frozen");
161: }
162:
163: this .initial = initial;
164: }
165:
166: public String getName() {
167: return (this .name);
168: }
169:
170: public void setName(String name) {
171: if (configured) {
172: throw new IllegalStateException("Configuration is frozen");
173: }
174:
175: this .name = name;
176: }
177:
178: public String getReset() {
179: return (this .reset);
180: }
181:
182: public void setReset(String reset) {
183: if (configured) {
184: throw new IllegalStateException("Configuration is frozen");
185: }
186:
187: this .reset = reset;
188: }
189:
190: public int getSize() {
191: return (this .size);
192: }
193:
194: public void setSize(int size) {
195: if (configured) {
196: throw new IllegalStateException("Configuration is frozen");
197: }
198:
199: if (size < 0) {
200: throw new IllegalArgumentException("size < 0");
201: }
202:
203: this .size = size;
204: }
205:
206: public String getType() {
207: return (this .type);
208: }
209:
210: public void setType(String type) {
211: if (configured) {
212: throw new IllegalStateException("Configuration is frozen");
213: }
214:
215: this .type = type;
216: }
217:
218: /**
219: * Return a Class corresponds to the value specified for the
220: * <code>type</code> property, taking into account the trailing "[]" for
221: * arrays (as well as the ability to specify primitive Java types).
222: */
223: public Class getTypeClass() {
224: // Identify the base class (in case an array was specified)
225: String baseType = getType();
226: boolean indexed = false;
227:
228: if (baseType.endsWith("[]")) {
229: baseType = baseType.substring(0, baseType.length() - 2);
230: indexed = true;
231: }
232:
233: // Construct an appropriate Class instance for the base class
234: Class baseClass = null;
235:
236: if ("boolean".equals(baseType)) {
237: baseClass = Boolean.TYPE;
238: } else if ("byte".equals(baseType)) {
239: baseClass = Byte.TYPE;
240: } else if ("char".equals(baseType)) {
241: baseClass = Character.TYPE;
242: } else if ("double".equals(baseType)) {
243: baseClass = Double.TYPE;
244: } else if ("float".equals(baseType)) {
245: baseClass = Float.TYPE;
246: } else if ("int".equals(baseType)) {
247: baseClass = Integer.TYPE;
248: } else if ("long".equals(baseType)) {
249: baseClass = Long.TYPE;
250: } else if ("short".equals(baseType)) {
251: baseClass = Short.TYPE;
252: } else {
253: ClassLoader classLoader = Thread.currentThread()
254: .getContextClassLoader();
255:
256: if (classLoader == null) {
257: classLoader = this .getClass().getClassLoader();
258: }
259:
260: try {
261: baseClass = classLoader.loadClass(baseType);
262: } catch (ClassNotFoundException ex) {
263: log.error("Class '" + baseType
264: + "' not found for property '" + name + "'");
265: baseClass = null;
266: }
267: }
268:
269: // Return the base class or an array appropriately
270: if (indexed) {
271: return (Array.newInstance(baseClass, 0).getClass());
272: } else {
273: return (baseClass);
274: }
275: }
276:
277: // --------------------------------------------------------- Public Methods
278:
279: /**
280: * <p>Return an object representing the initial value of this property.
281: * This is calculated according to the following algorithm:</p>
282: *
283: * <ul>
284: *
285: * <li>If the value you have specified for the <code>type</code> property
286: * represents an array (i.e. it ends with "[]"):
287: *
288: * <ul>
289: *
290: * <li>If you have specified a value for the <code>initial</code>
291: * property, <code>ConvertUtils.convert</code> will be called to convert
292: * it into an instance of the specified array type.</li>
293: *
294: * <li>If you have not specified a value for the <code>initial</code>
295: * property, an array of the length specified by the <code>size</code>
296: * property will be created. Each element of the array will be
297: * instantiated via the zero-args constructor on the specified class (if
298: * any). Otherwise, <code>null</code> will be returned.</li>
299: *
300: * </ul></li>
301: *
302: * <li>If the value you have specified for the <code>type</code> property
303: * does not represent an array:
304: *
305: * <ul>
306: *
307: * <li>If you have specified a value for the <code>initial</code>
308: * property, <code>ConvertUtils.convert</code> will be called to convert
309: * it into an object instance.</li>
310: *
311: * <li>If you have not specified a value for the <code>initial</code>
312: * attribute, Struts will instantiate an instance via the zero-args
313: * constructor on the specified class (if any). Otherwise,
314: * <code>null</code> will be returned.</li>
315: *
316: * </ul></li>
317: *
318: * </ul>
319: */
320: public Object initial() {
321: Object initialValue = null;
322:
323: try {
324: Class clazz = getTypeClass();
325:
326: if (clazz.isArray()) {
327: if (initial != null) {
328: initialValue = ConvertUtils.convert(initial, clazz);
329: } else {
330: initialValue = Array.newInstance(clazz
331: .getComponentType(), size);
332:
333: if (!(clazz.getComponentType().isPrimitive())) {
334: for (int i = 0; i < size; i++) {
335: try {
336: Array.set(initialValue, i, clazz
337: .getComponentType()
338: .newInstance());
339: } catch (Throwable t) {
340: log
341: .error("Unable to create instance of "
342: + clazz.getName()
343: + " for property="
344: + name
345: + ", type="
346: + type
347: + ", initial="
348: + initial
349: + ", size="
350: + size + ".");
351:
352: //FIXME: Should we just dump the entire application/module ?
353: }
354: }
355: }
356: }
357: } else {
358: if (initial != null) {
359: initialValue = ConvertUtils.convert(initial, clazz);
360: } else {
361: initialValue = clazz.newInstance();
362: }
363: }
364: } catch (Throwable t) {
365: initialValue = null;
366: }
367:
368: return (initialValue);
369: }
370:
371: /**
372: * <p>Inherit values that have not been overridden from the provided
373: * config object. Subclasses overriding this method should verify that
374: * the given parameter is of a class that contains a property it is trying
375: * to inherit:</p>
376: * <pre>
377: * if (config instanceof MyCustomFormPropertyConfig) {
378: * MyCustomFormPropertyConfig myConfig =
379: * (MyCustomFormPropertyConfig) config;
380: *
381: * if (getMyCustomProp() == null) {
382: * setMyCustomProp(myConfig.getMyCustomProp());
383: * }
384: * }
385: * </pre>
386: *
387: * @param config The object that this instance will be inheriting its
388: * values from.
389: */
390: public void inheritFrom(FormPropertyConfig config)
391: throws IllegalAccessException, InvocationTargetException,
392: InstantiationException, ClassNotFoundException {
393: if (configured) {
394: throw new IllegalStateException("Configuration is frozen");
395: }
396:
397: if (getInitial() == null) {
398: setInitial(config.getInitial());
399: }
400:
401: if (getName() == null) {
402: setName(config.getName());
403: }
404:
405: if (getSize() == 0) {
406: setSize(config.getSize());
407: }
408:
409: if (getType() == null) {
410: setType(config.getType());
411: }
412:
413: inheritProperties(config);
414: }
415:
416: /**
417: * Return a String representation of this object.
418: */
419: public String toString() {
420: StringBuffer sb = new StringBuffer("FormPropertyConfig[");
421:
422: sb.append("name=");
423: sb.append(this .name);
424: sb.append(",type=");
425: sb.append(this .type);
426: sb.append(",initial=");
427: sb.append(this .initial);
428: sb.append(",reset=");
429: sb.append(this .reset);
430: sb.append("]");
431:
432: return (sb.toString());
433: }
434: }
|