Package com.sun.xml.ws.encoding

Source Code of com.sun.xml.ws.encoding.SOAPBindingCodec$AcceptContentType

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.xml.ws.encoding;

import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.api.client.SelectOptimalEncodingFeature;
import com.sun.xml.ws.api.fastinfoset.FastInfosetFeature;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.message.ExceptionHasMessage;
import com.sun.xml.ws.api.pipe.Codec;
import com.sun.xml.ws.api.pipe.Codecs;
import com.sun.xml.ws.api.pipe.ContentType;
import com.sun.xml.ws.api.pipe.StreamSOAPCodec;
import com.sun.xml.ws.binding.SOAPBindingImpl;
import com.sun.xml.ws.client.ContentNegotiation;
import com.sun.xml.ws.protocol.soap.MessageCreationException;
import com.sun.xml.ws.resources.StreamingMessages;
import com.sun.xml.ws.server.UnsupportedMediaException;

import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.soap.MTOMFeature;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.StringTokenizer;

/**
* SOAP binding {@link Codec} that can handle MTOM, SwA, and SOAP messages
* encoded using XML or Fast Infoset.
*
* <p>
* This is used when we need to determine the encoding from what we received (for decoding)
* and from configuration and {@link Message} contents (for encoding)
*
* <p>
* TODO: Split this Codec into two, one that supports FI and one that does not.
* Then further split the FI Codec into two, one for client and one for
* server. This will simplify the logic and make it easier to understand/maintain.
*
* @author Vivek Pandey
* @author Kohsuke Kawaguchi
*/
public class SOAPBindingCodec extends MimeCodec implements com.sun.xml.ws.api.pipe.SOAPBindingCodec {

    /**
     * Based on request's Accept header this is set.
     * Currently only set if MTOMFeature is enabled.
     *
     * Should be used on server-side, for encoding the response.
     */
    private boolean acceptMtomMessages;

    /**
     * If the request's Content-Type is multipart/related; type=application/xop+xml, then this set to to true
     *
     * Used on server-side, for encoding the repsonse.
     */
    private boolean isRequestMtomMessage;

    private enum TriState {UNSET,TRUE,FALSE}

    /**
     * This captures is decode is called before encode,
     *  if true, infers that this is being used on Server-side
     */
    private TriState decodeFirst = TriState.UNSET;

    /**
     * True if Fast Infoset functionality has been
     * configured to be disabled, or the Fast Infoset
     * runtime is not available.
     */
    private boolean isFastInfosetDisabled;
   
    /**
     * True if the Fast Infoset codec should be used for encoding.
     */
    private boolean useFastInfosetForEncoding;
   
    /**
     * True if the content negotiation property should
     * be ignored by the client. This will be used in
     * the case of Fast Infoset being configured to be
     * disabled or automatically selected.
     */
    private boolean ignoreContentNegotiationProperty;
   
    // The XML SOAP codec
    private final StreamSOAPCodec xmlSoapCodec;
   
    // The Fast Infoset SOAP codec
    private final Codec fiSoapCodec;
   
    // The XML MTOM codec
    private final MimeCodec xmlMtomCodec;
   
    // The XML SWA codec
    private final MimeCodec xmlSwaCodec;
   
    // The Fast Infoset SWA codec
    private final MimeCodec fiSwaCodec;
   
    private final SOAPBindingImpl binding;
   
    /**
     * The XML SOAP MIME type
     */
    private final String xmlMimeType;
   
    /**
     * The Fast Infoset SOAP MIME type
     */
    private final String fiMimeType;
   
    /**
     * The Accept header for XML encodings
     */
    private final String xmlAccept;
   
    /**
     * The Accept header for Fast Infoset and XML encodings
     */
    private final String connegXmlAccept;
   
    public StreamSOAPCodec getXMLCodec() {
        return xmlSoapCodec;
    }
   
    private class AcceptContentType implements ContentType {
        private ContentType _c;
        private String _accept;
       
        public AcceptContentType set(Packet p, ContentType c) {
            if (!ignoreContentNegotiationProperty && p.contentNegotiation != ContentNegotiation.none) {
                _accept = connegXmlAccept;
            } else {
                _accept = xmlAccept;
            }
            _c = c;
            return this;
        }
       
