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 044package org.jfree.xml.generator; 045 046import java.beans.BeanInfo; 047import java.beans.IntrospectionException; 048import java.beans.Introspector; 049import java.beans.PropertyDescriptor; 050import java.io.File; 051import java.io.IOException; 052import java.net.URL; 053import java.util.ArrayList; 054 055import org.jfree.io.IOUtils; 056import org.jfree.xml.generator.model.ClassDescription; 057import org.jfree.xml.generator.model.Comments; 058import org.jfree.xml.generator.model.DescriptionModel; 059import org.jfree.xml.generator.model.IgnoredPropertyInfo; 060import org.jfree.xml.generator.model.ManualMappingInfo; 061import org.jfree.xml.generator.model.MultiplexMappingInfo; 062import org.jfree.xml.generator.model.PropertyInfo; 063import org.jfree.xml.generator.model.PropertyType; 064import org.jfree.xml.generator.model.TypeInfo; 065import org.jfree.xml.util.AbstractModelReader; 066import org.jfree.xml.util.ObjectDescriptionException; 067 068/** 069 * A reader for the class model. 070 */ 071public 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) 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}