src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java

Print this page




  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.ws.message.stream;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.istack.internal.XMLStreamReaderToContentHandler;
  31 import com.sun.xml.internal.bind.api.Bridge;
  32 import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;


  33 import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferCreator;
  34 import com.sun.xml.internal.ws.api.SOAPVersion;
  35 import com.sun.xml.internal.ws.api.message.AttachmentSet;
  36 import com.sun.xml.internal.ws.api.message.Header;
  37 import com.sun.xml.internal.ws.api.message.HeaderList;
  38 import com.sun.xml.internal.ws.api.message.Message;
  39 import com.sun.xml.internal.ws.api.message.MessageHeaders;

  40 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
  41 import com.sun.xml.internal.ws.encoding.TagInfoset;
  42 import com.sun.xml.internal.ws.message.AbstractMessageImpl;
  43 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;

  44 import com.sun.xml.internal.ws.spi.db.XMLBridge;
  45 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
  46 import com.sun.xml.internal.ws.util.xml.DummyLocation;
  47 import com.sun.xml.internal.ws.util.xml.StAXSource;

  48 import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter;


  49 import org.xml.sax.ContentHandler;
  50 import org.xml.sax.ErrorHandler;
  51 import org.xml.sax.SAXException;
  52 import org.xml.sax.SAXParseException;
  53 import org.xml.sax.helpers.NamespaceSupport;
  54 
  55 import javax.xml.bind.JAXBException;
  56 import javax.xml.bind.Unmarshaller;
  57 import javax.xml.stream.*;

  58 import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
  59 import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
  60 import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
  61 import javax.xml.transform.Source;
  62 import javax.xml.ws.WebServiceException;
  63 import java.util.ArrayList;
  64 import java.util.Enumeration;

  65 import java.util.List;

  66 
  67 /**
  68  * {@link Message} implementation backed by {@link XMLStreamReader}.
  69  *
  70  * TODO: we need another message class that keeps {@link XMLStreamReader} that points
  71  * at the start of the envelope element.
  72  */
  73 public class StreamMessage extends AbstractMessageImpl {
  74     /**
  75      * The reader will be positioned at
  76      * the first child of the SOAP body
  77      */
  78     private @NotNull XMLStreamReader reader;
  79 
  80     // lazily created
  81     private @Nullable MessageHeaders headers;
  82 
  83     /**
  84      * Because the StreamMessage leaves out the white spaces around payload
  85      * when being instantiated the space characters between soap:Body opening and
  86      * payload is stored in this field to be reused later (necessary for message security);
  87      * Instantiated after StreamMessage creation
  88      */
  89     private String bodyPrologue = null;
  90 
  91     /**
  92      * instantiated after writing message to XMLStreamWriter
  93      */
  94     private String bodyEpilogue = null;
  95 
  96     private final String payloadLocalName;
  97 
  98     private final String payloadNamespaceURI;
  99 
 100     /**
 101      * infoset about the SOAP envelope, header, and body.
 102      *
 103      * <p>
 104      * If the creater of this object didn't care about those,
 105      * we use stock values.
 106      */
 107     private @NotNull TagInfoset envelopeTag;
 108     private @NotNull TagInfoset headerTag;
 109     private @NotNull TagInfoset bodyTag;
 110 
 111     /**
 112      * Used only for debugging. This records where the message was consumed.
 113      */
 114     private Throwable consumedAt;
 115 
 116     /**
 117      * Default s:Envelope, s:Header, and s:Body tag infoset definitions.
 118      *
 119      * We need 3 for SOAP 1.1, 3 for SOAP 1.2.
 120      */
 121     private static final TagInfoset[] DEFAULT_TAGS;
 122 
 123     static {
 124         DEFAULT_TAGS = new TagInfoset[6];
 125         create(SOAPVersion.SOAP_11);
 126         create(SOAPVersion.SOAP_12);
 127     }
 128 
 129     public StreamMessage(SOAPVersion v) {
 130         super(v);
 131         payloadLocalName = null;
 132         payloadNamespaceURI = null;
 133     }





























 134     /**
 135      * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
 136      * that points at the start element of the payload, and headers.
 137      *
 138      * <p>
 139      * This method creates a {@link Message} from a payload.
 140      *
 141      * @param headers
 142      *      if null, it means no headers. if non-null,
 143      *      it will be owned by this message.
 144      * @param reader
 145      *      points at the start element/document of the payload (or the end element of the &lt;s:Body>
 146      *      if there's no payload)
 147      */
 148     public StreamMessage(@Nullable MessageHeaders headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 149         super(soapVersion);




 150         this.headers = headers;
 151         this.attachmentSet = attachmentSet;
 152         this.reader = reader;
 153 
 154         if(reader.getEventType()== START_DOCUMENT)
 155             XMLStreamReaderUtil.nextElementContent(reader);
 156 
 157         //if the reader is pointing to the end element </soapenv:Body> then its empty message
 158         // or no payload
 159         if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
 160             String body = reader.getLocalName();
 161             String nsUri = reader.getNamespaceURI();
 162             assert body != null;
 163             assert nsUri != null;
 164             //if its not soapenv:Body then throw exception, we received malformed stream
 165             if(body.equals("Body") && nsUri.equals(soapVersion.nsUri)){
 166                 this.payloadLocalName = null;
 167                 this.payloadNamespaceURI = null;
 168             }else{ //TODO: i18n and also we should be throwing better message that this
 169                 throw new WebServiceException("Malformed stream: {"+nsUri+"}"+body);
 170             }
 171         }else{
 172             this.payloadLocalName = reader.getLocalName();
 173             this.payloadNamespaceURI = reader.getNamespaceURI();
 174         }
 175 
 176         // use the default infoset representation for headers
 177         int base = soapVersion.ordinal()*3;
 178         this.envelopeTag = DEFAULT_TAGS[base];
 179         this.headerTag = DEFAULT_TAGS[base+1];
 180         this.bodyTag = DEFAULT_TAGS[base+2];
 181     }
 182 
 183     /**
 184      * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
 185      * and the complete infoset of the SOAP envelope.
 186      *
 187      * <p>
 188      * See {@link #StreamMessage(MessageHeaders, AttachmentSet, XMLStreamReader, SOAPVersion)} for
 189      * the description of the basic parameters.
 190      *
 191      * @param headerTag
 192      *      Null if the message didn't have a header tag.
 193      *
 194      */
 195     public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable MessageHeaders headers, @NotNull TagInfoset bodyTag, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 196         this(envelopeTag, headerTag, attachmentSet, headers, null, bodyTag, null, reader, soapVersion);
 197     }
 198 
 199     public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable MessageHeaders headers, @Nullable String bodyPrologue, @NotNull TagInfoset bodyTag, @Nullable String bodyEpilogue, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 200         this(headers,attachmentSet,reader,soapVersion);





 201         if(envelopeTag == null ) {
 202             throw new IllegalArgumentException("EnvelopeTag TagInfoset cannot be null");
 203         }
 204         if(bodyTag == null ) {
 205             throw new IllegalArgumentException("BodyTag TagInfoset cannot be null");
 206         }
 207         this.envelopeTag = envelopeTag;
 208         this.headerTag = headerTag;
 209         this.bodyTag = bodyTag;
 210         this.bodyPrologue = bodyPrologue;
 211         this.bodyEpilogue = bodyEpilogue;
 212     }
 213 
 214     public boolean hasHeaders() {

 215         return headers!=null && headers.hasHeaders();
 216     }
 217 
 218     public MessageHeaders getHeaders() {

 219         if (headers == null) {
 220             headers = new HeaderList(getSOAPVersion());
 221         }
 222         return headers;
 223     }
 224 
 225     public String getPayloadLocalPart() {

 226         return payloadLocalName;
 227     }
 228 
 229     public String getPayloadNamespaceURI() {

 230         return payloadNamespaceURI;
 231     }
 232 
 233     public boolean hasPayload() {

 234         return payloadLocalName!=null;
 235     }
 236 
 237     public Source readPayloadAsSource() {
 238         if(hasPayload()) {
 239             assert unconsumed();
 240             return new StAXSource(reader, true, getInscopeNamespaces());
 241         } else
 242             return null;
 243     }
 244 
 245     /**
 246      * There is no way to enumerate inscope namespaces for XMLStreamReader. That means
 247      * namespaces declared in envelope, and body tags need to be computed using their
 248      * {@link TagInfoset}s.
 249      *
 250      * @return array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
 251      */
 252     private String[] getInscopeNamespaces() {
 253         NamespaceSupport nss = new NamespaceSupport();


 312         return r;
 313     }
 314 
 315     @Override
 316     public void consume() {
 317         assert unconsumed();
 318         XMLStreamReaderUtil.readRest(reader);
 319         XMLStreamReaderUtil.close(reader);
 320         XMLStreamReaderFactory.recycle(reader);
 321     }
 322 
 323     public XMLStreamReader readPayload() {
 324         if(!hasPayload())
 325             return null;
 326         // TODO: What about access at and beyond </soap:Body>
 327         assert unconsumed();
 328         return this.reader;
 329     }
 330 
 331     public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException {

 332         assert unconsumed();
 333 
 334         if(payloadLocalName==null) {
 335             return; // no body
 336         }
 337 
 338         if (bodyPrologue != null) {
 339             writer.writeCharacters(bodyPrologue);
 340         }
 341 
 342         XMLStreamReaderToXMLStreamWriter conv = new XMLStreamReaderToXMLStreamWriter();
 343 
 344         while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 345             String name = reader.getLocalName();
 346             String nsUri = reader.getNamespaceURI();
 347 
 348             // After previous conv.bridge() call the cursor will be at END_ELEMENT.
 349             // Check if its not soapenv:Body then move to next ELEMENT
 350             if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
 351 


 362                     // body closed > exit
 363                     break;
 364                 }
 365 
 366             } else {
 367                 // payload opening element: copy payload to writer
 368                 conv.bridge(reader,writer);
 369             }
 370         }
 371 
 372         XMLStreamReaderUtil.readRest(reader);
 373         XMLStreamReaderUtil.close(reader);
 374         XMLStreamReaderFactory.recycle(reader);
 375     }
 376 
 377     private boolean isBodyElement(String name, String nsUri) {
 378         return name.equals("Body") && nsUri.equals(soapVersion.nsUri);
 379     }
 380 
 381     public void writeTo(XMLStreamWriter sw) throws XMLStreamException{

 382         writeEnvelope(sw);
 383     }
 384 
 385     /**
 386      * This method should be called when the StreamMessage is created with a payload
 387      * @param writer
 388      */
 389     private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException {

 390         writer.writeStartDocument();
 391         envelopeTag.writeStart(writer);
 392 
 393         //write headers
 394         MessageHeaders hl = getHeaders();
 395         if (hl.hasHeaders() && headerTag == null) headerTag = new TagInfoset(envelopeTag.nsUri,"Header",envelopeTag.prefix,EMPTY_ATTS);
 396         if (headerTag != null) {
 397             headerTag.writeStart(writer);
 398             if (hl.hasHeaders()){
 399                 for(Header h : hl.asList()){
 400                     h.writeTo(writer);
 401                 }
 402             }
 403             writer.writeEndElement();
 404         }
 405         bodyTag.writeStart(writer);
 406         if(hasPayload())
 407             writePayloadTo(writer);
 408         writer.writeEndElement();
 409         writer.writeEndElement();
 410         writer.writeEndDocument();
 411     }
 412 
 413     public void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {

 414         assert unconsumed();
 415 
 416         try {
 417             if(payloadLocalName==null)
 418                 return; // no body
 419 
 420             if (bodyPrologue != null) {
 421                 char[] chars = bodyPrologue.toCharArray();
 422                 contentHandler.characters(chars, 0, chars.length);
 423             }
 424 
 425             XMLStreamReaderToContentHandler conv = new XMLStreamReaderToContentHandler(reader,contentHandler,true,fragment,getInscopeNamespaces());
 426 
 427             while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 428                 String name = reader.getLocalName();
 429                 String nsUri = reader.getNamespaceURI();
 430 
 431                 // After previous conv.bridge() call the cursor will be at END_ELEMENT.
 432                 // Check if its not soapenv:Body then move to next ELEMENT
 433                 if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){


 448                     }
 449 
 450                 } else {
 451                     // payload opening element: copy payload to writer
 452                     conv.bridge();
 453                 }
 454             }
 455             XMLStreamReaderUtil.readRest(reader);
 456             XMLStreamReaderUtil.close(reader);
 457             XMLStreamReaderFactory.recycle(reader);
 458         } catch (XMLStreamException e) {
 459             Location loc = e.getLocation();
 460             if(loc==null)   loc = DummyLocation.INSTANCE;
 461 
 462             SAXParseException x = new SAXParseException(
 463                 e.getMessage(),loc.getPublicId(),loc.getSystemId(),loc.getLineNumber(),loc.getColumnNumber(),e);
 464             errorHandler.error(x);
 465         }
 466     }
 467 
 468     // TODO: this method should be probably rewritten to respect spaces between eelements; is it used at all?

 469     public Message copy() {

 470         try {
 471             assert unconsumed();
 472             consumedAt = null; // but we don't want to mark it as consumed
 473             MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
 474             StreamReaderBufferCreator c = new StreamReaderBufferCreator(xsb);
 475 
 476             // preserving inscope namespaces from envelope, and body. Other option
 477             // would be to create a filtering XMLStreamReader from reader+envelopeTag+bodyTag
 478             c.storeElement(envelopeTag.nsUri, envelopeTag.localName, envelopeTag.prefix, envelopeTag.ns);
 479             c.storeElement(bodyTag.nsUri, bodyTag.localName, bodyTag.prefix, bodyTag.ns);
 480 
 481             if (hasPayload()) {
 482                 // Loop all the way for multi payload case
 483                 while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 484                     String name = reader.getLocalName();
 485                     String nsUri = reader.getNamespaceURI();
 486                     if(isBodyElement(name, nsUri) || (reader.getEventType() == XMLStreamConstants.END_DOCUMENT))
 487                         break;
 488                     c.create(reader);
 489 


 511 
 512             // advance to the start tag of the <Body> first child element
 513             proceedToRootElement(reader);
 514             proceedToRootElement(clone);
 515 
 516             return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion);
 517         } catch (XMLStreamException e) {
 518             throw new WebServiceException("Failed to copy a message",e);
 519         }
 520     }
 521 
 522     private void proceedToRootElement(XMLStreamReader xsr) throws XMLStreamException {
 523         assert xsr.getEventType()==START_DOCUMENT;
 524         xsr.nextTag();
 525         xsr.nextTag();
 526         xsr.nextTag();
 527         assert xsr.getEventType()==START_ELEMENT || xsr.getEventType()==END_ELEMENT;
 528     }
 529 
 530     public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException {

 531         contentHandler.setDocumentLocator(NULL_LOCATOR);
 532         contentHandler.startDocument();
 533         envelopeTag.writeStart(contentHandler);
 534         if (hasHeaders() && headerTag == null) headerTag = new TagInfoset(envelopeTag.nsUri,"Header",envelopeTag.prefix,EMPTY_ATTS);
 535         if (headerTag != null) {
 536             headerTag.writeStart(contentHandler);
 537             if (hasHeaders()) {
 538                 MessageHeaders headers = getHeaders();
 539                 for (Header h : headers.asList()) {
 540                     // shouldn't JDK be smart enough to use array-style indexing for this foreach!?
 541                     h.writeTo(contentHandler,errorHandler);
 542                 }
 543             }
 544             headerTag.writeEnd(contentHandler);
 545         }
 546         bodyTag.writeStart(contentHandler);
 547         writePayloadTo(contentHandler,errorHandler, true);
 548         bodyTag.writeEnd(contentHandler);
 549         envelopeTag.writeEnd(contentHandler);
 550         contentHandler.endDocument();


 553     /**
 554      * Used for an assertion. Returns true when the message is unconsumed,
 555      * or otherwise throw an exception.
 556      *
 557      * <p>
 558      * Calling this method also marks the stream as 'consumed'
 559      */
 560     private boolean unconsumed() {
 561         if(payloadLocalName==null)
 562             return true;    // no payload. can be consumed multiple times.
 563 
 564         if(reader.getEventType()!=XMLStreamReader.START_ELEMENT) {
 565             AssertionError error = new AssertionError("StreamMessage has been already consumed. See the nested exception for where it's consumed");
 566             error.initCause(consumedAt);
 567             throw error;
 568         }
 569         consumedAt = new Exception().fillInStackTrace();
 570         return true;
 571     }
 572 
 573     private static void create(SOAPVersion v) {
 574         int base = v.ordinal()*3;
 575         DEFAULT_TAGS[base  ] = new TagInfoset(v.nsUri,"Envelope","S",EMPTY_ATTS,"S",v.nsUri);
 576         DEFAULT_TAGS[base+1] = new TagInfoset(v.nsUri,"Header","S",EMPTY_ATTS);
 577         DEFAULT_TAGS[base+2] = new TagInfoset(v.nsUri,"Body","S",EMPTY_ATTS);
 578     }
 579 
 580     public String getBodyPrologue() {

 581         return bodyPrologue;
 582     }
 583 
 584     public String getBodyEpilogue() {

 585         return bodyEpilogue;
 586     }
 587 
 588     public XMLStreamReader getReader() {

 589         assert unconsumed();
 590         return reader;












































































































































 591     }
 592 }


  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.ws.message.stream;
  27 
  28 import com.sun.istack.internal.NotNull;
  29 import com.sun.istack.internal.Nullable;
  30 import com.sun.istack.internal.XMLStreamReaderToContentHandler;
  31 import com.sun.xml.internal.bind.api.Bridge;
  32 import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
  33 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
  34 import com.sun.xml.internal.stream.buffer.XMLStreamBufferMark;
  35 import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferCreator;
  36 import com.sun.xml.internal.ws.api.SOAPVersion;
  37 import com.sun.xml.internal.ws.api.message.AttachmentSet;
  38 import com.sun.xml.internal.ws.api.message.Header;
  39 import com.sun.xml.internal.ws.api.message.HeaderList;
  40 import com.sun.xml.internal.ws.api.message.Message;
  41 import com.sun.xml.internal.ws.api.message.MessageHeaders;
  42 import com.sun.xml.internal.ws.api.message.StreamingSOAP;
  43 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
  44 import com.sun.xml.internal.ws.encoding.TagInfoset;
  45 import com.sun.xml.internal.ws.message.AbstractMessageImpl;
  46 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
  47 import com.sun.xml.internal.ws.protocol.soap.VersionMismatchException;
  48 import com.sun.xml.internal.ws.spi.db.XMLBridge;
  49 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
  50 import com.sun.xml.internal.ws.util.xml.DummyLocation;
  51 import com.sun.xml.internal.ws.util.xml.StAXSource;
  52 import com.sun.xml.internal.ws.util.xml.XMLReaderComposite;
  53 import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter;
  54 import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo;
  55 
  56 import org.xml.sax.ContentHandler;
  57 import org.xml.sax.ErrorHandler;
  58 import org.xml.sax.SAXException;
  59 import org.xml.sax.SAXParseException;
  60 import org.xml.sax.helpers.NamespaceSupport;
  61 
  62 import javax.xml.bind.JAXBException;
  63 import javax.xml.bind.Unmarshaller;
  64 import javax.xml.stream.*;
  65 
  66 import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
  67 import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
  68 import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
  69 import javax.xml.transform.Source;
  70 import javax.xml.ws.WebServiceException;
  71 import java.util.ArrayList;
  72 import java.util.Enumeration;
  73 import java.util.HashMap;
  74 import java.util.List;
  75 import java.util.Map;
  76 
  77 /**
  78  * {@link Message} implementation backed by {@link XMLStreamReader}.
  79  *
  80  * TODO: we need another message class that keeps {@link XMLStreamReader} that points
  81  * at the start of the envelope element.
  82  */
  83 public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP {
  84     /**
  85      * The reader will be positioned at
  86      * the first child of the SOAP body
  87      */
  88     private @NotNull XMLStreamReader reader;
  89 
  90     // lazily created
  91     private @Nullable MessageHeaders headers;
  92 
  93     /**
  94      * Because the StreamMessage leaves out the white spaces around payload
  95      * when being instantiated the space characters between soap:Body opening and
  96      * payload is stored in this field to be reused later (necessary for message security);
  97      * Instantiated after StreamMessage creation
  98      */
  99     private String bodyPrologue = null;
 100 
 101     /**
 102      * instantiated after writing message to XMLStreamWriter
 103      */
 104     private String bodyEpilogue = null;
 105 
 106     private String payloadLocalName;
 107 
 108     private String payloadNamespaceURI;











 109 
 110     /**
 111      * Used only for debugging. This records where the message was consumed.
 112      */
 113     private Throwable consumedAt;
 114 
 115     private XMLStreamReader envelopeReader;











 116 
 117     public StreamMessage(SOAPVersion v) {
 118         super(v);
 119         payloadLocalName = null;
 120         payloadNamespaceURI = null;
 121     }
 122 
 123     public StreamMessage(SOAPVersion v, @NotNull XMLStreamReader envelope, @NotNull AttachmentSet attachments) {
 124         super(v);
 125         envelopeReader = envelope;
 126         attachmentSet = attachments;
 127     }
 128 
 129     public XMLStreamReader readEnvelope() {
 130         if (envelopeReader == null) {
 131             List<XMLStreamReader> hReaders = new java.util.ArrayList<XMLStreamReader>();
 132             ElemInfo envElem =  new ElemInfo(envelopeTag, null);
 133             ElemInfo hdrElem =  (headerTag != null) ? new ElemInfo(headerTag, envElem) : null;
 134             ElemInfo bdyElem =  new ElemInfo(bodyTag,   envElem);
 135             for (Header h : getHeaders().asList()) {
 136                 try {
 137                     hReaders.add(h.readHeader());
 138                 } catch (XMLStreamException e) {
 139                     throw new RuntimeException(e);
 140                 }
 141             }
 142             XMLStreamReader soapHeader = (hdrElem != null) ? new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])) : null;
 143             XMLStreamReader[] payload = {readPayload()};
 144             XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, payload);
 145             XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody};
 146             return new XMLReaderComposite(envElem, soapContent);
 147         }
 148         return envelopeReader;
 149     }
 150 
 151     /**
 152      * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
 153      * that points at the start element of the payload, and headers.
 154      *
 155      * <p>
 156      * This method creates a {@link Message} from a payload.
 157      *
 158      * @param headers
 159      *      if null, it means no headers. if non-null,
 160      *      it will be owned by this message.
 161      * @param reader
 162      *      points at the start element/document of the payload (or the end element of the &lt;s:Body>
 163      *      if there's no payload)
 164      */
 165     public StreamMessage(@Nullable MessageHeaders headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 166         super(soapVersion);
 167         init(headers, attachmentSet, reader, soapVersion);
 168     }
 169 
 170     private void init(@Nullable MessageHeaders headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 171         this.headers = headers;
 172         this.attachmentSet = attachmentSet;
 173         this.reader = reader;
 174 
 175         if(reader.getEventType()== START_DOCUMENT)
 176             XMLStreamReaderUtil.nextElementContent(reader);
 177 
 178         //if the reader is pointing to the end element </soapenv:Body> then its empty message
 179         // or no payload
 180         if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
 181             String body = reader.getLocalName();
 182             String nsUri = reader.getNamespaceURI();
 183             assert body != null;
 184             assert nsUri != null;
 185             //if its not soapenv:Body then throw exception, we received malformed stream
 186             if(body.equals("Body") && nsUri.equals(soapVersion.nsUri)){
 187                 this.payloadLocalName = null;
 188                 this.payloadNamespaceURI = null;
 189             }else{ //TODO: i18n and also we should be throwing better message that this
 190                 throw new WebServiceException("Malformed stream: {"+nsUri+"}"+body);
 191             }
 192         }else{
 193             this.payloadLocalName = reader.getLocalName();
 194             this.payloadNamespaceURI = reader.getNamespaceURI();
 195         }
 196 
 197         // use the default infoset representation for headers
 198         int base = soapVersion.ordinal()*3;
 199         this.envelopeTag = DEFAULT_TAGS.get(base);
 200         this.headerTag = DEFAULT_TAGS.get(base+1);
 201         this.bodyTag = DEFAULT_TAGS.get(base+2);
 202     }
 203 
 204     /**
 205      * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
 206      * and the complete infoset of the SOAP envelope.
 207      *
 208      * <p>
 209      * See {@link #StreamMessage(MessageHeaders, AttachmentSet, XMLStreamReader, SOAPVersion)} for
 210      * the description of the basic parameters.
 211      *
 212      * @param headerTag
 213      *      Null if the message didn't have a header tag.
 214      *
 215      */
 216     public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable MessageHeaders headers, @NotNull TagInfoset bodyTag, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 217         this(envelopeTag, headerTag, attachmentSet, headers, null, bodyTag, null, reader, soapVersion);
 218     }
 219 
 220     public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable MessageHeaders headers, @Nullable String bodyPrologue, @NotNull TagInfoset bodyTag, @Nullable String bodyEpilogue, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 221         super(soapVersion);
 222         init(envelopeTag, headerTag, attachmentSet, headers, bodyPrologue, bodyTag, bodyEpilogue, reader, soapVersion);
 223     }
 224 
 225     private void init(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable MessageHeaders headers, @Nullable String bodyPrologue, @NotNull TagInfoset bodyTag, @Nullable String bodyEpilogue, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
 226         init(headers,attachmentSet,reader,soapVersion);
 227         if(envelopeTag == null ) {
 228             throw new IllegalArgumentException("EnvelopeTag TagInfoset cannot be null");
 229         }
 230         if(bodyTag == null ) {
 231             throw new IllegalArgumentException("BodyTag TagInfoset cannot be null");
 232         }
 233         this.envelopeTag = envelopeTag;
 234         this.headerTag = headerTag;
 235         this.bodyTag = bodyTag;
 236         this.bodyPrologue = bodyPrologue;
 237         this.bodyEpilogue = bodyEpilogue;
 238     }
 239 
 240     public boolean hasHeaders() {
 241         if ( envelopeReader != null ) readEnvelope(this);
 242         return headers!=null && headers.hasHeaders();
 243     }
 244 
 245     public MessageHeaders getHeaders() {
 246         if ( envelopeReader != null ) readEnvelope(this);
 247         if (headers == null) {
 248             headers = new HeaderList(getSOAPVersion());
 249         }
 250         return headers;
 251     }
 252 
 253     public String getPayloadLocalPart() {
 254         if ( envelopeReader != null ) readEnvelope(this);
 255         return payloadLocalName;
 256     }
 257 
 258     public String getPayloadNamespaceURI() {
 259         if ( envelopeReader != null ) readEnvelope(this);
 260         return payloadNamespaceURI;
 261     }
 262 
 263     public boolean hasPayload() {
 264         if ( envelopeReader != null ) readEnvelope(this);
 265         return payloadLocalName!=null;
 266     }
 267 
 268     public Source readPayloadAsSource() {
 269         if(hasPayload()) {
 270             assert unconsumed();
 271             return new StAXSource(reader, true, getInscopeNamespaces());
 272         } else
 273             return null;
 274     }
 275 
 276     /**
 277      * There is no way to enumerate inscope namespaces for XMLStreamReader. That means
 278      * namespaces declared in envelope, and body tags need to be computed using their
 279      * {@link TagInfoset}s.
 280      *
 281      * @return array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
 282      */
 283     private String[] getInscopeNamespaces() {
 284         NamespaceSupport nss = new NamespaceSupport();


 343         return r;
 344     }
 345 
 346     @Override
 347     public void consume() {
 348         assert unconsumed();
 349         XMLStreamReaderUtil.readRest(reader);
 350         XMLStreamReaderUtil.close(reader);
 351         XMLStreamReaderFactory.recycle(reader);
 352     }
 353 
 354     public XMLStreamReader readPayload() {
 355         if(!hasPayload())
 356             return null;
 357         // TODO: What about access at and beyond </soap:Body>
 358         assert unconsumed();
 359         return this.reader;
 360     }
 361 
 362     public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException {
 363         if ( envelopeReader != null ) readEnvelope(this);
 364         assert unconsumed();
 365 
 366         if(payloadLocalName==null) {
 367             return; // no body
 368         }
 369 
 370         if (bodyPrologue != null) {
 371             writer.writeCharacters(bodyPrologue);
 372         }
 373 
 374         XMLStreamReaderToXMLStreamWriter conv = new XMLStreamReaderToXMLStreamWriter();
 375 
 376         while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 377             String name = reader.getLocalName();
 378             String nsUri = reader.getNamespaceURI();
 379 
 380             // After previous conv.bridge() call the cursor will be at END_ELEMENT.
 381             // Check if its not soapenv:Body then move to next ELEMENT
 382             if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
 383 


 394                     // body closed > exit
 395                     break;
 396                 }
 397 
 398             } else {
 399                 // payload opening element: copy payload to writer
 400                 conv.bridge(reader,writer);
 401             }
 402         }
 403 
 404         XMLStreamReaderUtil.readRest(reader);
 405         XMLStreamReaderUtil.close(reader);
 406         XMLStreamReaderFactory.recycle(reader);
 407     }
 408 
 409     private boolean isBodyElement(String name, String nsUri) {
 410         return name.equals("Body") && nsUri.equals(soapVersion.nsUri);
 411     }
 412 
 413     public void writeTo(XMLStreamWriter sw) throws XMLStreamException{
 414         if ( envelopeReader != null ) readEnvelope(this);
 415         writeEnvelope(sw);
 416     }
 417 
 418     /**
 419      * This method should be called when the StreamMessage is created with a payload
 420      * @param writer
 421      */
 422     private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException {
 423         if ( envelopeReader != null ) readEnvelope(this);
 424         writer.writeStartDocument();
 425         envelopeTag.writeStart(writer);
 426 
 427         //write headers
 428         MessageHeaders hl = getHeaders();
 429         if (hl.hasHeaders() && headerTag == null) headerTag = new TagInfoset(envelopeTag.nsUri,"Header",envelopeTag.prefix,EMPTY_ATTS);
 430         if (headerTag != null) {
 431             headerTag.writeStart(writer);
 432             if (hl.hasHeaders()){
 433                 for(Header h : hl.asList()){
 434                     h.writeTo(writer);
 435                 }
 436             }
 437             writer.writeEndElement();
 438         }
 439         bodyTag.writeStart(writer);
 440         if(hasPayload())
 441             writePayloadTo(writer);
 442         writer.writeEndElement();
 443         writer.writeEndElement();
 444         writer.writeEndDocument();
 445     }
 446 
 447     public void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
 448         if ( envelopeReader != null ) readEnvelope(this);
 449         assert unconsumed();
 450 
 451         try {
 452             if(payloadLocalName==null)
 453                 return; // no body
 454 
 455             if (bodyPrologue != null) {
 456                 char[] chars = bodyPrologue.toCharArray();
 457                 contentHandler.characters(chars, 0, chars.length);
 458             }
 459 
 460             XMLStreamReaderToContentHandler conv = new XMLStreamReaderToContentHandler(reader,contentHandler,true,fragment,getInscopeNamespaces());
 461 
 462             while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 463                 String name = reader.getLocalName();
 464                 String nsUri = reader.getNamespaceURI();
 465 
 466                 // After previous conv.bridge() call the cursor will be at END_ELEMENT.
 467                 // Check if its not soapenv:Body then move to next ELEMENT
 468                 if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){


 483                     }
 484 
 485                 } else {
 486                     // payload opening element: copy payload to writer
 487                     conv.bridge();
 488                 }
 489             }
 490             XMLStreamReaderUtil.readRest(reader);
 491             XMLStreamReaderUtil.close(reader);
 492             XMLStreamReaderFactory.recycle(reader);
 493         } catch (XMLStreamException e) {
 494             Location loc = e.getLocation();
 495             if(loc==null)   loc = DummyLocation.INSTANCE;
 496 
 497             SAXParseException x = new SAXParseException(
 498                 e.getMessage(),loc.getPublicId(),loc.getSystemId(),loc.getLineNumber(),loc.getColumnNumber(),e);
 499             errorHandler.error(x);
 500         }
 501     }
 502 
 503     // TODO: this method should be probably rewritten to respect spaces between elements; is it used at all?
 504     @Override
 505     public Message copy() {
 506         if ( envelopeReader != null ) readEnvelope(this);
 507         try {
 508             assert unconsumed();
 509             consumedAt = null; // but we don't want to mark it as consumed
 510             MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
 511             StreamReaderBufferCreator c = new StreamReaderBufferCreator(xsb);
 512 
 513             // preserving inscope namespaces from envelope, and body. Other option
 514             // would be to create a filtering XMLStreamReader from reader+envelopeTag+bodyTag
 515             c.storeElement(envelopeTag.nsUri, envelopeTag.localName, envelopeTag.prefix, envelopeTag.ns);
 516             c.storeElement(bodyTag.nsUri, bodyTag.localName, bodyTag.prefix, bodyTag.ns);
 517 
 518             if (hasPayload()) {
 519                 // Loop all the way for multi payload case
 520                 while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
 521                     String name = reader.getLocalName();
 522                     String nsUri = reader.getNamespaceURI();
 523                     if(isBodyElement(name, nsUri) || (reader.getEventType() == XMLStreamConstants.END_DOCUMENT))
 524                         break;
 525                     c.create(reader);
 526 


 548 
 549             // advance to the start tag of the <Body> first child element
 550             proceedToRootElement(reader);
 551             proceedToRootElement(clone);
 552 
 553             return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion);
 554         } catch (XMLStreamException e) {
 555             throw new WebServiceException("Failed to copy a message",e);
 556         }
 557     }
 558 
 559     private void proceedToRootElement(XMLStreamReader xsr) throws XMLStreamException {
 560         assert xsr.getEventType()==START_DOCUMENT;
 561         xsr.nextTag();
 562         xsr.nextTag();
 563         xsr.nextTag();
 564         assert xsr.getEventType()==START_ELEMENT || xsr.getEventType()==END_ELEMENT;
 565     }
 566 
 567     public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException {
 568         if ( envelopeReader != null ) readEnvelope(this);
 569         contentHandler.setDocumentLocator(NULL_LOCATOR);
 570         contentHandler.startDocument();
 571         envelopeTag.writeStart(contentHandler);
 572         if (hasHeaders() && headerTag == null) headerTag = new TagInfoset(envelopeTag.nsUri,"Header",envelopeTag.prefix,EMPTY_ATTS);
 573         if (headerTag != null) {
 574             headerTag.writeStart(contentHandler);
 575             if (hasHeaders()) {
 576                 MessageHeaders headers = getHeaders();
 577                 for (Header h : headers.asList()) {
 578                     // shouldn't JDK be smart enough to use array-style indexing for this foreach!?
 579                     h.writeTo(contentHandler,errorHandler);
 580                 }
 581             }
 582             headerTag.writeEnd(contentHandler);
 583         }
 584         bodyTag.writeStart(contentHandler);
 585         writePayloadTo(contentHandler,errorHandler, true);
 586         bodyTag.writeEnd(contentHandler);
 587         envelopeTag.writeEnd(contentHandler);
 588         contentHandler.endDocument();


 591     /**
 592      * Used for an assertion. Returns true when the message is unconsumed,
 593      * or otherwise throw an exception.
 594      *
 595      * <p>
 596      * Calling this method also marks the stream as 'consumed'
 597      */
 598     private boolean unconsumed() {
 599         if(payloadLocalName==null)
 600             return true;    // no payload. can be consumed multiple times.
 601 
 602         if(reader.getEventType()!=XMLStreamReader.START_ELEMENT) {
 603             AssertionError error = new AssertionError("StreamMessage has been already consumed. See the nested exception for where it's consumed");
 604             error.initCause(consumedAt);
 605             throw error;
 606         }
 607         consumedAt = new Exception().fillInStackTrace();
 608         return true;
 609     }
 610 







 611     public String getBodyPrologue() {
 612         if ( envelopeReader != null ) readEnvelope(this);
 613         return bodyPrologue;
 614     }
 615 
 616     public String getBodyEpilogue() {
 617         if ( envelopeReader != null ) readEnvelope(this);
 618         return bodyEpilogue;
 619     }
 620 
 621     public XMLStreamReader getReader() {
 622         if ( envelopeReader != null ) readEnvelope(this);
 623         assert unconsumed();
 624         return reader;
 625     }
 626 
 627 
 628     private static final String SOAP_ENVELOPE = "Envelope";
 629     private static final String SOAP_HEADER = "Header";
 630     private static final String SOAP_BODY = "Body";
 631 
 632     protected interface StreamHeaderDecoder {
 633         public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark);
 634     }
 635 
 636     static final StreamHeaderDecoder SOAP12StreamHeaderDecoder = new StreamHeaderDecoder() {
 637         @Override
 638         public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark) {
 639             return new StreamHeader12(reader, mark);
 640         }
 641     };
 642 
 643     static final StreamHeaderDecoder SOAP11StreamHeaderDecoder = new StreamHeaderDecoder() {
 644         @Override
 645         public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark) {
 646             return new StreamHeader11(reader, mark);
 647         }
 648     };
 649 
 650     static private void readEnvelope(StreamMessage message) {
 651         if ( message.envelopeReader == null ) return;
 652         XMLStreamReader reader = message.envelopeReader;
 653         message.envelopeReader = null;
 654         SOAPVersion soapVersion = message.soapVersion;
 655         // Move to soap:Envelope and verify
 656         if(reader.getEventType()!=XMLStreamConstants.START_ELEMENT)
 657             XMLStreamReaderUtil.nextElementContent(reader);
 658         XMLStreamReaderUtil.verifyReaderState(reader,XMLStreamConstants.START_ELEMENT);
 659         if (SOAP_ENVELOPE.equals(reader.getLocalName()) && !soapVersion.nsUri.equals(reader.getNamespaceURI())) {
 660             throw new VersionMismatchException(soapVersion, soapVersion.nsUri, reader.getNamespaceURI());
 661         }
 662         XMLStreamReaderUtil.verifyTag(reader, soapVersion.nsUri, SOAP_ENVELOPE);
 663 
 664         TagInfoset envelopeTag = new TagInfoset(reader);
 665 
 666         // Collect namespaces on soap:Envelope
 667         Map<String,String> namespaces = new HashMap<String,String>();
 668         for(int i=0; i< reader.getNamespaceCount();i++){
 669                 namespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
 670         }
 671 
 672         // Move to next element
 673         XMLStreamReaderUtil.nextElementContent(reader);
 674         XMLStreamReaderUtil.verifyReaderState(reader,
 675                 javax.xml.stream.XMLStreamConstants.START_ELEMENT);
 676 
 677         HeaderList headers = null;
 678         TagInfoset headerTag = null;
 679 
 680         if (reader.getLocalName().equals(SOAP_HEADER)
 681                 && reader.getNamespaceURI().equals(soapVersion.nsUri)) {
 682             headerTag = new TagInfoset(reader);
 683 
 684             // Collect namespaces on soap:Header
 685             for(int i=0; i< reader.getNamespaceCount();i++){
 686                 namespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
 687             }
 688             // skip <soap:Header>
 689             XMLStreamReaderUtil.nextElementContent(reader);
 690 
 691             // If SOAP header blocks are present (i.e. not <soap:Header/>)
 692             if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
 693                 headers = new HeaderList(soapVersion);
 694 
 695                 try {
 696                     // Cache SOAP header blocks
 697                     StreamHeaderDecoder headerDecoder = SOAPVersion.SOAP_11.equals(soapVersion) ? SOAP11StreamHeaderDecoder : SOAP12StreamHeaderDecoder;
 698                     cacheHeaders(reader, namespaces, headers, headerDecoder);
 699                 } catch (XMLStreamException e) {
 700                     // TODO need to throw more meaningful exception
 701                     throw new WebServiceException(e);
 702                 }
 703             }
 704 
 705             // Move to soap:Body
 706             XMLStreamReaderUtil.nextElementContent(reader);
 707         }
 708 
 709         // Verify that <soap:Body> is present
 710         XMLStreamReaderUtil.verifyTag(reader, soapVersion.nsUri, SOAP_BODY);
 711         TagInfoset bodyTag = new TagInfoset(reader);
 712 
 713         String bodyPrologue = XMLStreamReaderUtil.nextWhiteSpaceContent(reader);
 714         message.init(envelopeTag,headerTag,message.attachmentSet,headers,bodyPrologue,bodyTag,null,reader,soapVersion);
 715         // when there's no payload,
 716         // it's tempting to use EmptyMessageImpl, but it doesn't preserve the infoset
 717         // of <envelope>,<header>, and <body>, so we need to stick to StreamMessage.
 718     }
 719 
 720 
 721     private static XMLStreamBuffer cacheHeaders(XMLStreamReader reader,
 722             Map<String, String> namespaces, HeaderList headers,
 723             StreamHeaderDecoder headerDecoder) throws XMLStreamException {
 724         MutableXMLStreamBuffer buffer = createXMLStreamBuffer();
 725         StreamReaderBufferCreator creator = new StreamReaderBufferCreator();
 726         creator.setXMLStreamBuffer(buffer);
 727 
 728         // Reader is positioned at the first header block
 729         while(reader.getEventType() == javax.xml.stream.XMLStreamConstants.START_ELEMENT) {
 730             Map<String,String> headerBlockNamespaces = namespaces;
 731 
 732             // Collect namespaces on SOAP header block
 733             if (reader.getNamespaceCount() > 0) {
 734                 headerBlockNamespaces = new HashMap<String,String>(namespaces);
 735                 for (int i = 0; i < reader.getNamespaceCount(); i++) {
 736                     headerBlockNamespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
 737                 }
 738             }
 739 
 740             // Mark
 741             XMLStreamBuffer mark = new XMLStreamBufferMark(headerBlockNamespaces, creator);
 742             // Create Header
 743             headers.add(headerDecoder.decodeHeader(reader, mark));
 744 
 745 
 746             // Cache the header block
 747             // After caching Reader will be positioned at next header block or
 748             // the end of the </soap:header>
 749             creator.createElementFragment(reader, false);
 750             if (reader.getEventType() != XMLStreamConstants.START_ELEMENT &&
 751                     reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
 752                 XMLStreamReaderUtil.nextElementContent(reader);
 753             }
 754         }
 755 
 756         return buffer;
 757     }
 758 
 759     private static MutableXMLStreamBuffer createXMLStreamBuffer() {
 760         // TODO: Decode should own one MutableXMLStreamBuffer for reuse
 761         // since it is more efficient. ISSUE: possible issue with
 762         // lifetime of information in the buffer if accessed beyond
 763         // the pipe line.
 764         return new MutableXMLStreamBuffer();
 765     }
 766 }