        public String getContentType() {
            return _c.getContentType();
        }
       
        public String getSOAPActionHeader() {
            return _c.getSOAPActionHeader();
        }
       
        public String getAcceptHeader() {
            return _accept;
        }
    }
   
    private AcceptContentType _adaptingContentType = new AcceptContentType();
   
    public SOAPBindingCodec(WSBinding binding) {
        this(binding, Codecs.createSOAPEnvelopeXmlCodec(binding.getSOAPVersion()));
    }
   
    public SOAPBindingCodec(WSBinding binding, StreamSOAPCodec xmlSoapCodec) {
        super(binding.getSOAPVersion(), binding);
       
        this.xmlSoapCodec = xmlSoapCodec;
        xmlMimeType = xmlSoapCodec.getMimeType();
       
        xmlMtomCodec = new MtomCodec(version, xmlSoapCodec, binding, binding.getFeature(MTOMFeature.class));
       
        xmlSwaCodec = new SwACodec(version, binding, xmlSoapCodec);
       
        String clientAcceptedContentTypes = xmlSoapCodec.getMimeType() + ", " +
                xmlMtomCodec.getMimeType();
       
        WebServiceFeature fi = binding.getFeature(FastInfosetFeature.class);
        isFastInfosetDisabled = (fi != null && !fi.isEnabled());
        if (!isFastInfosetDisabled) {
            fiSoapCodec = getFICodec(xmlSoapCodec, version);
            if (fiSoapCodec != null) {
                fiMimeType = fiSoapCodec.getMimeType();
                fiSwaCodec = new SwACodec(version, binding, fiSoapCodec);
                connegXmlAccept = fiMimeType + ", " + clientAcceptedContentTypes;
               
                /**
                 * This feature will only be present on the client side.
                 *
                 * Fast Infoset is enabled on the client if the service
                 * explicitly supports Fast Infoset.
                 */
                WebServiceFeature select = binding.getFeature(SelectOptimalEncodingFeature.class);
                if (select != null) { // if the client FI feature is set - ignore negotiation property
                    ignoreContentNegotiationProperty = true;
                    if (select.isEnabled()) {
                        // If the client's FI encoding feature is enabled, and server's is not disabled
                        if (fi != null) {  // if server's FI feature also enabled
                            useFastInfosetForEncoding = true;
                        }
                       
                        clientAcceptedContentTypes = connegXmlAccept;
                    } else // If client FI feature is disabled
                        isFastInfosetDisabled = true;
                    }
                }
            } else {
                // Fast Infoset could not be loaded by the runtime
                isFastInfosetDisabled = true;
                fiSwaCodec = null;
                fiMimeType = "";
                connegXmlAccept = clientAcceptedContentTypes;
                ignoreContentNegotiationProperty = true;
            }
        } else {
            // Fast Infoset is explicitly not supported by the service
            fiSoapCodec = fiSwaCodec = null;
            fiMimeType = "";
            connegXmlAccept = clientAcceptedContentTypes;
            ignoreContentNegotiationProperty = true;
        }
       
        xmlAccept = clientAcceptedContentTypes;

