org.mule.transport.comm.CommMessageReceiver.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.transport.comm.CommMessageReceiver.java

Source

/*
 * Generated by the Mule project wizard. http://mule.mulesource.org
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.transport.comm;

import org.mule.transport.AbstractMessageReceiver;
import org.mule.transport.ConnectException;
import org.mule.transport.AbstractReceiverResourceWorker;
import org.mule.transport.comm.i18n.CommMessages;
import org.mule.api.transport.Connector;
import org.mule.api.service.Service;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.lifecycle.CreateException;
import org.mule.api.lifecycle.DisposeException;
import org.mule.api.lifecycle.Disposable;
import org.mule.api.MuleException;
import org.mule.api.transaction.Transaction;
import org.mule.api.transaction.TransactionException;
import org.mule.api.retry.RetryCallback;
import org.mule.api.retry.RetryContext;
import org.mule.config.i18n.CoreMessages;
import org.mule.util.monitor.Expirable;
import org.mule.DefaultMuleMessage;
import org.apache.commons.validator.GenericValidator;

import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkManager;
import javax.resource.spi.work.WorkException;
import javax.comm.CommPort;
import java.net.*;
import java.io.*;
import java.util.List;
import java.util.Iterator;

import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 * User: Christopher Cheng
 * Date: Mar 1, 2009
 * Time: 4:16:42 PM
 * To change this template use File | Settings | File Templates.
 */
public class CommMessageReceiver extends AbstractMessageReceiver implements Work {
    private CommPort commPort = null;

    public CommMessageReceiver(Connector connector, Service service, InboundEndpoint endpoint)
            throws CreateException {
        super(connector, service, endpoint);
    }

    protected void doConnect() throws ConnectException {
        disposing.set(false);
        URI uri = endpoint.getEndpointURI().getUri();

        try {
            int baudrate = 9600;
            int databits = 8;
            int stopbits = 1;
            int parity = 0;
            int delay = 150;
            String host = "";

            if (GenericValidator.isInt((String) endpoint.getProperties().get("baudrate"))) {
                baudrate = Integer.valueOf((String) endpoint.getProperties().get("baudrate"));
            }
            if (GenericValidator.isInt((String) endpoint.getProperties().get("databits"))) {
                databits = Integer.valueOf((String) endpoint.getProperties().get("databits"));
            }
            if (GenericValidator.isInt((String) endpoint.getProperties().get("stopbits"))) {
                stopbits = Integer.valueOf((String) endpoint.getProperties().get("stopbits"));
            }
            if (GenericValidator.isInt((String) endpoint.getProperties().get("parity"))) {
                parity = Integer.valueOf((String) endpoint.getProperties().get("parity"));
            }
            host = uri.getHost();

            commPort = ((CommConnector) connector).getCommPort(host, baudrate, databits, stopbits, parity, delay);
        } catch (Exception e) {
            throw new org.mule.transport.ConnectException(CommMessages.failedToBindToUri(uri), e, this);
        }

        try {
            getWorkManager().scheduleWork(this, WorkManager.INDEFINITE, null, connector);
        } catch (WorkException e) {
            throw new ConnectException(CoreMessages.failedToScheduleWork(), e, this);
        }
    }

