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 * ModelWriter.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: ModelWriter.java,v 1.3 2005/10/18 13:32:20 mungady Exp $ 036 * 037 * Changes 038 * ------------------------- 039 * 21.06.2003 : Initial version 040 * 041 */ 042 043package org.jfree.xml.generator; 044 045import java.io.IOException; 046import java.io.Writer; 047 048import org.jfree.xml.generator.model.ClassDescription; 049import org.jfree.xml.generator.model.Comments; 050import org.jfree.xml.generator.model.DescriptionModel; 051import org.jfree.xml.generator.model.IgnoredPropertyInfo; 052import org.jfree.xml.generator.model.ManualMappingInfo; 053import org.jfree.xml.generator.model.MultiplexMappingInfo; 054import org.jfree.xml.generator.model.PropertyInfo; 055import org.jfree.xml.generator.model.PropertyType; 056import org.jfree.xml.generator.model.TypeInfo; 057import org.jfree.xml.util.ClassModelTags; 058import org.jfree.xml.writer.AttributeList; 059import org.jfree.xml.writer.SafeTagList; 060import org.jfree.xml.writer.XMLWriterSupport; 061 062/** 063 * A model writer. 064 */ 065public class ModelWriter { 066 067 /** The tags that can be split. */ 068 private static SafeTagList safeTags; 069 070 /** 071 * Returns the safe tag list. 072 * 073 * @return The safe tag list. 074 */ 075 public static SafeTagList getSafeTags() { 076 if (safeTags == null) { 077 safeTags = new SafeTagList(); 078 safeTags.add(ClassModelTags.OBJECTS_TAG); 079 safeTags.add(ClassModelTags.OBJECT_TAG); 080 safeTags.add(ClassModelTags.CONSTRUCTOR_TAG); 081 safeTags.add(ClassModelTags.ELEMENT_PROPERTY_TAG); 082 safeTags.add(ClassModelTags.LOOKUP_PROPERTY_TAG); 083 safeTags.add(ClassModelTags.ATTRIBUTE_PROPERTY_TAG); 084 safeTags.add(ClassModelTags.PARAMETER_TAG); 085 safeTags.add(ClassModelTags.INCLUDE_TAG); 086 safeTags.add(ClassModelTags.IGNORED_PROPERTY_TAG); 087 safeTags.add(ClassModelTags.MANUAL_TAG); 088 safeTags.add(ClassModelTags.MAPPING_TAG); 089 safeTags.add(ClassModelTags.TYPE_TAG); 090 } 091 return safeTags; 092 } 093 094 /** A support class for writing XML tags. */ 095 private XMLWriterSupport writerSupport; 096 097 /** A model containing class descriptions. */ 098 private DescriptionModel model; 099 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}