Package org.jibx.ws.http.servlet

Source Code of org.jibx.ws.http.servlet.WsServletDelegate$OutboundConnection

/*
* Copyright (c) 2007-2009, Sosnoski Software Associates Limited. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of
* JiBX nor the names of its contributors may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.jibx.ws.http.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.ParseException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jibx.runtime.IXMLReader;
import org.jibx.runtime.IXMLWriter;
import org.jibx.runtime.impl.InByteBuffer;
import org.jibx.runtime.impl.OutByteBuffer;
import org.jibx.ws.WsConfigurationException;
import org.jibx.ws.WsException;
import org.jibx.ws.codec.CodecDirectory;
import org.jibx.ws.codec.CodecPool;
import org.jibx.ws.codec.MediaType;
import org.jibx.ws.codec.XmlCodec;
import org.jibx.ws.io.XmlOptions;
import org.jibx.ws.server.MediaTypeMapper;
import org.jibx.ws.server.Service;
import org.jibx.ws.transport.InConnection;
import org.jibx.ws.transport.OutConnectionBase;
import org.jibx.ws.transport.OutServerConnection;
import org.jibx.ws.transport.StreamBufferInPool;
import org.jibx.ws.transport.StreamBufferOutPool;
import org.jibx.ws.transport.interceptor.InputStreamInterceptor;
import org.jibx.ws.transport.interceptor.OutputStreamInterceptor;
import org.jibx.ws.wsdl.WsdlProvider;

/**
* Web service request handler servlet. The configuration information for this servlet is obtained from one or more
* service definition files located with the WEB-INF directory of the web application. The particular service definition
* files handled by an instance of this servlet are configured as initialization parameters for the servlet. If the
* servlet is invoked with any path information in the request the path information is used to identify the particular
* service being requested. As a special case, the request parameter "?WSDL" is recognized as a request for the WSDL
* service description.
*
* @author Dennis M. Sosnoski
*/
public final class WsServletDelegate
{
    // TODO: make this a configuration parameter
    private static final int BUFFER_SIZE = 8192;

    /** The key of the character set parameter, which can be used as a parameter to the CONTENT_TYPE header field. */ 
    private static final String CHARSET_KEY = "charset";
   
    private static final Log logger = LogFactory.getLog(WsServletDelegate.class);

    /** Pool of codecs used for input and output. Access to this pool must be synchronized on the pool object. */
    private static final CodecPool s_codecPool = new CodecPool();

    /** Input byte buffer pool. Access to this pool must be synchronized on the {@link #s_codecPool} object. */
    private static final StreamBufferInPool s_inBufferCache = new StreamBufferInPool(BUFFER_SIZE);

    /** Output byte buffer pool. Access to this pool must be synchronized on the {@link #s_codecPool} object. */
    private static final StreamBufferOutPool s_outBufferCache = new StreamBufferOutPool(BUFFER_SIZE);

    /** Maps the incoming request to a service. */
    private ServiceMapper m_serviceMapper;
   
    /**
     * Sets the {@link ServiceMapper} which will determine which service to call based on the incoming request.
     *
     * @param mapper the service mapper
     */
    void setServiceMapper(ServiceMapper mapper) {
        m_serviceMapper = mapper;
    }

    /**
     * POST request handler. This processes the incoming request message and generates the response.
     *
     * @param req servlet request information
     * @param rsp servlet response information
     * @exception ServletException on message content or operational error
     * @exception IOException on error reading or writing
     */
    public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException {
        logger.debug("Entered WsServletDelegate.doPost()");
        Service serv = null;
        XmlCodec incodec = null;
        XmlCodec outcodec = null;
        InByteBuffer inbuff = null;
        OutByteBuffer outbuff = null;
        try {
            // make sure we have a service instance
            serv = m_serviceMapper.getServiceInstance(req);
            if (serv == null) {
                rsp.sendError(HttpServletResponse.SC_NOT_FOUND);
            } else {
                MediaType intype = getMediaType(req.getContentType(), serv.getMediaTypeMapper());
                MediaType outtype = getAcceptableMediaType(req.getHeader("Accept"), intype);

                synchronized (s_codecPool) {
                    // allocated codec(s) and buffers for the input and output
                    incodec = s_codecPool.getCodec(intype);
                    if (intype.equals(outtype)) {
                        outcodec = incodec;
                    } else {
                        outcodec = s_codecPool.getCodec(outtype);
                    }
                    inbuff = (InByteBuffer) s_inBufferCache.getInstance();
                    outbuff = (OutByteBuffer) s_outBufferCache.getInstance();
                }

                // pass the processing on to the service
                InboundConnection inconn = new InboundConnection(req, incodec, inbuff);
                OutboundConnection outconn = new OutboundConnection(rsp, req.getCharacterEncoding(),
                    serv.getXmlOptions(), outcodec, outbuff);
                HttpServletOptions options = (HttpServletOptions) serv.getTransportOptions(HttpServletOptions.class);
                if (options != null) {
                    if (options.getInputStreamInterceptor() != null) {
                        inconn.setInterceptor(options.getInputStreamInterceptor());
                    }
                    if (options.getOutputStreamInterceptor() != null) {
                        outconn.setInterceptor(options.getOutputStreamInterceptor());
                    }
                }
                serv.processRequest(inconn, outconn);
            }

        } catch (WsException e) {
            logger.error("Error processing request", e);
            rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        } finally {
            synchronized (s_codecPool) {

                // release all resources acquired for processing request
                if (serv != null) {
                    serv.releaseInstance();
                }
                if (incodec != null) {
                    s_codecPool.releaseCodec(incodec);
                }
                if (outcodec != null && outcodec != incodec) {
                    s_codecPool.releaseCodec(outcodec);
                }
                if (inbuff != null) {
                    s_inBufferCache.endUsage(inbuff);
                }
                if (outbuff != null) {
                    s_outBufferCache.endUsage(outbuff);
                }

            }
        }
    }