    protected void doDisconnect() throws ConnectException {
        // this will cause the server thread to quit
        disposing.set(true);

        try {
            if (commPort != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Closing: " + commPort);
                }
                commPort.close();
            }
        } catch (Exception e) {
            logger.warn("Failed to close server port: " + e.getMessage(), e);
        }
    }

    protected void doStart() throws MuleException {
        // nothing to do
    }

    protected void doStop() throws MuleException {
        // nothing to do
    }

    /**
     * Obtain the serverSocket
     * @return the server socket for this server
     */
    public CommPort getCommPort() {
        return commPort;
    }

    public void run() {
        System.out.println("CommMessageReceiver run");
        //        while (!disposing.get())
        //        {
        if (connector.isStarted() && !disposing.get()) {
            try {
                retryTemplate.execute(new RetryCallback() {
                    public void doWork(RetryContext context) throws Exception {
                        //                            CommPort commPort = this.commPort;
                        try {

                            //                                commPort = commPort.accept();
                        } catch (Exception e) {
                            if (!connector.isDisposed() && !disposing.get()) {
                                throw new ConnectException(e, null);
                            }
                        }

                        if (commPort != null) {
                            Work work = createWork(commPort);
                            getWorkManager().scheduleWork(work, WorkManager.INDEFINITE, null, connector);
                        }
                    }

                    public String getWorkDescription() {
                        return getConnectionDescription();
                    }
                }, getWorkManager());
            } catch (Exception e) {
                handleException(e);
            }
        }
        //        }
    }

    public void release() {
        // template method
    }

    protected void doDispose() {
        try {
            if (commPort != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Closing: " + commPort);
                }
                commPort.close();
            }
            commPort = null;
        } catch (Exception e) {
            logger.error(new DisposeException(CommMessages.failedToCloseSocket(), e, this));
        }
        logger.info("Closed Tcp port");
    }

    protected Work createWork(CommPort port) throws IOException {

        return new CommWorker(port, this);
    }

    protected class CommWorker extends AbstractReceiverResourceWorker implements Disposable, Expirable {
        protected CommPort commPort = null;
        protected CommInputStream dataIn;
        protected InputStream underlyingIn;
        protected OutputStream dataOut;
        protected CommProtocol protocol;
        protected boolean dataInWorkFinished = false;
        protected Object notify = new Object();
        private boolean moreMessages = true;

        public CommWorker(CommPort commPort, AbstractMessageReceiver receiver) throws IOException {
            super(commPort, receiver, ((CommConnector) connector).getCommProtocol().createResponse(commPort));
            this.commPort = commPort;

            final CommConnector tcpConnector = ((CommConnector) connector);
            protocol = tcpConnector.getCommProtocol();

            try {
                tcpConnector.configurePort(CommConnector.SERVER, commPort);

                underlyingIn = new BufferedInputStream(commPort.getInputStream());
                dataIn = new CommInputStream(underlyingIn) {
                    public void close() throws IOException {
                        // Don't actually close the stream, we just want to know if the
                        // we want to stop receiving messages on this sockete.
                        // The Protocol is responsible for closing this.
                        dataInWorkFinished = true;
                        moreMessages = false;

                        synchronized (notify) {
                            notify.notifyAll();
                        }
                    }
                };
                dataOut = new BufferedOutputStream(commPort.getOutputStream());
            } catch (IOException e) {
                logger.error("Failed to set Port properties: " + e.getMessage(), e);
            }
        }

        public void expired() {
            dispose();
        }

        public void dispose() {
            releasePort();
        }

        public void release() {
            waitForStreams();
            releasePort();
        }

        private void waitForStreams() {
            // The Message with the InputStream as a payload can be dispatched
            // into a different thread, in which case we need to wait for it to
            // finish streaming
            if (!dataInWorkFinished) {
                synchronized (notify) {
                    if (!dataInWorkFinished) {
                        try {
                            notify.wait();
                        } catch (InterruptedException e) {
                        }
                    }
                }
            }
        }

        /**
         * Releases the socket when the input stream is closed.
         */
        private void releasePort() {
            try {
                if (commPort != null) {
                    if (logger.isDebugEnabled()) {
                        // some dirty workaround for IBM JSSE's SSL implementation,
                        // which closes sockets asynchronously by that point.
                        String name = commPort.getName();
                        //                        final SocketAddress socketAddress = commPort.getLocalSocketAddress();
                        if (name == null) {
                            logger.debug("Listener has already been closed by other process.");
                        } else {
                            logger.debug("Closing listener: " + name);
                            //                            logger.debug("Closing listener: " + socketAddress);
                        }
                    }

                    shutdownPort();
                    commPort.close();
                }
            } catch (IOException e) {
                logger.warn("Socket close failed with: " + e);
            }
        }

        protected void shutdownPort() throws IOException {
            try {
                // todo check if commPort needs to do this
                //                commPort.shutdownOutput();
            } catch (UnsupportedOperationException e) {
                //Ignore, not supported by ssl sockets
            }
        }

        protected void bindTransaction(Transaction tx) throws TransactionException {
            //nothing to do
        }

        protected Object getNextMessage(Object resource) throws Exception {
            long keepAliveTimeout = ((CommConnector) connector).getKeepAliveTimeout();

            Object readMsg = null;
            try {
                // Create a monitor if expiry was set
                if (keepAliveTimeout > 0) {
                    ((CommConnector) connector).getKeepAliveMonitor().addExpirable(keepAliveTimeout,
                            TimeUnit.MILLISECONDS, this);
                }

                readMsg = protocol.read(dataIn);

                // There was some action so we can clear the monitor
                ((CommConnector) connector).getKeepAliveMonitor().removeExpirable(this);

                if (dataIn.isStreaming()) {
                    moreMessages = false;
                }

                return readMsg;
            } catch (SocketTimeoutException e) {
                ((CommConnector) connector).getKeepAliveMonitor().removeExpirable(this);
            } finally {
                if (readMsg == null) {
                    // Protocols can return a null object, which means we're done
                    // reading messages for now and can mark the stream for closing later.
                    // Also, exceptions can be thrown, in which case we're done reading.
                    dataIn.close();
                }
            }

            return null;
        }

        protected boolean hasMoreMessages(Object message) {
            return !dataInWorkFinished && !disposing.get() && moreMessages;
        }

        //@Override
        protected void handleResults(List messages) throws Exception {
            //should send back only if remote synch is set or no outbound endpoints
            if (endpoint.isRemoteSync() || !service.getOutboundRouter().hasEndpoints()) {
                for (Iterator iterator = messages.iterator(); iterator.hasNext();) {
                    Object o = iterator.next();
                    protocol.write(dataOut, o);
                    dataOut.flush();
                }
            }
        }

        protected void preRouteMuleMessage(final DefaultMuleMessage message) throws Exception {
            super.preRouteMuleMessage(message);

            // tod there's no remote address?
            //            final SocketAddress clientAddress = commPort.getRemoteSocketAddress();
            //            if (clientAddress != null)
            //            {
            //                message.setProperty(MuleProperties.MULE_REMOTE_CLIENT_ADDRESS, clientAddress.toString());
            //            }
        }
    }

}