001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.beanutils;
019:
020: import java.io.Serializable;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.InvocationTargetException;
023: import java.util.HashMap;
024:
025: /**
026: * <p>Minimal implementation of the <code>DynaClass</code> interface. Can be
027: * used as a convenience base class for more sophisticated implementations.</p> *
028: * <p><strong>IMPLEMENTATION NOTE</strong> - The <code>DynaBean</code>
029: * implementation class supplied to our constructor MUST have a one-argument
030: * constructor of its own that accepts a <code>DynaClass</code>. This is
031: * used to associate the DynaBean instance with this DynaClass.</p>
032: *
033: * @author Craig McClanahan
034: * @version $Revision: 556229 $ $Date: 2007-07-14 07:11:19 +0100 (Sat, 14 Jul 2007) $
035: */
036:
037: public class BasicDynaClass implements DynaClass, Serializable {
038:
039: // ----------------------------------------------------------- Constructors
040:
041: /**
042: * Construct a new BasicDynaClass with default parameters.
043: */
044: public BasicDynaClass() {
045:
046: this (null, null, null);
047:
048: }
049:
050: /**
051: * Construct a new BasicDynaClass with the specified parameters.
052: *
053: * @param name Name of this DynaBean class
054: * @param dynaBeanClass The implementation class for new instances
055: */
056: public BasicDynaClass(String name, Class dynaBeanClass) {
057:
058: this (name, dynaBeanClass, null);
059:
060: }
061:
062: /**
063: * Construct a new BasicDynaClass with the specified parameters.
064: *
065: * @param name Name of this DynaBean class
066: * @param dynaBeanClass The implementation class for new intances
067: * @param properties Property descriptors for the supported properties
068: */
069: public BasicDynaClass(String name, Class dynaBeanClass,
070: DynaProperty[] properties) {
071:
072: super ();
073: if (name != null) {
074: this .name = name;
075: }
076: if (dynaBeanClass == null) {
077: dynaBeanClass = BasicDynaBean.class;
078: }
079: setDynaBeanClass(dynaBeanClass);
080: if (properties != null) {
081: setProperties(properties);
082: }
083:
084: }
085:
086: // ----------------------------------------------------- Instance Variables
087:
088: /**
089: * The constructor of the <code>dynaBeanClass</code> that we will use
090: * for creating new instances.
091: */
092: protected transient Constructor constructor = null;
093:
094: /**
095: * The method signature of the constructor we will use to create
096: * new DynaBean instances.
097: */
098: protected static Class[] constructorTypes = { DynaClass.class };
099:
100: /**
101: * The argument values to be passed to the constructore we will use
102: * to create new DynaBean instances.
103: */
104: protected Object[] constructorValues = { this };
105:
106: /**
107: * The <code>DynaBean</code> implementation class we will use for
108: * creating new instances.
109: */
110: protected Class dynaBeanClass = BasicDynaBean.class;
111:
112: /**
113: * The "name" of this DynaBean class.
114: */
115: protected String name = this .getClass().getName();
116:
117: /**
118: * The set of dynamic properties that are part of this DynaClass.
119: */
120: protected DynaProperty[] properties = new DynaProperty[0];
121:
122: /**
123: * The set of dynamic properties that are part of this DynaClass,
124: * keyed by the property name. Individual descriptor instances will
125: * be the same instances as those in the <code>properties</code> list.
126: */
127: protected HashMap propertiesMap = new HashMap();
128:
129: // ------------------------------------------------------ DynaClass Methods
130:
131: /**
132: * Return the name of this DynaClass (analogous to the
133: * <code>getName()</code> method of <code>java.lang.Class</code), which
134: * allows the same <code>DynaClass</code> implementation class to support
135: * different dynamic classes, with different sets of properties.
136: *
137: * @return the name of the DynaClass
138: */
139: public String getName() {
140:
141: return (this .name);
142:
143: }
144:
145: /**
146: * Return a property descriptor for the specified property, if it exists;
147: * otherwise, return <code>null</code>.
148: *
149: * @param name Name of the dynamic property for which a descriptor
150: * is requested
151: * @return The descriptor for the specified property
152: *
153: * @exception IllegalArgumentException if no property name is specified
154: */
155: public DynaProperty getDynaProperty(String name) {
156:
157: if (name == null) {
158: throw new IllegalArgumentException(
159: "No property name specified");
160: }
161: return ((DynaProperty) propertiesMap.get(name));
162:
163: }
164:
165: /**
166: * <p>Return an array of <code>ProperyDescriptors</code> for the properties
167: * currently defined in this DynaClass. If no properties are defined, a
168: * zero-length array will be returned.</p>
169: *
170: * <p><strong>FIXME</strong> - Should we really be implementing
171: * <code>getBeanInfo()</code> instead, which returns property descriptors
172: * and a bunch of other stuff?</p>
173: *
174: * @return the set of properties for this DynaClass
175: */
176: public DynaProperty[] getDynaProperties() {
177:
178: return (properties);
179:
180: }
181:
182: /**
183: * Instantiate and return a new DynaBean instance, associated
184: * with this DynaClass.
185: *
186: * @return A new <code>DynaBean</code> instance
187: * @exception IllegalAccessException if the Class or the appropriate
188: * constructor is not accessible
189: * @exception InstantiationException if this Class represents an abstract
190: * class, an array class, a primitive type, or void; or if instantiation
191: * fails for some other reason
192: */
193: public DynaBean newInstance() throws IllegalAccessException,
194: InstantiationException {
195:
196: try {
197: // Refind the constructor after a deserialization (if needed)
198: if (constructor == null) {
199: setDynaBeanClass(this .dynaBeanClass);
200: }
201: // Invoke the constructor to create a new bean instance
202: return ((DynaBean) constructor
203: .newInstance(constructorValues));
204: } catch (InvocationTargetException e) {
205: throw new InstantiationException(e.getTargetException()
206: .getMessage());
207: }
208:
209: }
210:
211: // --------------------------------------------------------- Public Methods
212:
213: /**
214: * Return the Class object we will use to create new instances in the
215: * <code>newInstance()</code> method. This Class <strong>MUST</strong>
216: * implement the <code>DynaBean</code> interface.
217: *
218: * @return The class of the {@link DynaBean}
219: */
220: public Class getDynaBeanClass() {
221:
222: return (this .dynaBeanClass);
223:
224: }
225:
226: // ------------------------------------------------------ Protected Methods
227:
228: /**
229: * Set the Class object we will use to create new instances in the
230: * <code>newInstance()</code> method. This Class <strong>MUST</strong>
231: * implement the <code>DynaBean</code> interface.
232: *
233: * @param dynaBeanClass The new Class object
234: *
235: * @exception IllegalArgumentException if the specified Class does not
236: * implement the <code>DynaBean</code> interface
237: */
238: protected void setDynaBeanClass(Class dynaBeanClass) {
239:
240: // Validate the argument type specified
241: if (dynaBeanClass.isInterface()) {
242: throw new IllegalArgumentException("Class "
243: + dynaBeanClass.getName()
244: + " is an interface, not a class");
245: }
246: if (!DynaBean.class.isAssignableFrom(dynaBeanClass)) {
247: throw new IllegalArgumentException("Class "
248: + dynaBeanClass.getName()
249: + " does not implement DynaBean");
250: }
251:
252: // Identify the Constructor we will use in newInstance()
253: try {
254: this .constructor = dynaBeanClass
255: .getConstructor(constructorTypes);
256: } catch (NoSuchMethodException e) {
257: throw new IllegalArgumentException("Class "
258: + dynaBeanClass.getName()
259: + " does not have an appropriate constructor");
260: }
261: this .dynaBeanClass = dynaBeanClass;
262:
263: }
264:
265: /**
266: * Set the list of dynamic properties supported by this DynaClass.
267: *
268: * @param properties List of dynamic properties to be supported
269: */
270: protected void setProperties(DynaProperty[] properties) {
271:
272: this .properties = properties;
273: propertiesMap.clear();
274: for (int i = 0; i < properties.length; i++) {
275: propertiesMap.put(properties[i].getName(), properties[i]);
276: }
277:
278: }
279:
280: }
|