1 /*
2  * Copyright (c) 2005, 2014, 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      */
isCreated()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      */
isFragment()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      */
isElementFragment()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      */
isForest()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      */
getSystemId()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      */
getInscopeNamespaces()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      */
hasInternedStrings()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      */
readAsXMLStreamReader()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      */
writeToXMLStreamWriter(XMLStreamWriter writer, boolean writeAsFragment)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      */
writeToXMLStreamWriter(XMLStreamWriter writer)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      */
readAsXMLReader()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      */
readAsXMLReader(boolean produceFragmentEvent)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      */
writeTo(ContentHandler handler, boolean produceFragmentEvent)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      */
writeTo(ContentHandler handler)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      */
writeTo(ContentHandler handler, ErrorHandler errorHandler, boolean produceFragmentEvent)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 
writeTo(ContentHandler handler, ErrorHandler errorHandler)369     public final void writeTo(ContentHandler handler, ErrorHandler errorHandler) throws SAXException {
370         writeTo(handler, errorHandler, isFragment());
371     }
372 
373     private static final ContextClassloaderLocal<TransformerFactory> trnsformerFactory = new ContextClassloaderLocal<TransformerFactory>() {
374         @Override
375         protected TransformerFactory initialValue() throws Exception {
376             return TransformerFactory.newInstance();
377         }
378     };
379 
380     /**
381      * Writes out the contents of this buffer as DOM node and append that to the given node.
382      *
383      * Faster implementation would be desirable.
384      *
385      * @return
386      *      The newly added child node.
387      */
writeTo(Node n)388     public final Node writeTo(Node n) throws XMLStreamBufferException {
389         try {
390             Transformer t = trnsformerFactory.get().newTransformer();
391             t.transform(new XMLStreamBufferSource(this), new DOMResult(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      */
createNewBufferFromXMLStreamReader(XMLStreamReader reader)406     public static XMLStreamBuffer createNewBufferFromXMLStreamReader(XMLStreamReader reader)
407             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      */
createNewBufferFromXMLReader(XMLReader reader, InputStream in)423     public static XMLStreamBuffer createNewBufferFromXMLReader(XMLReader reader, InputStream in) throws SAXException, IOException {
424         MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
425         b.createFromXMLReader(reader, in);
426         return b;
427     }
428 
429     /**
430      * Create a new buffer from a {@link XMLReader} and {@link InputStream}.
431      *
432      * @param reader
433      * The {@link XMLReader} to use for parsing.
434      * @param in
435      * The {@link InputStream} to be parsed.
436      * @param systemId
437      * The system ID of the input stream.
438      * @return XMLStreamBuffer the created buffer
439      * @see MutableXMLStreamBuffer#createFromXMLReader(XMLReader, InputStream, String)
440      */
createNewBufferFromXMLReader(XMLReader reader, InputStream in, String systemId)441     public static XMLStreamBuffer createNewBufferFromXMLReader(XMLReader reader, InputStream in,
442                                                                String systemId) throws SAXException, IOException {
443         MutableXMLStreamBuffer b = new MutableXMLStreamBuffer();
444         b.createFromXMLReader(reader, in, systemId);
445         return b;
446     }
447 
getStructure()448     protected final FragmentedArray<byte[]> getStructure() {
449         return _structure;
450     }
451 
getStructurePtr()452     protected final int getStructurePtr() {
453         return _structurePtr;
454     }
455 
getStructureStrings()456     protected final FragmentedArray<String[]> getStructureStrings() {
457         return _structureStrings;
458     }
459 
getStructureStringsPtr()460     protected final int getStructureStringsPtr() {
461         return _structureStringsPtr;
462     }
463 
getContentCharactersBuffer()464     protected final FragmentedArray<char[]> getContentCharactersBuffer() {
465         return _contentCharactersBuffer;
466     }
467 
getContentCharactersBufferPtr()468     protected final int getContentCharactersBufferPtr() {
469         return _contentCharactersBufferPtr;
470     }
471 
getContentObjects()472     protected final FragmentedArray<Object[]> getContentObjects() {
473         return _contentObjects;
474     }
475 
getContentObjectsPtr()476     protected final int getContentObjectsPtr() {
477         return _contentObjectsPtr;
478     }
479 }
480