/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2006 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.xml;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.lang.IllegalStateException;
import javolution.context.ObjectFactory;
import javolution.lang.Reusable;
import javolution.xml.stream.XMLStreamException;
import javolution.xml.stream.XMLStreamWriter;
import javolution.xml.stream.XMLStreamWriterImpl;
/**
* <p> This class takes an object and formats it to XML; the resulting
* XML can be deserialized using a {@link XMLObjectReader}.</p>
*
* <p> When an object is formatted, the {@link XMLFormat} of the
* object's class as identified by the {@link XMLBinding} is used to
* write its XML representation.</p>
*
* <p> Multiple objects can be written to the same XML output.
* For example:[code]
* XMLObjectWriter writer = XMLObjectWriter.newInstance(outputStream);
* while (true)) {
* Message message = ...
* writer.write(message, "Message", Message.class);
* }
* writer.close(); // Writer is recycled, the underlying stream is closed.
* [/code]</p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 4.0, September 4, 2006
*/
public class XMLObjectWriter implements Reusable {
/**
* Holds the associated factory.
*/
private static final ObjectFactory FACTORY = new ObjectFactory() {
protected Object create() {
return new XMLObjectWriter();
}
};
/**
* Hold the xml element used when formatting.
*/
private final XMLFormat.OutputElement _xml
= new XMLFormat.OutputElement();
/**
* Holds writer if any.
*/
private Writer _writer;
/**
* Holds input stream if any.
*/
private OutputStream _outputStream;
/**
* Indicates if factory produced.
*/
private boolean _isFactoryProduced;
/**
* Default constructor.
*/
public XMLObjectWriter() {
}
/**
* Returns a XML object writer (potentially recycled) having the specified
* output stream as output.
*
* @param out the output stream.
*/
public static XMLObjectWriter newInstance(OutputStream out) throws XMLStreamException {
XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
writer._isFactoryProduced = true;
writer.setOutput(out);
return writer;
}
/**
* Returns a XML object writer (potentially recycled) having the specified
* output stream/encoding as output.
*
* @param out the output stream.
* @param encoding the output stream encoding.
*/
public static XMLObjectWriter newInstance(OutputStream out, String encoding) throws XMLStreamException {
XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
writer._isFactoryProduced = true;
writer.setOutput(out, encoding);
return writer;
}
/**
* Returns a XML object writer (potentially recycled) having the specified
* writer as output.
*
* @param out the writer output.
*/
public static XMLObjectWriter newInstance(Writer out) throws XMLStreamException {
XMLObjectWriter writer = (XMLObjectWriter) FACTORY.object();
writer._isFactoryProduced = true;
writer.setOutput(out);
return writer;
}
/**
* Returns the stream writer used by this object writer (it can be used
* to write prolog, write namespaces, etc). The stream writer is setup to
* automatically repair namespaces and to automatically output empty
* elements when a start element is immediately followed by matching end
* element.
*
* @return the stream writer.
*/
public XMLStreamWriter getStreamWriter() {
return _xml._writer;
}
/**
* Sets the output stream for this XML object writer.
*
* @param out the output stream destination.
* @return <code>this</code>
* @see XMLStreamWriterImpl#setOutput(OutputStream)
*/
public XMLObjectWriter setOutput(OutputStream out) throws XMLStreamException {
if ((_outputStream != null) || (_writer != null))
throw new IllegalStateException("Writer not closed or reset");
_xml._writer.setOutput(out);
_outputStream = out;
_xml._writer.writeStartDocument();
return this;
}
/**
* Sets the output stream and encoding for this XML object writer.
*
* @param out the output stream destination.
* @param encoding the stream encoding.
* @return <code>this</code>
* @see XMLStreamWriterImpl#setOutput(OutputStream, String)
*/
public XMLObjectWriter setOutput(OutputStream out, String encoding) throws XMLStreamException {
if ((_outputStream != null) || (_writer != null))
throw new IllegalStateException("Writer not closed or reset");
_xml._writer.setOutput(out, encoding);
_outputStream = out;
_xml._writer.writeStartDocument();
return this;
}
/**
* Sets the output writer for this XML object writer.
*
* @param out the writer destination.
* @return <code>this</code>
* @see XMLStreamWriterImpl#setOutput(Writer)
*/
public XMLObjectWriter setOutput(Writer out) throws XMLStreamException {
if ((_outputStream != null) || (_writer != null))
throw new IllegalStateException("Writer not closed or reset");
_xml._writer.setOutput(out);
_writer = out;
_xml._writer.writeStartDocument();
return this;
}
/**
* Sets the XML binding to use with this object writer.
*
* @param binding the XML binding to use.
* @return <code>this</code>
*/
public XMLObjectWriter setBinding(XMLBinding binding) {
_xml.setBinding(binding);
return this;
}
/**
* Sets the indentation to be used by this writer (no indentation
* by default).
*
* @param indentation the indentation string.
* @return <code>this</code>
*/
public XMLObjectWriter setIndentation(String indentation) {
_xml._writer.setIndentation(indentation);
return this;
}
/**
* Sets the XML reference resolver to use with this object writer
* (the same reference resolver can be used accross multiple writers).
*
* @param referenceResolver the XML reference resolver.
* @return <code>this</code>
*/
public XMLObjectWriter setReferenceResolver(XMLReferenceResolver referenceResolver) {
_xml.setReferenceResolver(referenceResolver);
return this;
}
/**
* Writes the specified object as an anonymous nested element of
* unknown type. This result in the actual type of the object being
* identified by the element name.
*
* @param obj the object written as nested element or <code>null</code>.
* @see XMLFormat.OutputElement#add(Object)
*/
public void write(Object obj) throws XMLStreamException {
_xml.add(obj);
}
/**
* Writes the specified object as a named nested element of unknown type
* (<code>null</code> objects are ignored). The nested XML element
* may contain a class attribute identifying the object type.
*
* @param obj the object added as nested element or <code>null</code>.
* @param name the name of the nested element.
* @see XMLFormat.OutputElement#add(Object, String)
*/
public void write(Object obj, String name) throws XMLStreamException {
_xml.add(obj, name);
}
/**
* Writes the specified object as a fully qualified nested element of
* unknown type (<code>null</code> objects are ignored).
* The nested XML element may contain a class attribute identifying
* the object type.
*
* @param obj the object added as nested element or <code>null</code>.
* @param localName the local name of the nested element.
* @param uri the namespace URI of the nested element.
* @see XMLFormat.OutputElement#add(Object, String, String)
*/
public void write(Object obj, String localName, String uri)
throws XMLStreamException {
_xml.add(obj, localName, uri);
}
/**
* Writes the specified object as a named nested element of actual type
* known (<code>null</code> objects are ignored).
*
* @param obj the object added as nested element or <code>null</code>.
* @param name the name of the nested element.
* @param cls the non-abstract class identifying the XML format to use.
* @see XMLFormat.OutputElement#add(Object, String, Class)
*/
public <T> void write( T obj, String name, Class <T> cls)
throws XMLStreamException {
_xml.add(obj, name, cls);
}
/**
* Writes the specified object as a fully qualified nested element of
* actual type known (<code>null</code> objects are ignored).
*
* @param obj the object added as nested element or <code>null</code>.
* @param localName the local name of the nested element.
* @param uri the namespace URI of the nested element.
* @param cls the class identifying the XML format to use.
* @see XMLFormat.OutputElement#add(Object, String, String, Class)
*/
public <T> void write( T obj, String localName, String uri, Class <T> cls)
throws XMLStreamException {
_xml.add(obj, localName, uri, cls);
}
/**
* Flushes the output stream of this writer (automatically done
* when {@link #close() closing}).
*/
public void flush() throws XMLStreamException {
_xml._writer.flush();
}
/**
* Ends document writting, closes this writer and its underlying
* output then {@link #reset reset} this Writer for potential reuse.
*/
public void close() throws XMLStreamException {
try {
if (_outputStream != null) {
_xml._writer.writeEndDocument();
_xml._writer.close();
_outputStream.close();
reset();
} else if (_writer != null) {
_xml._writer.writeEndDocument();
_xml._writer.close();
_writer.close();
reset();
}
if (_isFactoryProduced) {
FACTORY.recycle(this);
}
} catch (IOException e) {
throw new XMLStreamException(e);
}
}
/**
* Resets this object writer for reuse.
*/
public void reset() {
_xml.reset();
_outputStream = null;
_writer = null;
}
}