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.InputStream;
015: import java.io.Reader;
016:
017: import javolution.context.ObjectFactory;
018: import javolution.lang.Reusable;
019: import javolution.xml.stream.XMLStreamException;
020: import javolution.xml.stream.XMLStreamReader;
021: import javolution.xml.stream.XMLStreamReaderImpl;
022:
023: /**
024: * <p> This class restores objects which have been serialized in XML
025: * format using an {@link XMLObjectWriter}.</p>
026: *
027: * <p> When the XML document is parsed, each elements are recursively
028: * processed and Java objects are created using the {@link XMLFormat}
029: * of the class as identified by the {@link XMLBinding}.</p>
030: *
031: * <p> Multiple objects can be read from the same XML input.
032: * For example:[code]
033: * XMLObjectReader reader = XMLObjectReader.newInstance(inputStream);
034: * while (reader.hasNext()) {
035: * Message message = reader.read("Message", Message.class);
036: * }
037: * reader.close(); // Reader is recycled, the underlying stream is closed.
038: * [/code]</p>
039: *
040: * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
041: * @version 4.0, September 4, 2006
042: */
043: public class XMLObjectReader implements Reusable {
044:
045: /**
046: * Holds the associated factory.
047: */
048: private static final ObjectFactory FACTORY = new ObjectFactory() {
049:
050: protected Object create() {
051: return new XMLObjectReader();
052: }
053:
054: protected void cleanup(Object obj) {
055: ((XMLObjectReader) obj).reset();
056: }
057: };
058:
059: /**
060: * Hold the xml element used when parsing.
061: */
062: private final XMLFormat.InputElement _xml = new XMLFormat.InputElement();
063:
064: /**
065: * Holds reader if any.
066: */
067: private Reader _reader;
068:
069: /**
070: * Holds input stream if any.
071: */
072: private InputStream _inputStream;
073:
074: /**
075: * Indicates if factory produced.
076: */
077: private boolean _isFactoryProduced;
078:
079: /**
080: * Returns a XML object reader (potentially recycled) having the specified
081: * input stream as input.
082: *
083: * @param in the input stream.
084: */
085: public static XMLObjectReader newInstance(InputStream in)
086: throws XMLStreamException {
087: XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
088: reader._isFactoryProduced = true;
089: reader.setInput(in);
090: return reader;
091: }
092:
093: /**
094: * Returns a XML object reader (potentially recycled) having the specified
095: * input stream/encoding as input.
096: *
097: * @param in the input stream.
098: * @param encoding the input stream encoding
099: */
100: public static XMLObjectReader newInstance(InputStream in,
101: String encoding) throws XMLStreamException {
102: XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
103: reader._isFactoryProduced = true;
104: reader.setInput(in, encoding);
105: return reader;
106: }
107:
108: /**
109: * Returns a XML object reader (potentially recycled) having the specified
110: * reader as input.
111: *
112: * @param in the reader source.
113: */
114: public static XMLObjectReader newInstance(Reader in)
115: throws XMLStreamException {
116: XMLObjectReader reader = (XMLObjectReader) FACTORY.object();
117: reader._isFactoryProduced = true;
118: reader.setInput(in);
119: return reader;
120: }
121:
122: /**
123: * Default constructor.
124: */
125: public XMLObjectReader() {
126: }
127:
128: /**
129: * Returns the stream reader being used by this reader (it can be
130: * used to set prefix, read prologs, etc).
131: *
132: * @return the stream reader.
133: */
134: public XMLStreamReader getStreamReader() {
135: return _xml._reader;
136: }
137:
138: /**
139: * Sets the input stream source for this XML object reader
140: * (encoding retrieved from XML prolog if any).
141: *
142: * @param in the source input stream.
143: * @return <code>this</code>
144: * @see XMLStreamReaderImpl#setInput(InputStream)
145: */
146: public XMLObjectReader setInput(InputStream in)
147: throws XMLStreamException {
148: if ((_inputStream != null) || (_reader != null))
149: throw new IllegalStateException(
150: "Reader not closed or reset");
151: _xml._reader.setInput(in);
152: _inputStream = in;
153: return this ;
154: }
155:
156: /**
157: * Sets the input stream source and encoding for this XML object reader.
158: *
159: * @param in the input source.
160: * @param encoding the associated encoding.
161: * @return <code>this</code>
162: * @see XMLStreamReaderImpl#setInput(InputStream, String)
163: */
164: public XMLObjectReader setInput(InputStream in, String encoding)
165: throws XMLStreamException {
166: if ((_inputStream != null) || (_reader != null))
167: throw new IllegalStateException(
168: "Reader not closed or reset");
169: _xml._reader.setInput(in, encoding);
170: _inputStream = in;
171: return this ;
172: }
173:
174: /**
175: * Sets the reader input source for this XML stream reader.
176: *
177: * @param in the source reader.
178: * @return <code>this</code>
179: * @see XMLStreamReaderImpl#setInput(Reader)
180: */
181: public XMLObjectReader setInput(Reader in)
182: throws XMLStreamException {
183: if ((_inputStream != null) || (_reader != null))
184: throw new IllegalStateException(
185: "Reader not closed or reset");
186: _xml._reader.setInput(in);
187: _reader = in;
188: return this ;
189: }
190:
191: /**
192: * Sets the XML binding to use with this object reader.
193: *
194: * @param binding the XML binding to use.
195: * @return <code>this</code>
196: */
197: public XMLObjectReader setBinding(XMLBinding binding) {
198: _xml.setBinding(binding);
199: return this ;
200: }
201:
202: /**
203: * Sets the XML reference resolver to use with this object reader
204: * (the same resolver can be used accross multiple readers).
205: *
206: * @param referenceResolver the XML reference resolver.
207: * @return <code>this</code>
208: */
209: public XMLObjectReader setReferenceResolver(
210: XMLReferenceResolver referenceResolver) {
211: _xml.setReferenceResolver(referenceResolver);
212: return this ;
213: }
214:
215: /**
216: * Indicates if more elements can be read. This method
217: * positions the reader at the start of the
218: * next element to be read (if any).
219: *
220: * @return <code>true</code> if more element/data to be read;
221: * <code>false</code> otherwise.
222: * @see XMLFormat.InputElement#hasNext()
223: */
224: public boolean hasNext() throws XMLStreamException {
225: return _xml.hasNext();
226: }
227:
228: /**
229: * Returns the object corresponding to the next element/data.
230: *
231: * @return the next nested object (can be <code>null</code>)
232: * @throws XMLStreamException if <code>hasNext() == false</code>
233: * @see XMLFormat.InputElement#getNext()
234: */
235: public/*<T>*/Object/*{T}*/read() throws XMLStreamException {
236: return (Object/*{T}*/) _xml.getNext();
237: }
238:
239: /**
240: * Returns the object corresponding to the next nested element only
241: * if it has the specified local name.
242: *
243: * @param name the local name of the next element.
244: * @return the next content object or <code>null</code> if the
245: * local name does not match.
246: * @see XMLFormat.InputElement#get(String)
247: */
248: public/*<T>*/Object/*{T}*/read(String name)
249: throws XMLStreamException {
250: return (Object/*{T}*/) _xml.get(name);
251: }
252:
253: /**
254: * Returns the object corresponding to the next nested element only
255: * if it has the specified local name and namespace URI.
256: *
257: * @param localName the local name.
258: * @param uri the namespace URI.
259: * @return the next content object or <code>null</code> if the
260: * name/uri does not match.
261: * @see XMLFormat.InputElement#get(String, String)
262: */
263: public/*<T>*/Object/*{T}*/read(String localName, String uri)
264: throws XMLStreamException {
265: return (Object/*{T}*/) _xml.get(localName, uri);
266: }
267:
268: /**
269: * Returns the object corresponding to the next nested element only
270: * if it has the specified local name; the actual object type is identified
271: * by the specified class parameter.
272: *
273: * @param name the name of the element to match.
274: * @param cls the non-abstract class identifying the object to return.
275: * @return <code>read(name, null, cls)</code>
276: */
277: public/*<T>*/Object/*{T}*/read(String name, Class/*<T>*/cls)
278: throws XMLStreamException {
279: return _xml.get(name, cls);
280: }
281:
282: /**
283: * Returns the object corresponding to the next nested element only
284: * if it has the specified local name and namespace URI; the
285: * actual object type is identified by the specified class parameter.
286: *
287: * @param localName the local name.
288: * @param uri the namespace URI.
289: * @param cls the non-abstract class identifying the object to return.
290: * @return the next content object or <code>null</code> if no match.
291: */
292: public/*<T>*/Object/*{T}*/read(String localName, String uri,
293: Class/*<T>*/cls) throws XMLStreamException {
294: return _xml.get(localName, uri, cls);
295: }
296:
297: /**
298: * Closes this reader and its underlying input then {@link #reset reset}
299: * this reader for potential reuse.
300: */
301: public void close() throws XMLStreamException {
302: try {
303: if (_inputStream != null) {
304: _inputStream.close();
305: reset();
306: } else if (_reader != null) {
307: _reader.close();
308: reset();
309: }
310: if (_isFactoryProduced) {
311: FACTORY.recycle(this );
312: }
313: } catch (IOException e) {
314: throw new XMLStreamException(e);
315: }
316: }
317:
318: /**
319: * Resets this object reader for reuse.
320: */
321: public void reset() {
322: _xml.reset();
323: _reader = null;
324: _inputStream = null;
325: }
326: }
|