KickJava   Java API By Example, From Geeks To Geeks.

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


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  * ObjectFactoryLoader.java
29  * ------------------------
30  * (C) Copyright 2002-2005, by Thomas Morgner and Contributors.
31  *
32  * Original Author: Thomas Morgner;
33  * Contributor(s): -;
34  *
35  * $Id: ObjectFactoryLoader.java,v 1.4 2005/10/18 13:33:53 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 24-Sep-2003: Initial version
40  *
41  */

42
43 package org.jfree.xml.util;
44
45 import java.net.URL JavaDoc;
46 import java.util.ArrayList JavaDoc;
47 import java.util.Arrays JavaDoc;
48 import java.util.HashMap JavaDoc;
49 import java.util.Iterator JavaDoc;
50
51 import org.jfree.util.Log;
52 import org.jfree.xml.attributehandlers.AttributeHandler;
53
54 /**
55  * The object factory loader loads the xml specification for the generic
56  * handlers. The specification may be distributed over multiple files.
57  * <p>
58  * This class provides the model management for the reader and writer.
59  * The instantiation of the handlers is done elsewhere.
60  *
61  * @author TM
62  */

63 public class ObjectFactoryLoader extends AbstractModelReader implements ObjectFactory {
64
65     /** Maps classes to GenericObjectFactory instances. */
66     private HashMap JavaDoc objectMappings;
67     
68     /** Manual mappings. */
69     private HashMap JavaDoc manualMappings;
70     
71     /** Multiplex mappings. */
72     private HashMap JavaDoc multiplexMappings;
73
74     /** The target class. */
75     private Class JavaDoc target;
76     
77     /** The register name. */
78     private String JavaDoc registerName;
79     
80     /** The property definition. */
81     private ArrayList JavaDoc propertyDefinition;
82     
83     /** The attribute definition. */
84     private ArrayList JavaDoc attributeDefinition;
85     
86     /** The constructor definition. */
87     private ArrayList JavaDoc constructorDefinition;
88     
89     /** The lookup definitions. */
90     private ArrayList JavaDoc lookupDefinitions;
91     
92     /** The ordered names. */
93     private ArrayList JavaDoc orderedNames;
94
95     /** The base class. */
96     private String JavaDoc baseClass;
97     
98     /** The attribute name. */
99     private String JavaDoc attributeName;
100     
101     /** The multiplex entries. */
102     private ArrayList JavaDoc multiplexEntries;
103
104     /**
105      * Creates a new object factory loader for the given base file.
106      *
107      * @param resourceName the URL of the initial specification file.
108      *
109      * @throws ObjectDescriptionException if the file could not be parsed.
110      */

111     public ObjectFactoryLoader(final URL JavaDoc resourceName) throws ObjectDescriptionException {
112         this.objectMappings = new HashMap JavaDoc();
113         this.manualMappings = new HashMap JavaDoc();
114         this.multiplexMappings = new HashMap JavaDoc();
115         parseXml(resourceName);
116         rebuildSuperClasses();
117     }
118
119     private void rebuildSuperClasses() throws ObjectDescriptionException {
120         this.propertyDefinition = new ArrayList JavaDoc();
121         this.attributeDefinition = new ArrayList JavaDoc();
122         this.constructorDefinition = new ArrayList JavaDoc();
123         this.lookupDefinitions = new ArrayList JavaDoc();
124         this.orderedNames = new ArrayList JavaDoc();
125
126         final HashMap JavaDoc newObjectDescriptions = new HashMap JavaDoc();
127         final Iterator JavaDoc it = this.objectMappings.keySet().iterator();
128         while (it.hasNext()) {
129             final Object JavaDoc key = it.next();
130             final GenericObjectFactory gef = (GenericObjectFactory) this.objectMappings.get(key);
131             performSuperClassUpdate(gef);
132
133             final PropertyDefinition[] propertyDefs = (PropertyDefinition[])
134             this.propertyDefinition.toArray(new PropertyDefinition[0]);
135             final LookupDefinition[] lookupDefs = (LookupDefinition[])
136             this.lookupDefinitions.toArray(new LookupDefinition[0]);
137             final AttributeDefinition[] attribDefs = (AttributeDefinition[])
138             this.attributeDefinition.toArray(new AttributeDefinition[0]);
139             final ConstructorDefinition[] constructorDefs = (ConstructorDefinition[])
140             this.constructorDefinition.toArray(new ConstructorDefinition[0]);
141             final String JavaDoc[] orderedNamesDefs = (String JavaDoc[])
142             this.orderedNames.toArray(new String JavaDoc[0]);
143
144             final GenericObjectFactory objectFactory = new GenericObjectFactory
145                 (gef.getBaseClass(), gef.getRegisterName(), constructorDefs,
146                     propertyDefs, lookupDefs, attribDefs, orderedNamesDefs);
147             newObjectDescriptions.put(key, objectFactory);
148
149             this.propertyDefinition.clear();
150             this.attributeDefinition.clear();
151             this.constructorDefinition.clear();
152             this.lookupDefinitions.clear();
153             this.orderedNames.clear();
154         }
155
156         this.objectMappings.clear();
157         this.objectMappings = newObjectDescriptions;
158
159         this.propertyDefinition = null;
160         this.attributeDefinition = null;
161         this.constructorDefinition = null;
162         this.lookupDefinitions = null;
163         this.orderedNames = null;
164     }
165
166     private void performSuperClassUpdate(final GenericObjectFactory gef) {
167         // first handle the super classes, ...
168
final Class JavaDoc superClass = gef.getBaseClass().getSuperclass();
169         if (superClass != null && !superClass.equals(Object JavaDoc.class)) {
170             final GenericObjectFactory superGef = (GenericObjectFactory) this.objectMappings.get(
171                 superClass
172             );
173             if (superGef != null) {
174                 performSuperClassUpdate(superGef);
175             }
176         }
177
178         // and finally append all local properties ...
179
this.propertyDefinition.addAll(Arrays.asList(gef.getPropertyDefinitions()));
180         this.attributeDefinition.addAll(Arrays.asList(gef.getAttributeDefinitions()));
181         this.constructorDefinition.addAll(Arrays.asList(gef.getConstructorDefinitions()));
182         this.lookupDefinitions.addAll(Arrays.asList(gef.getLookupDefinitions()));
183         this.orderedNames.addAll(Arrays.asList(gef.getOrderedPropertyNames()));
184     }
185
186     /**
187      * Starts a object definition. The object definition collects all properties of
188      * an bean-class and defines, which constructor should be used when creating the
189      * class.
190      *
191      * @param className the class name of the defined object
192      * @param register the (optional) register name, to lookup and reference the object later.
193      * @param ignore ignore?
194      *
195      * @return true, if the definition was accepted, false otherwise.
196      * @throws ObjectDescriptionException if an unexpected error occured.
197      */

198     protected boolean startObjectDefinition(final String JavaDoc className, final String JavaDoc register, final boolean ignore)
199         throws ObjectDescriptionException {
200
201         if (ignore) {
202             return false;
203         }
204         this.target = loadClass(className);
205         if (this.target == null) {
206             Log.warn(new Log.SimpleMessage("Failed to load class ", className));
207             return false;
208         }
209         this.registerName = register;
210         this.propertyDefinition = new ArrayList JavaDoc();
211         this.attributeDefinition = new ArrayList JavaDoc();
212         this.constructorDefinition = new ArrayList JavaDoc();
213         this.lookupDefinitions = new ArrayList JavaDoc();
214         this.orderedNames = new ArrayList JavaDoc();
215         return true;
216     }
217
218     /**
219      * Handles an attribute definition. This method gets called after the object definition
220      * was started. The method will be called for every defined attribute property.
221      *
222      * @param name the name of the property
223      * @param attribName the xml-attribute name to use later.
224      * @param handlerClass the attribute handler class.
225      * @throws ObjectDescriptionException if an error occured.
226      */

227     protected void handleAttributeDefinition(final String JavaDoc name, final String JavaDoc attribName, final String JavaDoc handlerClass)
228         throws ObjectDescriptionException {
229         final AttributeHandler handler = loadAttributeHandler(handlerClass);
230         this.orderedNames.add(name);
231         this.attributeDefinition.add(new AttributeDefinition(name, attribName, handler));
232     }
233
234     /**
235      * Handles an element definition. This method gets called after the object definition
236      * was started. The method will be called for every defined element property. Element
237      * properties are used to describe complex objects.
238      *
239      * @param name the name of the property
240      * @param element the xml-tag name for the child element.
241      * @throws ObjectDescriptionException if an error occurs.
242      */

243     protected void handleElementDefinition(final String JavaDoc name, final String JavaDoc element)
244         throws ObjectDescriptionException {
245         this.orderedNames.add(name);
246         this.propertyDefinition.add(new PropertyDefinition(name, element));
247     }
248
249     /**
250      * Handles an lookup definition. This method gets called after the object definition
251      * was started. The method will be called for every defined lookup property. Lookup properties
252      * reference previously created object using the object's registry name.
253      *
254      * @param name the property name of the base object
255      * @param lookupKey the register key of the referenced object
256      * @throws ObjectDescriptionException if an error occured.
257      */

258     protected void handleLookupDefinition(final String JavaDoc name, final String JavaDoc lookupKey)
259         throws ObjectDescriptionException {
260         final LookupDefinition ldef = new LookupDefinition(name, lookupKey);
261         this.orderedNames.add(name);
262         this.lookupDefinitions.add(ldef);
263     }
264
265     /**
266      * Finializes the object definition.
267      *
268      * @throws ObjectDescriptionException if an error occures.
269      */

270     protected void endObjectDefinition()
271         throws ObjectDescriptionException {
272
273         final PropertyDefinition[] propertyDefs = (PropertyDefinition[])
274         this.propertyDefinition.toArray(new PropertyDefinition[0]);
275         final LookupDefinition[] lookupDefs = (LookupDefinition[])
276         this.lookupDefinitions.toArray(new LookupDefinition[0]);
277         final AttributeDefinition[] attribDefs = (AttributeDefinition[])
278         this.attributeDefinition.toArray(new AttributeDefinition[0]);
279         final ConstructorDefinition[] constructorDefs = (ConstructorDefinition[])
280         this.constructorDefinition.toArray(new ConstructorDefinition[0]);
281         final String JavaDoc[] orderedNamesDefs = (String JavaDoc[])
282         this.orderedNames.toArray(new String JavaDoc[0]);
283
284         final GenericObjectFactory objectFactory = new GenericObjectFactory
285             (this.target, this.registerName, constructorDefs,
286                 propertyDefs, lookupDefs, attribDefs, orderedNamesDefs);
287         this.objectMappings.put(this.target, objectFactory);
288     }
289
290     /**
291      * Handles a constructor definition. Only one constructor can be defined for
292      * a certain object type. The constructor will be filled using the given properties.
293      *
294      * @param propertyName the property name of the referenced local property
295      * @param parameterClass the parameter class for the parameter.
296      */

297     protected void handleConstructorDefinition(final String JavaDoc propertyName, final String JavaDoc parameterClass) {
298         final Class JavaDoc c = loadClass(parameterClass);
299         this.orderedNames.add(propertyName);
300         this.constructorDefinition.add(new ConstructorDefinition(propertyName, c));
301     }
302
303     /**
304      * Handles a manual mapping definition. The manual mapping maps specific
305      * read and write handlers to a given base class. Manual mappings always
306      * override any other definition.
307      *
308      * @param className the base class name
309      * @param readHandler the class name of the read handler
310      * @param writeHandler the class name of the write handler
311      * @return true, if the mapping was accepted, false otherwise.
312      * @throws ObjectDescriptionException if an unexpected error occured.
313      */

314     protected boolean handleManualMapping(final String JavaDoc className, final String JavaDoc readHandler, final String JavaDoc writeHandler)
315         throws ObjectDescriptionException {
316
317         if (!this.manualMappings.containsKey(className)) {
318             final Class JavaDoc loadedClass = loadClass(className);
319             this.manualMappings.put(loadedClass, new ManualMappingDefinition
320                 (loadedClass, readHandler, writeHandler));
321             return true;
322         }
323         return false;
324     }
325
326     /**
327      * Starts a multiplex mapping. Multiplex mappings are used to define polymorphic
328      * argument handlers. The mapper will collect all derived classes of the given
329      * base class and will select the corresponding mapping based on the given type
330      * attribute.
331      *
332      * @param className the base class name
333      * @param typeAttr the xml-attribute name containing the mapping key
334      */

335     protected void startMultiplexMapping(final String JavaDoc className, final String JavaDoc typeAttr) {
336         this.baseClass = className;
337         this.attributeName = typeAttr;
338         this.multiplexEntries = new ArrayList JavaDoc();
339     }
340
341     /**
342      * Defines an entry for the multiplex mapping. The new entry will be activated
343      * when the base mappers type attribute contains this <code>typename</code> and
344      * will resolve to the handler for the given classname.
345      *
346      * @param typeName the type value for this mapping.
347      * @param className the class name to which this mapping resolves.
348      * @throws ObjectDescriptionException if an error occurs.
349      */

350     protected void handleMultiplexMapping(final String JavaDoc typeName, final String JavaDoc className)
351         throws ObjectDescriptionException {
352         this.multiplexEntries.add
353             (new MultiplexMappingEntry(typeName, className));
354     }
355
356     /**
357      * Finializes the multiplexer mapping.
358      *
359      * @throws ObjectDescriptionException if an error occurs.
360      */

361     protected void endMultiplexMapping() throws ObjectDescriptionException {
362         final MultiplexMappingEntry[] mappings = (MultiplexMappingEntry[])
363         this.multiplexEntries.toArray(new MultiplexMappingEntry[0]);
364         final Class JavaDoc c = loadClass(this.baseClass);
365         this.multiplexMappings.put(c,
366             new MultiplexMappingDefinition(c, this.attributeName, mappings));
367         this.multiplexEntries = null;
368     }
369
370     /**
371      * Loads an instantiates the attribute handler specified by the given
372      * class name.
373      *
374      * @param attribute the attribute handlers classname.
375      * @return the created attribute handler instance
376      * @throws ObjectDescriptionException if the handler could not be loaded.
377      */

378     private AttributeHandler loadAttributeHandler(final String JavaDoc attribute)
379         throws ObjectDescriptionException {
380
381         final Class JavaDoc c = loadClass(attribute);
382         try {
383             return (AttributeHandler) c.newInstance();
384         }
385         catch (Exception JavaDoc e) {
386             throw new ObjectDescriptionException
387                 ("Invalid attribute handler specified: " + attribute);
388         }
389     }
390
391     /**
392      * Checks, whether the factory has a description for the given class.
393      *
394      * @param c the class to be handled by the factory.
395      * @return true, if an description exists for the given class, false otherwise.
396      */

397     public boolean isGenericHandler(final Class JavaDoc c) {
398         return this.objectMappings.containsKey(c);
399     }
400
401     /**
402      * Returns a factory instance for the given class. The factory is independent
403      * from all previously generated instances.
404      *
405      * @param c the class
406      * @return the object factory.
407      */

408     public GenericObjectFactory getFactoryForClass(final Class JavaDoc c) {
409         final GenericObjectFactory factory = (GenericObjectFactory) this.objectMappings.get(c);
410         if (factory == null) {
411             return null;
412         }
413         return factory.getInstance();
414     }
415
416     /**
417      * Returns the manual mapping definition for the given class, or null, if
418      * not manual definition exists.
419      *
420      * @param c the class for which to check the existence of the definition
421      * @return the manual mapping definition or null.
422      */

423     public ManualMappingDefinition getManualMappingDefinition(final Class JavaDoc c) {
424         return (ManualMappingDefinition) this.manualMappings.get(c);
425     }
426
427     /**
428      * Returns the multiplex definition for the given class, or null, if no
429      * such definition exists.
430      *
431      * @param c the class for which to check the existence of the multiplexer
432      * @return the multiplexer for the class, or null if no multiplexer exists.
433      */

434     public MultiplexMappingDefinition getMultiplexDefinition(final Class JavaDoc c) {
435         final MultiplexMappingDefinition definition = (MultiplexMappingDefinition)
436         this.multiplexMappings.get(c);
437         return definition;
438     }
439
440 }
441
Popular Tags