001: /*
002: * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
003: * Copyright (C) 2006 - Javolution (http://javolution.org/)
004: * All rights reserved.
005: *
006: * Permission to use, copy, modify, and distribute this software is
007: * freely granted, provided that this notice is preserved.
008: */
009: package javolution.xml;
010:
011: import j2me.lang.IllegalStateException;
012:
013: import java.io.IOException;
014: import java.io.OutputStream;
015: import java.io.Writer;
016:
017: import javolution.context.ObjectFactory;
018: import javolution.lang.Reusable;
019: import javolution.xml.stream.XMLStreamException;
020: import javolution.xml.stream.XMLStreamWriter;
021: import javolution.xml.stream.XMLStreamWriterImpl;
022:
023: /**
024: * <p> This class takes an object and formats it to XML; the resulting
025: * XML can be deserialized using a {@link XMLObjectReader}.</p>
026: *
027: * <p> When an object is formatted, the {@link XMLFormat} of the
028: * object's class as identified by the {@link XMLBinding} is used to
029: * write its XML representation.</p>
030: *
031: * <p> Multiple objects can be written to the same XML output.
032: * For example:[code]
033: * XMLObjectWriter writer = XMLObjectWriter.newInstance(outputStream);
034: * while (true)) {
035: * Message message = ...
036: * writer.write(message, "Message", Message.class);
037: * }
038: * writer.close(); // Writer is recycled, the underlying stream is closed.
039: * [/code]</p>
040: *
041: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
042: * @version 4.0, September 4, 2006
043: */
044: public class XMLObjectWriter implements Reusable {
045:
046: /**
047: * Holds the associated factory.
048: */
049: private static final ObjectFactory FACTORY = new ObjectFactory() {
050:
051: protected Object create() {
052: return new XMLObjectWriter();
053: }
054:
055: protected void cleanup(Object obj) {
056: ((XMLObjectWriter) obj).reset();
057: }
058: };
059:
060: /**
061: * Hold the xml element used when formatting.
062: */
063: private final XMLFormat.OutputElement _xml = new XMLFormat.OutputElement();
064:
065: /**
066: * Holds writer if any.
067: */
068: private Writer _writer;
069:
070: /**
071: * Holds input stream if any.
072: */
073: private OutputStream _outputStream;
074:
075: /**
076: * Indicates if factory produced.
077: */
078: private boolean _isFactoryProduced;
079:
080: /**
081: * Default constructor.
082: */
083: public XMLObjectWriter() {
084: }
085:
086: /**
087: * Returns a XML object writer (potentially recycled) having the specified
088: * output stream as output.
089: *
090: * @param out the output stream.
091: */
092: public static XMLObjectWriter newInstance(OutputStream out)
093: throws XMLStreamException {
094: XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
095: writer._isFactoryProduced = true;
096: writer.setOutput(out);
097: return writer;
098: }
099:
100: /**
101: * Returns a XML object writer (potentially recycled) having the specified
102: * output stream/encoding as output.
103: *
104: * @param out the output stream.
105: * @param encoding the output stream encoding.
106: */
107: public static XMLObjectWriter newInstance(OutputStream out,
108: String encoding) throws XMLStreamException {
109: XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
110: writer._isFactoryProduced = true;
111: writer.setOutput(out, encoding);
112: return writer;
113: }
114:
115: /**
116: * Returns a XML object writer (potentially recycled) having the specified
117: * writer as output.
118: *
119: * @param out the writer output.
120: */
121: public static XMLObjectWriter newInstance(Writer out)
122: throws XMLStreamException {
123: XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
124: writer._isFactoryProduced = true;
125: writer.setOutput(out);
126: return writer;
127: }
128:
129: /**
130: * Returns the stream writer used by this object writer (it can be used
131: * to write prolog, write namespaces, etc). The stream writer is setup to
132: * automatically repair namespaces and to automatically output empty
133: * elements when a start element is immediately followed by matching end
134: * element.
135: *
136: * @return the stream writer.
137: */
138: public XMLStreamWriter getStreamWriter() {
139: return _xml._writer;
140: }
141:
142: /**
143: * Sets the output stream for this XML object writer.
144: *
145: * @param out the output stream destination.
146: * @return <code>this</code>
147: * @see XMLStreamWriterImpl#setOutput(OutputStream)
148: */
149: public XMLObjectWriter setOutput(OutputStream out)
150: throws XMLStreamException {
151: if ((_outputStream != null) || (_writer != null))
152: throw new IllegalStateException(
153: "Writer not closed or reset");
154: _xml._writer.setOutput(out);
155: _outputStream = out;
156: _xml._writer.writeStartDocument();
157: return this ;
158: }
159:
160: /**
161: * Sets the output stream and encoding for this XML object writer.
162: *
163: * @param out the output stream destination.
164: * @param encoding the stream encoding.
165: * @return <code>this</code>
166: * @see XMLStreamWriterImpl#setOutput(OutputStream, String)
167: */
168: public XMLObjectWriter setOutput(OutputStream out, String encoding)
169: throws XMLStreamException {
170: if ((_outputStream != null) || (_writer != null))
171: throw new IllegalStateException(
172: "Writer not closed or reset");
173: _xml._writer.setOutput(out, encoding);
174: _outputStream = out;
175: _xml._writer.writeStartDocument();
176: return this ;
177: }
178:
179: /**
180: * Sets the output writer for this XML object writer.
181: *
182: * @param out the writer destination.
183: * @return <code>this</code>
184: * @see XMLStreamWriterImpl#setOutput(Writer)
185: */
186: public XMLObjectWriter setOutput(Writer out)
187: throws XMLStreamException {
188: if ((_outputStream != null) || (_writer != null))
189: throw new IllegalStateException(
190: "Writer not closed or reset");
191: _xml._writer.setOutput(out);
192: _writer = out;
193: _xml._writer.writeStartDocument();
194: return this ;
195: }
196:
197: /**
198: * Sets the XML binding to use with this object writer.
199: *
200: * @param binding the XML binding to use.
201: * @return <code>this</code>
202: */
203: public XMLObjectWriter setBinding(XMLBinding binding) {
204: _xml.setBinding(binding);
205: return this ;
206: }
207:
208: /**
209: * Sets the indentation to be used by this writer (no indentation
210: * by default).
211: *
212: * @param indentation the indentation string.
213: * @return <code>this</code>
214: */
215: public XMLObjectWriter setIndentation(String indentation) {
216: _xml._writer.setIndentation(indentation);
217: return this ;
218: }
219:
220: /**
221: * Sets the XML reference resolver to use with this object writer
222: * (the same reference resolver can be used accross multiple writers).
223: *
224: * @param referenceResolver the XML reference resolver.
225: * @return <code>this</code>
226: */
227: public XMLObjectWriter setReferenceResolver(
228: XMLReferenceResolver referenceResolver) {
229: _xml.setReferenceResolver(referenceResolver);
230: return this ;
231: }
232:
233: /**
234: * Writes the specified object as an anonymous nested element of
235: * unknown type.
236: *
237: * @param obj the object written as nested element or <code>null</code>.
238: * @see XMLFormat.OutputElement#add(Object)
239: */
240: public void write(Object obj) throws XMLStreamException {
241: _xml.add(obj);
242: }
243:
244: /**
245: * Writes the specified object as a named nested element of unknown type
246: * (<code>null</code> objects are ignored). The nested XML element
247: * may contain a class attribute identifying the object type.
248: *
249: * @param obj the object added as nested element or <code>null</code>.
250: * @param name the name of the nested element.
251: * @see XMLFormat.OutputElement#add(Object, String)
252: */
253: public void write(Object obj, String name)
254: throws XMLStreamException {
255: _xml.add(obj, name);
256: }
257:
258: /**
259: * Writes the specified object as a fully qualified nested element of
260: * unknown type (<code>null</code> objects are ignored).
261: * The nested XML element may contain a class attribute identifying
262: * the object type.
263: *
264: * @param obj the object added as nested element or <code>null</code>.
265: * @param localName the local name of the nested element.
266: * @param uri the namespace URI of the nested element.
267: * @see XMLFormat.OutputElement#add(Object, String, String)
268: */
269: public void write(Object obj, String localName, String uri)
270: throws XMLStreamException {
271: _xml.add(obj, localName, uri);
272: }
273:
274: /**
275: * Writes the specified object as a named nested element of actual type
276: * known (<code>null</code> objects are ignored).
277: *
278: * @param obj the object added as nested element or <code>null</code>.
279: * @param name the name of the nested element.
280: * @param cls the non-abstract class identifying the XML format to use.
281: * @see XMLFormat.OutputElement#add(Object, String, Class)
282: */
283: public/*<T>*/void write(Object/*{T}*/obj, String name,
284: Class/*<T>*/cls) throws XMLStreamException {
285: _xml.add(obj, name, cls);
286: }
287:
288: /**
289: * Writes the specified object as a fully qualified nested element of
290: * actual type known (<code>null</code> objects are ignored).
291: *
292: * @param obj the object added as nested element or <code>null</code>.
293: * @param localName the local name of the nested element.
294: * @param uri the namespace URI of the nested element.
295: * @param cls the class identifying the XML format to use.
296: * @see XMLFormat.OutputElement#add(Object, String, String, Class)
297: */
298: public/*<T>*/void write(Object/*{T}*/obj, String localName,
299: String uri, Class/*<T>*/cls) throws XMLStreamException {
300: _xml.add(obj, localName, uri, cls);
301: }
302:
303: /**
304: * Flushes the output stream of this writer (automatically done
305: * when {@link #close() closing}).
306: */
307: public void flush() throws XMLStreamException {
308: _xml._writer.flush();
309: }
310:
311: /**
312: * Ends document writting, closes this writer and its underlying
313: * output then {@link #reset reset} this Writer for potential reuse.
314: */
315: public void close() throws XMLStreamException {
316: try {
317: if (_outputStream != null) {
318: _xml._writer.writeEndDocument();
319: _xml._writer.close();
320: _outputStream.close();
321: reset();
322: } else if (_writer != null) {
323: _xml._writer.writeEndDocument();
324: _xml._writer.close();
325: _writer.close();
326: reset();
327: }
328: if (_isFactoryProduced) {
329: FACTORY.recycle(this );
330: }
331:
332: } catch (IOException e) {
333: throw new XMLStreamException(e);
334: }
335: }
336:
337: /**
338: * Resets this object writer for reuse.
339: */
340: public void reset() {
341: _xml.reset();
342: _outputStream = null;
343: _writer = null;
344: }
345: }
|