Source for org.jfree.xml.generator.ModelWriter

   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:  * ModelWriter.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: ModelWriter.java,v 1.3 2005/10/18 13:32:20 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------------------------
  39:  * 21.06.2003 : Initial version
  40:  *
  41:  */
  42: 
  43: package org.jfree.xml.generator;
  44: 
  45: import java.io.IOException;
  46: import java.io.Writer;
  47: 
  48: import org.jfree.xml.generator.model.ClassDescription;
  49: import org.jfree.xml.generator.model.Comments;
  50: import org.jfree.xml.generator.model.DescriptionModel;
  51: import org.jfree.xml.generator.model.IgnoredPropertyInfo;
  52: import org.jfree.xml.generator.model.ManualMappingInfo;
  53: import org.jfree.xml.generator.model.MultiplexMappingInfo;
  54: import org.jfree.xml.generator.model.PropertyInfo;
  55: import org.jfree.xml.generator.model.PropertyType;
  56: import org.jfree.xml.generator.model.TypeInfo;
  57: import org.jfree.xml.util.ClassModelTags;
  58: import org.jfree.xml.writer.AttributeList;
  59: import org.jfree.xml.writer.SafeTagList;
  60: import org.jfree.xml.writer.XMLWriterSupport;
  61: 
  62: /**
  63:  * A model writer.
  64:  */
  65: public class ModelWriter {
  66: 
  67:     /** The tags that can be split. */
  68:     private static SafeTagList safeTags;
  69: 
  70:     /**
  71:      * Returns the safe tag list.
  72:      * 
  73:      * @return The safe tag list.
  74:      */
  75:     public static SafeTagList getSafeTags() {
  76:         if (safeTags == null) {
  77:             safeTags = new SafeTagList();
  78:             safeTags.add(ClassModelTags.OBJECTS_TAG);
  79:             safeTags.add(ClassModelTags.OBJECT_TAG);
  80:             safeTags.add(ClassModelTags.CONSTRUCTOR_TAG);
  81:             safeTags.add(ClassModelTags.ELEMENT_PROPERTY_TAG);
  82:             safeTags.add(ClassModelTags.LOOKUP_PROPERTY_TAG);
  83:             safeTags.add(ClassModelTags.ATTRIBUTE_PROPERTY_TAG);
  84:             safeTags.add(ClassModelTags.PARAMETER_TAG);
  85:             safeTags.add(ClassModelTags.INCLUDE_TAG);
  86:             safeTags.add(ClassModelTags.IGNORED_PROPERTY_TAG);
  87:             safeTags.add(ClassModelTags.MANUAL_TAG);
  88:             safeTags.add(ClassModelTags.MAPPING_TAG);
  89:             safeTags.add(ClassModelTags.TYPE_TAG);
  90:         }
  91:         return safeTags;
  92:     }
  93: 
  94:     /** A support class for writing XML tags. */
  95:     private XMLWriterSupport writerSupport;
  96:     
  97:     /** A model containing class descriptions. */
  98:     private DescriptionModel model;
  99: 
 100:     /**
 101:      * Creates a new model writer instance.
 102:      */
 103:     public ModelWriter() {
 104:         this.writerSupport = new XMLWriterSupport(getSafeTags(), 0);
 105:     }
 106: 
 107:     /**
 108:      * Returns the model.
 109:      * 
 110:      * @return The model.
 111:      */
 112:     public DescriptionModel getModel() {
 113:         return this.model;
 114:     }
 115: 
 116:     /**
 117:      * Sets the model to be written.
 118:      * 
 119:      * @param model  the model.
 120:      */
 121:     public void setModel(final DescriptionModel model) {
 122:         this.model = model;
 123:     }
 124: 
 125:     /**
 126:      * Writes an XML header.
 127:      * 
 128:      * @param writer  the writer.
 129:      * 
 130:      * @throws IOException if there is an I/O problem.
 131:      */
 132:     public static void writeXMLHeader(final Writer writer) throws IOException {
 133:         writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 134:         writer.write(XMLWriterSupport.getLineSeparator());
 135:     }
 136: 
 137:     /**
 138:      * Writes a set of comments.
 139:      * 
 140:      * @param writer  the writer.
 141:      * @param comments  a set of comments.
 142:      * 
 143:      * @throws IOException if there is an I/O problem.
 144:      */
 145:     protected void writeStandardComment(final Writer writer, final Comments comments) throws IOException {
 146:         if ((comments == null) || (comments.getOpenTagComment() == null)) {
 147:             writer.write(
 148:                 "<!-- CVSTag: $Id: ModelWriter.java,v 1.3 2005/10/18 13:32:20 mungady Exp $ " 
 149:                 + comments + " -->"
 150:             );
 151:             writer.write(XMLWriterSupport.getLineSeparator());
 152:         }
 153:         else {
 154:             writeComment(writer, comments.getOpenTagComment());
 155:         }
 156:     }
 157: 
 158:     /**
 159:      * Writes a sequence of comments.
 160:      * 
 161:      * @param writer  the writer.
 162:      * @param comments  the comments (<code>null</code> ignored).
 163:      * 
 164:      * @throws IOException if there is an I/O problem.
 165:      */
 166:     protected void writeComment(final Writer writer, final String[] comments) throws IOException {
 167:         if (comments == null) {
 168:             return;
 169:         }
 170:         for (int i = 0; i < comments.length; i++) {
 171:             this.writerSupport.indent(writer, XMLWriterSupport.INDENT_ONLY);
 172:             writer.write("<!--");
 173:             writer.write(comments[i]);
 174:             writer.write("-->");
 175:             writer.write(XMLWriterSupport.getLineSeparator());
 176:         }
 177:     }
 178: 
 179:     /**
 180:      * Writes the open comments from a set of comments.
 181:      * 
 182:      * @param writer  the writer.
 183:      * @param comments  the set of comments.
 184:      * 
 185:      * @throws IOException if there is an I/O problem.
 186:      */
 187:     protected void writeOpenComment(final Writer writer, final Comments comments) throws IOException {
 188:         if (comments == null) {
 189:             return;
 190:         }
 191:         if (comments.getOpenTagComment() == null) {
 192:             return;
 193:         }
 194:         writeComment(writer, comments.getOpenTagComment());
 195:     }
 196: 
 197:     /**
 198:      * Writes the close comments from a set of comments.
 199:      * 
 200:      * @param writer  the writer.
 201:      * @param comments  the set of comments.
 202:      * 
 203:      * @throws IOException if there is an I/O problem.
 204:      */
 205:     protected void writeCloseComment(final Writer writer, final Comments comments) throws IOException {
 206:         if (comments == null) {
 207:             return;
 208:         }
 209:         if (comments.getCloseTagComment() == null) {
 210:             return;
 211:         }
 212:         writeComment(writer, comments.getCloseTagComment());
 213:     }
 214: 
 215:     /**
 216:      * Writes a closed (short) tag with eventually nested comments.
 217:      *
 218:      * @param writer  the writer.
 219:      * @param tagName  the tag name.
 220:      * @param attributes  the attributes.
 221:      * @param comments  the comments.
 222:      * 
 223:      * @throws IOException if there is an I/O problem.
 224:      */
 225:     protected void writeTag(final Writer writer, 
 226:                             final String tagName,
 227:                             final AttributeList attributes,
 228:                             final Comments comments) throws IOException {
 229:         if (comments == null) {
 230:             this.writerSupport.writeTag(writer, tagName, attributes, XMLWriterSupport.CLOSE);
 231:         }
 232:         else {
 233:             writeOpenComment(writer, comments);
 234:             if (comments.getCloseTagComment() != null) {
 235:                 this.writerSupport.writeTag(writer, tagName, attributes, XMLWriterSupport.OPEN);
 236:                 writeCloseComment(writer, comments);
 237:                 this.writerSupport.writeCloseTag(writer, tagName);
 238:             }
 239:             else {
 240:                 this.writerSupport.writeTag(writer, tagName, attributes, XMLWriterSupport.CLOSE);
 241:             }
 242:         }
 243:     }
 244: 
 245:     /**
 246:      * Writes a closed (short) tag with eventually nested comments.
 247:      *
 248:      * @param writer  the writer.
 249:      * @param tagName  the tag name.
 250:      * @param attribute  the attribute name.
 251:      * @param value  the attribute value.
 252:      * @param comments  the comments.
 253:      * 
 254:      * @throws IOException if there is an I/O problem.
 255:      */
 256:     protected void writeTag(final Writer writer, 
 257:                             final String tagName,
 258:                             final String attribute, 
 259:                             final String value,
 260:                             final Comments comments) throws IOException {
 261:         if (comments == null) {
 262:             this.writerSupport.writeTag(writer, tagName, attribute, value , XMLWriterSupport.CLOSE);
 263:         }
 264:         else {
 265:             writeOpenComment(writer, comments);
 266:             if (comments.getCloseTagComment() != null) {
 267:                 this.writerSupport.writeTag(
 268:                     writer, tagName, attribute, value, XMLWriterSupport.OPEN
 269:                 );
 270:                 writeCloseComment(writer, comments);
 271:                 this.writerSupport.writeCloseTag(writer, tagName);
 272:             }
 273:             else {
 274:                 this.writerSupport.writeTag(
 275:                     writer, tagName, attribute, value, XMLWriterSupport.CLOSE
 276:                 );
 277:             }
 278:         }
 279:     }
 280: 
 281:     /**
 282:      * Writes a model to the specified writer.
 283:      * 
 284:      * @param writer  the writer.
 285:      * 
 286:      * @throws IOException if there is an I/O problem.
 287:      */
 288:     public void write(final Writer writer) throws IOException {
 289:         
 290:         writeStandardComment(writer, this.model.getModelComments());
 291:         this.writerSupport.writeTag(writer, ClassModelTags.OBJECTS_TAG);
 292:         final String[] sources = this.model.getSources();
 293:         for (int i = 0; i < sources.length; i++) {
 294:             final Comments comments = this.model.getIncludeComment(sources[i]);
 295:             writeTag(
 296:                 writer, 
 297:                 ClassModelTags.INCLUDE_TAG, ClassModelTags.SOURCE_ATTR, sources[i], comments
 298:             );
 299:         }
 300: 
 301:         for (int i = 0; i < this.model.size(); i++) {
 302:             final ClassDescription cd = this.model.get(i);
 303:             writeClassDescription(writer, cd);
 304:         }
 305: 
 306:         final ManualMappingInfo[] mappings = getModel().getMappingModel().getManualMapping();
 307:         for (int i = 0; i < mappings.length; i++) {
 308:             final ManualMappingInfo mi = mappings[i];
 309:             writeManualMapping(writer, mi);
 310:         }
 311: 
 312:         final MultiplexMappingInfo[] mmappings = getModel().getMappingModel().getMultiplexMapping();
 313:         for (int i = 0; i < mmappings.length; i++) {
 314:             final MultiplexMappingInfo mi = mmappings[i];
 315:             writeMultiplexMapping(writer, mi);
 316:         }
 317: 
 318:         writeCloseComment(writer, this.model.getModelComments());
 319:         this.writerSupport.writeCloseTag(writer, ClassModelTags.OBJECTS_TAG);
 320:         
 321:     }
 322: 
 323:     /**
 324:      * Writes a manual mapping to the XML output.
 325:      * 
 326:      * @param writer  the writer.
 327:      * @param mi  the mapping info.
 328:      * 
 329:      * @throws IOException if there is an I/O problem.
 330:      */
 331:     protected void writeManualMapping(final Writer writer, final ManualMappingInfo mi) throws IOException {
 332:         final AttributeList al = new AttributeList();
 333:         al.setAttribute(ClassModelTags.CLASS_ATTR, mi.getBaseClass().getName());
 334:         al.setAttribute(ClassModelTags.READ_HANDLER_ATTR, mi.getReadHandler().getName());
 335:         al.setAttribute(ClassModelTags.WRITE_HANDLER_ATTR, mi.getWriteHandler().getName());
 336:         writeTag(writer, ClassModelTags.MANUAL_TAG, al, mi.getComments());
 337:     }
 338: 
 339:     /**
 340:      * Writes a multiplex mapping to the XML output.
 341:      * 
 342:      * @param writer  the writer.
 343:      * @param mi  the mapping info.
 344:      * 
 345:      * @throws IOException if there is an I/O problem.
 346:      */
 347:     protected void writeMultiplexMapping(final Writer writer, final MultiplexMappingInfo mi)
 348:         throws IOException {
 349:         
 350:         final TypeInfo[] tis = mi.getChildClasses();
 351: 
 352:         final AttributeList al = new AttributeList();
 353:         al.setAttribute(ClassModelTags.BASE_CLASS_ATTR, mi.getBaseClass().getName());
 354:         al.setAttribute(ClassModelTags.TYPE_ATTR, mi.getTypeAttribute());
 355:         getWriterSupport().writeTag(writer, ClassModelTags.MAPPING_TAG, al, XMLWriterSupport.OPEN);
 356: 
 357:         for (int j = 0; j < tis.length; j++) {
 358:             final AttributeList tiAttr = new AttributeList();
 359:             tiAttr.setAttribute(ClassModelTags.NAME_ATTR, tis[j].getName());
 360:             tiAttr.setAttribute(ClassModelTags.CLASS_ATTR, tis[j].getType().getName());
 361:             writeTag(writer, ClassModelTags.TYPE_TAG, tiAttr, tis[j].getComments());
 362:         }
 363: 
 364:         getWriterSupport().writeCloseTag(writer, ClassModelTags.MAPPING_TAG);
 365:     }
 366: 
 367:     /**
 368:      * Writes a class description.
 369:      * 
 370:      * @param writer  the writer.
 371:      * @param cd  the class description.
 372:      * 
 373:      * @throws IOException if there is an I/O problem.
 374:      */
 375:     protected void writeClassDescription(final Writer writer, final ClassDescription cd) throws IOException {
 376: 
 377:         if (cd.isUndefined()) {
 378:             return;
 379:         }
 380: 
 381:         final AttributeList al = new AttributeList();
 382:         al.setAttribute(ClassModelTags.CLASS_ATTR, cd.getName());
 383:         if (cd.getRegisterKey() != null) {
 384:             al.setAttribute(ClassModelTags.REGISTER_NAMES_ATTR, cd.getRegisterKey());
 385:         }
 386:         if (cd.isPreserve()) {
 387:             al.setAttribute(ClassModelTags.IGNORE_ATTR, "true");
 388:         }
 389:         this.writerSupport.writeTag(writer, ClassModelTags.OBJECT_TAG, al, XMLWriterSupport.OPEN);
 390: 
 391:         final TypeInfo[] constructorInfo = cd.getConstructorDescription();
 392:         if (constructorInfo != null && constructorInfo.length != 0) {
 393:             this.writerSupport.writeTag(writer, ClassModelTags.CONSTRUCTOR_TAG);
 394:             for (int i = 0; i < constructorInfo.length; i++) {
 395:                 final AttributeList constructorList = new AttributeList();
 396:                 constructorList.setAttribute(
 397:                     ClassModelTags.CLASS_ATTR, constructorInfo[i].getType().getName()
 398:                 );
 399:                 constructorList.setAttribute(
 400:                     ClassModelTags.PROPERTY_ATTR, constructorInfo[i].getName()
 401:                 );
 402:                 writeTag(writer, ClassModelTags.PARAMETER_TAG, constructorList, 
 403:                          constructorInfo[i].getComments());
 404:             }
 405:             this.writerSupport.writeCloseTag(writer, ClassModelTags.CONSTRUCTOR_TAG);
 406:         }
 407: 
 408:         final PropertyInfo[] properties = cd.getProperties();
 409:         for (int i = 0; i < properties.length; i++) {
 410:             writePropertyInfo(writer, properties[i]);
 411:         }
 412: 
 413:         this.writerSupport.writeCloseTag(writer, ClassModelTags.OBJECT_TAG);
 414:     }
 415: 
 416:     /**
 417:      * Writes a property info element.
 418:      * 
 419:      * @param writer  the writer.
 420:      * @param ipi  the property info.
 421:      * 
 422:      * @throws IOException if there is an I/O problem.
 423:      */
 424:     private void writePropertyInfo(final Writer writer, final PropertyInfo ipi) throws IOException {
 425:         final AttributeList props = new AttributeList();
 426:         props.setAttribute(ClassModelTags.NAME_ATTR, ipi.getName());
 427: 
 428:         if (ipi instanceof IgnoredPropertyInfo) {
 429:             writeTag(writer, ClassModelTags.IGNORED_PROPERTY_TAG, props, ipi.getComments());
 430:             return;
 431:         }
 432: 
 433:         if (ipi.getPropertyType().equals(PropertyType.ATTRIBUTE)) {
 434:             props.setAttribute(ClassModelTags.ATTRIBUTE_ATTR, ipi.getXmlName());
 435:             props.setAttribute(ClassModelTags.ATTRIBUTE_HANDLER_ATTR, ipi.getXmlHandler());
 436:             writeTag(writer, ClassModelTags.ATTRIBUTE_PROPERTY_TAG, props, ipi.getComments());
 437:         }
 438:         else if (ipi.getPropertyType().equals(PropertyType.ELEMENT)) {
 439:             if (ipi.getComments() == null || ipi.getComments().getOpenTagComment() == null)
 440:             {
 441:                 this.writerSupport.indent(writer, XMLWriterSupport.INDENT_ONLY);
 442:                 writer.write("<!-- property type is " + ipi.getType() + " -->");
 443:                 writer.write(System.getProperty("line.separator", "\n"));
 444:             }
 445:             props.setAttribute(ClassModelTags.ELEMENT_ATTR, ipi.getXmlName());
 446:             writeTag(writer, ClassModelTags.ELEMENT_PROPERTY_TAG, props, ipi.getComments());
 447:         }
 448:         else {
 449:             props.setAttribute(ClassModelTags.LOOKUP_ATTR, ipi.getXmlName());
 450:             writeTag(writer, ClassModelTags.LOOKUP_PROPERTY_TAG, props, ipi.getComments());
 451:         }
 452:     }
 453: 
 454:     /**
 455:      * Returns the writer support object.
 456:      * 
 457:      * @return The writer support object.
 458:      */
 459:     public XMLWriterSupport getWriterSupport() {
 460:         return this.writerSupport;
 461:     }
 462: }