    /**
     * Obtain the media type from the media type string.  If <code>mediastring</code> is <code>null</code>, this returns
     * the default text media type for the protocol that the service is using.
     * <p>
     * All of the parameters on the <code>mediastring</code> are ignored. 
     *
     * @param mediastring media type string (e.g., "text/xml" or "application/soap+xml;action=xyz")
     * @param protocol the protocol that the service is using
     * @return media type with parameters removed
     * @throws ServletException if <code>mediastring</code> contains no supported media type
     */
    private MediaType getMediaType(String mediastring, MediaTypeMapper mapper) throws ServletException {
        MediaType media;
        if (mediastring == null) {
            try {
                media = mapper.getMediaTypeFor(null);
            } catch (WsConfigurationException e) {
                throw new ServletException("Internal JiBX/WS error. Unable to find default media type due to '"
                    + e.getMessage() + "'.");
            }
        } else {
            try {
                media = new MediaType(mediastring, true);
            } catch (ParseException e) {
                throw new ServletException("Error parsing media type in content-type from request: " + mediastring);
            }
            if (!CodecDirectory.hasCodecFor(media)) {
                throw new ServletException("No supported media type in content-type from request: " + mediastring);
            }
        }
        return media;
    }


    /**
     * See {@link CodecDirectory#getAcceptableMediaType(String)}.
     */
    private MediaType getAcceptableMediaType(String acceptable, MediaType contentType) throws ServletException {
        try {
            return CodecDirectory.getAcceptableMediaType(acceptable, contentType);
        } catch (ParseException e) {
            throw new ServletException("Error parsing media type in accept-type from request: " + acceptable, e);
        }
    }

    /**
     * GET request handler. The only type of GET request supported is one to get the WSDL for a service.
     *
     * @param context the servlet context
     * @param req servlet request information
     * @param rsp servlet response information
     * @exception ServletException on message content or operational error
     * @exception IOException on error reading or writing
     */
    protected void doGet(ServletContext context, HttpServletRequest req, HttpServletResponse rsp)
        throws ServletException, IOException {

        if (logger.isDebugEnabled()) {
            logger.debug("Entered WsServletDelegate.doGet() with query string: " + req.getQueryString());
        }
       
        // look up service information and check request
        if ("wsdl".equalsIgnoreCase(req.getQueryString())) {
            Service service = null;
            try {
                logger.debug("Looking up service for WSDL");
                service = m_serviceMapper.getServiceInstance(req);
                if (service == null) {
                    logger.debug("Unable to find service for WSDL");
                    rsp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                } else {
                    WsdlProvider wsdlProvider = service.getWsdlProvider();
                    if (wsdlProvider == null) {
                        logger.debug("Unable to WSDL provider for service");
                        rsp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                    } else {
                        logger.debug("Returning WSDL");
                        wsdlProvider.writeWSDL(rsp.getOutputStream(), req);
                    }
                }
            } catch (WsException e) {
                logger.error("Error creating WSDL", e);
                throw new ServletException(e.getMessage(), e);
            } finally {
                // release all resources acquired for processing request
                if (service != null) {
                    service.releaseInstance();
                }
            }
        } else {
            rsp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }
    }

    /**
     * Inbound connection (data received from client).
     */
    private static class InboundConnection implements InConnection
    {
        /** Request data. */
        private final HttpServletRequest m_request;

        /** Codec to be used for input. */
        private final XmlCodec m_codec;

        /** Buffer used for input data. */
        private final InByteBuffer m_buffer;

        /** Reader for connection. */
        private IXMLReader m_reader;

        /** An interceptor for intercepting input stream, or <code>null</code> if no interceptor. */ 
        private InputStreamInterceptor m_interceptor;

        /**
         * Constructor.
         *
         * @param request
         * @param codec
         * @param buff
         */
        public InboundConnection(HttpServletRequest request, XmlCodec codec, InByteBuffer buff) {
            m_request = request;
            m_codec = codec;
            m_buffer = buff;
        }

        /** {@inheritDoc} */
        public String getCharacterEncoding() {
            return m_request.getCharacterEncoding();
        }

