Thu, 31 Aug 2017 15:18:52 +0800
merge
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. Oracle designates this |
aoqi@0 | 8 | * particular file as subject to the "Classpath" exception as provided |
aoqi@0 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
aoqi@0 | 10 | * |
aoqi@0 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 15 | * accompanied this code). |
aoqi@0 | 16 | * |
aoqi@0 | 17 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 20 | * |
aoqi@0 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 22 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 23 | * questions. |
aoqi@0 | 24 | */ |
aoqi@0 | 25 | |
aoqi@0 | 26 | package com.sun.xml.internal.stream.buffer.stax; |
aoqi@0 | 27 | |
aoqi@0 | 28 | import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer; |
aoqi@0 | 29 | import com.sun.xml.internal.org.jvnet.staxex.Base64Data; |
aoqi@0 | 30 | import com.sun.xml.internal.org.jvnet.staxex.XMLStreamReaderEx; |
aoqi@0 | 31 | |
aoqi@0 | 32 | import javax.xml.stream.XMLStreamException; |
aoqi@0 | 33 | import javax.xml.stream.XMLStreamReader; |
aoqi@0 | 34 | import java.util.HashMap; |
aoqi@0 | 35 | import java.util.Map; |
aoqi@0 | 36 | |
aoqi@0 | 37 | /** |
aoqi@0 | 38 | * Create a buffer using an {@link XMLStreamReader}. |
aoqi@0 | 39 | * <p> |
aoqi@0 | 40 | * TODO: Implement the marking the stream on the element when an ID |
aoqi@0 | 41 | * attribute on the element is defined |
aoqi@0 | 42 | */ |
aoqi@0 | 43 | public class StreamReaderBufferCreator extends StreamBufferCreator { |
aoqi@0 | 44 | private int _eventType; |
aoqi@0 | 45 | private boolean _storeInScopeNamespacesOnElementFragment; |
aoqi@0 | 46 | private Map<String, Integer> _inScopePrefixes; |
aoqi@0 | 47 | |
aoqi@0 | 48 | /** |
aoqi@0 | 49 | * Create a stream reader buffer creator. |
aoqi@0 | 50 | * <p> |
aoqi@0 | 51 | * A stream buffer will be created for storing the infoset |
aoqi@0 | 52 | * from a stream reader. |
aoqi@0 | 53 | */ |
aoqi@0 | 54 | public StreamReaderBufferCreator() { |
aoqi@0 | 55 | } |
aoqi@0 | 56 | |
aoqi@0 | 57 | /** |
aoqi@0 | 58 | * Create a stream reader buffer creator using a mutable stream buffer. |
aoqi@0 | 59 | * <p> |
aoqi@0 | 60 | * @param buffer the mutable stream buffer. |
aoqi@0 | 61 | */ |
aoqi@0 | 62 | public StreamReaderBufferCreator(MutableXMLStreamBuffer buffer) { |
aoqi@0 | 63 | setBuffer(buffer); |
aoqi@0 | 64 | } |
aoqi@0 | 65 | |
aoqi@0 | 66 | /** |
aoqi@0 | 67 | * Create the buffer from a stream reader. |
aoqi@0 | 68 | * <p> |
aoqi@0 | 69 | * The stream reader must be positioned at the start of the document |
aoqi@0 | 70 | * or the start of an element. |
aoqi@0 | 71 | * <p> |
aoqi@0 | 72 | * If the stream is positioned at the start of the document then the |
aoqi@0 | 73 | * whole document is stored and after storing the stream will be positioned |
aoqi@0 | 74 | * at the end of the document. |
aoqi@0 | 75 | * <p> |
aoqi@0 | 76 | * If the stream is positioned at the start of an element then the |
aoqi@0 | 77 | * element and all its children will be stored and after storing the stream |
aoqi@0 | 78 | * will be positioned at the next event after the end of the element. |
aoqi@0 | 79 | * <p> |
aoqi@0 | 80 | * @return the mutable stream buffer. |
aoqi@0 | 81 | * @throws XMLStreamException if the stream reader is not positioned at |
aoqi@0 | 82 | * the start of the document or at an element. |
aoqi@0 | 83 | */ |
aoqi@0 | 84 | public MutableXMLStreamBuffer create(XMLStreamReader reader) throws XMLStreamException { |
aoqi@0 | 85 | if (_buffer == null) { |
aoqi@0 | 86 | createBuffer(); |
aoqi@0 | 87 | } |
aoqi@0 | 88 | store(reader); |
aoqi@0 | 89 | |
aoqi@0 | 90 | return getXMLStreamBuffer(); |
aoqi@0 | 91 | } |
aoqi@0 | 92 | |
aoqi@0 | 93 | /** |
aoqi@0 | 94 | * Creates the buffer from a stream reader that is an element fragment. |
aoqi@0 | 95 | * <p> |
aoqi@0 | 96 | * The stream reader will be moved to the position of the next start of |
aoqi@0 | 97 | * an element if the stream reader is not already positioned at the start |
aoqi@0 | 98 | * of an element. |
aoqi@0 | 99 | * <p> |
aoqi@0 | 100 | * The element and all its children will be stored and after storing the stream |
aoqi@0 | 101 | * will be positioned at the next event after the end of the element. |
aoqi@0 | 102 | * <p> |
aoqi@0 | 103 | * @param storeInScopeNamespaces true if in-scope namespaces of the element |
aoqi@0 | 104 | * fragment should be stored. |
aoqi@0 | 105 | * @return the mutable stream buffer. |
aoqi@0 | 106 | * @throws XMLStreamException if the stream reader cannot be positioned at |
aoqi@0 | 107 | * the start of an element. |
aoqi@0 | 108 | */ |
aoqi@0 | 109 | public MutableXMLStreamBuffer createElementFragment(XMLStreamReader reader, |
aoqi@0 | 110 | boolean storeInScopeNamespaces) throws XMLStreamException { |
aoqi@0 | 111 | if (_buffer == null) { |
aoqi@0 | 112 | createBuffer(); |
aoqi@0 | 113 | } |
aoqi@0 | 114 | |
aoqi@0 | 115 | if (!reader.hasNext()) { |
aoqi@0 | 116 | return _buffer; |
aoqi@0 | 117 | } |
aoqi@0 | 118 | |
aoqi@0 | 119 | _storeInScopeNamespacesOnElementFragment = storeInScopeNamespaces; |
aoqi@0 | 120 | |
aoqi@0 | 121 | _eventType = reader.getEventType(); |
aoqi@0 | 122 | if (_eventType != XMLStreamReader.START_ELEMENT) { |
aoqi@0 | 123 | do { |
aoqi@0 | 124 | _eventType = reader.next(); |
aoqi@0 | 125 | } while(_eventType != XMLStreamReader.START_ELEMENT && _eventType != XMLStreamReader.END_DOCUMENT); |
aoqi@0 | 126 | } |
aoqi@0 | 127 | |
aoqi@0 | 128 | if (storeInScopeNamespaces) { |
aoqi@0 | 129 | _inScopePrefixes = new HashMap<String,Integer>(); |
aoqi@0 | 130 | } |
aoqi@0 | 131 | |
aoqi@0 | 132 | storeElementAndChildren(reader); |
aoqi@0 | 133 | |
aoqi@0 | 134 | return getXMLStreamBuffer(); |
aoqi@0 | 135 | } |
aoqi@0 | 136 | |
aoqi@0 | 137 | private void store(XMLStreamReader reader) throws XMLStreamException { |
aoqi@0 | 138 | if (!reader.hasNext()) { |
aoqi@0 | 139 | return; |
aoqi@0 | 140 | } |
aoqi@0 | 141 | |
aoqi@0 | 142 | _eventType = reader.getEventType(); |
aoqi@0 | 143 | switch (_eventType) { |
aoqi@0 | 144 | case XMLStreamReader.START_DOCUMENT: |
aoqi@0 | 145 | storeDocumentAndChildren(reader); |
aoqi@0 | 146 | break; |
aoqi@0 | 147 | case XMLStreamReader.START_ELEMENT: |
aoqi@0 | 148 | storeElementAndChildren(reader); |
aoqi@0 | 149 | break; |
aoqi@0 | 150 | default: |
aoqi@0 | 151 | throw new XMLStreamException("XMLStreamReader not positioned at a document or element"); |
aoqi@0 | 152 | } |
aoqi@0 | 153 | |
aoqi@0 | 154 | increaseTreeCount(); |
aoqi@0 | 155 | } |
aoqi@0 | 156 | |
aoqi@0 | 157 | private void storeDocumentAndChildren(XMLStreamReader reader) throws XMLStreamException { |
aoqi@0 | 158 | storeStructure(T_DOCUMENT); |
aoqi@0 | 159 | |
aoqi@0 | 160 | _eventType = reader.next(); |
aoqi@0 | 161 | while (_eventType != XMLStreamReader.END_DOCUMENT) { |
aoqi@0 | 162 | switch (_eventType) { |
aoqi@0 | 163 | case XMLStreamReader.START_ELEMENT: |
aoqi@0 | 164 | storeElementAndChildren(reader); |
aoqi@0 | 165 | continue; |
aoqi@0 | 166 | case XMLStreamReader.COMMENT: |
aoqi@0 | 167 | storeComment(reader); |
aoqi@0 | 168 | break; |
aoqi@0 | 169 | case XMLStreamReader.PROCESSING_INSTRUCTION: |
aoqi@0 | 170 | storeProcessingInstruction(reader); |
aoqi@0 | 171 | break; |
aoqi@0 | 172 | } |
aoqi@0 | 173 | _eventType = reader.next(); |
aoqi@0 | 174 | } |
aoqi@0 | 175 | |
aoqi@0 | 176 | storeStructure(T_END); |
aoqi@0 | 177 | } |
aoqi@0 | 178 | |
aoqi@0 | 179 | private void storeElementAndChildren(XMLStreamReader reader) throws XMLStreamException { |
aoqi@0 | 180 | if (reader instanceof XMLStreamReaderEx) { |
aoqi@0 | 181 | storeElementAndChildrenEx((XMLStreamReaderEx)reader); |
aoqi@0 | 182 | } else { |
aoqi@0 | 183 | storeElementAndChildrenNoEx(reader); |
aoqi@0 | 184 | } |
aoqi@0 | 185 | } |
aoqi@0 | 186 | |
aoqi@0 | 187 | private void storeElementAndChildrenEx(XMLStreamReaderEx reader) throws XMLStreamException { |
aoqi@0 | 188 | int depth = 1; |
aoqi@0 | 189 | if (_storeInScopeNamespacesOnElementFragment) { |
aoqi@0 | 190 | storeElementWithInScopeNamespaces(reader); |
aoqi@0 | 191 | } else { |
aoqi@0 | 192 | storeElement(reader); |
aoqi@0 | 193 | } |
aoqi@0 | 194 | |
aoqi@0 | 195 | while(depth > 0) { |
aoqi@0 | 196 | _eventType = reader.next(); |
aoqi@0 | 197 | switch (_eventType) { |
aoqi@0 | 198 | case XMLStreamReader.START_ELEMENT: |
aoqi@0 | 199 | depth++; |
aoqi@0 | 200 | storeElement(reader); |
aoqi@0 | 201 | break; |
aoqi@0 | 202 | case XMLStreamReader.END_ELEMENT: |
aoqi@0 | 203 | depth--; |
aoqi@0 | 204 | storeStructure(T_END); |
aoqi@0 | 205 | break; |
aoqi@0 | 206 | case XMLStreamReader.NAMESPACE: |
aoqi@0 | 207 | storeNamespaceAttributes(reader); |
aoqi@0 | 208 | break; |
aoqi@0 | 209 | case XMLStreamReader.ATTRIBUTE: |
aoqi@0 | 210 | storeAttributes(reader); |
aoqi@0 | 211 | break; |
aoqi@0 | 212 | case XMLStreamReader.SPACE: |
aoqi@0 | 213 | case XMLStreamReader.CHARACTERS: |
aoqi@0 | 214 | case XMLStreamReader.CDATA: { |
aoqi@0 | 215 | CharSequence c = reader.getPCDATA(); |
aoqi@0 | 216 | if (c instanceof Base64Data) { |
aoqi@0 | 217 | storeStructure(T_TEXT_AS_OBJECT); |
aoqi@0 | 218 | //Instead of clone the Base64Data, the original Base64Data instance is used here to preserve the DataHandler |
aoqi@0 | 219 | storeContentObject(c); |
aoqi@0 | 220 | } else { |
aoqi@0 | 221 | storeContentCharacters(T_TEXT_AS_CHAR_ARRAY, |
aoqi@0 | 222 | reader.getTextCharacters(), reader.getTextStart(), |
aoqi@0 | 223 | reader.getTextLength()); |
aoqi@0 | 224 | } |
aoqi@0 | 225 | break; |
aoqi@0 | 226 | } |
aoqi@0 | 227 | case XMLStreamReader.COMMENT: |
aoqi@0 | 228 | storeComment(reader); |
aoqi@0 | 229 | break; |
aoqi@0 | 230 | case XMLStreamReader.PROCESSING_INSTRUCTION: |
aoqi@0 | 231 | storeProcessingInstruction(reader); |
aoqi@0 | 232 | break; |
aoqi@0 | 233 | } |
aoqi@0 | 234 | } |
aoqi@0 | 235 | |
aoqi@0 | 236 | /* |
aoqi@0 | 237 | * Move to next item after the end of the element |
aoqi@0 | 238 | * that has been stored |
aoqi@0 | 239 | */ |
aoqi@0 | 240 | _eventType = reader.next(); |
aoqi@0 | 241 | } |
aoqi@0 | 242 | |
aoqi@0 | 243 | private void storeElementAndChildrenNoEx(XMLStreamReader reader) throws XMLStreamException { |
aoqi@0 | 244 | int depth = 1; |
aoqi@0 | 245 | if (_storeInScopeNamespacesOnElementFragment) { |
aoqi@0 | 246 | storeElementWithInScopeNamespaces(reader); |
aoqi@0 | 247 | } else { |
aoqi@0 | 248 | storeElement(reader); |
aoqi@0 | 249 | } |
aoqi@0 | 250 | |
aoqi@0 | 251 | while(depth > 0) { |
aoqi@0 | 252 | _eventType = reader.next(); |
aoqi@0 | 253 | switch (_eventType) { |
aoqi@0 | 254 | case XMLStreamReader.START_ELEMENT: |
aoqi@0 | 255 | depth++; |
aoqi@0 | 256 | storeElement(reader); |
aoqi@0 | 257 | break; |
aoqi@0 | 258 | case XMLStreamReader.END_ELEMENT: |
aoqi@0 | 259 | depth--; |
aoqi@0 | 260 | storeStructure(T_END); |
aoqi@0 | 261 | break; |
aoqi@0 | 262 | case XMLStreamReader.NAMESPACE: |
aoqi@0 | 263 | storeNamespaceAttributes(reader); |
aoqi@0 | 264 | break; |
aoqi@0 | 265 | case XMLStreamReader.ATTRIBUTE: |
aoqi@0 | 266 | storeAttributes(reader); |
aoqi@0 | 267 | break; |
aoqi@0 | 268 | case XMLStreamReader.SPACE: |
aoqi@0 | 269 | case XMLStreamReader.CHARACTERS: |
aoqi@0 | 270 | case XMLStreamReader.CDATA: { |
aoqi@0 | 271 | storeContentCharacters(T_TEXT_AS_CHAR_ARRAY, |
aoqi@0 | 272 | reader.getTextCharacters(), reader.getTextStart(), |
aoqi@0 | 273 | reader.getTextLength()); |
aoqi@0 | 274 | break; |
aoqi@0 | 275 | } |
aoqi@0 | 276 | case XMLStreamReader.COMMENT: |
aoqi@0 | 277 | storeComment(reader); |
aoqi@0 | 278 | break; |
aoqi@0 | 279 | case XMLStreamReader.PROCESSING_INSTRUCTION: |
aoqi@0 | 280 | storeProcessingInstruction(reader); |
aoqi@0 | 281 | break; |
aoqi@0 | 282 | } |
aoqi@0 | 283 | } |
aoqi@0 | 284 | |
aoqi@0 | 285 | /* |
aoqi@0 | 286 | * Move to next item after the end of the element |
aoqi@0 | 287 | * that has been stored |
aoqi@0 | 288 | */ |
aoqi@0 | 289 | _eventType = reader.next(); |
aoqi@0 | 290 | } |
aoqi@0 | 291 | |
aoqi@0 | 292 | private void storeElementWithInScopeNamespaces(XMLStreamReader reader) { |
aoqi@0 | 293 | storeQualifiedName(T_ELEMENT_LN, |
aoqi@0 | 294 | reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName()); |
aoqi@0 | 295 | |
aoqi@0 | 296 | if (reader.getNamespaceCount() > 0) { |
aoqi@0 | 297 | storeNamespaceAttributes(reader); |
aoqi@0 | 298 | } |
aoqi@0 | 299 | |
aoqi@0 | 300 | if (reader.getAttributeCount() > 0) { |
aoqi@0 | 301 | storeAttributes(reader); |
aoqi@0 | 302 | } |
aoqi@0 | 303 | } |
aoqi@0 | 304 | |
aoqi@0 | 305 | private void storeElement(XMLStreamReader reader) { |
aoqi@0 | 306 | storeQualifiedName(T_ELEMENT_LN, |
aoqi@0 | 307 | reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName()); |
aoqi@0 | 308 | |
aoqi@0 | 309 | if (reader.getNamespaceCount() > 0) { |
aoqi@0 | 310 | storeNamespaceAttributes(reader); |
aoqi@0 | 311 | } |
aoqi@0 | 312 | |
aoqi@0 | 313 | if (reader.getAttributeCount() > 0) { |
aoqi@0 | 314 | storeAttributes(reader); |
aoqi@0 | 315 | } |
aoqi@0 | 316 | } |
aoqi@0 | 317 | |
aoqi@0 | 318 | /** |
aoqi@0 | 319 | * A low level method a create a structure element explicitly. This is useful when xsb is |
aoqi@0 | 320 | * created from a fragment's XMLStreamReader and inscope namespaces can be passed using |
aoqi@0 | 321 | * this method. Note that there is no way to enumerate namespaces from XMLStreamReader. |
aoqi@0 | 322 | * |
aoqi@0 | 323 | * For e.g: Say the SOAP message is as follows |
aoqi@0 | 324 | * |
aoqi@0 | 325 | * <S:Envelope xmlns:n1=".."><S:Body><ns2:A> ... |
aoqi@0 | 326 | * |
aoqi@0 | 327 | * when xsb is to be created using a reader that is at <ns2:A> tag, the inscope |
aoqi@0 | 328 | * namespace like 'n1' can be passed using this method. |
aoqi@0 | 329 | * |
aoqi@0 | 330 | * WARNING: Instead of using this, try other methods(if you don't know what you are |
aoqi@0 | 331 | * doing). |
aoqi@0 | 332 | * |
aoqi@0 | 333 | * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }. |
aoqi@0 | 334 | */ |
aoqi@0 | 335 | public void storeElement(String nsURI, String localName, String prefix, String[] ns) { |
aoqi@0 | 336 | storeQualifiedName(T_ELEMENT_LN, prefix, nsURI, localName); |
aoqi@0 | 337 | storeNamespaceAttributes(ns); |
aoqi@0 | 338 | } |
aoqi@0 | 339 | |
aoqi@0 | 340 | /** |
aoqi@0 | 341 | * A low level method a create a structure element explicitly. This is |
aoqi@0 | 342 | * required to support {@link #storeElement} method. |
aoqi@0 | 343 | * |
aoqi@0 | 344 | * WARNING: Instead of using this, try other methods(if you don't know what |
aoqi@0 | 345 | * you are doing). |
aoqi@0 | 346 | */ |
aoqi@0 | 347 | public void storeEndElement() { |
aoqi@0 | 348 | storeStructure(T_END); |
aoqi@0 | 349 | } |
aoqi@0 | 350 | |
aoqi@0 | 351 | private void storeNamespaceAttributes(XMLStreamReader reader) { |
aoqi@0 | 352 | int count = reader.getNamespaceCount(); |
aoqi@0 | 353 | for (int i = 0; i < count; i++) { |
aoqi@0 | 354 | storeNamespaceAttribute(reader.getNamespacePrefix(i), reader.getNamespaceURI(i)); |
aoqi@0 | 355 | } |
aoqi@0 | 356 | } |
aoqi@0 | 357 | |
aoqi@0 | 358 | /** |
aoqi@0 | 359 | * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }. |
aoqi@0 | 360 | */ |
aoqi@0 | 361 | private void storeNamespaceAttributes(String[] ns) { |
aoqi@0 | 362 | for (int i = 0; i < ns.length; i=i+2) { |
aoqi@0 | 363 | storeNamespaceAttribute(ns[i], ns[i+1]); |
aoqi@0 | 364 | } |
aoqi@0 | 365 | } |
aoqi@0 | 366 | |
aoqi@0 | 367 | private void storeAttributes(XMLStreamReader reader) { |
aoqi@0 | 368 | int count = reader.getAttributeCount(); |
aoqi@0 | 369 | for (int i = 0; i < count; i++) { |
aoqi@0 | 370 | storeAttribute(reader.getAttributePrefix(i), reader.getAttributeNamespace(i), reader.getAttributeLocalName(i), |
aoqi@0 | 371 | reader.getAttributeType(i), reader.getAttributeValue(i)); |
aoqi@0 | 372 | } |
aoqi@0 | 373 | } |
aoqi@0 | 374 | |
aoqi@0 | 375 | private void storeComment(XMLStreamReader reader) { |
aoqi@0 | 376 | storeContentCharacters(T_COMMENT_AS_CHAR_ARRAY, |
aoqi@0 | 377 | reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); |
aoqi@0 | 378 | } |
aoqi@0 | 379 | |
aoqi@0 | 380 | private void storeProcessingInstruction(XMLStreamReader reader) { |
aoqi@0 | 381 | storeProcessingInstruction(reader.getPITarget(), reader.getPIData()); |
aoqi@0 | 382 | } |
aoqi@0 | 383 | } |