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.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 storeContentObject(((Base64Data)c).clone()); 219 } else { 220 storeContentCharacters(T_TEXT_AS_CHAR_ARRAY, 221 reader.getTextCharacters(), reader.getTextStart(), 222 reader.getTextLength()); 223 } 224 break; 225 } 226 case XMLStreamReader.COMMENT: 227 storeComment(reader); 228 break; 229 case XMLStreamReader.PROCESSING_INSTRUCTION: 230 storeProcessingInstruction(reader); 231 break; 232 } 233 } 234 235 /* 236 * Move to next item after the end of the element 237 * that has been stored 238 */ 239 _eventType = reader.next(); 240 } 241 242 private void storeElementAndChildrenNoEx(XMLStreamReader reader) throws XMLStreamException { 243 int depth = 1; 244 if (_storeInScopeNamespacesOnElementFragment) { 245 storeElementWithInScopeNamespaces(reader); 246 } else { 247 storeElement(reader); 248 } 249 250 while(depth > 0) { 251 _eventType = reader.next(); 252 switch (_eventType) { 253 case XMLStreamReader.START_ELEMENT: 254 depth++; 255 storeElement(reader); 256 break; 257 case XMLStreamReader.END_ELEMENT: 258 depth--; 259 storeStructure(T_END); 260 break; 261 case XMLStreamReader.NAMESPACE: 262 storeNamespaceAttributes(reader); 263 break; 264 case XMLStreamReader.ATTRIBUTE: 265 storeAttributes(reader); 266 break; 267 case XMLStreamReader.SPACE: 268 case XMLStreamReader.CHARACTERS: 269 case XMLStreamReader.CDATA: { 270 storeContentCharacters(T_TEXT_AS_CHAR_ARRAY, 271 reader.getTextCharacters(), reader.getTextStart(), 272 reader.getTextLength()); 273 break; 274 } 275 case XMLStreamReader.COMMENT: 276 storeComment(reader); 277 break; 278 case XMLStreamReader.PROCESSING_INSTRUCTION: 279 storeProcessingInstruction(reader); 280 break; 281 } 282 } 283 284 /* 285 * Move to next item after the end of the element 286 * that has been stored 287 */ 288 _eventType = reader.next(); 289 } 290 291 private void storeElementWithInScopeNamespaces(XMLStreamReader reader) { 292 storeQualifiedName(T_ELEMENT_LN, 293 reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName()); 294 295 if (reader.getNamespaceCount() > 0) { 296 storeNamespaceAttributes(reader); 297 } 298 299 if (reader.getAttributeCount() > 0) { 300 storeAttributes(reader); 301 } 302 } 303 304 private void storeElement(XMLStreamReader reader) { 305 storeQualifiedName(T_ELEMENT_LN, 306 reader.getPrefix(), reader.getNamespaceURI(), reader.getLocalName()); 307 308 if (reader.getNamespaceCount() > 0) { 309 storeNamespaceAttributes(reader); 310 } 311 312 if (reader.getAttributeCount() > 0) { 313 storeAttributes(reader); 314 } 315 } 316 317 /** 318 * A low level method a create a structure element explicitly. This is useful when xsb is 319 * created from a fragment's XMLStreamReader and inscope namespaces can be passed using 320 * this method. Note that there is no way to enumerate namespaces from XMLStreamReader. 321 * 322 * For e.g: Say the SOAP message is as follows 323 * 324 * <S:Envelope xmlns:n1=".."><S:Body><ns2:A> ... 325 * 326 * when xsb is to be created using a reader that is at <ns2:A> tag, the inscope 327 * namespace like 'n1' can be passed using this method. 328 * 329 * WARNING: Instead of using this, try other methods(if you don't know what you are 330 * doing). 331 * 332 * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }. 333 */ 334 public void storeElement(String nsURI, String localName, String prefix, String[] ns) { 335 storeQualifiedName(T_ELEMENT_LN, prefix, nsURI, localName); 336 storeNamespaceAttributes(ns); 337 } 338 339 /** 340 * A low level method a create a structure element explicitly. This is 341 * required to support {@link #storeElement} method. 342 * 343 * WARNING: Instead of using this, try other methods(if you don't know what 344 * you are doing). 345 */ 346 public void storeEndElement() { 347 storeStructure(T_END); 348 } 349 350 private void storeNamespaceAttributes(XMLStreamReader reader) { 351 int count = reader.getNamespaceCount(); 352 for (int i = 0; i < count; i++) { 353 storeNamespaceAttribute(reader.getNamespacePrefix(i), reader.getNamespaceURI(i)); 354 } 355 } 356 357 /** 358 * @param ns an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }. 359 */ 360 private void storeNamespaceAttributes(String[] ns) { 361 for (int i = 0; i < ns.length; i=i+2) { 362 storeNamespaceAttribute(ns[i], ns[i+1]); 363 } 364 } 365 366 private void storeAttributes(XMLStreamReader reader) { 367 int count = reader.getAttributeCount(); 368 for (int i = 0; i < count; i++) { 369 storeAttribute(reader.getAttributePrefix(i), reader.getAttributeNamespace(i), reader.getAttributeLocalName(i), 370 reader.getAttributeType(i), reader.getAttributeValue(i)); 371 } 372 } 373 374 private void storeComment(XMLStreamReader reader) { 375 storeContentCharacters(T_COMMENT_AS_CHAR_ARRAY, 376 reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); 377 } 378 379 private void storeProcessingInstruction(XMLStreamReader reader) { 380 storeProcessingInstruction(reader.getPITarget(), reader.getPIData()); 381 } 382 }