View Javadoc
1   /*
2    * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.stream.buffer;
27  
28  import com.sun.xml.internal.stream.buffer.sax.SAXBufferProcessor;
29  import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferProcessor;
30  import com.sun.xml.internal.stream.buffer.stax.StreamWriterBufferProcessor;
31  import java.io.IOException;
32  import java.io.InputStream;
33  import java.util.Collections;
34  import java.util.Map;
35  import javax.xml.stream.XMLStreamException;
36  import javax.xml.stream.XMLStreamReader;
37  import javax.xml.stream.XMLStreamWriter;
38  import javax.xml.transform.TransformerFactory;
39  import javax.xml.transform.Transformer;
40  import javax.xml.transform.TransformerException;
41  import javax.xml.transform.dom.DOMResult;
42  
43  import org.xml.sax.ContentHandler;
44  import org.xml.sax.DTDHandler;
45  import org.xml.sax.ErrorHandler;
46  import org.xml.sax.SAXException;
47  import org.xml.sax.XMLReader;
48  import org.xml.sax.ext.LexicalHandler;
49  import org.w3c.dom.Node;
50  
51  /**
52   * An immutable stream-based buffer of an XML infoset.
53   *
54   * <p>
55   * A XMLStreamBuffer is an abstract class. It is immutable with
56   * respect to the methods on the class, which are non-modifying in terms
57   * of state.
58   *
59   * <p>
60   * A XMLStreamBuffer can be processed using specific SAX and StAX-based
61   * processors. Utility methods on XMLStreamBuffer are provided for
62   * such functionality that utilize SAX and StAX-based processors.
63   * The same instance of a XMLStreamBuffer may be processed
64   * multiple times and concurrently by more than one processor.
65   *
66   * <p>
67   * There are two concrete implementations of XMLStreamBuffer.
68   * The first, {@link MutableXMLStreamBuffer}, can be instantiated for the creation
69   * of a buffer using SAX and StAX-based creators, and from which may be
70   * processed as an XMLStreamBuffer. The second,
71   * {@link XMLStreamBufferMark}, can be instantiated to mark into an existing
72   * buffer that is being created or processed. This allows a subtree of
73   * {@link XMLStreamBuffer} to be treated as its own {@link XMLStreamBuffer}.
74   *
75   * <p>
76   * A XMLStreamBuffer can represent a complete XML infoset or a subtree
77   * of an XML infoset. It is also capable of representing a "forest",
78   * where the buffer represents multiple adjacent XML elements, although
79   * in this mode there are restrictions about how you can consume such
80   * forest, because not all XML APIs handle forests very well.
81   */
82  public abstract class XMLStreamBuffer {
83  
84      /**
85       * In scope namespaces on a fragment
86       */
87      protected Map<String,String> _inscopeNamespaces = Collections.emptyMap();
88  
89      /**
90       * True if the buffer was created from a parser that interns Strings
91       * as specified by the SAX interning features
92       */
93      protected boolean _hasInternedStrings;
94  
95      /**
96       * Fragmented array to hold structural information
97       */
98      protected FragmentedArray<byte[]> _structure;
99      protected int _structurePtr;
100 
101     /**
102      * Fragmented array to hold structural information as strings
103      */
104     protected FragmentedArray<String[]> _structureStrings;
105     protected int _structureStringsPtr;
106 
107     /**
108      * Fragmented array to hold content information in a shared char[]
109      */
110     protected FragmentedArray<char[]> _contentCharactersBuffer;
111     protected int _contentCharactersBufferPtr;
112 
113     /**
114      * Fragmented array to hold content information as objects
115      */
116     protected FragmentedArray<Object[]> _contentObjects;
117     protected int _contentObjectsPtr;
118 
119     /**
120      * Number of trees in this stream buffer.
121      *
122      * <p>
123      * 1 if there's only one, which is the normal case. When the buffer
124      * holds a forest, this value is greater than 1. If the buffer is empty, then 0.
125      *
126      * <p>
127      * Notice that we cannot infer this value by looking at the {@link FragmentedArray}s,
128      * because this {@link XMLStreamBuffer} maybe a view of a portion of another bigger
129      * {@link XMLStreamBuffer}.
130      */
131     protected int treeCount;
132 
133     /**
134      * The system identifier associated with the buffer
135      */
136     protected String systemId;
137 
138     /**
139      * Is the buffer created by creator.
140      *
141      * @return
142      * <code>true</code> if the buffer has been created.
143      */
144     public final boolean isCreated() {
145         return _structure.getArray()[0] != AbstractCreatorProcessor.T_END;
146     }
147 
148     /**
149      * Is the buffer a representation of a fragment of an XML infoset.
150      *
151      * @return
152      * <code>true</code> if the buffer is a representation of a fragment
153      * of an XML infoset.
154      */
155     public final boolean isFragment() {
156         return (isCreated() && (_structure.getArray()[_structurePtr] & AbstractCreatorProcessor.TYPE_MASK)
157                 != AbstractCreatorProcessor.T_DOCUMENT);
158     }
159 
160     /**
161      * Is the buffer a representation of a fragment of an XML infoset
162      * that is an element (and its contents).
163      *
164      * @return
165      * <code>true</code> if the buffer a representation
166      * of a fragment of an XML infoset that is an element (and its contents).
167      */
168     public final boolean isElementFragment() {
169         return (isCreated() && (_structure.getArray()[_structurePtr] & AbstractCreatorProcessor.TYPE_MASK)
170                 == AbstractCreatorProcessor.T_ELEMENT);
171     }
172 
173     /**
174      * Returns ture if this buffer represents a forest, which is
175      * are more than one adjacent XML elements.
176      */
177     public final boolean isForest() {
178         return isCreated() && treeCount>1;
179     }
180 
181     /**
182      * Get the system identifier associated with the buffer.
183      * @return The system identifier.
184      */
185     public final String getSystemId() {
186         return systemId;
187     }
188 
189     /**
190      * Get the in-scope namespaces.
191      *
192      * <p>
193      *
194      * The in-scope namespaces will be empty if the buffer is not a
195      * fragment ({@link #isFragment} returns <code>false</code>).
196      *
197      * The in-scope namespace will correspond to the in-scope namespaces of the
198      * fragment if the buffer is a fragment ({@link #isFragment}
199      * returns <code>false</code>). The in-scope namespaces will include any
200      * namespace delcarations on an element if the fragment correspond to that
201      * of an element ({@link #isElementFragment} returns <code>false</code>).
202      *
203      * @return
204      *      The in-scope namespaces of the XMLStreamBuffer.
205      *      Prefix to namespace URI.
206      */
207     public final Map<String,String> getInscopeNamespaces() {
208         return _inscopeNamespaces;
209     }
210 
211     /**
212      * Has the buffer been created using Strings that have been interned
213      * for certain properties of information items. The Strings that are interned
214      * are those that correspond to Strings that are specified by the SAX API
215      * "string-interning" property
216      * (see <a href="http://java.sun.com/j2se/1.5.0/docs/api/org/xml/sax/package-summary.html#package_description">here</a>).
217      *
218      * <p>
219      * An buffer may have been created, for example, from an XML document parsed
220      * using the Xerces SAX parser. The Xerces SAX parser will have interned certain Strings
221      * according to the SAX string interning property.
222      * This method enables processors to avoid the duplication of
223      * String interning if such a feature is required by a procesing application and the
224      * buffer being processed was created using Strings that have been interned.
225      *
226      * @return
227      * <code>true</code> if the buffer has been created using Strings that
228      * have been interned.
229      */
230     public final boolean hasInternedStrings() {
231         return _hasInternedStrings;
232     }
233 
234     /**
235      * Read the contents of the buffer as a {@link XMLStreamReader}.
236      *
237      * @return
238      * A an instance of a {@link StreamReaderBufferProcessor}. Always non-null.
239      */
240     public final StreamReaderBufferProcessor readAsXMLStreamReader() throws XMLStreamException {
241         return new StreamReaderBufferProcessor(this);
242     }
243 
244     /**
245      * Write the contents of the buffer to an XMLStreamWriter.
246      *
247      * <p>
248      * The XMLStreamBuffer will be written out to the XMLStreamWriter using
249      * an instance of {@link StreamWriterBufferProcessor}.
250      *
251      * @param writer
252      *      A XMLStreamWriter to write to.
253      * @param writeAsFragment
254      *      If true, {@link XMLStreamWriter} will not receive {@link XMLStreamWriter#writeStartDocument()}
255      *      nor {@link XMLStreamWriter#writeEndDocument()}. This is desirable behavior when
256      *      you are writing the contents of a buffer into a bigger document.
257      */
258     public final void writeToXMLStreamWriter(XMLStreamWriter writer, boolean writeAsFragment) throws XMLStreamException {
259         StreamWriterBufferProcessor p = new StreamWriterBufferProcessor(this,writeAsFragment);
260         p.process(writer);
261     }
262 
263     /**
264      * @deprecated
265      *      Use {@link #writeToXMLStreamWriter(XMLStreamWriter, boolean)}
266      */
267     public final void writeToXMLStreamWriter(XMLStreamWriter writer) throws XMLStreamException {
268         writeToXMLStreamWriter(writer, this.isFragment());
269     }
270 
271     /**
272      * Reads the contents of the buffer from a {@link XMLReader}.
273      *
274      * @return
275      * A an instance of a {@link SAXBufferProcessor}.
276      * @deprecated
277      *      Use {@link #readAsXMLReader(boolean)}
278      */
279     public final SAXBufferProcessor readAsXMLReader() {
280         return new SAXBufferProcessor(this,isFragment());
281     }
282 
283     /**
284      * Reads the contents of the buffer from a {@link XMLReader}.
285      *
286      * @param produceFragmentEvent
287      *      True to generate fragment SAX events without start/endDocument.
288      *      False to generate a full document SAX events.
289      * @return
290      *      A an instance of a {@link SAXBufferProcessor}.
291      */
292     public final SAXBufferProcessor readAsXMLReader(boolean produceFragmentEvent) {
293         return new SAXBufferProcessor(this,produceFragmentEvent);
294     }
295 
296     /**
297      * Write the contents of the buffer to a {@link ContentHandler}.
298      *
299      * <p>
300      * If the <code>handler</code> is also an instance of other SAX-based
301      * handlers, such as {@link LexicalHandler}, than corresponding SAX events
302      * will be reported to those handlers.
303      *
304      * @param handler
305      *      The ContentHandler to receive SAX events.
306      * @param produceFragmentEvent
307      *      True to generate fragment SAX events without start/endDocument.
308      *      False to generate a full document SAX events.
309      *
310      * @throws SAXException
311      *      if a parsing fails, or if {@link ContentHandler} throws a {@link SAXException}.
312      */
313     public final void writeTo(ContentHandler handler, boolean produceFragmentEvent) throws SAXException {
314         SAXBufferProcessor p = readAsXMLReader(produceFragmentEvent);
315         p.setContentHandler(handler);
316         if (p instanceof LexicalHandler) {
317             p.setLexicalHandler((LexicalHandler)handler);
318         }
319         if (p instanceof DTDHandler) {
320             p.setDTDHandler((DTDHandler)handler);
321         }
322         if (p instanceof ErrorHandler) {
323             p.setErrorHandler((ErrorHandler)handler);
324         }
325         p.process();
326     }
327 
328     /**
329      * @deprecated
330      *      Use {@link #writeTo(ContentHandler,boolean)}
331      */
332     public final void writeTo(ContentHandler handler) 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, ErrorHandler errorHandler, boolean produceFragmentEvent) throws SAXException {
355         SAXBufferProcessor p = readAsXMLReader(produceFragmentEvent);
356         p.setContentHandler(handler);
357         if (p instanceof LexicalHandler) {
358             p.setLexicalHandler((LexicalHandler)handler);
359         }
360         if (p instanceof DTDHandler) {
361             p.setDTDHandler((DTDHandler)handler);
362         }
363 
364         p.setErrorHandler(errorHandler);
365 
366         p.process();
367     }
368 
369     public final void writeTo(ContentHandler handler, ErrorHandler errorHandler) throws SAXException {
370         writeTo(handler, errorHandler, isFragment());
371     }
372 
373     private static final TransformerFactory trnsformerFactory = TransformerFactory.newInstance();
374 
375     /**
376      * Writes out the contents of this buffer as DOM node and append that to the given node.
377      *
378      * Faster implementation would be desirable.
379      *
380      * @return
381      *      The newly added child node.
382      */
383     public final Node writeTo(Node n) throws XMLStreamBufferException {
384         try {
385             Transformer t = trnsformerFactory.newTransformer();
386             t.transform(new XMLStreamBufferSource(this), new DOMResult(n));
387             return n.getLastChild();
388         } catch (TransformerException e) {
389             throw new XMLStreamBufferException(e);
390         }
391     }
392 
393     /**
394      * Create a new buffer from a XMLStreamReader.
395      *
396      * @param reader
397      * A XMLStreamReader to read from to create.
398      * @return XMLStreamBuffer the created buffer
399      * @see MutableXMLStreamBuffer#createFromXMLStreamReader(XMLStreamReader)
400      */
401     public static XMLStreamBuffer createNewBufferFromXMLStreamReader(XMLStreamReader reader)
402             throws XMLStreamException {
403         MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
404         b.createFromXMLStreamReader(reader);
405         return b;
406     }
407 
408     /**
409      * Create a new buffer from a {@link XMLReader} and {@link InputStream}.
410      *
411      * @param reader
412      * The {@link XMLReader} to use for parsing.
413      * @param in
414      * The {@link InputStream} to be parsed.
415      * @return XMLStreamBuffer the created buffer
416      * @see MutableXMLStreamBuffer#createFromXMLReader(XMLReader, InputStream)
417      */
418     public static XMLStreamBuffer createNewBufferFromXMLReader(XMLReader reader, InputStream in) throws SAXException, IOException {
419         MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
420         b.createFromXMLReader(reader, in);
421         return b;
422     }
423 
424     /**
425      * Create a new buffer from a {@link XMLReader} and {@link InputStream}.
426      *
427      * @param reader
428      * The {@link XMLReader} to use for parsing.
429      * @param in
430      * The {@link InputStream} to be parsed.
431      * @param systemId
432      * The system ID of the input stream.
433      * @return XMLStreamBuffer the created buffer
434      * @see MutableXMLStreamBuffer#createFromXMLReader(XMLReader, InputStream, String)
435      */
436     public static XMLStreamBuffer createNewBufferFromXMLReader(XMLReader reader, InputStream in,
437                                                                String systemId) throws SAXException, IOException {
438         MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
439         b.createFromXMLReader(reader, in, systemId);
440         return b;
441     }
442 
443     protected final FragmentedArray<byte[]> getStructure() {
444         return _structure;
445     }
446 
447     protected final int getStructurePtr() {
448         return _structurePtr;
449     }
450 
451     protected final FragmentedArray<String[]> getStructureStrings() {
452         return _structureStrings;
453     }
454 
455     protected final int getStructureStringsPtr() {
456         return _structureStringsPtr;
457     }
458 
459     protected final FragmentedArray<char[]> getContentCharactersBuffer() {
460         return _contentCharactersBuffer;
461     }
462 
463     protected final int getContentCharactersBufferPtr() {
464         return _contentCharactersBufferPtr;
465     }
466 
467     protected final FragmentedArray<Object[]> getContentObjects() {
468         return _contentObjects;
469     }
470 
471     protected final int getContentObjectsPtr() {
472         return _contentObjectsPtr;
473     }
474 }