001: /*
002: * $Id: DynaActionFormClass.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.action;
022:
023: import org.apache.commons.beanutils.DynaBean;
024: import org.apache.commons.beanutils.DynaClass;
025: import org.apache.commons.beanutils.DynaProperty;
026: import org.apache.struts.config.FormBeanConfig;
027: import org.apache.struts.config.FormPropertyConfig;
028: import org.apache.struts.util.RequestUtils;
029:
030: import java.io.Serializable;
031:
032: import java.util.HashMap;
033:
034: /**
035: * <p>Implementation of <code>DynaClass</code> for <code>DynaActionForm</code>
036: * classes that allow developers to define ActionForms without having to
037: * individually code all of the classes. <strong>NOTE</strong> - This class is
038: * only used in the internal implementation of dynamic action form beans.
039: * Application developers never need to consult this documentation.</p>
040: *
041: * @version $Rev: 471754 $ $Date: 2006-01-17 07:26:20 -0500 (Tue, 17 Jan 2006)
042: * $
043: * @since Struts 1.1
044: */
045: public class DynaActionFormClass implements DynaClass, Serializable {
046: // ----------------------------------------------------- Instance Variables
047:
048: /**
049: * <p>The <code>DynaActionForm</code> implementation <code>Class</code>
050: * which we will use to create new bean instances.</p>
051: */
052: protected transient Class beanClass = null;
053:
054: /**
055: * <p>The form bean configuration information for this class.</p>
056: */
057: protected FormBeanConfig config = null;
058:
059: /**
060: * <p>The "dynamic class name" for this <code>DynaClass</code>.</p>
061: */
062: protected String name = null;
063:
064: /**
065: * <p>The set of dynamic properties that are part of this DynaClass.</p>
066: */
067: protected DynaProperty[] properties = null;
068:
069: /**
070: * <p>The set of dynamic properties that are part of this
071: * <code>DynaClass</code>, keyed by the property name. Individual
072: * descriptor instances will be the same instances as those in the
073: * <code>properties</code> list.
074: */
075: protected HashMap propertiesMap = new HashMap();
076:
077: // ----------------------------------------------------------- Constructors
078:
079: /**
080: * <p>Construct a new <code>DynaActionFormClass</code> for the specified
081: * form bean configuration. This constructor is private;
082: * <code>DynaActionFormClass</code> instances will be created as needed
083: * via calls to the static <code>createDynaActionFormClass()</code>
084: * method.</p>
085: *
086: * @param config The FormBeanConfig instance describing the properties of
087: * the bean to be created
088: * @throws IllegalArgumentException if the bean implementation class
089: * specified in the configuration is not
090: * DynaActionForm (or a subclass of
091: * DynaActionForm)
092: */
093: public DynaActionFormClass(FormBeanConfig config) {
094: introspect(config);
095: }
096:
097: // ------------------------------------------------------ DynaClass Methods
098:
099: /**
100: * <p>Return the name of this <code>DynaClass</code> (analogous to the
101: * <code>getName()</code> method of <code>java.lang.Class</code>, which
102: * allows the same <code>DynaClass</code> implementation class to support
103: * different dynamic classes, with different sets of properties.
104: *
105: * @return The name of this <code>DynaClass</code>.
106: */
107: public String getName() {
108: return (this .name);
109: }
110:
111: /**
112: * <p>Return a property descriptor for the specified property, if it
113: * exists; otherwise, return <code>null</code>.</p>
114: *
115: * @param name Name of the dynamic property for which a descriptor is
116: * requested
117: * @return A property descriptor for the specified property.
118: * @throws IllegalArgumentException if no property name is specified
119: */
120: public DynaProperty getDynaProperty(String name) {
121: if (name == null) {
122: throw new IllegalArgumentException(
123: "No property name specified");
124: }
125:
126: return ((DynaProperty) propertiesMap.get(name));
127: }
128:
129: /**
130: * <p>Return an array of <code>DynaProperty</code>s for the properties
131: * currently defined in this <code>DynaClass</code>. If no properties are
132: * defined, a zero-length array will be returned.</p>
133: *
134: * @return An array of property instances for this class.
135: */
136: public DynaProperty[] getDynaProperties() {
137: return (properties);
138:
139: // :FIXME: Should we really be implementing
140: // getBeanInfo instead, which returns property descriptors
141: // and a bunch of other stuff?
142: }
143:
144: /**
145: * <p>Instantiate and return a new {@link DynaActionForm} instance,
146: * associated with this <code>DynaActionFormClass</code>. The properties
147: * of the returned {@link DynaActionForm} will have been initialized to
148: * the default values specified in the form bean configuration
149: * information.</p>
150: *
151: * @return A new {@link DynaActionForm} instance.
152: * @throws IllegalAccessException if the Class or the appropriate
153: * constructor is not accessible
154: * @throws InstantiationException if this Class represents an abstract
155: * class, an array class, a primitive type,
156: * or void; or if instantiation fails for
157: * some other reason
158: */
159: public DynaBean newInstance() throws IllegalAccessException,
160: InstantiationException {
161: DynaActionForm dynaBean = (DynaActionForm) getBeanClass()
162: .newInstance();
163:
164: dynaBean.setDynaActionFormClass(this );
165:
166: FormPropertyConfig[] props = config.findFormPropertyConfigs();
167:
168: for (int i = 0; i < props.length; i++) {
169: dynaBean.set(props[i].getName(), props[i].initial());
170: }
171:
172: return (dynaBean);
173: }
174:
175: // --------------------------------------------------------- Public Methods
176:
177: /**
178: * <p>Render a <code>String</code> representation of this object.</p>
179: *
180: * @return The string representation of this instance.
181: */
182: public String toString() {
183: StringBuffer sb = new StringBuffer("DynaActionFormBean[name=");
184:
185: sb.append(name);
186:
187: DynaProperty[] props = getDynaProperties();
188:
189: if (props == null) {
190: props = new DynaProperty[0];
191: }
192:
193: for (int i = 0; i < props.length; i++) {
194: sb.append(',');
195: sb.append(props[i].getName());
196: sb.append('/');
197: sb.append(props[i].getType());
198: }
199:
200: sb.append("]");
201:
202: return (sb.toString());
203: }
204:
205: // --------------------------------------------------------- Static Methods
206:
207: /**
208: * Return the <code>DynaActionFormClass</code> instance for the specified
209: * form bean configuration instance.
210: *
211: * @param config The config for which the class should be created.
212: * @return The instance for the specified form bean config.
213: */
214: public static DynaActionFormClass createDynaActionFormClass(
215: FormBeanConfig config) {
216: return config.getDynaActionFormClass();
217: }
218:
219: // ------------------------------------------------------ Protected Methods
220:
221: /**
222: * <p>Return the implementation class we are using to construct new
223: * instances, re-introspecting our {@link FormBeanConfig} if necessary
224: * (that is, after being deserialized, since <code>beanClass</code> is
225: * marked transient).</p>
226: *
227: * @return The implementation class used to construct new instances.
228: */
229: protected Class getBeanClass() {
230: if (beanClass == null) {
231: introspect(config);
232: }
233:
234: return (beanClass);
235: }
236:
237: /**
238: * <p>Introspect our form bean configuration to identify the supported
239: * properties.</p>
240: *
241: * @param config The FormBeanConfig instance describing the properties of
242: * the bean to be created
243: * @throws IllegalArgumentException if the bean implementation class
244: * specified in the configuration is not
245: * DynaActionForm (or a subclass of
246: * DynaActionForm)
247: */
248: protected void introspect(FormBeanConfig config) {
249: this .config = config;
250:
251: // Validate the ActionFormBean implementation class
252: try {
253: beanClass = RequestUtils.applicationClass(config.getType());
254: } catch (Throwable t) {
255: throw new IllegalArgumentException(
256: "Cannot instantiate ActionFormBean class '"
257: + config.getType() + "': " + t);
258: }
259:
260: if (!DynaActionForm.class.isAssignableFrom(beanClass)) {
261: throw new IllegalArgumentException("Class '"
262: + config.getType() + "' is not a subclass of "
263: + "'org.apache.struts.action.DynaActionForm'");
264: }
265:
266: // Set the name we will know ourselves by from the form bean name
267: this .name = config.getName();
268:
269: // Look up the property descriptors for this bean class
270: FormPropertyConfig[] descriptors = config
271: .findFormPropertyConfigs();
272:
273: if (descriptors == null) {
274: descriptors = new FormPropertyConfig[0];
275: }
276:
277: // Create corresponding dynamic property definitions
278: properties = new DynaProperty[descriptors.length];
279:
280: for (int i = 0; i < descriptors.length; i++) {
281: properties[i] = new DynaProperty(descriptors[i].getName(),
282: descriptors[i].getTypeClass());
283: propertiesMap.put(properties[i].getName(), properties[i]);
284: }
285: }
286:
287: // -------------------------------------------------------- Private Methods
288: }
|