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

changeset 397
b99d7e355d4b
parent 384
8f2986ff0235
child 637
9c07ef4934dd
     1.1 --- a/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java	Thu Aug 08 10:10:38 2013 -0700
     1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java	Fri Aug 23 09:57:21 2013 +0100
     1.3 @@ -30,6 +30,8 @@
     1.4  import com.sun.istack.internal.XMLStreamReaderToContentHandler;
     1.5  import com.sun.xml.internal.bind.api.Bridge;
     1.6  import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
     1.7 +import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
     1.8 +import com.sun.xml.internal.stream.buffer.XMLStreamBufferMark;
     1.9  import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferCreator;
    1.10  import com.sun.xml.internal.ws.api.SOAPVersion;
    1.11  import com.sun.xml.internal.ws.api.message.AttachmentSet;
    1.12 @@ -37,15 +39,20 @@
    1.13  import com.sun.xml.internal.ws.api.message.HeaderList;
    1.14  import com.sun.xml.internal.ws.api.message.Message;
    1.15  import com.sun.xml.internal.ws.api.message.MessageHeaders;
    1.16 +import com.sun.xml.internal.ws.api.message.StreamingSOAP;
    1.17  import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
    1.18  import com.sun.xml.internal.ws.encoding.TagInfoset;
    1.19  import com.sun.xml.internal.ws.message.AbstractMessageImpl;
    1.20  import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
    1.21 +import com.sun.xml.internal.ws.protocol.soap.VersionMismatchException;
    1.22  import com.sun.xml.internal.ws.spi.db.XMLBridge;
    1.23  import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
    1.24  import com.sun.xml.internal.ws.util.xml.DummyLocation;
    1.25  import com.sun.xml.internal.ws.util.xml.StAXSource;
    1.26 +import com.sun.xml.internal.ws.util.xml.XMLReaderComposite;
    1.27  import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter;
    1.28 +import com.sun.xml.internal.ws.util.xml.XMLReaderComposite.ElemInfo;
    1.29 +
    1.30  import org.xml.sax.ContentHandler;
    1.31  import org.xml.sax.ErrorHandler;
    1.32  import org.xml.sax.SAXException;
    1.33 @@ -55,6 +62,7 @@
    1.34  import javax.xml.bind.JAXBException;
    1.35  import javax.xml.bind.Unmarshaller;
    1.36  import javax.xml.stream.*;
    1.37 +
    1.38  import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
    1.39  import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
    1.40  import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
    1.41 @@ -62,7 +70,9 @@
    1.42  import javax.xml.ws.WebServiceException;
    1.43  import java.util.ArrayList;
    1.44  import java.util.Enumeration;
    1.45 +import java.util.HashMap;
    1.46  import java.util.List;
    1.47 +import java.util.Map;
    1.48  
    1.49  /**
    1.50   * {@link Message} implementation backed by {@link XMLStreamReader}.
    1.51 @@ -70,7 +80,7 @@
    1.52   * TODO: we need another message class that keeps {@link XMLStreamReader} that points
    1.53   * at the start of the envelope element.
    1.54   */
    1.55 -public class StreamMessage extends AbstractMessageImpl {
    1.56 +public class StreamMessage extends AbstractMessageImpl implements StreamingSOAP {
    1.57      /**
    1.58       * The reader will be positioned at
    1.59       * the first child of the SOAP body
    1.60 @@ -93,44 +103,51 @@
    1.61       */
    1.62      private String bodyEpilogue = null;
    1.63  
    1.64 -    private final String payloadLocalName;
    1.65 +    private String payloadLocalName;
    1.66  
    1.67 -    private final String payloadNamespaceURI;
    1.68 -
    1.69 -    /**
    1.70 -     * infoset about the SOAP envelope, header, and body.
    1.71 -     *
    1.72 -     * <p>
    1.73 -     * If the creater of this object didn't care about those,
    1.74 -     * we use stock values.
    1.75 -     */
    1.76 -    private @NotNull TagInfoset envelopeTag;
    1.77 -    private @NotNull TagInfoset headerTag;
    1.78 -    private @NotNull TagInfoset bodyTag;
    1.79 +    private String payloadNamespaceURI;
    1.80  
    1.81      /**
    1.82       * Used only for debugging. This records where the message was consumed.
    1.83       */
    1.84      private Throwable consumedAt;
    1.85  
    1.86 -    /**
    1.87 -     * Default s:Envelope, s:Header, and s:Body tag infoset definitions.
    1.88 -     *
    1.89 -     * We need 3 for SOAP 1.1, 3 for SOAP 1.2.
    1.90 -     */
    1.91 -    private static final TagInfoset[] DEFAULT_TAGS;
    1.92 -
    1.93 -    static {
    1.94 -        DEFAULT_TAGS = new TagInfoset[6];
    1.95 -        create(SOAPVersion.SOAP_11);
    1.96 -        create(SOAPVersion.SOAP_12);
    1.97 -    }
    1.98 +    private XMLStreamReader envelopeReader;
    1.99  
   1.100      public StreamMessage(SOAPVersion v) {
   1.101          super(v);
   1.102          payloadLocalName = null;
   1.103          payloadNamespaceURI = null;
   1.104      }
   1.105 +
   1.106 +    public StreamMessage(SOAPVersion v, @NotNull XMLStreamReader envelope, @NotNull AttachmentSet attachments) {
   1.107 +        super(v);
   1.108 +        envelopeReader = envelope;
   1.109 +        attachmentSet = attachments;
   1.110 +    }
   1.111 +
   1.112 +    public XMLStreamReader readEnvelope() {
   1.113 +        if (envelopeReader == null) {
   1.114 +            List<XMLStreamReader> hReaders = new java.util.ArrayList<XMLStreamReader>();
   1.115 +            ElemInfo envElem =  new ElemInfo(envelopeTag, null);
   1.116 +            ElemInfo hdrElem =  (headerTag != null) ? new ElemInfo(headerTag, envElem) : null;
   1.117 +            ElemInfo bdyElem =  new ElemInfo(bodyTag,   envElem);
   1.118 +            for (Header h : getHeaders().asList()) {
   1.119 +                try {
   1.120 +                    hReaders.add(h.readHeader());
   1.121 +                } catch (XMLStreamException e) {
   1.122 +                    throw new RuntimeException(e);
   1.123 +                }
   1.124 +            }
   1.125 +            XMLStreamReader soapHeader = (hdrElem != null) ? new XMLReaderComposite(hdrElem, hReaders.toArray(new XMLStreamReader[hReaders.size()])) : null;
   1.126 +            XMLStreamReader[] payload = {readPayload()};
   1.127 +            XMLStreamReader soapBody = new XMLReaderComposite(bdyElem, payload);
   1.128 +            XMLStreamReader[] soapContent = (soapHeader != null) ? new XMLStreamReader[]{soapHeader, soapBody} : new XMLStreamReader[]{soapBody};
   1.129 +            return new XMLReaderComposite(envElem, soapContent);
   1.130 +        }
   1.131 +        return envelopeReader;
   1.132 +    }
   1.133 +
   1.134      /**
   1.135       * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
   1.136       * that points at the start element of the payload, and headers.
   1.137 @@ -147,6 +164,10 @@
   1.138       */
   1.139      public StreamMessage(@Nullable MessageHeaders headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
   1.140          super(soapVersion);
   1.141 +        init(headers, attachmentSet, reader, soapVersion);
   1.142 +    }
   1.143 +
   1.144 +    private void init(@Nullable MessageHeaders headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
   1.145          this.headers = headers;
   1.146          this.attachmentSet = attachmentSet;
   1.147          this.reader = reader;
   1.148 @@ -175,9 +196,9 @@
   1.149  
   1.150          // use the default infoset representation for headers
   1.151          int base = soapVersion.ordinal()*3;
   1.152 -        this.envelopeTag = DEFAULT_TAGS[base];
   1.153 -        this.headerTag = DEFAULT_TAGS[base+1];
   1.154 -        this.bodyTag = DEFAULT_TAGS[base+2];
   1.155 +        this.envelopeTag = DEFAULT_TAGS.get(base);
   1.156 +        this.headerTag = DEFAULT_TAGS.get(base+1);
   1.157 +        this.bodyTag = DEFAULT_TAGS.get(base+2);
   1.158      }
   1.159  
   1.160      /**
   1.161 @@ -197,7 +218,12 @@
   1.162      }
   1.163  
   1.164      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) {
   1.165 -        this(headers,attachmentSet,reader,soapVersion);
   1.166 +        super(soapVersion);
   1.167 +        init(envelopeTag, headerTag, attachmentSet, headers, bodyPrologue, bodyTag, bodyEpilogue, reader, soapVersion);
   1.168 +    }
   1.169 +
   1.170 +    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) {
   1.171 +        init(headers,attachmentSet,reader,soapVersion);
   1.172          if(envelopeTag == null ) {
   1.173              throw new IllegalArgumentException("EnvelopeTag TagInfoset cannot be null");
   1.174          }
   1.175 @@ -212,10 +238,12 @@
   1.176      }
   1.177  
   1.178      public boolean hasHeaders() {
   1.179 +        if ( envelopeReader != null ) readEnvelope(this);
   1.180          return headers!=null && headers.hasHeaders();
   1.181      }
   1.182  
   1.183      public MessageHeaders getHeaders() {
   1.184 +        if ( envelopeReader != null ) readEnvelope(this);
   1.185          if (headers == null) {
   1.186              headers = new HeaderList(getSOAPVersion());
   1.187          }
   1.188 @@ -223,14 +251,17 @@
   1.189      }
   1.190  
   1.191      public String getPayloadLocalPart() {
   1.192 +        if ( envelopeReader != null ) readEnvelope(this);
   1.193          return payloadLocalName;
   1.194      }
   1.195  
   1.196      public String getPayloadNamespaceURI() {
   1.197 +        if ( envelopeReader != null ) readEnvelope(this);
   1.198          return payloadNamespaceURI;
   1.199      }
   1.200  
   1.201      public boolean hasPayload() {
   1.202 +        if ( envelopeReader != null ) readEnvelope(this);
   1.203          return payloadLocalName!=null;
   1.204      }
   1.205  
   1.206 @@ -329,6 +360,7 @@
   1.207      }
   1.208  
   1.209      public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException {
   1.210 +        if ( envelopeReader != null ) readEnvelope(this);
   1.211          assert unconsumed();
   1.212  
   1.213          if(payloadLocalName==null) {
   1.214 @@ -379,6 +411,7 @@
   1.215      }
   1.216  
   1.217      public void writeTo(XMLStreamWriter sw) throws XMLStreamException{
   1.218 +        if ( envelopeReader != null ) readEnvelope(this);
   1.219          writeEnvelope(sw);
   1.220      }
   1.221  
   1.222 @@ -387,6 +420,7 @@
   1.223       * @param writer
   1.224       */
   1.225      private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException {
   1.226 +        if ( envelopeReader != null ) readEnvelope(this);
   1.227          writer.writeStartDocument();
   1.228          envelopeTag.writeStart(writer);
   1.229  
   1.230 @@ -411,6 +445,7 @@
   1.231      }
   1.232  
   1.233      public void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
   1.234 +        if ( envelopeReader != null ) readEnvelope(this);
   1.235          assert unconsumed();
   1.236  
   1.237          try {
   1.238 @@ -465,8 +500,10 @@
   1.239          }
   1.240      }
   1.241  
   1.242 -    // TODO: this method should be probably rewritten to respect spaces between eelements; is it used at all?
   1.243 +    // TODO: this method should be probably rewritten to respect spaces between elements; is it used at all?
   1.244 +    @Override
   1.245      public Message copy() {
   1.246 +        if ( envelopeReader != null ) readEnvelope(this);
   1.247          try {
   1.248              assert unconsumed();
   1.249              consumedAt = null; // but we don't want to mark it as consumed
   1.250 @@ -528,6 +565,7 @@
   1.251      }
   1.252  
   1.253      public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException {
   1.254 +        if ( envelopeReader != null ) readEnvelope(this);
   1.255          contentHandler.setDocumentLocator(NULL_LOCATOR);
   1.256          contentHandler.startDocument();
   1.257          envelopeTag.writeStart(contentHandler);
   1.258 @@ -570,23 +608,159 @@
   1.259          return true;
   1.260      }
   1.261  
   1.262 -    private static void create(SOAPVersion v) {
   1.263 -        int base = v.ordinal()*3;
   1.264 -        DEFAULT_TAGS[base  ] = new TagInfoset(v.nsUri,"Envelope","S",EMPTY_ATTS,"S",v.nsUri);
   1.265 -        DEFAULT_TAGS[base+1] = new TagInfoset(v.nsUri,"Header","S",EMPTY_ATTS);
   1.266 -        DEFAULT_TAGS[base+2] = new TagInfoset(v.nsUri,"Body","S",EMPTY_ATTS);
   1.267 -    }
   1.268 -
   1.269      public String getBodyPrologue() {
   1.270 +        if ( envelopeReader != null ) readEnvelope(this);
   1.271          return bodyPrologue;
   1.272      }
   1.273  
   1.274      public String getBodyEpilogue() {
   1.275 +        if ( envelopeReader != null ) readEnvelope(this);
   1.276          return bodyEpilogue;
   1.277      }
   1.278  
   1.279      public XMLStreamReader getReader() {
   1.280 +        if ( envelopeReader != null ) readEnvelope(this);
   1.281          assert unconsumed();
   1.282          return reader;
   1.283      }
   1.284 +
   1.285 +
   1.286 +    private static final String SOAP_ENVELOPE = "Envelope";
   1.287 +    private static final String SOAP_HEADER = "Header";
   1.288 +    private static final String SOAP_BODY = "Body";
   1.289 +
   1.290 +    protected interface StreamHeaderDecoder {
   1.291 +        public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark);
   1.292 +    }
   1.293 +
   1.294 +    static final StreamHeaderDecoder SOAP12StreamHeaderDecoder = new StreamHeaderDecoder() {
   1.295 +        @Override
   1.296 +        public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark) {
   1.297 +            return new StreamHeader12(reader, mark);
   1.298 +        }
   1.299 +    };
   1.300 +
   1.301 +    static final StreamHeaderDecoder SOAP11StreamHeaderDecoder = new StreamHeaderDecoder() {
   1.302 +        @Override
   1.303 +        public Header decodeHeader(XMLStreamReader reader, XMLStreamBuffer mark) {
   1.304 +            return new StreamHeader11(reader, mark);
   1.305 +        }
   1.306 +    };
   1.307 +
   1.308 +    static private void readEnvelope(StreamMessage message) {
   1.309 +        if ( message.envelopeReader == null ) return;
   1.310 +        XMLStreamReader reader = message.envelopeReader;
   1.311 +        message.envelopeReader = null;
   1.312 +        SOAPVersion soapVersion = message.soapVersion;
   1.313 +        // Move to soap:Envelope and verify
   1.314 +        if(reader.getEventType()!=XMLStreamConstants.START_ELEMENT)
   1.315 +            XMLStreamReaderUtil.nextElementContent(reader);
   1.316 +        XMLStreamReaderUtil.verifyReaderState(reader,XMLStreamConstants.START_ELEMENT);
   1.317 +        if (SOAP_ENVELOPE.equals(reader.getLocalName()) && !soapVersion.nsUri.equals(reader.getNamespaceURI())) {
   1.318 +            throw new VersionMismatchException(soapVersion, soapVersion.nsUri, reader.getNamespaceURI());
   1.319 +        }
   1.320 +        XMLStreamReaderUtil.verifyTag(reader, soapVersion.nsUri, SOAP_ENVELOPE);
   1.321 +
   1.322 +        TagInfoset envelopeTag = new TagInfoset(reader);
   1.323 +
   1.324 +        // Collect namespaces on soap:Envelope
   1.325 +        Map<String,String> namespaces = new HashMap<String,String>();
   1.326 +        for(int i=0; i< reader.getNamespaceCount();i++){
   1.327 +                namespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
   1.328 +        }
   1.329 +
   1.330 +        // Move to next element
   1.331 +        XMLStreamReaderUtil.nextElementContent(reader);
   1.332 +        XMLStreamReaderUtil.verifyReaderState(reader,
   1.333 +                javax.xml.stream.XMLStreamConstants.START_ELEMENT);
   1.334 +
   1.335 +        HeaderList headers = null;
   1.336 +        TagInfoset headerTag = null;
   1.337 +
   1.338 +        if (reader.getLocalName().equals(SOAP_HEADER)
   1.339 +                && reader.getNamespaceURI().equals(soapVersion.nsUri)) {
   1.340 +            headerTag = new TagInfoset(reader);
   1.341 +
   1.342 +            // Collect namespaces on soap:Header
   1.343 +            for(int i=0; i< reader.getNamespaceCount();i++){
   1.344 +                namespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
   1.345 +            }
   1.346 +            // skip <soap:Header>
   1.347 +            XMLStreamReaderUtil.nextElementContent(reader);
   1.348 +
   1.349 +            // If SOAP header blocks are present (i.e. not <soap:Header/>)
   1.350 +            if (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
   1.351 +                headers = new HeaderList(soapVersion);
   1.352 +
   1.353 +                try {
   1.354 +                    // Cache SOAP header blocks
   1.355 +                    StreamHeaderDecoder headerDecoder = SOAPVersion.SOAP_11.equals(soapVersion) ? SOAP11StreamHeaderDecoder : SOAP12StreamHeaderDecoder;
   1.356 +                    cacheHeaders(reader, namespaces, headers, headerDecoder);
   1.357 +                } catch (XMLStreamException e) {
   1.358 +                    // TODO need to throw more meaningful exception
   1.359 +                    throw new WebServiceException(e);
   1.360 +                }
   1.361 +            }
   1.362 +
   1.363 +            // Move to soap:Body
   1.364 +            XMLStreamReaderUtil.nextElementContent(reader);
   1.365 +        }
   1.366 +
   1.367 +        // Verify that <soap:Body> is present
   1.368 +        XMLStreamReaderUtil.verifyTag(reader, soapVersion.nsUri, SOAP_BODY);
   1.369 +        TagInfoset bodyTag = new TagInfoset(reader);
   1.370 +
   1.371 +        String bodyPrologue = XMLStreamReaderUtil.nextWhiteSpaceContent(reader);
   1.372 +        message.init(envelopeTag,headerTag,message.attachmentSet,headers,bodyPrologue,bodyTag,null,reader,soapVersion);
   1.373 +        // when there's no payload,
   1.374 +        // it's tempting to use EmptyMessageImpl, but it doesn't preserve the infoset
   1.375 +        // of <envelope>,<header>, and <body>, so we need to stick to StreamMessage.
   1.376 +    }
   1.377 +
   1.378 +
   1.379 +    private static XMLStreamBuffer cacheHeaders(XMLStreamReader reader,
   1.380 +            Map<String, String> namespaces, HeaderList headers,
   1.381 +            StreamHeaderDecoder headerDecoder) throws XMLStreamException {
   1.382 +        MutableXMLStreamBuffer buffer = createXMLStreamBuffer();
   1.383 +        StreamReaderBufferCreator creator = new StreamReaderBufferCreator();
   1.384 +        creator.setXMLStreamBuffer(buffer);
   1.385 +
   1.386 +        // Reader is positioned at the first header block
   1.387 +        while(reader.getEventType() == javax.xml.stream.XMLStreamConstants.START_ELEMENT) {
   1.388 +            Map<String,String> headerBlockNamespaces = namespaces;
   1.389 +
   1.390 +            // Collect namespaces on SOAP header block
   1.391 +            if (reader.getNamespaceCount() > 0) {
   1.392 +                headerBlockNamespaces = new HashMap<String,String>(namespaces);
   1.393 +                for (int i = 0; i < reader.getNamespaceCount(); i++) {
   1.394 +                    headerBlockNamespaces.put(reader.getNamespacePrefix(i), reader.getNamespaceURI(i));
   1.395 +                }
   1.396 +            }
   1.397 +
   1.398 +            // Mark
   1.399 +            XMLStreamBuffer mark = new XMLStreamBufferMark(headerBlockNamespaces, creator);
   1.400 +            // Create Header
   1.401 +            headers.add(headerDecoder.decodeHeader(reader, mark));
   1.402 +
   1.403 +
   1.404 +            // Cache the header block
   1.405 +            // After caching Reader will be positioned at next header block or
   1.406 +            // the end of the </soap:header>
   1.407 +            creator.createElementFragment(reader, false);
   1.408 +            if (reader.getEventType() != XMLStreamConstants.START_ELEMENT &&
   1.409 +                    reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
   1.410 +                XMLStreamReaderUtil.nextElementContent(reader);
   1.411 +            }
   1.412 +        }
   1.413 +
   1.414 +        return buffer;
   1.415 +    }
   1.416 +
   1.417 +    private static MutableXMLStreamBuffer createXMLStreamBuffer() {
   1.418 +        // TODO: Decode should own one MutableXMLStreamBuffer for reuse
   1.419 +        // since it is more efficient. ISSUE: possible issue with
   1.420 +        // lifetime of information in the buffer if accessed beyond
   1.421 +        // the pipe line.
   1.422 +        return new MutableXMLStreamBuffer();
   1.423 +    }
   1.424  }

mercurial