1 /*
   2  * Copyright (c) 2005, 2010, 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.Properties;
  29 import com.sun.xml.internal.stream.buffer.sax.SAXBufferCreator;
  30 import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferCreator;
  31 import com.sun.xml.internal.stream.buffer.stax.StreamWriterBufferCreator;
  32 import org.xml.sax.ContentHandler;
  33 import org.xml.sax.SAXException;
  34 import org.xml.sax.XMLReader;
  35 
  36 import javax.xml.stream.XMLStreamException;
  37 import javax.xml.stream.XMLStreamReader;
  38 import javax.xml.stream.XMLStreamWriter;
  39 import java.io.IOException;
  40 import java.io.InputStream;
  41 
  42 /**
  43  *
  44  * A mutable stream-based buffer of an XML infoset.
  45  *
  46  * <p>
  47  * A MutableXMLStreamBuffer is created using specific SAX and StAX-based
  48  * creators. Utility methods on MutableXMLStreamBuffer are provided for
  49  * such functionality that utilize SAX and StAX-based creators.
  50  *
  51  * <p>
  52  * Once instantiated the same instance of a MutableXMLStreamBuffer may be reused for
  53  * creation to reduce the amount of Objects instantiated and garbage
  54  * collected that are required for internally representing an XML infoset.
  55  *
  56  * <p>
  57  * A MutableXMLStreamBuffer is not designed to be created and processed
  58  * concurrently. If done so unspecified behaviour may occur.
  59  */
  60 public class MutableXMLStreamBuffer extends XMLStreamBuffer {
  61     /**
  62      * The default array size for the arrays used in internal representation
  63      * of the XML infoset.
  64      */
  65     public static final int DEFAULT_ARRAY_SIZE = 512;
  66 
  67     /**
  68      * Create a new MutableXMLStreamBuffer using the
  69      * {@link MutableXMLStreamBuffer#DEFAULT_ARRAY_SIZE}.
  70      */
  71     public MutableXMLStreamBuffer() {
  72         this(DEFAULT_ARRAY_SIZE);
  73     }
  74 
  75     /**
  76      * Set the system identifier for this buffer.
  77      * @param systemId The system identifier.
  78      */
  79     public void setSystemId(String systemId) {
  80         this.systemId = systemId;
  81     }
  82 
  83     /**
  84      * Create a new MutableXMLStreamBuffer.
  85      *
  86      * @param size
  87      * The size of the arrays used in the internal representation
  88      * of the XML infoset.
  89      * @throws NegativeArraySizeException
  90      * If the <code>size</code> argument is less than <code>0</code>.
  91      */
  92     public MutableXMLStreamBuffer(int size) {
  93         _structure = new FragmentedArray<byte[]>(new byte[size]);
  94         _structureStrings = new FragmentedArray<String[]>(new String[size]);
  95         _contentCharactersBuffer = new FragmentedArray<char[]>(new char[4096]);
  96         _contentObjects = new FragmentedArray<Object[]>(new Object[size]);
  97 
  98         // Set the first element of structure array to indicate an empty buffer
  99         // that has not been created
 100         _structure.getArray()[0] = (byte) AbstractCreatorProcessor.T_END;
 101     }
 102 
 103     /**
 104      * Create contents of a buffer from a XMLStreamReader.
 105      *
 106      * <p>
 107      * The MutableXMLStreamBuffer is reset (see {@link #reset}) before creation.
 108      *
 109      * <p>
 110      * The MutableXMLStreamBuffer is created by consuming the events on the XMLStreamReader using
 111      * an instance of {@link StreamReaderBufferCreator}.
 112      *
 113      * @param reader
 114      * A XMLStreamReader to read from to create.
 115      */
 116     public void createFromXMLStreamReader(XMLStreamReader reader) throws XMLStreamException {
 117         reset();
 118         StreamReaderBufferCreator c = new StreamReaderBufferCreator(this);
 119         c.create(reader);
 120     }
 121 
 122     /**
 123      * Create contents of a buffer from a XMLStreamWriter.
 124      *
 125      * <p>
 126      * The MutableXMLStreamBuffer is reset (see {@link #reset}) before creation.
 127      *
 128      * <p>
 129      * The MutableXMLStreamBuffer is created by consuming events on a XMLStreamWriter using
 130      * an instance of {@link StreamWriterBufferCreator}.
 131      */
 132     public XMLStreamWriter createFromXMLStreamWriter() {
 133         reset();
 134         return new StreamWriterBufferCreator(this);
 135     }
 136 
 137     /**
 138      * Create contents of a buffer from a {@link SAXBufferCreator}.
 139      *
 140      * <p>
 141      * The MutableXMLStreamBuffer is reset (see {@link #reset}) before creation.
 142      *
 143      * <p>
 144      * The MutableXMLStreamBuffer is created by consuming events from a {@link ContentHandler} using
 145      * an instance of {@link SAXBufferCreator}.
 146      *
 147      * @return The {@link SAXBufferCreator} to create from.
 148      */
 149     public SAXBufferCreator createFromSAXBufferCreator() {
 150         reset();
 151         SAXBufferCreator c = new SAXBufferCreator();
 152         c.setBuffer(this);
 153         return c;
 154     }
 155 
 156     /**
 157      * Create contents of a buffer from a {@link XMLReader} and {@link InputStream}.
 158      *
 159      * <p>
 160      * The MutableXMLStreamBuffer is reset (see {@link #reset}) before creation.
 161      *
 162      * <p>
 163      * The MutableXMLStreamBuffer is created by using an instance of {@link SAXBufferCreator}
 164      * and registering associated handlers on the {@link XMLReader}.
 165      *
 166      * @param reader
 167      * The {@link XMLReader} to use for parsing.
 168      * @param in
 169      * The {@link InputStream} to be parsed.
 170      */
 171     public void createFromXMLReader(XMLReader reader, InputStream in) throws SAXException, IOException {
 172         createFromXMLReader(reader, in, null);
 173     }
 174 
 175     /**
 176      * Create contents of a buffer from a {@link XMLReader} and {@link InputStream}.
 177      *
 178      * <p>
 179      * The MutableXMLStreamBuffer is reset (see {@link #reset}) before creation.
 180      *
 181      * <p>
 182      * The MutableXMLStreamBuffer is created by using an instance of {@link SAXBufferCreator}
 183      * and registering associated handlers on the {@link XMLReader}.
 184      *
 185      * @param reader
 186      * The {@link XMLReader} to use for parsing.
 187      * @param in
 188      * The {@link InputStream} to be parsed.
 189      * @param systemId
 190      * The system ID of the input stream.
 191      */
 192     public void createFromXMLReader(XMLReader reader, InputStream in, String systemId) throws SAXException, IOException {
 193         reset();
 194         SAXBufferCreator c = new SAXBufferCreator(this);
 195 
 196         reader.setContentHandler(c);
 197         reader.setDTDHandler(c);
 198         reader.setProperty(Properties.LEXICAL_HANDLER_PROPERTY, c);
 199 
 200         c.create(reader, in, systemId);
 201     }
 202 
 203     /**
 204      * Reset the MutableXMLStreamBuffer.
 205      *
 206      * <p>
 207      * This method will reset the MutableXMLStreamBuffer to a state of being "uncreated"
 208      * similar to the state of a newly instantiated MutableXMLStreamBuffer.
 209      *
 210      * <p>
 211      * As many Objects as possible will be retained for reuse in future creation.
 212      */
 213     public void reset() {
 214         // Reset the ptrs in arrays to 0
 215         _structurePtr =
 216                 _structureStringsPtr =
 217                 _contentCharactersBufferPtr =
 218                 _contentObjectsPtr = 0;
 219 
 220         // Set the first element of structure array to indicate an empty buffer
 221         // that has not been created
 222         _structure.getArray()[0] = (byte)AbstractCreatorProcessor.T_END;
 223 
 224         // Clean up content objects
 225         _contentObjects.setNext(null);
 226         final Object[] o = _contentObjects.getArray();
 227         for (int i = 0; i < o.length; i++) {
 228             if (o[i] != null) {
 229                 o[i] = null;
 230             } else {
 231                 break;
 232             }
 233         }
 234 
 235         treeCount = 0;
 236 
 237         /*
 238          * TODO consider truncating the size of _structureStrings and
 239          * _contentCharactersBuffer to limit the memory used by the buffer
 240          */
 241     }
 242 
 243 
 244     protected void setHasInternedStrings(boolean hasInternedStrings) {
 245         _hasInternedStrings = hasInternedStrings;
 246     }
 247 }