001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020: package com.sun.xml.stream.buffer;
021:
022: import com.sun.xml.stream.buffer.sax.SAXBufferProcessor;
023: import com.sun.xml.stream.buffer.stax.StreamReaderBufferProcessor;
024: import com.sun.xml.stream.buffer.stax.StreamWriterBufferProcessor;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.util.Collections;
028: import java.util.Map;
029: import javax.xml.stream.XMLStreamException;
030: import javax.xml.stream.XMLStreamReader;
031: import javax.xml.stream.XMLStreamWriter;
032: import javax.xml.transform.TransformerFactory;
033: import javax.xml.transform.Transformer;
034: import javax.xml.transform.TransformerException;
035: import javax.xml.transform.dom.DOMResult;
036:
037: import org.xml.sax.ContentHandler;
038: import org.xml.sax.DTDHandler;
039: import org.xml.sax.ErrorHandler;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.XMLReader;
042: import org.xml.sax.ext.LexicalHandler;
043: import org.w3c.dom.Node;
044:
045: /**
046: * An immutable stream-based buffer of an XML infoset.
047: *
048: * <p>
049: * A XMLStreamBuffer is an abstract class. It is immutable with
050: * respect to the methods on the class, which are non-modifying in terms
051: * of state.
052: *
053: * <p>
054: * A XMLStreamBuffer can be processed using specific SAX and StAX-based
055: * processors. Utility methods on XMLStreamBuffer are provided for
056: * such functionality that utilize SAX and StAX-based processors.
057: * The same instance of a XMLStreamBuffer may be processed
058: * multiple times and concurrently by more than one processor.
059: *
060: * <p>
061: * There are two concrete implementations of XMLStreamBuffer.
062: * The first, {@link MutableXMLStreamBuffer}, can be instantiated for the creation
063: * of a buffer using SAX and StAX-based creators, and from which may be
064: * processed as an XMLStreamBuffer. The second,
065: * {@link XMLStreamBufferMark}, can be instantiated to mark into an existing
066: * buffer that is being created or processed. This allows a subtree of
067: * {@link XMLStreamBuffer} to be treated as its own {@link XMLStreamBuffer}.
068: *
069: * <p>
070: * A XMLStreamBuffer can represent a complete XML infoset or a subtree
071: * of an XML infoset. It is also capable of representing a "forest",
072: * where the buffer represents multiple adjacent XML elements, although
073: * in this mode there are restrictions about how you can consume such
074: * forest, because not all XML APIs handle forests very well.
075: */
076: public abstract class XMLStreamBuffer {
077:
078: /**
079: * In scope namespaces on a fragment
080: */
081: protected Map<String, String> _inscopeNamespaces = Collections
082: .emptyMap();
083:
084: /**
085: * True if the buffer was created from a parser that interns Strings
086: * as specified by the SAX interning features
087: */
088: protected boolean _hasInternedStrings;
089:
090: /**
091: * Fragmented array to hold structural information
092: */
093: protected FragmentedArray<byte[]> _structure;
094: protected int _structurePtr;
095:
096: /**
097: * Fragmented array to hold structural information as strings
098: */
099: protected FragmentedArray<String[]> _structureStrings;
100: protected int _structureStringsPtr;
101:
102: /**
103: * Fragmented array to hold content information in a shared char[]
104: */
105: protected FragmentedArray<char[]> _contentCharactersBuffer;
106: protected int _contentCharactersBufferPtr;
107:
108: /**
109: * Fragmented array to hold content information as objects
110: */
111: protected FragmentedArray<Object[]> _contentObjects;
112: protected int _contentObjectsPtr;
113:
114: /**
115: * Number of trees in this stream buffer.
116: *
117: * <p>
118: * 1 if there's only one, which is the normal case. When the buffer
119: * holds a forest, this value is greater than 1. If the buffer is empty, then 0.
120: *
121: * <p>
122: * Notice that we cannot infer this value by looking at the {@link FragmentedArray}s,
123: * because this {@link XMLStreamBuffer} maybe a view of a portion of another bigger
124: * {@link XMLStreamBuffer}.
125: */
126: protected int treeCount;
127:
128: /**
129: * The system identifier associated with the buffer
130: */
131: protected String systemId;
132:
133: /**
134: * Is the buffer created by creator.
135: *
136: * @return
137: * <code>true</code> if the buffer has been created.
138: */
139: public final boolean isCreated() {
140: return _structure.getArray()[0] != AbstractCreatorProcessor.T_END;
141: }
142:
143: /**
144: * Is the buffer a representation of a fragment of an XML infoset.
145: *
146: * @return
147: * <code>true</code> if the buffer is a representation of a fragment
148: * of an XML infoset.
149: */
150: public final boolean isFragment() {
151: return (isCreated() && (_structure.getArray()[_structurePtr] & AbstractCreatorProcessor.TYPE_MASK) != AbstractCreatorProcessor.T_DOCUMENT);
152: }
153:
154: /**
155: * Is the buffer a representation of a fragment of an XML infoset
156: * that is an element (and its contents).
157: *
158: * @return
159: * <code>true</code> if the buffer a representation
160: * of a fragment of an XML infoset that is an element (and its contents).
161: */
162: public final boolean isElementFragment() {
163: return (isCreated() && (_structure.getArray()[_structurePtr] & AbstractCreatorProcessor.TYPE_MASK) == AbstractCreatorProcessor.T_ELEMENT);
164: }
165:
166: /**
167: * Returns ture if this buffer represents a forest, which is
168: * are more than one adjacent XML elements.
169: */
170: public final boolean isForest() {
171: return isCreated() && treeCount > 1;
172: }
173:
174: /**
175: * Get the system identifier associated with the buffer.
176: * @return The system identifier.
177: */
178: public final String getSystemId() {
179: return systemId;
180: }
181:
182: /**
183: * Get the in-scope namespaces.
184: *
185: * <p>
186: *
187: * The in-scope namespaces will be empty if the buffer is not a
188: * fragment ({@link #isFragment} returns <code>false</code>).
189: *
190: * The in-scope namespace will correspond to the in-scope namespaces of the
191: * fragment if the buffer is a fragment ({@link #isFragment}
192: * returns <code>false</code>). The in-scope namespaces will include any
193: * namespace delcarations on an element if the fragment correspond to that
194: * of an element ({@link #isElementFragment} returns <code>false</code>).
195: *
196: * @return
197: * The in-scope namespaces of the XMLStreamBuffer.
198: * Prefix to namespace URI.
199: */
200: public final Map<String, String> getInscopeNamespaces() {
201: return _inscopeNamespaces;
202: }
203:
204: /**
205: * Has the buffer been created using Strings that have been interned
206: * for certain properties of information items. The Strings that are interned
207: * are those that correspond to Strings that are specified by the SAX API
208: * "string-interning" property
209: * (see <a href="http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/package-summary.html#package_description">here</a>).
210: *
211: * <p>
212: * An buffer may have been created, for example, from an XML document parsed
213: * using the Xerces SAX parser. The Xerces SAX parser will have interned certain Strings
214: * according to the SAX string interning property.
215: * This method enables processors to avoid the duplication of
216: * String interning if such a feature is required by a procesing application and the
217: * buffer being processed was created using Strings that have been interned.
218: *
219: * @return
220: * <code>true</code> if the buffer has been created using Strings that
221: * have been interned.
222: */
223: public final boolean hasInternedStrings() {
224: return _hasInternedStrings;
225: }
226:
227: /**
228: * Read the contents of the buffer as a {@link XMLStreamReader}.
229: *
230: * @return
231: * A an instance of a {@link StreamReaderBufferProcessor}. Always non-null.
232: */
233: public final StreamReaderBufferProcessor readAsXMLStreamReader()
234: throws XMLStreamException {
235: return new StreamReaderBufferProcessor(this );
236: }
237:
238: /**
239: * Write the contents of the buffer to an XMLStreamWriter.
240: *
241: * <p>
242: * The XMLStreamBuffer will be written out to the XMLStreamWriter using
243: * an instance of {@link StreamWriterBufferProcessor}.
244: *
245: * @param writer
246: * A XMLStreamWriter to write to.
247: * @param writeAsFragment
248: * If true, {@link XMLStreamWriter} will not receive {@link XMLStreamWriter#writeStartDocument()}
249: * nor {@link XMLStreamWriter#writeEndDocument()}. This is desirable behavior when
250: * you are writing the contents of a buffer into a bigger document.
251: */
252: public final void writeToXMLStreamWriter(XMLStreamWriter writer,
253: boolean writeAsFragment) throws XMLStreamException {
254: StreamWriterBufferProcessor p = new StreamWriterBufferProcessor(
255: this , writeAsFragment);
256: p.process(writer);
257: }
258:
259: /**
260: * @deprecated
261: * Use {@link #writeToXMLStreamWriter(XMLStreamWriter, boolean)}
262: */
263: public final void writeToXMLStreamWriter(XMLStreamWriter writer)
264: throws XMLStreamException {
265: writeToXMLStreamWriter(writer, this .isFragment());
266: }
267:
268: /**
269: * Reads the contents of the buffer from a {@link XMLReader}.
270: *
271: * @return
272: * A an instance of a {@link SAXBufferProcessor}.
273: * @deprecated
274: * Use {@link #readAsXMLReader(boolean)}
275: */
276: public final SAXBufferProcessor readAsXMLReader() {
277: return new SAXBufferProcessor(this , isFragment());
278: }
279:
280: /**
281: * Reads the contents of the buffer from a {@link XMLReader}.
282: *
283: * @param produceFragmentEvent
284: * True to generate fragment SAX events without start/endDocument.
285: * False to generate a full document SAX events.
286: * @return
287: * A an instance of a {@link SAXBufferProcessor}.
288: */
289: public final SAXBufferProcessor readAsXMLReader(
290: boolean produceFragmentEvent) {
291: return new SAXBufferProcessor(this , produceFragmentEvent);
292: }
293:
294: /**
295: * Write the contents of the buffer to a {@link ContentHandler}.
296: *
297: * <p>
298: * If the <code>handler</code> is also an instance of other SAX-based
299: * handlers, such as {@link LexicalHandler}, than corresponding SAX events
300: * will be reported to those handlers.
301: *
302: * @param handler
303: * The ContentHandler to receive SAX events.
304: * @param produceFragmentEvent
305: * True to generate fragment SAX events without start/endDocument.
306: * False to generate a full document SAX events.
307: *
308: * @throws SAXException
309: * if a parsing fails, or if {@link ContentHandler} throws a {@link SAXException}.
310: */
311: public final void writeTo(ContentHandler handler,
312: boolean produceFragmentEvent) throws SAXException {
313: SAXBufferProcessor p = readAsXMLReader(produceFragmentEvent);
314: p.setContentHandler(handler);
315: if (p instanceof LexicalHandler) {
316: p.setLexicalHandler((LexicalHandler) handler);
317: }
318: if (p instanceof DTDHandler) {
319: p.setDTDHandler((DTDHandler) handler);
320: }
321: if (p instanceof ErrorHandler) {
322: p.setErrorHandler((ErrorHandler) handler);
323: }
324: p.process();
325: }
326:
327: /**
328: * @deprecated
329: * Use {@link #writeTo(ContentHandler,boolean)}
330: */
331: public final void writeTo(ContentHandler handler)
332: throws SAXException {
333: writeTo(handler, isFragment());
334: }
335:
336: /**
337: * Write the contents of the buffer to a {@link ContentHandler} with errors
338: * report to a {@link ErrorHandler}.
339: *
340: * <p>
341: * If the <code>handler</code> is also an instance of other SAX-based
342: * handlers, such as {@link LexicalHandler}, than corresponding SAX events
343: * will be reported to those handlers.
344: *
345: * @param handler
346: * The ContentHandler to receive SAX events.
347: * @param errorHandler
348: * The ErrorHandler to receive error events.
349: *
350: * @throws SAXException
351: * if a parsing fails and {@link ErrorHandler} throws a {@link SAXException},
352: * or if {@link ContentHandler} throws a {@link SAXException}.
353: */
354: public final void writeTo(ContentHandler handler,
355: ErrorHandler errorHandler, boolean produceFragmentEvent)
356: throws SAXException {
357: SAXBufferProcessor p = readAsXMLReader(produceFragmentEvent);
358: p.setContentHandler(handler);
359: if (p instanceof LexicalHandler) {
360: p.setLexicalHandler((LexicalHandler) handler);
361: }
362: if (p instanceof DTDHandler) {
363: p.setDTDHandler((DTDHandler) handler);
364: }
365:
366: p.setErrorHandler(errorHandler);
367:
368: p.process();
369: }
370:
371: public final void writeTo(ContentHandler handler,
372: ErrorHandler errorHandler) throws SAXException {
373: writeTo(handler, errorHandler, isFragment());
374: }
375:
376: private static final TransformerFactory trnsformerFactory = TransformerFactory
377: .newInstance();
378:
379: /**
380: * Writes out the contents of this buffer as DOM node and append that to the given node.
381: *
382: * Faster implementation would be desirable.
383: *
384: * @return
385: * The newly added child node.
386: */
387: public final Node writeTo(Node n) throws XMLStreamBufferException {
388: try {
389: Transformer t = trnsformerFactory.newTransformer();
390: t.transform(new XMLStreamBufferSource(this ), new DOMResult(
391: n));
392: return n.getLastChild();
393: } catch (TransformerException e) {
394: throw new XMLStreamBufferException(e);
395: }
396: }
397:
398: /**
399: * Create a new buffer from a XMLStreamReader.
400: *
401: * @param reader
402: * A XMLStreamReader to read from to create.
403: * @return XMLStreamBuffer the created buffer
404: * @see MutableXMLStreamBuffer#createFromXMLStreamReader(XMLStreamReader)
405: */
406: public static XMLStreamBuffer createNewBufferFromXMLStreamReader(
407: XMLStreamReader reader) throws XMLStreamException {
408: MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
409: b.createFromXMLStreamReader(reader);
410: return b;
411: }
412:
413: /**
414: * Create a new buffer from a {@link XMLReader} and {@link InputStream}.
415: *
416: * @param reader
417: * The {@link XMLReader} to use for parsing.
418: * @param in
419: * The {@link InputStream} to be parsed.
420: * @return XMLStreamBuffer the created buffer
421: * @see MutableXMLStreamBuffer#createFromXMLReader(XMLReader, InputStream)
422: */
423: public static XMLStreamBuffer createNewBufferFromXMLReader(
424: XMLReader reader, InputStream in) throws SAXException,
425: IOException {
426: MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
427: b.createFromXMLReader(reader, in);
428: return b;
429: }
430:
431: /**
432: * Create a new buffer from a {@link XMLReader} and {@link InputStream}.
433: *
434: * @param reader
435: * The {@link XMLReader} to use for parsing.
436: * @param in
437: * The {@link InputStream} to be parsed.
438: * @param systemId
439: * The system ID of the input stream.
440: * @return XMLStreamBuffer the created buffer
441: * @see MutableXMLStreamBuffer#createFromXMLReader(XMLReader, InputStream, String)
442: */
443: public static XMLStreamBuffer createNewBufferFromXMLReader(
444: XMLReader reader, InputStream in, String systemId)
445: throws SAXException, IOException {
446: MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
447: b.createFromXMLReader(reader, in, systemId);
448: return b;
449: }
450:
451: protected final FragmentedArray<byte[]> getStructure() {
452: return _structure;
453: }
454:
455: protected final int getStructurePtr() {
456: return _structurePtr;
457: }
458:
459: protected final FragmentedArray<String[]> getStructureStrings() {
460: return _structureStrings;
461: }
462:
463: protected final int getStructureStringsPtr() {
464: return _structureStringsPtr;
465: }
466:
467: protected final FragmentedArray<char[]> getContentCharactersBuffer() {
468: return _contentCharactersBuffer;
469: }
470:
471: protected final int getContentCharactersBufferPtr() {
472: return _contentCharactersBufferPtr;
473: }
474:
475: protected final FragmentedArray<Object[]> getContentObjects() {
476: return _contentObjects;
477: }
478:
479: protected final int getContentObjectsPtr() {
480: return _contentObjectsPtr;
481: }
482: }
|