src/share/jaxws_classes/com/sun/xml/internal/stream/buffer/XMLStreamBuffer.java

Fri, 14 Feb 2014 11:13:45 +0100

author
mkos
date
Fri, 14 Feb 2014 11:13:45 +0100
changeset 558
d950f4a0753b
parent 515
6cd506508147
child 637
9c07ef4934dd
permissions
-rw-r--r--

8026188: Enhance envelope factory
Summary: Avoiding caching data initialized via TCCL in static context; fix also reviewed by Alexander Fomin
Reviewed-by: ahgross, mgrebac, skoivu

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

mercurial