View Javadoc

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