/* * 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 j2me.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>*/Object/*{T}*/ read() throws XMLStreamException { return (Object/*{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>*/Object/*{T}*/ read(String name) throws XMLStreamException { return (Object/*{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>*/Object/*{T}*/ read(String localName, String uri) throws XMLStreamException { return (Object/*{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>*/Object/*{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>*/Object/*{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; } }