Package org.jibx.ws.tcp.server

Source Code of org.jibx.ws.tcp.server.SocketRunner$TcpInConnection

/*
* 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.tcp.server;

import java.io.IOException;
import java.net.Socket;
import java.text.ParseException;

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.codec.CodecCache;
import org.jibx.ws.codec.CodecDirectory;
import org.jibx.ws.codec.MediaType;
import org.jibx.ws.codec.XmlCodec;
import org.jibx.ws.encoding.dime.DimeCommon;
import org.jibx.ws.encoding.dime.DimeInputBuffer;
import org.jibx.ws.encoding.dime.DimeOutputBuffer;
import org.jibx.ws.io.XmlOptions;
import org.jibx.ws.protocol.Protocol;
import org.jibx.ws.protocol.ProtocolDirectory;
import org.jibx.ws.server.Service;
import org.jibx.ws.server.ServiceDefinition;
import org.jibx.ws.server.ServiceFactory;
import org.jibx.ws.server.ServicePool;
import org.jibx.ws.transport.InConnection;
import org.jibx.ws.transport.OutConnectionBase;
import org.jibx.ws.transport.OutServerConnection;

/**
* Handles the client connection to a service. Each service uses a unique port, and each client receives its own socket
* when it connects to that port, so this just needs to implement the actual processing loop.
*
* @author Dennis M. Sosnoski
*/
public class SocketRunner implements Runnable
{
    private static final Log s_logger = LogFactory.getLog(SocketRunner.class);
   
    /** Socket to be handled. */
    private final Socket m_socket;
   
    /** Service accessed by this socket. */
    private final ServiceDefinition m_sdef;
   
    /** Server which started this instance. */
    private final TcpServer m_server;
   
    /** Client address (used for identifying the source of the unmarshalled messages). */
    private final String m_clientAddress;
   
    /** Cache for codec instances. */
    private final CodecCache m_codecCache;
   
    /** Next runner in server list (<code>null</code> if none). */
    SocketRunner m_next;
   
    /** Preceding runner in server list (<code>null</code> if none). */
    SocketRunner m_last;
   
    /** DIME input buffer. */
    private DimeInputBuffer m_dimeInput;
   
    /** DIME output buffer. */
    private DimeOutputBuffer m_dimeOutput;
   
    /** Thread exit flag. */
    private boolean m_exit;
   
    /**
     * Constructor.
     *
     * @param socket socket to be handled
     * @param sdef definition of service to be accessed by this socket
     * @param server server which started this instance
     * @throws IOException on error accessing input or output streams
     */
    public SocketRunner(Socket socket, ServiceDefinition sdef, TcpServer server) throws IOException {
        m_socket = socket;
        m_socket.setTcpNoDelay(true);
        m_sdef = sdef;
        m_server = server;
        m_clientAddress = socket.getInetAddress().getHostAddress();
        m_dimeInput = new DimeInputBuffer();
        InByteBuffer ibuff = new InByteBuffer();
        m_dimeInput.setBuffer(ibuff);
        ibuff.setInput(socket.getInputStream());
        m_dimeOutput = new DimeOutputBuffer();
        OutByteBuffer obuff = new OutByteBuffer();
        obuff.setOutput(socket.getOutputStream());
        m_dimeOutput.setBuffer(obuff);
        m_codecCache = new CodecCache();
    }
   
    /**
     * Set thread exit flag. This also terminates the socket connection if called with value <code>true</code>.
     *
     * @param exit <code>true</code> if thread is to exit, <code>false</code> otherwise
     */
    public synchronized void setExit(boolean exit) {
        m_exit = exit;
        if (exit) {
            try {
                m_socket.close();
            } catch (IOException e) {
                // nothing to be done if this fails
            }
        }
    }
   
    /**
     * Thread execution method. The execution loop is simple, consisting of the thread reading messages from the
     * socket and running the associated service code to send the response. Execution continues until either the
     * socket is closed or the exit flag is set.
     */
    public void run() {
        try {
            while (!m_exit && m_dimeInput.nextMessage() && m_dimeInput.nextPart()) {
                Service serv = null;
                try {
                    if (s_logger.isDebugEnabled()) {
                        s_logger.debug("Beginning processing of receive message from " + m_clientAddress);
                    }
                    MediaType mediaType = null;
                    if (m_dimeInput.getPartTypeCode() == DimeCommon.TYPE_MEDIA) {
                        String partTypeText = m_dimeInput.getPartTypeText();
                        try {
                            MediaType partMediaType = new MediaType(partTypeText);
                            if (CodecDirectory.hasCodecFor(partMediaType)) {
                                mediaType = partMediaType;
                            }
                        } catch (ParseException e) {
                            throw new IOException("Unable to parse media type '" + partTypeText + "'");
                        }
                    }
                    if (mediaType == null) {
                        mediaType = CodecDirectory.TEXT_XML_MEDIA_TYPE;
                    }
                    XmlCodec codec = m_codecCache.getCodec(mediaType);
                    IXMLReader reader = codec.getReader(m_dimeInput, null, m_clientAddress, false);
                    Protocol protocol = ProtocolDirectory.getProtocol(m_sdef.getProtocolName());
                    ServiceFactory serviceFactory = protocol.getServiceFactory();
                    serv = ServicePool.getInstance(serviceFactory, m_sdef);
                    serv.processRequest(new TcpInConnection(m_dimeInput, reader), new TcpOutConnection(codec,
                        serv.getXmlOptions()));
                    if (s_logger.isDebugEnabled()) {
                        s_logger.debug("Completed processing of receive message from " + m_clientAddress);
                    }
                } finally {
                    if (serv != null) {
                        serv.releaseInstance();
                    }
                }
            }
        } catch (Exception e) {
           
            // just log the error and exit
            e.printStackTrace();
            s_logger.error("TCP service error with client " + m_clientAddress, e);
           
        } finally {
           
            // make sure the socket is closed
            try {
                m_socket.close();
            } catch (IOException e) {
                // nothing to be done if this fails
            }
           
            // unlink from service list
            m_server.unlink(this);
        }
    }
   