        if(!(binding instanceof SOAPBindingImpl))
            throw new WebServiceException("Expecting a SOAP binding but found "+binding);
        this.binding = (SOAPBindingImpl)binding;
    }
   
    public String getMimeType() {
        return null;
    }
   
    public ContentType getStaticContentType(Packet packet) {
        ContentType toAdapt = getEncoder(packet).getStaticContentType(packet);
        return (toAdapt != null) ? _adaptingContentType.set(packet, toAdapt) : null;
    }
   
    public ContentType encode(Packet packet, OutputStream out) throws IOException {
       preEncode(packet);
       ContentType ct = _adaptingContentType.set(packet, getEncoder(packet).encode(packet, out));
       postEncode();
       return ct;
    }
   
    public ContentType encode(Packet packet, WritableByteChannel buffer) {
        preEncode(packet);
        ContentType ct = _adaptingContentType.set(packet, getEncoder(packet).encode(packet, buffer));
        postEncode();
        return ct;
    }

    /**
     * Should be called before encode().
     * Set the state so that such state is used by encode process.
     */
    private void preEncode(Packet p) {
        if (decodeFirst == TriState.UNSET)
            decodeFirst = TriState.FALSE;
    }

    /**
     * Should be called after encode()
     * Reset the encoding state.
     */
    private void postEncode() {
        decodeFirst = TriState.UNSET;
        acceptMtomMessages = false;
        isRequestMtomMessage = false;
    }

    /**
     * Should be called before decode().
     * Set the state so that such state is used by decode().
     */
    private void preDecode(Packet p) {
        if (p.contentNegotiation == null)
            useFastInfosetForEncoding = false;
    }

    /**
     * Should be called after decode().
     * Set the state so that such state is used by encode().
     */
    private void postDecode(Packet p) {
        if(decodeFirst == TriState.UNSET)
            decodeFirst = TriState.TRUE;
        if(binding.isFeatureEnabled(MTOMFeature.class))
            acceptMtomMessages =isMtomAcceptable(p.acceptableMimeTypes);
        if (!useFastInfosetForEncoding) {
            useFastInfosetForEncoding = isFastInfosetAcceptable(p.acceptableMimeTypes);
        }
    }


    private boolean isServerSide() {
        return decodeFirst ==  TriState.TRUE;
    }

    public void decode(InputStream in, String contentType, Packet packet) throws IOException {
        if (contentType == null) {
            contentType = xmlMimeType;
        }

        preDecode(packet);
        try {
            if(isMultipartRelated(contentType))
                // parse the multipart portion and then decide whether it's MTOM or SwA
                super.decode(in, contentType, packet);
            else if(isFastInfoset(contentType)) {
                if (!ignoreContentNegotiationProperty && packet.contentNegotiation == ContentNegotiation.none)
                    throw noFastInfosetForDecoding();

                useFastInfosetForEncoding = true;
                fiSoapCodec.decode(in, contentType, packet);
            } else
                xmlSoapCodec.decode(in, contentType, packet);
        } catch(RuntimeException we) {
            if (we instanceof ExceptionHasMessage || we instanceof UnsupportedMediaException) {
                throw we;
            } else {
                throw new MessageCreationException(binding.getSOAPVersion(), we);
            }
        }
        postDecode(packet);
    }

    public void decode(ReadableByteChannel in, String contentType, Packet packet) {
        if (contentType == null) {
            throw new UnsupportedMediaException();
        }

        preDecode(packet);
        try {
            if(isMultipartRelated(contentType))
                super.decode(in, contentType, packet);
            else if(isFastInfoset(contentType)) {
                if (packet.contentNegotiation == ContentNegotiation.none)
                    throw noFastInfosetForDecoding();

                useFastInfosetForEncoding = true;
                fiSoapCodec.decode(in, contentType, packet);
            } else
                xmlSoapCodec.decode(in, contentType, packet);
        } catch(RuntimeException we) {
            if (we instanceof ExceptionHasMessage || we instanceof UnsupportedMediaException) {
                throw we;
            } else {
                throw new MessageCreationException(binding.getSOAPVersion(), we);
            }
        }
        postDecode(packet);
    }

    public SOAPBindingCodec copy() {
        return new SOAPBindingCodec(binding, (StreamSOAPCodec)xmlSoapCodec.copy());
    }
   
    @Override
    protected void decode(MimeMultipartParser mpp, Packet packet) throws IOException {
        // is this SwA or XOP?
        final String rootContentType = mpp.getRootPart().getContentType();
       
        if(isApplicationXopXml(rootContentType)) {
            isRequestMtomMessage = true;
            xmlMtomCodec.decode(mpp,packet);
        } else if (isFastInfoset(rootContentType)) {
            if (packet.contentNegotiation == ContentNegotiation.none)
                throw noFastInfosetForDecoding();
           
            useFastInfosetForEncoding = true;
            fiSwaCodec.decode(mpp,packet);
        } else if (isXml(rootContentType))
            xmlSwaCodec.decode(mpp,packet);
        else {
            // TODO localize exception
            throw new IOException("");
        }
//        checkDuplicateKnownHeaders(packet);
    }
   
    private boolean isMultipartRelated(String contentType) {
        return compareStrings(contentType, MimeCodec.MULTIPART_RELATED_MIME_TYPE);
    }
   
    private boolean isApplicationXopXml(String contentType) {
        return compareStrings(contentType, MtomCodec.XOP_XML_MIME_TYPE);
    }
   
    private boolean isXml(String contentType) {
        return compareStrings(contentType, xmlMimeType);
    }
   
    private boolean isFastInfoset(String contentType) {
        if (isFastInfosetDisabled) return false;
       
        return compareStrings(contentType, fiMimeType);
    }
   
    private boolean compareStrings(String a, String b) {
        return a.length() >= b.length() &&
                b.equalsIgnoreCase(
                a.substring(0,
                b.length()));
    }
   
    private boolean isFastInfosetAcceptable(String accept) {
        if (accept == null || isFastInfosetDisabled) return false;
       
        StringTokenizer st = new StringTokenizer(accept, ",");
        while (st.hasMoreTokens()) {
            final String token = st.nextToken().trim();
            if (token.equalsIgnoreCase(fiMimeType)) {
                return true;
            }
        }
        return false;
    }

    /*
     * Just check if the Accept header contains application/xop+xml,
     * no need to worry about q values.
     */
    private boolean isMtomAcceptable(String accept) {
        if (accept == null || isFastInfosetDisabled) return false;

        StringTokenizer st = new StringTokenizer(accept, ",");
        while (st.hasMoreTokens()) {
            final String token = st.nextToken().trim();
            if (token.toLowerCase().contains(MtomCodec.XOP_XML_MIME_TYPE)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Determines the encoding codec.
     */
    private Codec getEncoder(Packet p) {
        /**
         * The following logic is only for outbound packets
         * to be encoded by a client.
         * For a server the p.contentNegotiation == null.
         */
        if (!ignoreContentNegotiationProperty) {
            if (p.contentNegotiation == ContentNegotiation.none) {
                // The client may have changed the negotiation property from
                // pessismistic to none between invocations
                useFastInfosetForEncoding = false;
            } else if (p.contentNegotiation == ContentNegotiation.optimistic) {
                // Always encode using Fast Infoset if in optimisitic mode
                useFastInfosetForEncoding = true;
            }
        }
       
        // Override the MTOM binding for now
        // Note: Using FI with MTOM does not make sense
        if (useFastInfosetForEncoding) {
            final Message m = p.getMessage();
            if(m==null || m.getAttachments().isEmpty() || binding.isFeatureEnabled(MTOMFeature.class))
                return fiSoapCodec;
            else
                return fiSwaCodec;
        }
       
        if(binding.isFeatureEnabled(MTOMFeature.class) ) {
            //On client, always use XOP encoding if MTOM is enabled
            // On Server, use XOP encoding if either request is XOP encoded or client accepts XOP encoding
            if(!isServerSide() || isRequestMtomMessage || acceptMtomMessages)
                return xmlMtomCodec;
        }

        Message m = p.getMessage();
        if(m==null || m.getAttachments().isEmpty())
            return xmlSoapCodec;
        else
            return xmlSwaCodec;
    }
   
    private RuntimeException noFastInfosetForDecoding() {
        return new RuntimeException(StreamingMessages.FASTINFOSET_DECODING_NOT_ACCEPTED());
    }
   
    /**
     * Obtain an FI SOAP codec instance using reflection.
     */
    private static Codec getFICodec(StreamSOAPCodec soapCodec, SOAPVersion version) {
        try {
            Class c = Class.forName("com.sun.xml.ws.encoding.fastinfoset.FastInfosetStreamSOAPCodec");
            Method m = c.getMethod("create", StreamSOAPCodec.class, SOAPVersion.class);
            return (Codec)m.invoke(null, soapCodec, version);
        } catch (Exception e) {
            // TODO Log that FI cannot be loaded
            return null;
        }
    }
}
TOP

Related Classes of com.sun.xml.ws.encoding.SOAPBindingCodec$AcceptContentType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.