KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > xml > util > GenericObjectFactory


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * -------------------------
28  * GenericObjectFactory.java
29  * -------------------------
30  * (C)opyright 2003-2005, by Thomas Morgner and Contributors.
31  *
32  * Original Author: Thomas Morgner;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: GenericObjectFactory.java,v 1.4 2005/10/18 13:33:53 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 23-Sep-2003 : Initial version (TM);
40  *
41  */

42
43 package org.jfree.xml.util;
44
45 import java.beans.BeanInfo JavaDoc;
46 import java.beans.IntrospectionException JavaDoc;
47 import java.beans.Introspector JavaDoc;
48 import java.beans.PropertyDescriptor JavaDoc;
49 import java.lang.reflect.Constructor JavaDoc;
50 import java.lang.reflect.Method JavaDoc;
51 import java.util.HashMap JavaDoc;
52
53 /**
54  * The generic object factory contains all methods necessary to collect
55  * the property values needed to produce a fully instantiated object.
56  */

57 public final class GenericObjectFactory {
58
59     /** Storage for the constructor definitions. */
60     private final ConstructorDefinition[] constructorDefinitions;
61     
62     /** Storage for the property definitions. */
63     private final PropertyDefinition[] propertyDefinitions;
64     
65     /** Storage for the lookup definitions. */
66     private final LookupDefinition[] lookupDefinitions;
67     
68     /** Storage for the attribute definitions. */
69     private final AttributeDefinition[] attributeDefinitions;
70     
71     /** The ordered property names. */
72     private final String JavaDoc[] orderedPropertyNames;
73
74     /** Storage for property info. */
75     private final HashMap JavaDoc propertyInfos;
76     
77     /** Storage for property values. */
78     private final HashMap JavaDoc propertyValues;
79
80     /** The base class. */
81     private final Class JavaDoc baseClass;
82     
83     /** The register name. */
84     private final String JavaDoc registerName;
85
86     /**
87      * Creates a new generic object factory.
88      *
89      * @param c the class.
90      * @param registerName the (optional) name under which to register the class for
91      * any later lookup.
92      * @param constructors the constructor definitions.
93      * @param propertyDefinitions the property definitions.
94      * @param lookupDefinitions the lookup definitions.
95      * @param attributeDefinitions the attribute definitions.
96      * @param orderedPropertyNames the ordered property names.
97      *
98      * @throws ObjectDescriptionException if there is a problem.
99      */

100     public GenericObjectFactory(final Class JavaDoc c,
101                                 final String JavaDoc registerName,
102                                 final ConstructorDefinition[] constructors,
103                                 final PropertyDefinition[] propertyDefinitions,
104                                 final LookupDefinition[] lookupDefinitions,
105                                 final AttributeDefinition[] attributeDefinitions,
106                                 final String JavaDoc[] orderedPropertyNames)
107         throws ObjectDescriptionException {
108
109         if (c == null) {
110             throw new NullPointerException JavaDoc("BaseClass cannot be null.");
111         }
112         this.baseClass = c;
113         this.registerName = registerName;
114
115         this.propertyInfos = new HashMap JavaDoc();
116         this.propertyValues = new HashMap JavaDoc();
117
118         this.constructorDefinitions = constructors;
119         this.propertyDefinitions = propertyDefinitions;
120         this.lookupDefinitions = lookupDefinitions;
121         this.attributeDefinitions = attributeDefinitions;
122         this.orderedPropertyNames = orderedPropertyNames;
123
124         try {
125             final BeanInfo JavaDoc chartBeaninfo = Introspector.getBeanInfo(c, Object JavaDoc.class);
126             final PropertyDescriptor JavaDoc[] pd = chartBeaninfo.getPropertyDescriptors();
127             for (int i = 0; i < pd.length; i++) {
128                 this.propertyInfos.put(pd[i].getName(), pd[i]);
129             }
130         }
131         catch (IntrospectionException JavaDoc ioe) {
132             throw new ObjectDescriptionException(
133                 "This is an ugly solution right now ... dirty hack attack"
134             );
135         }
136     }
137
138     /**
139      * A copy constructor.
140      *
141      * @param factory the factory to copy.
142      */

143     private GenericObjectFactory (final GenericObjectFactory factory) {
144         this.baseClass = factory.baseClass;
145         this.propertyValues = new HashMap JavaDoc();
146         this.orderedPropertyNames = factory.orderedPropertyNames;
147         this.constructorDefinitions = factory.constructorDefinitions;
148         this.propertyDefinitions = factory.propertyDefinitions;
149         this.attributeDefinitions = factory.attributeDefinitions;
150         this.propertyInfos = factory.propertyInfos;
151         this.registerName = factory.registerName;
152         this.lookupDefinitions = factory.lookupDefinitions;
153     }
154
155     /**
156      * Returns a copy of this instance.
157      *
158      * @return a copy of this instance.
159      */

160     public GenericObjectFactory getInstance () {
161         return new GenericObjectFactory(this);
162     }
163
164     /**
165      * Returns the register name.
166      *
167      * @return the register name.
168      */

169     public String JavaDoc getRegisterName() {
170         return this.registerName;
171     }
172
173     /**
174      * Returns a property descriptor.
175      *
176      * @param propertyName the property name.
177      *
178      * @return a property descriptor.
179      */

180     private PropertyDescriptor JavaDoc getPropertyDescriptor(final String JavaDoc propertyName) {
181         return (PropertyDescriptor JavaDoc) this.propertyInfos.get(propertyName);
182     }
183
184     /**
185      * Returns the class for a tag name.
186      *
187      * @param tagName the tag name.
188      *
189      * @return the class.
190      *
191      * @throws ObjectDescriptionException if there is a problem.
192      */

193     public Class JavaDoc getTypeForTagName(final String JavaDoc tagName) throws ObjectDescriptionException {
194         final PropertyDefinition pdef = getPropertyDefinitionByTagName(tagName);
195         final PropertyDescriptor JavaDoc pdescr = getPropertyDescriptor(pdef.getPropertyName());
196         if (pdescr == null) {
197             throw new ObjectDescriptionException("Invalid Definition: " + pdef.getPropertyName());
198         }
199         return pdescr.getPropertyType();
200     }
201
202     /**
203      * Returns true if there is a property definition for the specified property name.
204      *
205      * @param propertyName the property name.
206      *
207      * @return A boolean.
208      */

209     public boolean isPropertyDefinition (final String JavaDoc propertyName) {
210         for (int i = 0; i < this.propertyDefinitions.length; i++) {
211             final PropertyDefinition pdef = this.propertyDefinitions[i];
212             if (pdef.getPropertyName().equals(propertyName)) {
213                 return true;
214             }
215         }
216         return false;
217     }
218
219     /**
220      * Returns the property definition for the specified property name.
221      *
222      * @param propertyName the property name.
223      *
224      * @return the property definition.
225      *
226      * @throws ObjectDescriptionException if there is no such property for this object.
227      */

228     public PropertyDefinition getPropertyDefinitionByPropertyName(final String JavaDoc propertyName)
229         throws ObjectDescriptionException {
230         for (int i = 0; i < this.propertyDefinitions.length; i++) {
231             final PropertyDefinition pdef = this.propertyDefinitions[i];
232             if (pdef.getPropertyName().equals(propertyName)) {
233                 return pdef;
234             }
235         }
236         throw new ObjectDescriptionException(
237             "This property is not defined for this kind of object. : " + propertyName
238         );
239     }
240
241     /**
242      * Returns a property definition for the specified tag name.
243      *
244      * @param tagName the tag name.
245      *
246      * @return the property definition.
247      *
248      * @throws ObjectDescriptionException if there is no such tag defined for this object.
249      */

250     public PropertyDefinition getPropertyDefinitionByTagName(final String JavaDoc tagName)
251         throws ObjectDescriptionException {
252         for (int i = 0; i < this.propertyDefinitions.length; i++) {
253             final PropertyDefinition pdef = this.propertyDefinitions[i];
254             if (pdef.getElementName().equals(tagName)) {
255                 return pdef;
256             }
257         }
258         throw new ObjectDescriptionException(
259             "This tag is not defined for this kind of object. : " + tagName
260         );
261     }
262
263     /**
264      * Returns the constructor definitions.
265      *
266      * @return the constructor definitions.
267      */

268     public ConstructorDefinition[] getConstructorDefinitions() {
269         return this.constructorDefinitions;
270     }
271
272     /**
273      * Returns the attribute definitions.
274      *
275      * @return the attribute definitions.
276      */

277     public AttributeDefinition[] getAttributeDefinitions() {
278         return this.attributeDefinitions;
279     }
280
281     /**
282      * Returns the property definitions.
283      *
284      * @return the property definitions.
285      */

286     public PropertyDefinition[] getPropertyDefinitions() {
287         return this.propertyDefinitions;
288     }
289
290     /**
291      * Returns the property names.
292      *
293      * @return the property names.
294      */

295     public String JavaDoc[] getOrderedPropertyNames() {
296         return this.orderedPropertyNames;
297     }
298
299     /**
300      * Returns the lookup definitions.
301      *
302      * @return the lookup definitions.
303      */

304     public LookupDefinition[] getLookupDefinitions() {
305         return this.lookupDefinitions;
306     }
307
308     /**
309      * Returns the value of the specified property.
310      *
311      * @param name the property name.
312      *
313      * @return the property value.
314      */

315     public Object JavaDoc getProperty(final String JavaDoc name) {
316         return this.propertyValues.get(name);
317     }
318
319     /**
320      * Creates an object according to the definition.
321      *
322      * @return the object.
323      *
324      * @throws ObjectDescriptionException if there is a problem with the object description.
325      */

326     public Object JavaDoc createObject() throws ObjectDescriptionException {
327         final Class JavaDoc[] cArgs = new Class JavaDoc[this.constructorDefinitions.length];
328         final Object JavaDoc[] oArgs = new Object JavaDoc[this.constructorDefinitions.length];
329         for (int i = 0; i < cArgs.length; i++) {
330             final ConstructorDefinition cDef = this.constructorDefinitions[i];
331             cArgs[i] = cDef.getType();
332             if (cDef.isNull()) {
333                 oArgs[i] = null;
334             }
335             else {
336                 oArgs[i] = getProperty(cDef.getPropertyName());
337             }
338         }
339
340         try {
341             final Constructor JavaDoc constr = this.baseClass.getConstructor(cArgs);
342             final Object JavaDoc o = constr.newInstance(oArgs);
343             return o;
344         }
345         catch (Exception JavaDoc e) {
346             throw new ObjectDescriptionException("Ugh! Constructor made a buuuh!", e);
347         }
348     }
349
350     /**
351      * Sets a property value.
352      *
353      * @param propertyName the property name.
354      * @param value the property value.
355      *
356      * @throws ObjectDescriptionException if there is a problem with the object description.
357      */

358     public void setProperty(final String JavaDoc propertyName, final Object JavaDoc value)
359         throws ObjectDescriptionException {
360         final PropertyDescriptor JavaDoc pdesc = getPropertyDescriptor(propertyName);
361         if (pdesc == null) {
362             throw new ObjectDescriptionException("Unknown property " + propertyName);
363         }
364
365         if (!isAssignableOrPrimitive(pdesc.getPropertyType(), value.getClass())) {
366             throw new ObjectDescriptionException(
367                 "Invalid value: " + pdesc.getPropertyType() + " vs. " + value.getClass()
368             );
369         }
370
371         this.propertyValues.put(propertyName, value);
372     }
373
374     /**
375      * Returns <code>true</code> if the base type is a primitive or assignable from the value type.
376      *
377      * @param baseType the base class.
378      * @param valueType the value class.
379      *
380      * @return A boolean.
381      */

382     private boolean isAssignableOrPrimitive(final Class JavaDoc baseType, final Class JavaDoc valueType) {
383         if (BasicTypeSupport.isBasicDataType(baseType)) {
384             return true;
385         }
386         // verbose stuff below *should* no longer be needed
387
return baseType.isAssignableFrom(valueType);
388     }
389
390     /**
391      * Returns <code>true<code> if the specified property is...
392      *
393      * @param propertyName the property name.
394      *
395      * @return A boolean.
396      */

397     private boolean isConstructorProperty(final String JavaDoc propertyName) {
398         for (int i = 0; i < this.constructorDefinitions.length; i++) {
399             final ConstructorDefinition cDef = this.constructorDefinitions[i];
400             if (propertyName.equals(cDef.getPropertyName())) {
401                 return true;
402             }
403         }
404         return false;
405     }
406
407     /**
408      * Writes the properties for the object.
409      *
410      * @param object the object.
411      *
412      * @throws ObjectDescriptionException if there is a problem.
413      */

414     public void writeObjectProperties(final Object JavaDoc object) throws ObjectDescriptionException {
415         // this assumes that the order of setting the attributes does not matter.
416
for (int i = 0; i < this.orderedPropertyNames.length; i++) {
417             try {
418                 final String JavaDoc name = this.orderedPropertyNames[i];
419                 if (isConstructorProperty(name)) {
420                     continue;
421                 }
422                 final Object JavaDoc value = getProperty(name);
423                 if (value == null) {
424                     // do nothing if value is not defined ...
425
continue;
426                 }
427                 final PropertyDescriptor JavaDoc pdescr = getPropertyDescriptor(name);
428                 final Method JavaDoc setter = pdescr.getWriteMethod();
429                 setter.invoke(object, new Object JavaDoc[]{value});
430             }
431             catch (Exception JavaDoc e) {
432                 throw new ObjectDescriptionException(
433                     "Failed to set properties." + getBaseClass(), e
434                 );
435             }
436         }
437     }
438
439     /**
440      * Reads the properties.
441      *
442      * @param object the object.
443      *
444      * @throws ObjectDescriptionException if there is a problem.
445      */

446     public void readProperties(final Object JavaDoc object) throws ObjectDescriptionException {
447         // this assumes that the order of setting the attributes does not matter.
448
for (int i = 0; i < this.orderedPropertyNames.length; i++) {
449             try {
450                 final String JavaDoc name = this.orderedPropertyNames[i];
451                 final PropertyDescriptor JavaDoc pdescr = getPropertyDescriptor(name);
452                 if (pdescr == null) {
453                     throw new IllegalStateException JavaDoc("No property defined: " + name);
454                 }
455                 final Method JavaDoc setter = pdescr.getReadMethod();
456                 final Object JavaDoc value = setter.invoke(object, new Object JavaDoc[0]);
457                 if (value == null) {
458                     // do nothing if value is not defined ... or null
459
continue;
460                 }
461                 setProperty(name, value);
462             }
463             catch (Exception JavaDoc e) {
464                 throw new ObjectDescriptionException("Failed to set properties.", e);
465             }
466         }
467     }
468
469     /**
470      * Returns the base class.
471      *
472      * @return the base class.
473      */

474     public Class JavaDoc getBaseClass() {
475         return this.baseClass;
476     }
477     
478 }
479
Popular Tags