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