Package org.codehaus.activemq.transport.tcp

Source Code of org.codehaus.activemq.transport.tcp.TcpTransportChannel

/**
*
* Copyright 2004 Protique Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
package org.codehaus.activemq.transport.tcp;

import EDU.oswego.cs.dl.util.concurrent.BoundedBuffer;
import EDU.oswego.cs.dl.util.concurrent.BoundedChannel;
import EDU.oswego.cs.dl.util.concurrent.BoundedLinkedQueue;
import EDU.oswego.cs.dl.util.concurrent.Executor;
import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.message.Packet;
import org.codehaus.activemq.message.WireFormat;
import org.codehaus.activemq.transport.AbstractTransportChannel;
import org.codehaus.activemq.util.JMSExceptionHelper;

import javax.jms.JMSException;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.UnknownHostException;

/**
* A tcp implementation of a TransportChannel
*
* @version $Revision: 1.38 $
*/
public class TcpTransportChannel extends AbstractTransportChannel implements Runnable {
    private static final int SOCKET_BUFFER_SIZE = 64 * 1024;
    private static final int SO_TIMEOUT = 5000;
    private static final Log log = LogFactory.getLog(TcpTransportChannel.class);

    protected Socket socket;
    private WireFormat wireFormat;
    private DataOutputStream dataOut;
    private DataInputStream dataIn;
    private SynchronizedBoolean closed;
    private SynchronizedBoolean started;
    private Object outboundLock;
    private Executor executor;
    private Thread thread;
    private boolean useAsyncSend = false;
    private boolean serverSide = false;
    private BoundedChannel exceptionsList;

    /**
     * Construct basic helpers
     */
    protected TcpTransportChannel(WireFormat wireFormat) {
        this.wireFormat = wireFormat;
        closed = new SynchronizedBoolean(false);
        started = new SynchronizedBoolean(false);
        // there's not much point logging all exceptions, lets just keep a few around
        exceptionsList = new BoundedLinkedQueue(10);
        outboundLock = new Object();
        if (useAsyncSend) {
            executor = new PooledExecutor(new BoundedBuffer(1000), 1);
        }
    }

