src/share/jaxws_classes/com/sun/xml/internal/ws/encoding/XMLHTTPBindingCodec.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;
    28 import com.sun.xml.internal.ws.api.SOAPVersion;
    29 import com.sun.xml.internal.ws.api.WSFeatureList;
    30 import com.sun.xml.internal.ws.api.message.Packet;
    31 import com.sun.xml.internal.ws.api.pipe.Codec;
    32 import com.sun.xml.internal.ws.api.pipe.ContentType;
    33 import com.sun.xml.internal.ws.client.ContentNegotiation;
    34 import com.sun.xml.internal.ws.encoding.xml.XMLCodec;
    35 import com.sun.xml.internal.ws.encoding.xml.XMLMessage;
    36 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.MessageDataSource;
    37 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.UnknownContent;
    38 import com.sun.xml.internal.ws.encoding.xml.XMLMessage.XMLMultiPart;
    39 import com.sun.xml.internal.ws.resources.StreamingMessages;
    40 import com.sun.xml.internal.ws.util.ByteArrayBuffer;
    42 import javax.activation.DataSource;
    43 import javax.xml.ws.WebServiceException;
    45 import java.io.IOException;
    46 import java.io.InputStream;
    47 import java.io.OutputStream;
    48 import java.lang.reflect.Method;
    49 import java.nio.channels.WritableByteChannel;
    50 import java.util.StringTokenizer;
    52 /**
    53  * XML (infoset) over HTTP binding {@link Codec}.
    54  * <p>
    55  * TODO: Support FI for multipart/related
    56  *       Support FI for MessageDataSource
    57  *
    58  * @author Jitendra Kotamraju
    59  */
    60 public final class XMLHTTPBindingCodec extends MimeCodec {
    61     /**
    62      * Base HTTP Accept request-header.
    63      */
    64     private static final String BASE_ACCEPT_VALUE =
    65         "*";
    67     /**
    68      * Fast Infoset MIME type.
    69      */
    70     private static final String APPLICATION_FAST_INFOSET_MIME_TYPE =
    71         "application/fastinfoset";
    73     /**
    74      * True if the Fast Infoset codec should be used
    75      */
    76     private boolean useFastInfosetForEncoding;
    78     /**
    79      * The XML codec
    80      */
    81     private final Codec xmlCodec;
    83     /**
    84      * The FI codec
    85      */
    86     private final Codec fiCodec;
    88     /**
    89      * The Accept header for XML encodings
    90      */
    91     private static final String xmlAccept = null;
    93     /**
    94      * The Accept header for Fast Infoset and XML encodings
    95      */
    96     private static final String fiXmlAccept = APPLICATION_FAST_INFOSET_MIME_TYPE + ", " + BASE_ACCEPT_VALUE;
    98     private ContentTypeImpl setAcceptHeader(Packet p, ContentType c) {
    99         ContentTypeImpl ctImpl = (ContentTypeImpl)c;
   100         if (p.contentNegotiation == ContentNegotiation.optimistic
   101                 || p.contentNegotiation == ContentNegotiation.pessimistic) {
   102             ctImpl.setAcceptHeader(fiXmlAccept);
   103         } else {
   104             ctImpl.setAcceptHeader(xmlAccept);
   105         }
   106         p.setContentType(ctImpl);
   107         return ctImpl;
   108     }
   110     public XMLHTTPBindingCodec(WSFeatureList f) {
   111         super(SOAPVersion.SOAP_11, f);
   113         xmlCodec = new XMLCodec(f);
   115         fiCodec = getFICodec();
   116     }
   118     @Override
   119     public String getMimeType() {
   120         return null;
   121     }
   123     @Override
   124     public ContentType getStaticContentType(Packet packet) {
   125         ContentType ct;
   126         if (packet.getInternalMessage() instanceof MessageDataSource) {
   127             final MessageDataSource mds = (MessageDataSource)packet.getInternalMessage();
   128             if (mds.hasUnconsumedDataSource()) {
   129                 ct = getStaticContentType(mds);
   130                 return (ct != null)
   131                     ? setAcceptHeader(packet, ct) //_adaptingContentType.set(packet, ct)
   132                     : null;
   133             }
   134         }
   136         ct = super.getStaticContentType(packet);
   137         return (ct != null)
   138             ? setAcceptHeader(packet, ct) //_adaptingContentType.set(packet, ct)
   139             : null;
   140     }
   142     @Override
   143     public ContentType encode(Packet packet, OutputStream out) throws IOException {
   144         if (packet.getInternalMessage() instanceof MessageDataSource) {
   145             final MessageDataSource mds = (MessageDataSource)packet.getInternalMessage();
   146             if (mds.hasUnconsumedDataSource())
   147                 return setAcceptHeader(packet, encode(mds, out));
   148         }
   150         return setAcceptHeader(packet, super.encode(packet, out));
   151     }
   153     @Override
   154     public ContentType encode(Packet packet, WritableByteChannel buffer) {
   155         throw new UnsupportedOperationException();
   156     }
   158     @Override
   159     public void decode(InputStream in, String contentType, Packet packet) throws IOException {
   160         /**
   161          * Reset the encoding state when on the server side for each
   162          * decode/encode step.
   163          */
   164         if (packet.contentNegotiation == null)
   165             useFastInfosetForEncoding = false;
   167         if (contentType == null) {
   168             xmlCodec.decode(in, contentType, packet);
   169         } else if (isMultipartRelated(contentType)) {
   170             packet.setMessage(new XMLMultiPart(contentType, in, features));
   171         } else if(isFastInfoset(contentType)) {
   172             if (fiCodec == null) {
   173                 throw new RuntimeException(StreamingMessages.FASTINFOSET_NO_IMPLEMENTATION());
   174             }
   176             useFastInfosetForEncoding = true;
   177             fiCodec.decode(in, contentType, packet);
   178         } else if (isXml(contentType)) {
   179             xmlCodec.decode(in, contentType, packet);
   180         } else {
   181             packet.setMessage(new UnknownContent(contentType, in));
   182         }
   184         if (!useFastInfosetForEncoding) {
   185             useFastInfosetForEncoding = isFastInfosetAcceptable(packet.acceptableMimeTypes);
   186         }
   187     }
   189     @Override
   190     protected void decode(MimeMultipartParser mpp, Packet packet) throws IOException {
   191         // This method will never be invoked
   192     }
   194     @Override
   195     public MimeCodec copy() {
   196         return new XMLHTTPBindingCodec(features);
   197     }
   199     private boolean isMultipartRelated(String contentType) {
   200         return compareStrings(contentType, MimeCodec.MULTIPART_RELATED_MIME_TYPE);
   201     }
   203     private boolean isXml(String contentType) {
   204         return compareStrings(contentType, XMLCodec.XML_APPLICATION_MIME_TYPE)
   205                 || compareStrings(contentType, XMLCodec.XML_TEXT_MIME_TYPE)
   206                 || (compareStrings(contentType, "application/")&&(contentType.toLowerCase().indexOf("+xml") != -1));
   207     }
   209     private boolean isFastInfoset(String contentType) {
   210         return compareStrings(contentType, APPLICATION_FAST_INFOSET_MIME_TYPE);
   211     }
   213     private boolean compareStrings(String a, String b) {
   214         return a.length() >= b.length() &&
   215                 b.equalsIgnoreCase(
   216                     a.substring(0,
   217                         b.length()));
   218     }
   220     private boolean isFastInfosetAcceptable(String accept) {
   221         if (accept == null) return false;
   223         StringTokenizer st = new StringTokenizer(accept, ",");
   224         while (st.hasMoreTokens()) {
   225             final String token = st.nextToken().trim();
   226             if (token.equalsIgnoreCase(APPLICATION_FAST_INFOSET_MIME_TYPE)) {
   227                 return true;
   228             }
   229         }
   230         return false;
   231     }
   233     private ContentType getStaticContentType(MessageDataSource mds) {
   234         final String contentType = mds.getDataSource().getContentType();
   235         final boolean isFastInfoset = XMLMessage.isFastInfoset(contentType);
   237         if (!requiresTransformationOfDataSource(isFastInfoset,
   238                 useFastInfosetForEncoding)) {
   239             return new ContentTypeImpl(contentType);
   240         } else {
   241             return null;
   242         }
   243     }
   245     private ContentType encode(MessageDataSource mds, OutputStream out) {
   246         try {
   247             final boolean isFastInfoset = XMLMessage.isFastInfoset(
   248                     mds.getDataSource().getContentType());
   249             DataSource ds = transformDataSource(mds.getDataSource(),
   250                     isFastInfoset, useFastInfosetForEncoding, features);
   252             InputStream is = ds.getInputStream();
   253             byte[] buf = new byte[1024];
   254             int count;
   255             while((count=is.read(buf)) != -1) {
   256                 out.write(buf, 0, count);
   257             }
   258             return new ContentTypeImpl(ds.getContentType());
   259         } catch(IOException ioe) {
   260             throw new WebServiceException(ioe);
   261         }
   262     }
   264     @Override
   265     protected Codec getMimeRootCodec(Packet p) {
   266         /**
   267          * The following logic is only for outbound packets
   268          * to be encoded by client.
   269          * On the server the p.contentNegotiation == null.
   270          */
   271         if (p.contentNegotiation == ContentNegotiation.none) {
   272             // The client may have changed the negotiation property from
   273             // pessismistic to none between invocations
   274             useFastInfosetForEncoding = false;
   275         } else if (p.contentNegotiation == ContentNegotiation.optimistic) {
   276             // Always encode using Fast Infoset if in optimisitic mode
   277             useFastInfosetForEncoding = true;
   278         }
   280         return (useFastInfosetForEncoding && fiCodec != null)? fiCodec : xmlCodec;
   281     }
   283     public static boolean requiresTransformationOfDataSource(
   284             boolean isFastInfoset, boolean useFastInfoset) {
   285         return (isFastInfoset && !useFastInfoset) || (!isFastInfoset && useFastInfoset);
   286     }
   288     public static DataSource transformDataSource(DataSource in,
   289             boolean isFastInfoset, boolean useFastInfoset, WSFeatureList f) {
   290         try {
   291             if (isFastInfoset && !useFastInfoset) {
   292                 // Convert from Fast Infoset to XML
   293                 Codec codec = new XMLHTTPBindingCodec(f);
   294                 Packet p = new Packet();
   295                 codec.decode(in.getInputStream(), in.getContentType(), p);
   297                 p.getMessage().getAttachments();
   298                 codec.getStaticContentType(p);
   300                 ByteArrayBuffer bos = new ByteArrayBuffer();
   301                 ContentType ct = codec.encode(p, bos);
   302                 return XMLMessage.createDataSource(ct.getContentType(), bos.newInputStream());
   303             } else if (!isFastInfoset && useFastInfoset) {
   304                 // Convert from XML to Fast Infoset
   305                 Codec codec = new XMLHTTPBindingCodec(f);
   306                 Packet p = new Packet();
   307                 codec.decode(in.getInputStream(), in.getContentType(), p);
   309                 p.contentNegotiation = ContentNegotiation.optimistic;
   310                 p.getMessage().getAttachments();
   311                 codec.getStaticContentType(p);
   313                 ByteArrayBuffer bos = new ByteArrayBuffer();
   314                 com.sun.xml.internal.ws.api.pipe.ContentType ct = codec.encode(p, bos);
   315                 return XMLMessage.createDataSource(ct.getContentType(), bos.newInputStream());
   316             }
   317         } catch(Exception ex) {
   318             throw new WebServiceException(ex);
   319         }
   321         return in;
   322     }
   324     /**
   325      * Obtain an FI SOAP codec instance using reflection.
   326      */
   327     private static Codec getFICodec() {
   328         try {
   329             Class c = Class.forName("com.sun.xml.internal.ws.encoding.fastinfoset.FastInfosetCodec");
   330             Method m = c.getMethod("create");
   331             return (Codec)m.invoke(null);
   332         } catch (Exception e) {
   333             return null;
   334         }
   335     }
   336 }

mercurial