    /**
     * Inbound connection (data received from client).
     */
    private static class TcpInConnection implements InConnection
    {
        /** DIME input buffer. */
        private final DimeInputBuffer m_dimeInput;
       
        /** XML reader instance. */
        private final IXMLReader m_reader;
       
        /**
         * Constructor.
         *
         * @param dimein
         * @param reader
         */
        public TcpInConnection(DimeInputBuffer dimein, IXMLReader reader) {
            m_dimeInput = dimein;
            m_reader = reader;
        }

        /** {@inheritDoc} */
        public String getCharacterEncoding() {
            return m_reader.getInputEncoding();
        }
       
        /** {@inheritDoc} */
        public String getContentType() {
            if (m_dimeInput.getPartTypeCode() == DimeCommon.TYPE_MEDIA) {
                return m_dimeInput.getPartTypeText();
            } else {
                return null;
            }
        }
       
        /** {@inheritDoc} */
        public String getDestination() {
            return null;
        }
       
        /** {@inheritDoc} */
        public String getId() {
            return m_dimeInput.getPartIdentifier();
        }
       
        /** {@inheritDoc} */
        public String getOperationName() {
            return null;
        }
       
        /** {@inheritDoc} */
        public String getOrigin() {
            return null;
        }
       
        /** {@inheritDoc} */
        public String getProperty(String name) {
            return null;
        }
       
        /** {@inheritDoc} */
        public IXMLReader getReader() {
            return m_reader;
        }
       
        /** {@inheritDoc} */
        public void init() throws IOException {
            m_reader.init();
        }

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

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

        /** {@inheritDoc} */
        public String getErrorMessage() throws IOException {
            return null;
        }

        /** {@inheritDoc} */
        public void inputComplete() {
        }
    }
   
    /**
     * Outbound connection (data sent to client).
     */
    private class TcpOutConnection extends OutConnectionBase implements OutServerConnection
    {
        /** Codec used for response to client. */
        private final XmlCodec m_codec;
       
        /** XML writer instance. */
        private IXMLWriter m_writer;
       
        /** Message initialized at DIME transport layer flag. */
        private boolean m_initialized;
       
        /**
         * Constructor.
         *
         * @param codec
         * @param xmlOptions formatting options for XML
         */
        public TcpOutConnection(XmlCodec codec, XmlOptions xmlOptions) {
            super(xmlOptions);
            m_codec = codec;
        }

        /**
         * {@inheritDoc}
         */
        public IXMLWriter getNormalWriter(String[] uris) throws IOException {
            if (!m_initialized) {
               
                // initialize DIME output first, then hook to writer, so data offset will be past header
                MediaType mediaType = m_codec.getMediaType();
                int typecode = mediaType == null ? DimeCommon.TYPE_NONE : DimeCommon.TYPE_MEDIA;
                m_dimeOutput.nextMessage();
                m_dimeOutput.nextPart(null, typecode, mediaType.toString());
                m_writer = m_codec.getWriter(m_dimeOutput, null, uris);
                initializeWriter(m_writer);
                m_initialized = true;
               
            }
            return m_writer;
        }
       
        /** {@inheritDoc} */
        public IXMLWriter getFaultWriter(String[] uris) throws IOException {
            return getNormalWriter(uris);
        }
       
        /** {@inheritDoc} */
        public void close() throws IOException {
            if (m_initialized) {
                m_writer.flush();
                m_dimeOutput.endMessage();
                m_dimeOutput.flush();
            }
            m_initialized = false;
        }
       
        /** {@inheritDoc} */
        public boolean isCommitted() {
            return true;
        }
       
        /** {@inheritDoc} */
        public void sendNotFoundError() throws IOException {
        }
       
        /** {@inheritDoc} */
        public void setInternalServerError() {
        }

        /** {@inheritDoc} */
        public void outputComplete() {
        }
    }
}
TOP

Related Classes of org.jibx.ws.tcp.server.SocketRunner$TcpInConnection

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.
y>