        /** {@inheritDoc} */
        public String getContentType() {
            return m_request.getContentType();
        }

        /** {@inheritDoc} */
        public String getDestination() {
            return null;
        }

        /** {@inheritDoc} */
        public String getId() {
            return null;
        }

        /** {@inheritDoc} */
        public String getOperationName() {
            return null;
        }

        /** {@inheritDoc} */
        public String getOrigin() {
            return m_request.getRemoteHost();
        }

        /** {@inheritDoc} */
        public String getProperty(String name) {
            return m_request.getHeader(name);
        }

        /** {@inheritDoc} */
        public IXMLReader getReader() throws IOException {
            if (m_reader == null) {
                InputStream inputStream = m_request.getInputStream();
                if (m_interceptor != null) {
                    inputStream = m_interceptor.intercept(inputStream);
                }
                m_buffer.setInput(inputStream);
                m_reader = m_codec.getReader(m_buffer, m_request.getCharacterEncoding(), m_request.getRemoteAddr(),
                    true);
            }
            return m_reader;
        }

        /** {@inheritDoc} */
        public void init() throws IOException {
            getReader();
            m_reader.init();
        }

        /** {@inheritDoc} */
        public boolean hasError() throws IOException {
            return false;
        }

        /** {@inheritDoc} */
        public String getErrorMessage() throws IOException {
            return null;
        }
       
        /**
         * Sets an interceptor for intercepting the input stream.
         *
         * @param interceptor the interceptor
         */
        private void setInterceptor(InputStreamInterceptor interceptor) throws WsConfigurationException {
            m_interceptor = interceptor;
        }
       
        public void inputComplete() {
            if (m_interceptor != null) {
                m_interceptor.inputComplete();
            }
        }

        /** {@inheritDoc} */
        public void close() throws IOException {
            m_buffer.finish();
        }
    }

    /**
     * Outbound connection (data sent to client).
     */
    private static class OutboundConnection extends OutConnectionBase implements OutServerConnection
    {
        /** Response data. */
        private final HttpServletResponse m_response;

        /** Codec to be used for output. */
        private final XmlCodec m_codec;

        /** Character encoding to be used for output (<code>null</code> if unknown or not applicable). */
        private final String m_characterCode;

        /** Buffer used by connection. */
        private OutByteBuffer m_buffer;

        /** Writer for connection. */
        private IXMLWriter m_writer;

        /** An interceptor for intercepting output stream, or <code>null</code> if no interceptor. */ 
        private OutputStreamInterceptor m_interceptor;

        /**
         * Constructor.
         *
         * @param response
         * @param charcode
         * @param xmlOptions formatting options for outbound XML
         * @param codec
         * @param buff
         */
        public OutboundConnection(HttpServletResponse response, String charcode, XmlOptions xmlOptions, XmlCodec codec,
                OutByteBuffer buff) {
            super(xmlOptions);
            m_response = response;
            m_buffer = buff;
            m_codec = codec;
            m_characterCode = charcode;
        }


        /** {@inheritDoc} */
        public void sendNotFoundError() throws IOException {
            m_response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }

        /** {@inheritDoc} */
        public void setInternalServerError() {
            m_response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }

        /** {@inheritDoc} */
        public boolean isCommitted() {
            return m_response.isCommitted();
        }

        /** {@inheritDoc} */
        public IXMLWriter getNormalWriter(String[] uris) throws IOException {
            if (m_writer == null) {

                // first set the output content type
                MediaType contentType = m_codec.getMediaType();

                MediaType.Parameter charset = null;
                if (m_characterCode != null) {
                    charset = new MediaType.Parameter(CHARSET_KEY, m_characterCode);
                }
                m_response.setContentType(contentType.toStringWithParams(new MediaType.Parameter[]{charset}));

                // set up the actual writer
                OutputStream outputStream = m_response.getOutputStream();
                if (m_interceptor != null) {
                    outputStream = m_interceptor.intercept(outputStream);
                }
               
                m_buffer.setOutput(outputStream);
               
                m_writer = m_codec.getWriter(m_buffer, null, uris);
                initializeWriter(m_writer);
            }
            return m_writer;
        }

        /** {@inheritDoc} */
        public IXMLWriter getFaultWriter(String[] uris) throws IOException {
            return getNormalWriter(uris);
        }

        /**
         * Sets an interceptor for intercepting the output stream.
         *
         * @param interceptor the interceptor
         */
        private void setInterceptor(OutputStreamInterceptor interceptor) {
            m_interceptor = interceptor;
        }

        /** {@inheritDoc} */
        public void outputComplete() {
            if (m_interceptor != null) {
                m_interceptor.outputComplete();
            }
        }

        /** {@inheritDoc} */
        public void close() throws IOException {
            logger.debug("Closing output connection");
            if (m_writer != null) {
                logger.debug("Closing writer");
                m_writer.close();
                m_writer.reset();
            }
        }
    }
}
TOP

Related Classes of org.jibx.ws.http.servlet.WsServletDelegate$OutboundConnection

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.