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:
043: package org.jfree.xml.generator;
044:
045: import java.io.IOException;
046: import java.io.Writer;
047:
048: import org.jfree.xml.generator.model.ClassDescription;
049: import org.jfree.xml.generator.model.Comments;
050: import org.jfree.xml.generator.model.DescriptionModel;
051: import org.jfree.xml.generator.model.IgnoredPropertyInfo;
052: import org.jfree.xml.generator.model.ManualMappingInfo;
053: import org.jfree.xml.generator.model.MultiplexMappingInfo;
054: import org.jfree.xml.generator.model.PropertyInfo;
055: import org.jfree.xml.generator.model.PropertyType;
056: import org.jfree.xml.generator.model.TypeInfo;
057: import org.jfree.xml.util.ClassModelTags;
058: import org.jfree.xml.writer.AttributeList;
059: import org.jfree.xml.writer.SafeTagList;
060: import org.jfree.xml.writer.XMLWriterSupport;
061:
062: /**
063: * A model writer.
064: */
065: public 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)
133: throws IOException {
134: writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
135: writer.write(XMLWriterSupport.getLineSeparator());
136: }
137:
138: /**
139: * Writes a set of comments.
140: *
141: * @param writer the writer.
142: * @param comments a set of comments.
143: *
144: * @throws IOException if there is an I/O problem.
145: */
146: protected void writeStandardComment(final Writer writer,
147: final Comments comments) throws IOException {
148: if ((comments == null)
149: || (comments.getOpenTagComment() == null)) {
150: writer
151: .write("<!-- CVSTag: $Id: ModelWriter.java,v 1.3 2005/10/18 13:32:20 mungady Exp $ "
152: + comments + " -->");
153: writer.write(XMLWriterSupport.getLineSeparator());
154: } else {
155: writeComment(writer, comments.getOpenTagComment());
156: }
157: }
158:
159: /**
160: * Writes a sequence of comments.
161: *
162: * @param writer the writer.
163: * @param comments the comments (<code>null</code> ignored).
164: *
165: * @throws IOException if there is an I/O problem.
166: */
167: protected void writeComment(final Writer writer,
168: final String[] comments) throws IOException {
169: if (comments == null) {
170: return;
171: }
172: for (int i = 0; i < comments.length; i++) {
173: this .writerSupport.indent(writer,
174: XMLWriterSupport.INDENT_ONLY);
175: writer.write("<!--");
176: writer.write(comments[i]);
177: writer.write("-->");
178: writer.write(XMLWriterSupport.getLineSeparator());
179: }
180: }
181:
182: /**
183: * Writes the open comments from a set of comments.
184: *
185: * @param writer the writer.
186: * @param comments the set of comments.
187: *
188: * @throws IOException if there is an I/O problem.
189: */
190: protected void writeOpenComment(final Writer writer,
191: final Comments comments) throws IOException {
192: if (comments == null) {
193: return;
194: }
195: if (comments.getOpenTagComment() == null) {
196: return;
197: }
198: writeComment(writer, comments.getOpenTagComment());
199: }
200:
201: /**
202: * Writes the close comments from a set of comments.
203: *
204: * @param writer the writer.
205: * @param comments the set of comments.
206: *
207: * @throws IOException if there is an I/O problem.
208: */
209: protected void writeCloseComment(final Writer writer,
210: final Comments comments) throws IOException {
211: if (comments == null) {
212: return;
213: }
214: if (comments.getCloseTagComment() == null) {
215: return;
216: }
217: writeComment(writer, comments.getCloseTagComment());
218: }
219:
220: /**
221: * Writes a closed (short) tag with eventually nested comments.
222: *
223: * @param writer the writer.
224: * @param tagName the tag name.
225: * @param attributes the attributes.
226: * @param comments the comments.
227: *
228: * @throws IOException if there is an I/O problem.
229: */
230: protected void writeTag(final Writer writer, final String tagName,
231: final AttributeList attributes, final Comments comments)
232: throws IOException {
233: if (comments == null) {
234: this .writerSupport.writeTag(writer, tagName, attributes,
235: XMLWriterSupport.CLOSE);
236: } else {
237: writeOpenComment(writer, comments);
238: if (comments.getCloseTagComment() != null) {
239: this .writerSupport.writeTag(writer, tagName,
240: attributes, XMLWriterSupport.OPEN);
241: writeCloseComment(writer, comments);
242: this .writerSupport.writeCloseTag(writer, tagName);
243: } else {
244: this .writerSupport.writeTag(writer, tagName,
245: attributes, XMLWriterSupport.CLOSE);
246: }
247: }
248: }
249:
250: /**
251: * Writes a closed (short) tag with eventually nested comments.
252: *
253: * @param writer the writer.
254: * @param tagName the tag name.
255: * @param attribute the attribute name.
256: * @param value the attribute value.
257: * @param comments the comments.
258: *
259: * @throws IOException if there is an I/O problem.
260: */
261: protected void writeTag(final Writer writer, final String tagName,
262: final String attribute, final String value,
263: final Comments comments) throws IOException {
264: if (comments == null) {
265: this .writerSupport.writeTag(writer, tagName, attribute,
266: value, XMLWriterSupport.CLOSE);
267: } else {
268: writeOpenComment(writer, comments);
269: if (comments.getCloseTagComment() != null) {
270: this .writerSupport.writeTag(writer, tagName, attribute,
271: value, XMLWriterSupport.OPEN);
272: writeCloseComment(writer, comments);
273: this .writerSupport.writeCloseTag(writer, tagName);
274: } else {
275: this .writerSupport.writeTag(writer, tagName, attribute,
276: value, XMLWriterSupport.CLOSE);
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
295: .getIncludeComment(sources[i]);
296: writeTag(writer, ClassModelTags.INCLUDE_TAG,
297: ClassModelTags.SOURCE_ATTR, sources[i], comments);
298: }
299:
300: for (int i = 0; i < this .model.size(); i++) {
301: final ClassDescription cd = this .model.get(i);
302: writeClassDescription(writer, cd);
303: }
304:
305: final ManualMappingInfo[] mappings = getModel()
306: .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()
313: .getMappingModel().getMultiplexMapping();
314: for (int i = 0; i < mmappings.length; i++) {
315: final MultiplexMappingInfo mi = mmappings[i];
316: writeMultiplexMapping(writer, mi);
317: }
318:
319: writeCloseComment(writer, this .model.getModelComments());
320: this .writerSupport.writeCloseTag(writer,
321: ClassModelTags.OBJECTS_TAG);
322:
323: }
324:
325: /**
326: * Writes a manual mapping to the XML output.
327: *
328: * @param writer the writer.
329: * @param mi the mapping info.
330: *
331: * @throws IOException if there is an I/O problem.
332: */
333: protected void writeManualMapping(final Writer writer,
334: final ManualMappingInfo mi) throws IOException {
335: final AttributeList al = new AttributeList();
336: al.setAttribute(ClassModelTags.CLASS_ATTR, mi.getBaseClass()
337: .getName());
338: al.setAttribute(ClassModelTags.READ_HANDLER_ATTR, mi
339: .getReadHandler().getName());
340: al.setAttribute(ClassModelTags.WRITE_HANDLER_ATTR, mi
341: .getWriteHandler().getName());
342: writeTag(writer, ClassModelTags.MANUAL_TAG, al, mi
343: .getComments());
344: }
345:
346: /**
347: * Writes a multiplex mapping to the XML output.
348: *
349: * @param writer the writer.
350: * @param mi the mapping info.
351: *
352: * @throws IOException if there is an I/O problem.
353: */
354: protected void writeMultiplexMapping(final Writer writer,
355: final MultiplexMappingInfo mi) throws IOException {
356:
357: final TypeInfo[] tis = mi.getChildClasses();
358:
359: final AttributeList al = new AttributeList();
360: al.setAttribute(ClassModelTags.BASE_CLASS_ATTR, mi
361: .getBaseClass().getName());
362: al
363: .setAttribute(ClassModelTags.TYPE_ATTR, mi
364: .getTypeAttribute());
365: getWriterSupport().writeTag(writer, ClassModelTags.MAPPING_TAG,
366: al, XMLWriterSupport.OPEN);
367:
368: for (int j = 0; j < tis.length; j++) {
369: final AttributeList tiAttr = new AttributeList();
370: tiAttr.setAttribute(ClassModelTags.NAME_ATTR, tis[j]
371: .getName());
372: tiAttr.setAttribute(ClassModelTags.CLASS_ATTR, tis[j]
373: .getType().getName());
374: writeTag(writer, ClassModelTags.TYPE_TAG, tiAttr, tis[j]
375: .getComments());
376: }
377:
378: getWriterSupport().writeCloseTag(writer,
379: ClassModelTags.MAPPING_TAG);
380: }
381:
382: /**
383: * Writes a class description.
384: *
385: * @param writer the writer.
386: * @param cd the class description.
387: *
388: * @throws IOException if there is an I/O problem.
389: */
390: protected void writeClassDescription(final Writer writer,
391: final ClassDescription cd) throws IOException {
392:
393: if (cd.isUndefined()) {
394: return;
395: }
396:
397: final AttributeList al = new AttributeList();
398: al.setAttribute(ClassModelTags.CLASS_ATTR, cd.getName());
399: if (cd.getRegisterKey() != null) {
400: al.setAttribute(ClassModelTags.REGISTER_NAMES_ATTR, cd
401: .getRegisterKey());
402: }
403: if (cd.isPreserve()) {
404: al.setAttribute(ClassModelTags.IGNORE_ATTR, "true");
405: }
406: this .writerSupport.writeTag(writer, ClassModelTags.OBJECT_TAG,
407: al, XMLWriterSupport.OPEN);
408:
409: final TypeInfo[] constructorInfo = cd
410: .getConstructorDescription();
411: if (constructorInfo != null && constructorInfo.length != 0) {
412: this .writerSupport.writeTag(writer,
413: ClassModelTags.CONSTRUCTOR_TAG);
414: for (int i = 0; i < constructorInfo.length; i++) {
415: final AttributeList constructorList = new AttributeList();
416: constructorList.setAttribute(ClassModelTags.CLASS_ATTR,
417: constructorInfo[i].getType().getName());
418: constructorList.setAttribute(
419: ClassModelTags.PROPERTY_ATTR,
420: constructorInfo[i].getName());
421: writeTag(writer, ClassModelTags.PARAMETER_TAG,
422: constructorList, constructorInfo[i]
423: .getComments());
424: }
425: this .writerSupport.writeCloseTag(writer,
426: ClassModelTags.CONSTRUCTOR_TAG);
427: }
428:
429: final PropertyInfo[] properties = cd.getProperties();
430: for (int i = 0; i < properties.length; i++) {
431: writePropertyInfo(writer, properties[i]);
432: }
433:
434: this .writerSupport.writeCloseTag(writer,
435: ClassModelTags.OBJECT_TAG);
436: }
437:
438: /**
439: * Writes a property info element.
440: *
441: * @param writer the writer.
442: * @param ipi the property info.
443: *
444: * @throws IOException if there is an I/O problem.
445: */
446: private void writePropertyInfo(final Writer writer,
447: final PropertyInfo ipi) throws IOException {
448: final AttributeList props = new AttributeList();
449: props.setAttribute(ClassModelTags.NAME_ATTR, ipi.getName());
450:
451: if (ipi instanceof IgnoredPropertyInfo) {
452: writeTag(writer, ClassModelTags.IGNORED_PROPERTY_TAG,
453: props, ipi.getComments());
454: return;
455: }
456:
457: if (ipi.getPropertyType().equals(PropertyType.ATTRIBUTE)) {
458: props.setAttribute(ClassModelTags.ATTRIBUTE_ATTR, ipi
459: .getXmlName());
460: props.setAttribute(ClassModelTags.ATTRIBUTE_HANDLER_ATTR,
461: ipi.getXmlHandler());
462: writeTag(writer, ClassModelTags.ATTRIBUTE_PROPERTY_TAG,
463: props, ipi.getComments());
464: } else if (ipi.getPropertyType().equals(PropertyType.ELEMENT)) {
465: if (ipi.getComments() == null
466: || ipi.getComments().getOpenTagComment() == null) {
467: this .writerSupport.indent(writer,
468: XMLWriterSupport.INDENT_ONLY);
469: writer.write("<!-- property type is " + ipi.getType()
470: + " -->");
471: writer
472: .write(System.getProperty("line.separator",
473: "\n"));
474: }
475: props.setAttribute(ClassModelTags.ELEMENT_ATTR, ipi
476: .getXmlName());
477: writeTag(writer, ClassModelTags.ELEMENT_PROPERTY_TAG,
478: props, ipi.getComments());
479: } else {
480: props.setAttribute(ClassModelTags.LOOKUP_ATTR, ipi
481: .getXmlName());
482: writeTag(writer, ClassModelTags.LOOKUP_PROPERTY_TAG, props,
483: ipi.getComments());
484: }
485: }
486:
487: /**
488: * Returns the writer support object.
489: *
490: * @return The writer support object.
491: */
492: public XMLWriterSupport getWriterSupport() {
493: return this.writerSupport;
494: }
495: }
|