/*
* $Id: FormPropertyConfig.java 471754 2006-11-06 14:55:09Z husted $
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts.config;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
/**
* <p>A JavaBean representing the configuration information of a
* <code><form-property></code> element in a Struts configuration
* file.<p>
*
* @version $Rev: 471754 $ $Date: 2005-11-12 11:52:08 -0500 (Sat, 12 Nov 2005)$
* @since Struts 1.1
*/
public class FormPropertyConfig extends BaseConfig {
/**
* The logging instance
*/
private static final Log log = LogFactory.getLog(FormPropertyConfig.class);
// ----------------------------------------------------- Instance Variables
// ------------------------------------------------------------- Properties
/**
* String representation of the initial value for this property.
*/
protected String initial = null;
/**
* The JavaBean property name of the property described by this element.
*/
protected String name = null;
/**
* <p>The conditions under which the property described by this element
* should be reset to its <code>initial</code> value when the form's
* <code>reset</code> method is called.</p> <p>This may be set to true (to
* always reset the property) or a comma-separated list of HTTP request
* methods.</p>
*
* @since Struts 1.3
*/
protected String reset = null;
/**
* <p>The size of the array to be created if this property is an array
* type and there is no specified <code>initial</code> value. This value
* must be non-negative.</p>
*
* @since Struts 1.1
*/
protected int size = 0;
/**
* The fully qualified Java class name of the implementation class of this
* bean property, optionally followed by <code>[]</code> to indicate that
* the property is indexed.
*/
protected String type = null;
// ----------------------------------------------------------- Constructors
/**
* Standard no-arguments constructor for dynamic instantiation.
*/
public FormPropertyConfig() {
super();
}
/**
* Constructor that preconfigures the relevant properties.
*
* @param name Name of this property
* @param type Fully qualified class name of this property
* @param initial Initial value of this property (if any)
*/
public FormPropertyConfig(String name, String type, String initial) {
this(name, type, initial, 0);
}
/**
* Constructor that preconfigures the relevant properties.
*
* @param name Name of this property
* @param type Fully qualified class name of this property
* @param initial Initial value of this property (if any)
* @param reset The conditions under which this property will be reset
* to its initial value.
*/
public FormPropertyConfig(String name, String type, String initial,
String reset) {
this(name, type, initial, reset, 0);
}
/**
* Constructor that preconfigures the relevant properties.
*
* @param name Name of this property
* @param type Fully qualified class name of this property
* @param initial Initial value of this property (if any)
* @param size Size of the array to be created if this property is an
* array with no defined initial value
*/
public FormPropertyConfig(String name, String type, String initial, int size) {
this(name, type, initial, null, size);
}
/**
* Constructor that preconfigures the relevant properties.
*
* @param name Name of this property
* @param type Fully qualified class name of this property
* @param initial Initial value of this property (if any)
* @param size Size of the array to be created if this property is an
* array with no defined initial value
* @param reset The conditions under which this property will be reset
* to its initial value.
*/
public FormPropertyConfig(String name, String type, String initial,
String reset, int size) {
super();
setName(name);
setType(type);
setInitial(initial);
setReset(reset);
setSize(size);
}
public String getInitial() {
return (this.initial);
}
public void setInitial(String initial) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.initial = initial;
}
public String getName() {
return (this.name);
}
public void setName(String name) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.name = name;
}
public String getReset() {
return (this.reset);
}
public void setReset(String reset) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.reset = reset;
}
public int getSize() {
return (this.size);
}
public void setSize(int size) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
if (size < 0) {
throw new IllegalArgumentException("size < 0");
}
this.size = size;
}
public String getType() {
return (this.type);
}
public void setType(String type) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.type = type;
}
/**
* Return a Class corresponds to the value specified for the
* <code>type</code> property, taking into account the trailing "[]" for
* arrays (as well as the ability to specify primitive Java types).
*/
public Class getTypeClass() {
// Identify the base class (in case an array was specified)
String baseType = getType();
boolean indexed = false;
if (baseType.endsWith("[]")) {
baseType = baseType.substring(0, baseType.length() - 2);
indexed = true;
}
// Construct an appropriate Class instance for the base class
Class baseClass = null;
if ("boolean".equals(baseType)) {
baseClass = Boolean.TYPE;
} else if ("byte".equals(baseType)) {
baseClass = Byte.TYPE;
} else if ("char".equals(baseType)) {
baseClass = Character.TYPE;
} else if ("double".equals(baseType)) {
baseClass = Double.TYPE;
} else if ("float".equals(baseType)) {
baseClass = Float.TYPE;
} else if ("int".equals(baseType)) {
baseClass = Integer.TYPE;
} else if ("long".equals(baseType)) {
baseClass = Long.TYPE;
} else if ("short".equals(baseType)) {
baseClass = Short.TYPE;
} else {
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = this.getClass().getClassLoader();
}
try {
baseClass = classLoader.loadClass(baseType);
} catch (ClassNotFoundException ex) {
log.error("Class '" + baseType +
"' not found for property '" + name + "'");
baseClass = null;
}
}
// Return the base class or an array appropriately
if (indexed) {
return (Array.newInstance(baseClass, 0).getClass());
} else {
return (baseClass);
}
}
// --------------------------------------------------------- Public Methods
/**
* <p>Return an object representing the initial value of this property.
* This is calculated according to the following algorithm:</p>
*
* <ul>
*
* <li>If the value you have specified for the <code>type</code> property
* represents an array (i.e. it ends with "[]"):
*
* <ul>
*
* <li>If you have specified a value for the <code>initial</code>
* property, <code>ConvertUtils.convert</code> will be called to convert
* it into an instance of the specified array type.</li>
*
* <li>If you have not specified a value for the <code>initial</code>
* property, an array of the length specified by the <code>size</code>
* property will be created. Each element of the array will be
* instantiated via the zero-args constructor on the specified class (if
* any). Otherwise, <code>null</code> will be returned.</li>
*
* </ul></li>
*
* <li>If the value you have specified for the <code>type</code> property
* does not represent an array:
*
* <ul>
*
* <li>If you have specified a value for the <code>initial</code>
* property, <code>ConvertUtils.convert</code> will be called to convert
* it into an object instance.</li>
*
* <li>If you have not specified a value for the <code>initial</code>
* attribute, Struts will instantiate an instance via the zero-args
* constructor on the specified class (if any). Otherwise,
* <code>null</code> will be returned.</li>
*
* </ul></li>
*
* </ul>
*/
public Object initial() {
Object initialValue = null;
try {
Class clazz = getTypeClass();
if (clazz.isArray()) {
if (initial != null) {
initialValue = ConvertUtils.convert(initial, clazz);
} else {
initialValue =
Array.newInstance(clazz.getComponentType(), size);
if (!(clazz.getComponentType().isPrimitive())) {
for (int i = 0; i < size; i++) {
try {
Array.set(initialValue, i,
clazz.getComponentType().newInstance());
} catch (Throwable t) {
log.error("Unable to create instance of "
+ clazz.getName() + " for property=" + name
+ ", type=" + type + ", initial=" + initial
+ ", size=" + size + ".");
//FIXME: Should we just dump the entire application/module ?
}
}
}
}
} else {
if (initial != null) {
initialValue = ConvertUtils.convert(initial, clazz);
} else {
initialValue = clazz.newInstance();
}
}
} catch (Throwable t) {
initialValue = null;
}
return (initialValue);
}
/**
* <p>Inherit values that have not been overridden from the provided
* config object. Subclasses overriding this method should verify that
* the given parameter is of a class that contains a property it is trying
* to inherit:</p>
* <pre>
* if (config instanceof MyCustomFormPropertyConfig) {
* MyCustomFormPropertyConfig myConfig =
* (MyCustomFormPropertyConfig) config;
*
* if (getMyCustomProp() == null) {
* setMyCustomProp(myConfig.getMyCustomProp());
* }
* }
* </pre>
*
* @param config The object that this instance will be inheriting its
* values from.
*/
public void inheritFrom(FormPropertyConfig config)
throws IllegalAccessException, InvocationTargetException,
InstantiationException, ClassNotFoundException {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
if (getInitial() == null) {
setInitial(config.getInitial());
}
if (getName() == null) {
setName(config.getName());
}
if (getSize() == 0) {
setSize(config.getSize());
}
if (getType() == null) {
setType(config.getType());
}
inheritProperties(config);
}
/**
* Return a String representation of this object.
*/
public String toString() {
StringBuffer sb = new StringBuffer("FormPropertyConfig[");
sb.append("name=");
sb.append(this.name);
sb.append(",type=");
sb.append(this.type);
sb.append(",initial=");
sb.append(this.initial);
sb.append(",reset=");
sb.append(this.reset);
sb.append("]");
return (sb.toString());
}
}