src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/xml/XMLMessage.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1997, 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  */
    26 package com.sun.xml.internal.ws.encoding.xml;
    28 import com.sun.istack.internal.NotNull;
    29 import com.sun.xml.internal.bind.api.Bridge;
    30 import com.sun.xml.internal.ws.api.SOAPVersion;
    31 import com.sun.xml.internal.ws.api.WSFeatureList;
    32 import com.sun.xml.internal.ws.api.message.*;
    33 import com.sun.xml.internal.ws.api.model.wsdl.WSDLPort;
    34 import com.sun.xml.internal.ws.api.pipe.Codec;
    35 import com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory;
    36 import com.sun.xml.internal.ws.developer.StreamingAttachmentFeature;
    37 import com.sun.xml.internal.ws.encoding.ContentType;
    38 import com.sun.xml.internal.ws.encoding.MimeMultipartParser;
    39 import com.sun.xml.internal.ws.encoding.XMLHTTPBindingCodec;
    40 import com.sun.xml.internal.ws.message.AbstractMessageImpl;
    41 import com.sun.xml.internal.ws.message.EmptyMessageImpl;
    42 import com.sun.xml.internal.ws.message.MimeAttachmentSet;
    43 import com.sun.xml.internal.ws.message.source.PayloadSourceMessage;
    44 import com.sun.xml.internal.ws.util.ByteArrayBuffer;
    45 import com.sun.xml.internal.ws.util.StreamUtils;
    46 import org.xml.sax.ContentHandler;
    47 import org.xml.sax.ErrorHandler;
    48 import org.xml.sax.SAXException;
    50 import javax.activation.DataSource;
    51 import javax.xml.bind.JAXBException;
    52 import javax.xml.bind.Unmarshaller;
    53 import javax.xml.soap.SOAPException;
    54 import javax.xml.soap.SOAPMessage;
    55 import javax.xml.stream.XMLStreamException;
    56 import javax.xml.stream.XMLStreamReader;
    57 import javax.xml.stream.XMLStreamWriter;
    58 import javax.xml.transform.Source;
    59 import javax.xml.transform.stream.StreamSource;
    60 import javax.xml.ws.WebServiceException;
    62 import java.io.IOException;
    63 import java.io.InputStream;
    64 import java.io.OutputStream;
    66 /**
    67  *
    68  * @author Jitendra Kotamraju
    69  */
    70 public final class XMLMessage {
    72     private static final int PLAIN_XML_FLAG      = 1;       // 00001
    73     private static final int MIME_MULTIPART_FLAG = 2;       // 00010
    74     private static final int FI_ENCODED_FLAG     = 16;      // 10000
    76     /*
    77      * Construct a message given a content type and an input stream.
    78      */
    79     public static Message create(final String ct, InputStream in, WSFeatureList f) {
    80         Message data;
    81         try {
    82             in = StreamUtils.hasSomeData(in);
    83             if (in == null) {
    84                 return Messages.createEmpty(SOAPVersion.SOAP_11);
    85             }
    87             if (ct != null) {
    88                 final ContentType contentType = new ContentType(ct);
    89                 final int contentTypeId = identifyContentType(contentType);
    90                 if ((contentTypeId & MIME_MULTIPART_FLAG) != 0) {
    91                     data = new XMLMultiPart(ct, in, f);
    92                 } else if ((contentTypeId & PLAIN_XML_FLAG) != 0) {
    93                     data = new XmlContent(ct, in, f);
    94                 } else {
    95                     data = new UnknownContent(ct, in);
    96                 }
    97             } else {
    98                 // According to HTTP spec 7.2.1, if the media type remain
    99                 // unknown, treat as application/octet-stream
   100                 data = new UnknownContent("application/octet-stream", in);
   101             }
   102         } catch(Exception ex) {
   103             throw new WebServiceException(ex);
   104         }
   105         return data;
   106     }
   109     public static Message create(Source source) {
   110         return (source == null) ?
   111             Messages.createEmpty(SOAPVersion.SOAP_11) :
   112             Messages.createUsingPayload(source, SOAPVersion.SOAP_11);
   113     }
   115     public static Message create(DataSource ds, WSFeatureList f) {
   116         try {
   117             return (ds == null) ?
   118                 Messages.createEmpty(SOAPVersion.SOAP_11) :
   119                 create(ds.getContentType(), ds.getInputStream(), f);
   120         } catch(IOException ioe) {
   121             throw new WebServiceException(ioe);
   122         }
   123     }
   125     public static Message create(Exception e) {
   126         return new FaultMessage(SOAPVersion.SOAP_11);
   127     }
   129     /*
   130      * Get the content type ID from the content type.
   131      */
   132     private static int getContentId(String ct) {
   133         try {
   134             final ContentType contentType = new ContentType(ct);
   135             return identifyContentType(contentType);
   136         } catch(Exception ex) {
   137             throw new WebServiceException(ex);
   138         }
   139     }
   141     /**
   142      * Return true if the content uses fast infoset.
   143      */
   144     public static boolean isFastInfoset(String ct) {
   145         return (getContentId(ct) & FI_ENCODED_FLAG) != 0;
   146     }
   148     /*
   149      * Verify a contentType.
   150      *
   151      * @return
   152      * MIME_MULTIPART_FLAG | PLAIN_XML_FLAG
   153      * MIME_MULTIPART_FLAG | FI_ENCODED_FLAG;
   154      * PLAIN_XML_FLAG
   155      * FI_ENCODED_FLAG
   156      *
   157      */
   158     public static int identifyContentType(ContentType contentType) {
   159         String primary = contentType.getPrimaryType();
   160         String sub = contentType.getSubType();
   162         if (primary.equalsIgnoreCase("multipart") && sub.equalsIgnoreCase("related")) {
   163             String type = contentType.getParameter("type");
   164             if (type != null) {
   165                 if (isXMLType(type)) {
   166                     return MIME_MULTIPART_FLAG | PLAIN_XML_FLAG;
   167                 } else if (isFastInfosetType(type)) {
   168                     return MIME_MULTIPART_FLAG | FI_ENCODED_FLAG;
   169                 }
   170             }
   171             return 0;
   172         } else if (isXMLType(primary, sub)) {
   173             return PLAIN_XML_FLAG;
   174         } else if (isFastInfosetType(primary, sub)) {
   175             return FI_ENCODED_FLAG;
   176         }
   177         return 0;
   178     }
   180     protected static boolean isXMLType(@NotNull String primary, @NotNull String sub) {
   181         return (primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml"))
   182                 || (primary.equalsIgnoreCase("application") && sub.equalsIgnoreCase("xml"))
   183                 || (primary.equalsIgnoreCase("application") && sub.toLowerCase().endsWith("+xml"));
   184     }
   186     protected static boolean isXMLType(String type) {
   187         String lowerType = type.toLowerCase();
   188         return lowerType.startsWith("text/xml")
   189                 || lowerType.startsWith("application/xml")
   190                 || (lowerType.startsWith("application/") && (lowerType.indexOf("+xml") != -1));
   191     }
   193     protected static boolean isFastInfosetType(String primary, String sub) {
   194         return primary.equalsIgnoreCase("application") && sub.equalsIgnoreCase("fastinfoset");
   195     }
   197     protected static boolean isFastInfosetType(String type) {
   198         return type.toLowerCase().startsWith("application/fastinfoset");
   199     }
   202     /**
   203      * Access a {@link Message} as a {@link DataSource}.
   204      * <p>
   205      * A {@link Message} implementation will implement this if the
   206      * messages is to be access as data source.
   207      * <p>
   208      * TODO: consider putting as part of the API.
   209      */
   210     public static interface MessageDataSource {
   211         /**
   212          * Check if the data source has been consumed.
   213          * @return true of the data source has been consumed, otherwise false.
   214          */
   215         boolean hasUnconsumedDataSource();
   217         /**
   218          * Get the data source.
   219          * @return the data source.
   220          */
   221         DataSource getDataSource();
   222     }
   224     /**
   225      * It's conent-type is some XML type
   226      *
   227      */
   228     private static class XmlContent extends AbstractMessageImpl implements MessageDataSource {
   229         private final XmlDataSource dataSource;
   230         private boolean consumed;
   231         private Message delegate;
   232         private final HeaderList headerList;
   233 //      private final WSBinding binding;
   234         private WSFeatureList features;
   236         public XmlContent(String ct, InputStream in, WSFeatureList f) {
   237             super(SOAPVersion.SOAP_11);
   238             dataSource = new XmlDataSource(ct, in);
   239             this.headerList = new HeaderList(SOAPVersion.SOAP_11);
   240 //            this.binding = binding;
   241             features = f;
   242         }
   244         private Message getMessage() {
   245             if (delegate == null) {
   246                 InputStream in = dataSource.getInputStream();
   247                 assert in != null;
   248                 delegate = Messages.createUsingPayload(new StreamSource(in), SOAPVersion.SOAP_11);
   249                 consumed = true;
   250             }
   251             return delegate;
   252         }
   254         public boolean hasUnconsumedDataSource() {
   255             return !dataSource.consumed()&&!consumed;
   256         }
   258         public DataSource getDataSource() {
   259             return hasUnconsumedDataSource() ? dataSource :
   260                 XMLMessage.getDataSource(getMessage(), features);
   261         }
   263         public boolean hasHeaders() {
   264             return false;
   265         }
   267         public @NotNull MessageHeaders getHeaders() {
   268             return headerList;
   269         }
   271         public String getPayloadLocalPart() {
   272             return getMessage().getPayloadLocalPart();
   273         }
   275         public String getPayloadNamespaceURI() {
   276             return getMessage().getPayloadNamespaceURI();
   277         }
   279         public boolean hasPayload() {
   280             return true;
   281         }
   283         public boolean isFault() {
   284             return false;
   285         }
   287         public Source readEnvelopeAsSource() {
   288             return getMessage().readEnvelopeAsSource();
   289         }
   291         public Source readPayloadAsSource() {
   292             return getMessage().readPayloadAsSource();
   293         }
   295         public SOAPMessage readAsSOAPMessage() throws SOAPException {
   296             return getMessage().readAsSOAPMessage();
   297         }
   299         public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException {
   300             return getMessage().readAsSOAPMessage(packet, inbound);
   301         }
   303         public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
   304             return (T)getMessage().readPayloadAsJAXB(unmarshaller);
   305         }
   306         /** @deprecated */
   307         public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
   308             return getMessage().readPayloadAsJAXB(bridge);
   309         }
   311         public XMLStreamReader readPayload() throws XMLStreamException {
   312             return getMessage().readPayload();
   313         }
   316         public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
   317             getMessage().writePayloadTo(sw);
   318         }
   320         public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
   321             getMessage().writeTo(sw);
   322         }
   324         public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException {
   325             getMessage().writeTo(contentHandler, errorHandler);
   326         }
   328         public Message copy() {
   329             return getMessage().copy();
   330         }
   332         protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
   333             throw new UnsupportedOperationException();
   334         }
   336     }
   340     /**
   341      * Data represented as a multi-part MIME message.
   342      * <p>
   343      * The root part may be an XML or an FI document. This class
   344      * parses MIME message lazily.
   345      */
   346     public static final class XMLMultiPart extends AbstractMessageImpl implements MessageDataSource {
   347         private final DataSource dataSource;
   348         private final StreamingAttachmentFeature feature;
   349         private Message delegate;
   350         private HeaderList headerList;// = new HeaderList();
   351 //      private final WSBinding binding;
   352         private final WSFeatureList features;
   354         public XMLMultiPart(final String contentType, final InputStream is, WSFeatureList f) {
   355             super(SOAPVersion.SOAP_11);
   356             headerList = new HeaderList(SOAPVersion.SOAP_11);
   357             dataSource = createDataSource(contentType, is);
   358             this.feature = f.get(StreamingAttachmentFeature.class);
   359             this.features = f;
   360         }
   362         private Message getMessage() {
   363             if (delegate == null) {
   364                 MimeMultipartParser mpp;
   365                 try {
   366                     mpp = new MimeMultipartParser(dataSource.getInputStream(),
   367                             dataSource.getContentType(), feature);
   368                 } catch(IOException ioe) {
   369                     throw new WebServiceException(ioe);
   370                 }
   371                 InputStream in = mpp.getRootPart().asInputStream();
   372                 assert in != null;
   373                 delegate = new PayloadSourceMessage(headerList, new StreamSource(in), new MimeAttachmentSet(mpp), SOAPVersion.SOAP_11);
   374             }
   375             return delegate;
   376         }
   378         public boolean hasUnconsumedDataSource() {
   379             return delegate == null;
   380         }
   382         public DataSource getDataSource() {
   383             return hasUnconsumedDataSource() ? dataSource :
   384                 XMLMessage.getDataSource(getMessage(), features);
   385         }
   387         public boolean hasHeaders() {
   388             return false;
   389         }
   391         public @NotNull MessageHeaders getHeaders() {
   392             return headerList;
   393         }
   395         public String getPayloadLocalPart() {
   396             return getMessage().getPayloadLocalPart();
   397         }
   399         public String getPayloadNamespaceURI() {
   400             return getMessage().getPayloadNamespaceURI();
   401         }
   403         public boolean hasPayload() {
   404             return true;
   405         }
   407         public boolean isFault() {
   408             return false;
   409         }
   411         public Source readEnvelopeAsSource() {
   412             return getMessage().readEnvelopeAsSource();
   413         }
   415         public Source readPayloadAsSource() {
   416             return getMessage().readPayloadAsSource();
   417         }
   419         public SOAPMessage readAsSOAPMessage() throws SOAPException {
   420             return getMessage().readAsSOAPMessage();
   421         }
   423         public SOAPMessage readAsSOAPMessage(Packet packet, boolean inbound) throws SOAPException {
   424             return getMessage().readAsSOAPMessage(packet, inbound);
   425         }
   427         public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
   428             return (T)getMessage().readPayloadAsJAXB(unmarshaller);
   429         }
   431         public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
   432             return getMessage().readPayloadAsJAXB(bridge);
   433         }
   435         public XMLStreamReader readPayload() throws XMLStreamException {
   436             return getMessage().readPayload();
   437         }
   439         public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
   440             getMessage().writePayloadTo(sw);
   441         }
   443         public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
   444             getMessage().writeTo(sw);
   445         }
   447         public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException {
   448             getMessage().writeTo(contentHandler, errorHandler);
   449         }
   451         public Message copy() {
   452             return getMessage().copy();
   453         }
   455         protected void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
   456             throw new UnsupportedOperationException();
   457         }
   459         @Override
   460         public boolean isOneWay(@NotNull WSDLPort port) {
   461             return false;
   462         }
   464         public @NotNull AttachmentSet getAttachments() {
   465             return getMessage().getAttachments();
   466         }
   468     }
   470     private static class FaultMessage extends EmptyMessageImpl {
   472         public FaultMessage(SOAPVersion version) {
   473             super(version);
   474         }
   476         @Override
   477         public boolean isFault() {
   478             return true;
   479         }
   480     }
   483     /**
   484      * Don't know about this content. It's conent-type is NOT the XML types
   485      * we recognize(text/xml, application/xml, multipart/related;text/xml etc).
   486      *
   487      * This could be used to represent image/jpeg etc
   488      */
   489     public static class UnknownContent extends AbstractMessageImpl implements MessageDataSource {
   490         private final DataSource ds;
   491         private final HeaderList headerList;
   493         public UnknownContent(final String ct, final InputStream in) {
   494             this(createDataSource(ct,in));
   495         }
   497         public UnknownContent(DataSource ds) {
   498             super(SOAPVersion.SOAP_11);
   499             this.ds = ds;
   500             this.headerList = new HeaderList(SOAPVersion.SOAP_11);
   501         }
   503         /*
   504          * Copy constructor.
   505          */
   506         private UnknownContent(UnknownContent that) {
   507             super(that.soapVersion);
   508             this.ds = that.ds;
   509             this.headerList = HeaderList.copy(that.headerList);
   510         }
   512         public boolean hasUnconsumedDataSource() {
   513             return true;
   514         }
   516         public DataSource getDataSource() {
   517             assert ds != null;
   518             return ds;
   519         }
   521         protected void writePayloadTo(ContentHandler contentHandler,
   522                 ErrorHandler errorHandler, boolean fragment) throws SAXException {
   523             throw new UnsupportedOperationException();
   524         }
   526         public boolean hasHeaders() {
   527             return false;
   528         }
   530         public boolean isFault() {
   531             return false;
   532         }
   534         public MessageHeaders getHeaders() {
   535             return headerList;
   536         }
   538         public String getPayloadLocalPart() {
   539             throw new UnsupportedOperationException();
   540         }
   542         public String getPayloadNamespaceURI() {
   543             throw new UnsupportedOperationException();
   544         }
   546         public boolean hasPayload() {
   547             return false;
   548         }
   550         public Source readPayloadAsSource() {
   551             return null;
   552         }
   554         public XMLStreamReader readPayload() throws XMLStreamException {
   555             throw new WebServiceException("There isn't XML payload. Shouldn't come here.");
   556         }
   558         public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException {
   559             // No XML. Nothing to do
   560         }
   562         public Message copy() {
   563             return new UnknownContent(this);
   564         }
   566     }
   568     public static DataSource getDataSource(Message msg, WSFeatureList f) {
   569         if (msg == null)
   570             return null;
   571         if (msg instanceof MessageDataSource) {
   572             return ((MessageDataSource)msg).getDataSource();
   573         } else {
   574             AttachmentSet atts = msg.getAttachments();
   575             if (atts != null && !atts.isEmpty()) {
   576                 final ByteArrayBuffer bos = new ByteArrayBuffer();
   577                 try {
   578                     Codec codec = new XMLHTTPBindingCodec(f);
   579                     Packet packet = new Packet(msg);
   580                     com.sun.xml.internal.ws.api.pipe.ContentType ct = codec.getStaticContentType(packet);
   581                     codec.encode(packet, bos);
   582                     return createDataSource(ct.getContentType(), bos.newInputStream());
   583                 } catch(IOException ioe) {
   584                     throw new WebServiceException(ioe);
   585                 }
   587             } else {
   588                 final ByteArrayBuffer bos = new ByteArrayBuffer();
   589                 XMLStreamWriter writer = XMLStreamWriterFactory.create(bos);
   590                 try {
   591                     msg.writePayloadTo(writer);
   592                     writer.flush();
   593                 } catch (XMLStreamException e) {
   594                     throw new WebServiceException(e);
   595                 }
   596                 return XMLMessage.createDataSource("text/xml", bos.newInputStream());
   597             }
   598         }
   599     }
   601     public static DataSource createDataSource(final String contentType, final InputStream is) {
   602         return new XmlDataSource(contentType, is);
   603     }
   605     private static class XmlDataSource implements DataSource {
   606         private final String contentType;
   607         private final InputStream is;
   608         private boolean consumed;
   610         XmlDataSource(String contentType, final InputStream is) {
   611             this.contentType = contentType;
   612             this.is = is;
   613         }
   615         public boolean consumed() {
   616             return consumed;
   617         }
   619         public InputStream getInputStream() {
   620             consumed = !consumed;
   621             return is;
   622         }
   624         public OutputStream getOutputStream() {
   625             return null;
   626         }
   628         public String getContentType() {
   629             return contentType;
   630         }
   632         public String getName() {
   633             return "";
   634         }
   635     }
   636 }

mercurial