    /**
     * Connect to a remote Node - e.g. a Broker
     *
     * @param remoteLocation
     * @throws JMSException
     */
    public TcpTransportChannel(WireFormat wireFormat, URI remoteLocation) throws JMSException {
        this(wireFormat);
        try {
            this.socket = createSocket(remoteLocation);
            socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE);
            socket.setSendBufferSize(SOCKET_BUFFER_SIZE);
            BufferedInputStream buffIn = new BufferedInputStream(socket.getInputStream());
            this.dataIn = new DataInputStream(buffIn);
            TcpBufferedOutputStream buffOut = new TcpBufferedOutputStream(socket.getOutputStream());
            this.dataOut = new DataOutputStream(buffOut);
        }
        catch (Exception ioe) {
            throw JMSExceptionHelper.newJMSException("Initialization of TcpTransportChannel failed: " + ioe, ioe);
        }
    }

    /**
     * Connect to a remote Node - e.g. a Broker
     *
     * @param remoteLocation
     * @param localLocation  - e.g. local InetAddress and local port
     * @throws JMSException
     */
    public TcpTransportChannel(WireFormat wireFormat, URI remoteLocation, URI localLocation) throws JMSException {
        this(wireFormat);
        try {
            this.socket = createSocket(remoteLocation, localLocation);
            socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE);
            socket.setSendBufferSize(SOCKET_BUFFER_SIZE);
            BufferedInputStream buffIn = new BufferedInputStream(socket.getInputStream());
            this.dataIn = new DataInputStream(buffIn);
            TcpBufferedOutputStream buffOut = new TcpBufferedOutputStream(socket.getOutputStream());
            this.dataOut = new DataOutputStream(buffOut);
        }
        catch (Exception ioe) {
            throw JMSExceptionHelper.newJMSException("Initialization of TcpTransportChannel failed: " + ioe, ioe);
        }
    }

    /**
     * @param socket
     * @throws JMSException
     */
    public TcpTransportChannel(WireFormat wireFormat, Socket socket, Executor executor) throws JMSException {
        this(wireFormat);
        this.socket = socket;
        this.executor = executor;
        this.serverSide = true;
        try {
            socket.setReceiveBufferSize(SOCKET_BUFFER_SIZE);
            socket.setSendBufferSize(SOCKET_BUFFER_SIZE);
            TcpBufferedOutputStream buffOut = new TcpBufferedOutputStream(socket.getOutputStream());
            this.dataOut = new DataOutputStream(buffOut);
            BufferedInputStream buffIn = new BufferedInputStream(socket.getInputStream());
            this.dataIn = new DataInputStream(buffIn);
        }
        catch (IOException ioe) {
            throw JMSExceptionHelper.newJMSException("Initialization of TcpTransportChannel failed: " + ioe, ioe);
        }
    }

    /**
     * close the channel
     */
    public void stop() {
        if (closed.commit(false, true)) {
            super.stop();
            try {
                stopExecutor(executor);
                dataOut.close();
                dataIn.close();
                socket.close();

                // lets wait for the receive thread to terminate
                // TODO thread.join();
            }
            catch (Exception e) {
                log.warn("Caught while closing: " + e + ". Now Closed", e);
            }

        }
    }

    /**
     * start listeneing for events
     *
     * @throws JMSException if an error occurs
     */
    public void start() throws JMSException {
        if (started.commit(false, true)) {
            thread = new Thread(this, "Thread:" + toString());
            thread.setDaemon(true);
            if (!serverSide) {
                thread.setPriority(Thread.NORM_PRIORITY + 2);
            }
            thread.start();
        }
    }


    /**
     * Asynchronously send a Packet
     *
     * @param packet
     * @throws JMSException
     */
    public void asyncSend(final Packet packet) throws JMSException {
        if (executor != null) {
            try {
                executor.execute(new Runnable() {
                    public void run() {
                        try {
                            if (!closed.get()) {
                                doAsyncSend(packet);
                            }
                        }
                        catch (JMSException e) {
                            try {
                                exceptionsList.put(e);
                            }
                            catch (InterruptedException e1) {
                                log.warn("Failed to add element to exception list: " + e1);
                            }
                        }
                    }

                });
            }
            catch (InterruptedException e) {
                log.info("Caught: " + e, e);
            }
            try {
                JMSException e = (JMSException) exceptionsList.poll(0);
                if (e != null) {
                    throw e;
                }
            }
            catch (InterruptedException e1) {
                log.warn("Failed to remove element to exception list: " + e1);
            }
        }
        else {
            doAsyncSend(packet);
        }
    }

    /**
     * @return false
     */
    public boolean isMulticast() {
        return false;
    }

    /**
     * reads packets from a Socket
     */
    public void run() {
        log.trace("TCP consumer thread starting");
        int count = 0;
        while (!closed.get()) {
            if (serverSide && ++count > 500) {
                count = 0;
                Thread.yield();
            }
            int type = 0;
            try {
                socket.setSoTimeout(SO_TIMEOUT);
                while ((type = dataIn.read()) == 0) {
                }
                if (type == -1) {
                    log.trace("The socket peer is now closed");
                    //doClose(new IOException("Socket peer is now closed"));
                    stop();
                }
                else {
                    socket.setSoTimeout(0);

                    Packet packet = wireFormat.readPacket(type, dataIn);
                    if (packet != null) {
                        doConsumePacket(packet);
                    }
                }
            }
            catch (SocketTimeoutException ste) {
                // ignore timeouts, they are expected
            }
            catch (InterruptedIOException ioe) {
                // TODO confirm that this really is a bug in the AS/400 JVM
                // Patch for AS/400 JVM

                // lets ignore these exceptions
                // as they typically just indicate the thread was interupted
                // while waiting for input, not that the socket is in error
            }
            catch (IOException e) {
                doClose(e);
            }
        }
    }

    /**
     * pretty print for object
     *
     * @return String representation of this object
     */
    public String toString() {
        return "TcpTransportChannel: " + socket;
    }

    /**
     * Actually performs the async send of a packet
     *
     * @param packet
     * @throws JMSException
     */
    protected void doAsyncSend(Packet packet) throws JMSException {
        try {
            synchronized (outboundLock) {
                wireFormat.writePacket(packet, dataOut);
                dataOut.flush();
            }
        }
        catch (IOException e) {
            throw JMSExceptionHelper.newJMSException("asyncSend failed: " + e, e);
        }
    }


    private void doClose(Exception ex) {
        if (!closed.get()) {
            onAsyncException(JMSExceptionHelper.newJMSException("Error reading socket: " + ex, ex));
            stop();
        }
    }

    /**
     * Factory method to create a new socket
     *
     * @param remoteLocation the URI to connect to
     * @return the newly created socket
     * @throws UnknownHostException
     * @throws IOException
     */
    protected Socket createSocket(URI remoteLocation) throws UnknownHostException, IOException {
        return new Socket(remoteLocation.getHost(), remoteLocation.getPort());
    }

    /**
     * Factory method to create a new socket
     *
     * @param remoteLocation
     * @param localLocation
     * @return @throws IOException
     * @throws IOException
     * @throws UnknownHostException
     */
    protected Socket createSocket(URI remoteLocation, URI localLocation) throws IOException, UnknownHostException {
        return new Socket(remoteLocation.getHost(), remoteLocation.getPort(), InetAddress.getByName(localLocation
                .getHost()), localLocation.getPort());
    }

}
TOP

Related Classes of org.codehaus.activemq.transport.tcp.TcpTransportChannel

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.