/*
* 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.InputStream;
import java.io.Reader;
import java.lang.IllegalStateException;
import javolution.context.ObjectFactory;
import javolution.lang.Reusable;
import javolution.xml.stream.XMLStreamException;
import javolution.xml.stream.XMLStreamReader;
import javolution.xml.stream.XMLStreamReaderImpl;
/**
* <p> This class restores objects which have been serialized in XML
* format using an {@link XMLObjectWriter}.</p>
*
* <p> When the XML document is parsed, each elements are recursively
* processed and Java objects are created using the {@link XMLFormat}
* of the class as identified by the {@link XMLBinding}.</p>
*
* <p> Multiple objects can be read from the same XML input.
* For example:[code]
* XMLObjectReader reader = XMLObjectReader.newInstance(inputStream);
* while (reader.hasNext()) {
* Message message = reader.read("Message", Message.class);
* }
* reader.close(); // Reader 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 XMLObjectReader implements Reusable {
/**
* Holds the associated factory.
*/
private static final ObjectFactory FACTORY = new ObjectFactory() {
protected Object create() {
return new XMLObjectReader();
}
};
/**
* Hold the xml element used when parsing.
*/
private final XMLFormat.InputElement _xml = new XMLFormat.InputElement();
/**
* Holds reader if any.
*/
private Reader _reader;
/**
* Holds input stream if any.
*/
private InputStream _inputStream;
/**
* Indicates if factory produced.
*/
private boolean _isFactoryProduced;
/**
* Returns a XML object reader (potentially recycled) having the specified
* input stream as input.
*
* @param in the input stream.
*/
public static XMLObjectReader newInstance(InputStream in) throws XMLStreamException {
XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
reader._isFactoryProduced = true;
reader.setInput(in);
return reader;
}
/**
* Returns a XML object reader (potentially recycled) having the specified
* input stream/encoding as input.
*
* @param in the input stream.
* @param encoding the input stream encoding
*/
public static XMLObjectReader newInstance(InputStream in, String encoding) throws XMLStreamException {
XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
reader._isFactoryProduced = true;
reader.setInput(in, encoding);
return reader;
}
/**
* Returns a XML object reader (potentially recycled) having the specified
* reader as input.
*
* @param in the reader source.
*/
public static XMLObjectReader newInstance(Reader in) throws XMLStreamException {
XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
reader._isFactoryProduced = true;
reader.setInput(in);
return reader;
}
/**
* Recycles the specified XMLObjectReader.
*
* @param that the instance to recycle.
*/
public static void recycle(XMLObjectReader that) {
FACTORY.recycle(that);
}
/**
* Default constructor.
*/
public XMLObjectReader() {
}
/**
* Returns the stream reader being used by this reader (it can be
* used to set prefix, read prologs, etc).
*
* @return the stream reader.
*/
public XMLStreamReader getStreamReader() {
return _xml._reader;
}
/**
* Sets the input stream source for this XML object reader
* (encoding retrieved from XML prolog if any).
*
* @param in the source input stream.
* @return <code>this</code>
* @see XMLStreamReaderImpl#setInput(InputStream)
*/
public XMLObjectReader setInput(InputStream in) throws XMLStreamException {
if ((_inputStream != null) || (_reader != null))
throw new IllegalStateException("Reader not closed or reset");
_xml._reader.setInput(in);
_inputStream = in;
return this;
}
/**
* Sets the input stream source and encoding for this XML object reader.
*
* @param in the input source.
* @param encoding the associated encoding.
* @return <code>this</code>
* @see XMLStreamReaderImpl#setInput(InputStream, String)
*/
public XMLObjectReader setInput(InputStream in, String encoding)
throws XMLStreamException {
if ((_inputStream != null) || (_reader != null))
throw new IllegalStateException("Reader not closed or reset");
_xml._reader.setInput(in, encoding);
_inputStream = in;
return this;
}
/**
* Sets the reader input source for this XML stream reader.
*
* @param in the source reader.
* @return <code>this</code>
* @see XMLStreamReaderImpl#setInput(Reader)
*/
public XMLObjectReader setInput(Reader in) throws XMLStreamException {
if ((_inputStream != null) || (_reader != null))
throw new IllegalStateException("Reader not closed or reset");
_xml._reader.setInput(in);
_reader = in;
return this;
}
/**
* Sets the XML binding to use with this object reader.
*
* @param binding the XML binding to use.
* @return <code>this</code>
*/
public XMLObjectReader setBinding(XMLBinding binding) {
_xml.setBinding(binding);
return this;
}
/**
* Sets the XML reference resolver to use with this object reader
* (the same resolver can be used accross multiple readers).
*
* @param referenceResolver the XML reference resolver.
* @return <code>this</code>
*/
public XMLObjectReader setReferenceResolver(
XMLReferenceResolver referenceResolver) {
_xml.setReferenceResolver(referenceResolver);
return this;
}
/**
* Indicates if more elements can be read. This method
* positions the reader at the start of the
* next element to be read (if any).
*
* @return <code>true</code> if more element/data to be read;
* <code>false</code> otherwise.
* @see XMLFormat.InputElement#hasNext()
*/
public boolean hasNext() throws XMLStreamException {
return _xml.hasNext();
}
/**
* Returns the object corresponding to the next element/data.
*
* @return the next nested object (can be <code>null</code>)
* @throws XMLStreamException if <code>hasNext() == false</code>
* @see XMLFormat.InputElement#getNext()
*/
public <T> T read() throws XMLStreamException {
return ( T )_xml.getNext();
}
/**
* Returns the object corresponding to the next nested element only
* if it has the specified local name.
*
* @param name the local name of the next element.
* @return the next content object or <code>null</code> if the
* local name does not match.
* @see XMLFormat.InputElement#get(String)
*/
public <T> T read(String name) throws XMLStreamException {
return ( T ) _xml.get(name);
}
/**
* Returns the object corresponding to the next nested element only
* if it has the specified local name and namespace URI.
*
* @param localName the local name.
* @param uri the namespace URI.
* @return the next content object or <code>null</code> if the
* name/uri does not match.
* @see XMLFormat.InputElement#get(String, String)
*/
public <T> T read(String localName, String uri)
throws XMLStreamException {
return ( T ) _xml.get(localName, uri);
}
/**
* Returns the object corresponding to the next nested element only
* if it has the specified local name; the actual object type is identified
* by the specified class parameter.
*
* @param name the name of the element to match.
* @param cls the non-abstract class identifying the object to return.
* @return <code>read(name, null, cls)</code>
*/
public <T> T read(String name, Class <T> cls)
throws XMLStreamException {
return _xml.get(name, cls);
}
/**
* Returns the object corresponding to the next nested element only
* if it has the specified local name and namespace URI; the
* actual object type is identified by the specified class parameter.
*
* @param localName the local name.
* @param uri the namespace URI.
* @param cls the non-abstract class identifying the object to return.
* @return the next content object or <code>null</code> if no match.
*/
public <T> T read(String localName, String uri,
Class <T> cls) throws XMLStreamException {
return _xml.get(localName, uri, cls);
}
/**
* Closes this reader and its underlying input then {@link #reset reset}
* this reader for potential reuse.
*/
public void close() throws XMLStreamException {
try {
if (_inputStream != null) {
_inputStream.close();
reset();
} else if (_reader != null) {
_reader.close();
reset();
}
if (_isFactoryProduced) {
FACTORY.recycle(this);
}
} catch (IOException e) {
throw new XMLStreamException(e);
}
}
/**
* Resets this object reader for reuse.
*/
public void reset() {
_xml.reset();
_reader = null;
_inputStream = null;
}
}