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) 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 }