Source for org.jfree.xml.generator.DefaultModelReader

   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:  * DefaultModelReader.java
  29:  * -----------------------
  30:  * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
  31:  *
  32:  * Original Author:  Thomas Morgner;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: DefaultModelReader.java,v 1.2 2005/10/18 13:32:20 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 12-Nov-2003 : Initial version (TM);
  40:  * 26-Nov-2003 : Updated header and Javadocs (DG);
  41:  *
  42:  */
  43: 
  44: package org.jfree.xml.generator;
  45: 
  46: import java.beans.BeanInfo;
  47: import java.beans.IntrospectionException;
  48: import java.beans.Introspector;
  49: import java.beans.PropertyDescriptor;
  50: import java.io.File;
  51: import java.io.IOException;
  52: import java.net.URL;
  53: import java.util.ArrayList;
  54: 
  55: import org.jfree.io.IOUtils;
  56: import org.jfree.xml.generator.model.ClassDescription;
  57: import org.jfree.xml.generator.model.Comments;
  58: import org.jfree.xml.generator.model.DescriptionModel;
  59: import org.jfree.xml.generator.model.IgnoredPropertyInfo;
  60: import org.jfree.xml.generator.model.ManualMappingInfo;
  61: import org.jfree.xml.generator.model.MultiplexMappingInfo;
  62: import org.jfree.xml.generator.model.PropertyInfo;
  63: import org.jfree.xml.generator.model.PropertyType;
  64: import org.jfree.xml.generator.model.TypeInfo;
  65: import org.jfree.xml.util.AbstractModelReader;
  66: import org.jfree.xml.util.ObjectDescriptionException;
  67: 
  68: /**
  69:  * A reader for the class model.
  70:  */
  71: public class DefaultModelReader extends AbstractModelReader {
  72: 
  73:     /** A model containing classes and the corresponding class descriptions. */
  74:     private DescriptionModel model;
  75: 
  76:     /** The class description under construction. */
  77:     private ClassDescription currentClassDescription;
  78: 
  79:     /** Information about the class being processed. */
  80:     private BeanInfo currentBeanInfo;
  81: 
  82:     /** The base URL. */
  83:     private URL baseURL;
  84:     
  85:     /** The source. */
  86:     private String source;
  87:     
  88:     /** The multiplex mapping info. */
  89:     private MultiplexMappingInfo multiplexInfo;
  90:     
  91:     /** The multiplex type info.*/
  92:     private ArrayList multiplexTypeInfos;
  93: 
  94:     /** Storage for the properties of the current class. */
  95:     private ArrayList propertyList;
  96: 
  97:     /** Storage for the constructors of the current class. */
  98:     private ArrayList constructorList;
  99: 
 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) throws IOException,
 118:                                                                   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 superCD = this.model.get(parent);
 140:             if (superCD != null) {
 141:                 cd.setSuperClass(superCD.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, final String register, final boolean ignore) {
 156:         final Class c = loadClass(className);
 157:         if (c == null) {
 158:             return false;
 159:         }
 160:         this.currentClassDescription = new ClassDescription(c);
 161:         this.currentClassDescription.setPreserve(ignore);
 162:         this.currentClassDescription.setRegisterKey(register);
 163:         try {
 164:             this.currentBeanInfo = Introspector.getBeanInfo(c, Object.class);
 165:         }
 166:         catch (IntrospectionException ie) {
 167:             return false;
 168:         }
 169:         this.propertyList = new java.util.ArrayList();
 170:         this.constructorList = new java.util.ArrayList();
 171:         return true;
 172:     }
 173: 
 174:     /**
 175:      * Finishes processing an object definition (sets the constructor and property info for the
 176:      * class description, and adds the class description to the model).
 177:      * 
 178:      * @throws ObjectDescriptionException if there is a problem with the object description.
 179:      */
 180:     protected void endObjectDefinition() throws ObjectDescriptionException {
 181:         final PropertyInfo[] pis = (PropertyInfo[])
 182:             this.propertyList.toArray(new PropertyInfo[this.propertyList.size()]);
 183:         this.currentClassDescription.setProperties(pis);
 184: 
 185:         final TypeInfo[] tis = (TypeInfo[])
 186:         this.constructorList.toArray(new TypeInfo[this.constructorList.size()]);
 187: 
 188:         this.currentClassDescription.setConstructorDescription(tis);
 189:         this.currentClassDescription.setComments
 190:             (new Comments(getOpenComment(), getCloseComment()));
 191:         this.currentClassDescription.setSource(this.source);
 192: 
 193:         this.model.addClassDescription(this.currentClassDescription);
 194: 
 195:         this.propertyList = null;
 196:         this.currentBeanInfo = null;
 197:         this.currentClassDescription = null;
 198:     }
 199: 
 200:     /**
 201:      * Handles the description of an attribute within an object definition.
 202:      *
 203:      * @param name  the name.
 204:      * @param attribName  the attribute name.
 205:      * @param handlerClass  the fully qualified class name for the attribute handler.
 206:      * 
 207:      * @throws ObjectDescriptionException if there is a problem with the object description.
 208:      */
 209:     protected void handleAttributeDefinition(final String name, final String attribName, final String handlerClass)
 210:         throws ObjectDescriptionException {
 211: 
 212:         final PropertyInfo propertyInfo = ModelBuilder.getInstance().createSimplePropertyInfo
 213:             (getPropertyDescriptor(name));
 214: 
 215:         if (propertyInfo == null) {
 216:             throw new ObjectDescriptionException("Unable to load property " + name);
 217:         }
 218: 
 219:         propertyInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 220:         propertyInfo.setPropertyType(PropertyType.ATTRIBUTE);
 221:         propertyInfo.setXmlName(attribName);
 222:         propertyInfo.setXmlHandler(handlerClass);
 223:         this.propertyList.add(propertyInfo);
 224:     }
 225: 
 226:     /**
 227:      * Handles the constructor definition.
 228:      * 
 229:      * @param tagName  the tag name.
 230:      * @param parameterClass  the parameter class.
 231:      * 
 232:      * @throws ObjectDescriptionException if there is a problem with the object description.
 233:      */
 234:     protected void handleConstructorDefinition(final String tagName, final String parameterClass)
 235:         throws ObjectDescriptionException {
 236: 
 237:         final Class c = loadClass(parameterClass);
 238:         if (c == null) {
 239:             throw new ObjectDescriptionException("Failed to load class " + parameterClass);
 240:         }
 241:         final TypeInfo ti = new TypeInfo(tagName, c);
 242:         ti.setComments(new Comments(getOpenComment(), getCloseComment()));
 243:         this.constructorList.add (ti);
 244:     }
 245: 
 246:     /**
 247:      * Handles the description of an element within an object definition.
 248:      *
 249:      * @param name  the property name.
 250:      * @param element  the element name.
 251:      * 
 252:      * @throws ObjectDescriptionException if there is a problem with the object description.
 253:      */
 254:     protected void handleElementDefinition(final String name, final String element)
 255:         throws ObjectDescriptionException {
 256: 
 257:         final PropertyInfo propertyInfo = ModelBuilder.getInstance().createSimplePropertyInfo
 258:             (getPropertyDescriptor(name));
 259: 
 260:         if (propertyInfo == null) {
 261:             throw new ObjectDescriptionException("Unable to load property " + name);
 262:         }
 263: 
 264:         propertyInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 265:         propertyInfo.setPropertyType(PropertyType.ELEMENT);
 266:         propertyInfo.setXmlName(element);
 267:         propertyInfo.setXmlHandler(null);
 268:         this.propertyList.add(propertyInfo);
 269: 
 270:     }
 271: 
 272:     /**
 273:      * Handles a lookup definition.
 274:      * 
 275:      * @param name  the name.
 276:      * @param lookupKey  the lookup key.
 277:      * 
 278:      * @throws ObjectDescriptionException if there is a problem with the object description.
 279:      */
 280:     protected void handleLookupDefinition(final String name, final String lookupKey)
 281:         throws ObjectDescriptionException {
 282:         final PropertyInfo propertyInfo = ModelBuilder.getInstance().createSimplePropertyInfo
 283:             (getPropertyDescriptor(name));
 284: 
 285:         if (propertyInfo == null) {
 286:             throw new ObjectDescriptionException("Unable to load property " + name);
 287:         }
 288: 
 289:         propertyInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 290:         propertyInfo.setPropertyType(PropertyType.LOOKUP);
 291:         propertyInfo.setXmlName(lookupKey);
 292:         propertyInfo.setXmlHandler(null);
 293:         this.propertyList.add(propertyInfo);
 294:     }
 295: 
 296:     /**
 297:      * Returns a property descriptor for the named property, or <code>null</code> if there is
 298:      * no descriptor with the given name.
 299:      *
 300:      * @param propertyName  the property name.
 301:      *
 302:      * @return a property descriptor.
 303:      */
 304:     protected PropertyDescriptor getPropertyDescriptor(final String propertyName) {
 305:         final PropertyDescriptor[] pds = this.currentBeanInfo.getPropertyDescriptors();
 306:         for (int i = 0; i < pds.length; i++) {
 307:             if (pds[i].getName().equals(propertyName)) {
 308:                 return pds[i];
 309:             }
 310:         }
 311:         return null;
 312:     }
 313: 
 314:     /**
 315:      * Handles an ignored property.
 316:      * 
 317:      * @param name  the name.
 318:      */
 319:     protected void handleIgnoredProperty(final String name) {
 320:         final IgnoredPropertyInfo propertyInfo = new IgnoredPropertyInfo(name);
 321:         propertyInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 322:         this.propertyList.add(propertyInfo);
 323:     }
 324: 
 325:     /**
 326:      * Handles a manual mapping.
 327:      *
 328:      * @param className  the class name.
 329:      * @param readHandler  the read handler.
 330:      * @param writeHandler  the write handler.
 331:      * 
 332:      * @return A boolean.
 333:      * 
 334:      * @throws ObjectDescriptionException if there is a problem with the object description.
 335:      */
 336:     protected boolean handleManualMapping(final String className, final String readHandler, final String writeHandler)
 337:         throws ObjectDescriptionException {
 338: 
 339:         final ManualMappingInfo manualMappingInfo =
 340:             new ManualMappingInfo(loadClass(className),
 341:                 loadClass(readHandler), loadClass(writeHandler));
 342:         manualMappingInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 343:         manualMappingInfo.setSource(this.source);
 344:         this.model.getMappingModel().addManualMapping(manualMappingInfo);
 345:         return true;
 346:     }
 347: 
 348:     /**
 349:      * Start a multiplex mapping.
 350:      * 
 351:      * @param className  the class name.
 352:      * @param typeAttr  the type.
 353:      */
 354:     protected void startMultiplexMapping(final String className, final String typeAttr) {
 355:         this.multiplexInfo = new MultiplexMappingInfo(loadClass(className), typeAttr);
 356:         this.multiplexInfo.setSource(this.source);
 357:         this.multiplexTypeInfos = new ArrayList();
 358:     }
 359: 
 360:     /**
 361:      * Handles a multiplex mapping.
 362:      * 
 363:      * @param typeName  the type name.
 364:      * @param className  the class name.
 365:      * 
 366:      * @throws ObjectDescriptionException if there is a problem with the object description.
 367:      */
 368:     protected void handleMultiplexMapping(final String typeName, final String className)
 369:         throws ObjectDescriptionException {
 370:         final TypeInfo info = new TypeInfo(typeName, loadClass(className));
 371:         info.setComments(new Comments(getOpenComment(), getCloseComment()));
 372:         this.multiplexTypeInfos.add (info);
 373:     }
 374: 
 375:     /**
 376:      * Ends a multiplex mapping.
 377:      * 
 378:      * @throws ObjectDescriptionException if there is a problem with the object description. 
 379:      */
 380:     protected void endMultiplexMapping() throws ObjectDescriptionException {
 381:         final TypeInfo[] typeInfos = (TypeInfo[]) this.multiplexTypeInfos.toArray(
 382:             new TypeInfo[this.multiplexTypeInfos.size()]
 383:         );
 384:         this.multiplexInfo.setComments(new Comments(getOpenComment(), getCloseComment()));
 385:         this.multiplexInfo.setChildClasses(typeInfos);
 386:         this.model.getMappingModel().addMultiplexMapping(this.multiplexInfo);
 387:         this.multiplexInfo = null;
 388:     }
 389: 
 390:     /**
 391:      * Starts include handling.
 392:      * 
 393:      * @param resource  the URL.
 394:      */
 395:     protected void startIncludeHandling(final URL resource) {
 396:         this.source = IOUtils.getInstance().createRelativeURL(resource, this.baseURL);
 397:         this.model.addSource(this.source);
 398:         this.model.addIncludeComment(
 399:             this.source, new Comments(getOpenComment(), getCloseComment())
 400:         );
 401:     }
 402: 
 403:     /**
 404:      * Ends include handling.
 405:      */
 406:     protected void endIncludeHandling() {
 407:         this.source = "";
 408:     }
 409: 
 410:     /**
 411:      * Starts the root document.
 412:      */
 413:     protected void startRootDocument() {
 414:         this.source = "";
 415:     }
 416: 
 417:     /**
 418:      * Ends the root document.
 419:      */
 420:     protected void endRootDocument() {
 421:         this.model.setModelComments(new Comments(getOpenComment(), getCloseComment()));
 422:     }
 423: }