View Javadoc

1   /*
2    * $Id: FormPropertyConfig.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 1999-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.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>&lt;form-property&gt;</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      // ----------------------------------------------------- Instance Variables
43      // ------------------------------------------------------------- Properties
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      // ----------------------------------------------------------- Constructors
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         // Identify the base class (in case an array was specified)
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         // Construct an appropriate Class instance for the base class
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         // Return the base class or an array appropriately
264         if (indexed) {
265             return (Array.newInstance(baseClass, 0).getClass());
266         } else {
267             return (baseClass);
268         }
269     }
270 
271     // --------------------------------------------------------- Public Methods
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                                 //FIXME: Should we just dump the entire application/module ?
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 }