001: /* ========================================================================
002: * JCommon : a free general purpose class library for the Java(tm) platform
003: * ========================================================================
004: *
005: * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jcommon/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -----------------------
028: * DefaultModelReader.java
029: * -----------------------
030: * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
031: *
032: * Original Author: Thomas Morgner;
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: *
035: * $Id: DefaultModelReader.java,v 1.2 2005/10/18 13:32:20 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 12-Nov-2003 : Initial version (TM);
040: * 26-Nov-2003 : Updated header and Javadocs (DG);
041: *
042: */
043:
044: package org.jfree.xml.generator;
045:
046: import java.beans.BeanInfo;
047: import java.beans.IntrospectionException;
048: import java.beans.Introspector;
049: import java.beans.PropertyDescriptor;
050: import java.io.File;
051: import java.io.IOException;
052: import java.net.URL;
053: import java.util.ArrayList;
054:
055: import org.jfree.io.IOUtils;
056: import org.jfree.xml.generator.model.ClassDescription;
057: import org.jfree.xml.generator.model.Comments;
058: import org.jfree.xml.generator.model.DescriptionModel;
059: import org.jfree.xml.generator.model.IgnoredPropertyInfo;
060: import org.jfree.xml.generator.model.ManualMappingInfo;
061: import org.jfree.xml.generator.model.MultiplexMappingInfo;
062: import org.jfree.xml.generator.model.PropertyInfo;
063: import org.jfree.xml.generator.model.PropertyType;
064: import org.jfree.xml.generator.model.TypeInfo;
065: import org.jfree.xml.util.AbstractModelReader;
066: import org.jfree.xml.util.ObjectDescriptionException;
067:
068: /**
069: * A reader for the class model.
070: */
071: public class DefaultModelReader extends AbstractModelReader {
072:
073: /** A model containing classes and the corresponding class descriptions. */
074: private DescriptionModel model;
075:
076: /** The class description under construction. */
077: private ClassDescription currentClassDescription;
078:
079: /** Information about the class being processed. */
080: private BeanInfo currentBeanInfo;
081:
082: /** The base URL. */
083: private URL baseURL;
084:
085: /** The source. */
086: private String source;
087:
088: /** The multiplex mapping info. */
089: private MultiplexMappingInfo multiplexInfo;
090:
091: /** The multiplex type info.*/
092: private ArrayList multiplexTypeInfos;
093:
094: /** Storage for the properties of the current class. */
095: private ArrayList propertyList;
096:
097: /** Storage for the constructors of the current class. */
098: private ArrayList constructorList;
099:
100: /**
101: * Creates a new model reader.
102: */
103: public DefaultModelReader() {
104: super ();
105: }
106:
107: /**
108: * Loads a description model.
109: *
110: * @param file the file name.
111: *
112: * @return A description model.
113: *
114: * @throws IOException if there is an I/O problem.
115: * @throws ObjectDescriptionException if there is a problem reading the object descriptions.
116: */
117: public synchronized DescriptionModel load(final String file)
118: throws IOException, ObjectDescriptionException {
119:
120: this .model = new DescriptionModel();
121: this .baseURL = new File(file).toURL();
122: parseXml(this .baseURL);
123: fillSuperClasses();
124: return this .model;
125:
126: }
127:
128: /**
129: * Iterates through all the class descriptions in the model, setting the superclass
130: * attribute in all cases where the superclass definitions are contained in the model.
131: */
132: protected void fillSuperClasses() {
133: for (int i = 0; i < this .model.size(); i++) {
134: final ClassDescription cd = this .model.get(i);
135: final Class parent = cd.getObjectClass().getSuperclass();
136: if (parent == null) {
137: continue;
138: }
139: final ClassDescription super CD = this .model.get(parent);
140: if (super CD != null) {
141: cd.setSuperClass(super CD.getObjectClass());
142: }
143: }
144: }
145:
146: /**
147: * Begin processing an object definition element.
148: *
149: * @param className the class name.
150: * @param register the register name (<code>null</code> permitted).
151: * @param ignore ??
152: *
153: * @return <code>true</code> if the class is available, and <code>false</code> otherwise.
154: */
155: protected boolean startObjectDefinition(final String className,
156: final String register, final boolean ignore) {
157: final Class c = loadClass(className);
158: if (c == null) {
159: return false;
160: }
161: this .currentClassDescription = new ClassDescription(c);
162: this .currentClassDescription.setPreserve(ignore);
163: this .currentClassDescription.setRegisterKey(register);
164: try {
165: this .currentBeanInfo = Introspector.getBeanInfo(c,
166: Object.class);
167: } catch (IntrospectionException ie) {
168: return false;
169: }
170: this .propertyList = new java.util.ArrayList();
171: this .constructorList = new java.util.ArrayList();
172: return true;
173: }
174:
175: /**
176: * Finishes processing an object definition (sets the constructor and property info for the
177: * class description, and adds the class description to the model).
178: *
179: * @throws ObjectDescriptionException if there is a problem with the object description.
180: */
181: protected void endObjectDefinition()
182: throws ObjectDescriptionException {
183: final PropertyInfo[] pis = (PropertyInfo[]) this .propertyList
184: .toArray(new PropertyInfo[this .propertyList.size()]);
185: this .currentClassDescription.setProperties(pis);
186:
187: final TypeInfo[] tis = (TypeInfo[]) this .constructorList
188: .toArray(new TypeInfo[this .constructorList.size()]);
189:
190: this .currentClassDescription.setConstructorDescription(tis);
191: this .currentClassDescription.setComments(new Comments(
192: getOpenComment(), getCloseComment()));
193: this .currentClassDescription.setSource(this .source);
194:
195: this .model.addClassDescription(this .currentClassDescription);
196:
197: this .propertyList = null;
198: this .currentBeanInfo = null;
199: this .currentClassDescription = null;
200: }
201:
202: /**
203: * Handles the description of an attribute within an object definition.
204: *
205: * @param name the name.
206: * @param attribName the attribute name.
207: * @param handlerClass the fully qualified class name for the attribute handler.
208: *
209: * @throws ObjectDescriptionException if there is a problem with the object description.
210: */
211: protected void handleAttributeDefinition(final String name,
212: final String attribName, final String handlerClass)
213: throws ObjectDescriptionException {
214:
215: final PropertyInfo propertyInfo = ModelBuilder.getInstance()
216: .createSimplePropertyInfo(getPropertyDescriptor(name));
217:
218: if (propertyInfo == null) {
219: throw new ObjectDescriptionException(
220: "Unable to load property " + name);
221: }
222:
223: propertyInfo.setComments(new Comments(getOpenComment(),
224: getCloseComment()));
225: propertyInfo.setPropertyType(PropertyType.ATTRIBUTE);
226: propertyInfo.setXmlName(attribName);
227: propertyInfo.setXmlHandler(handlerClass);
228: this .propertyList.add(propertyInfo);
229: }
230:
231: /**
232: * Handles the constructor definition.
233: *
234: * @param tagName the tag name.
235: * @param parameterClass the parameter class.
236: *
237: * @throws ObjectDescriptionException if there is a problem with the object description.
238: */
239: protected void handleConstructorDefinition(final String tagName,
240: final String parameterClass)
241: throws ObjectDescriptionException {
242:
243: final Class c = loadClass(parameterClass);
244: if (c == null) {
245: throw new ObjectDescriptionException(
246: "Failed to load class " + parameterClass);
247: }
248: final TypeInfo ti = new TypeInfo(tagName, c);
249: ti
250: .setComments(new Comments(getOpenComment(),
251: getCloseComment()));
252: this .constructorList.add(ti);
253: }
254:
255: /**
256: * Handles the description of an element within an object definition.
257: *
258: * @param name the property name.
259: * @param element the element name.
260: *
261: * @throws ObjectDescriptionException if there is a problem with the object description.
262: */
263: protected void handleElementDefinition(final String name,
264: final String element) throws ObjectDescriptionException {
265:
266: final PropertyInfo propertyInfo = ModelBuilder.getInstance()
267: .createSimplePropertyInfo(getPropertyDescriptor(name));
268:
269: if (propertyInfo == null) {
270: throw new ObjectDescriptionException(
271: "Unable to load property " + name);
272: }
273:
274: propertyInfo.setComments(new Comments(getOpenComment(),
275: getCloseComment()));
276: propertyInfo.setPropertyType(PropertyType.ELEMENT);
277: propertyInfo.setXmlName(element);
278: propertyInfo.setXmlHandler(null);
279: this .propertyList.add(propertyInfo);
280:
281: }
282:
283: /**
284: * Handles a lookup definition.
285: *
286: * @param name the name.
287: * @param lookupKey the lookup key.
288: *
289: * @throws ObjectDescriptionException if there is a problem with the object description.
290: */
291: protected void handleLookupDefinition(final String name,
292: final String lookupKey) throws ObjectDescriptionException {
293: final PropertyInfo propertyInfo = ModelBuilder.getInstance()
294: .createSimplePropertyInfo(getPropertyDescriptor(name));
295:
296: if (propertyInfo == null) {
297: throw new ObjectDescriptionException(
298: "Unable to load property " + name);
299: }
300:
301: propertyInfo.setComments(new Comments(getOpenComment(),
302: getCloseComment()));
303: propertyInfo.setPropertyType(PropertyType.LOOKUP);
304: propertyInfo.setXmlName(lookupKey);
305: propertyInfo.setXmlHandler(null);
306: this .propertyList.add(propertyInfo);
307: }
308:
309: /**
310: * Returns a property descriptor for the named property, or <code>null</code> if there is
311: * no descriptor with the given name.
312: *
313: * @param propertyName the property name.
314: *
315: * @return a property descriptor.
316: */
317: protected PropertyDescriptor getPropertyDescriptor(
318: final String propertyName) {
319: final PropertyDescriptor[] pds = this .currentBeanInfo
320: .getPropertyDescriptors();
321: for (int i = 0; i < pds.length; i++) {
322: if (pds[i].getName().equals(propertyName)) {
323: return pds[i];
324: }
325: }
326: return null;
327: }
328:
329: /**
330: * Handles an ignored property.
331: *
332: * @param name the name.
333: */
334: protected void handleIgnoredProperty(final String name) {
335: final IgnoredPropertyInfo propertyInfo = new IgnoredPropertyInfo(
336: name);
337: propertyInfo.setComments(new Comments(getOpenComment(),
338: getCloseComment()));
339: this .propertyList.add(propertyInfo);
340: }
341:
342: /**
343: * Handles a manual mapping.
344: *
345: * @param className the class name.
346: * @param readHandler the read handler.
347: * @param writeHandler the write handler.
348: *
349: * @return A boolean.
350: *
351: * @throws ObjectDescriptionException if there is a problem with the object description.
352: */
353: protected boolean handleManualMapping(final String className,
354: final String readHandler, final String writeHandler)
355: throws ObjectDescriptionException {
356:
357: final ManualMappingInfo manualMappingInfo = new ManualMappingInfo(
358: loadClass(className), loadClass(readHandler),
359: loadClass(writeHandler));
360: manualMappingInfo.setComments(new Comments(getOpenComment(),
361: getCloseComment()));
362: manualMappingInfo.setSource(this .source);
363: this .model.getMappingModel()
364: .addManualMapping(manualMappingInfo);
365: return true;
366: }
367:
368: /**
369: * Start a multiplex mapping.
370: *
371: * @param className the class name.
372: * @param typeAttr the type.
373: */
374: protected void startMultiplexMapping(final String className,
375: final String typeAttr) {
376: this .multiplexInfo = new MultiplexMappingInfo(
377: loadClass(className), typeAttr);
378: this .multiplexInfo.setSource(this .source);
379: this .multiplexTypeInfos = new ArrayList();
380: }
381:
382: /**
383: * Handles a multiplex mapping.
384: *
385: * @param typeName the type name.
386: * @param className the class name.
387: *
388: * @throws ObjectDescriptionException if there is a problem with the object description.
389: */
390: protected void handleMultiplexMapping(final String typeName,
391: final String className) throws ObjectDescriptionException {
392: final TypeInfo info = new TypeInfo(typeName,
393: loadClass(className));
394: info.setComments(new Comments(getOpenComment(),
395: getCloseComment()));
396: this .multiplexTypeInfos.add(info);
397: }
398:
399: /**
400: * Ends a multiplex mapping.
401: *
402: * @throws ObjectDescriptionException if there is a problem with the object description.
403: */
404: protected void endMultiplexMapping()
405: throws ObjectDescriptionException {
406: final TypeInfo[] typeInfos = (TypeInfo[]) this .multiplexTypeInfos
407: .toArray(new TypeInfo[this .multiplexTypeInfos.size()]);
408: this .multiplexInfo.setComments(new Comments(getOpenComment(),
409: getCloseComment()));
410: this .multiplexInfo.setChildClasses(typeInfos);
411: this .model.getMappingModel().addMultiplexMapping(
412: this .multiplexInfo);
413: this .multiplexInfo = null;
414: }
415:
416: /**
417: * Starts include handling.
418: *
419: * @param resource the URL.
420: */
421: protected void startIncludeHandling(final URL resource) {
422: this .source = IOUtils.getInstance().createRelativeURL(resource,
423: this .baseURL);
424: this .model.addSource(this .source);
425: this .model.addIncludeComment(this .source, new Comments(
426: getOpenComment(), getCloseComment()));
427: }
428:
429: /**
430: * Ends include handling.
431: */
432: protected void endIncludeHandling() {
433: this .source = "";
434: }
435:
436: /**
437: * Starts the root document.
438: */
439: protected void startRootDocument() {
440: this .source = "";
441: }
442:
443: /**
444: * Ends the root document.
445: */
446: protected void endRootDocument() {
447: this .model.setModelComments(new Comments(getOpenComment(),
448: getCloseComment()));
449: }
450: }
|