All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.crankuptheamps.client.TCPTransport Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2022 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties.  This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights.  This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////

package com.crankuptheamps.client;

import java.net.Socket;
import java.net.URI;
import java.nio.ByteBuffer;
import java.beans.ExceptionListener;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.crankuptheamps.client.Message.SerializationResult;
import com.crankuptheamps.client.exception.AlreadyConnectedException;
import com.crankuptheamps.client.exception.ConnectionRefusedException;
import com.crankuptheamps.client.exception.DisconnectedException;
import com.crankuptheamps.client.exception.InvalidURIException;
import com.crankuptheamps.client.exception.RetryOperationException;

/**
* Implements an AMPS transport over standard TCP/IP. 
* Use this transport by connecting to URIs beginning with tcp://. 
*/

public class TCPTransport implements Transport
{
    protected TCPTransportImpl _impl                  = null;
    private Protocol           _protocol              = null;
    private final Lock         _sendLock              = new ReentrantLock();
    private ByteBuffer         _sendBuffer            = ByteBuffer.allocate(4096);
    private static int         _defaultReadTimeout    = 0;
    private static int         _defaultConnectTimeout = 0;

    // Other clients use daemon threads by default, but
    // we have customer that depends on non-daemon threads (i.e. they
    // want the program to continue running even once main() exits.)
    private static boolean _useDaemonThreads       = false;

    protected TCPTransportImpl constructTransportImpl(Protocol protocol, Properties properties)
    {
        return new TCPTransportImpl(protocol, properties, new DefaultTransportFilter());
    }
    public TCPTransport(Protocol protocol, Properties properties)
    {
        this._protocol = protocol;
        this._impl = constructTransportImpl(protocol,properties);
    }

    public TCPTransport(Protocol msgType)
    {
        this(msgType, null);
    }

    public static void setDaemon(boolean daemonThreads)
    {
        TCPTransport._useDaemonThreads = daemonThreads;
    }

    public static boolean isDaemon()
    {
        return TCPTransport._useDaemonThreads;
    }

    /**
     * Sets the default read timeout used for socket reads. This value is
     * used for new connections, but not applied to existing connections. A 0
     * value means to wait forever for incoming data, or until an error occurs.
     *
     * @param defaultReadTimeoutMillis_ The default read timeout in milliseconds.
     */
    public static void setDefaultReadTimeout(int defaultReadTimeoutMillis_)
    {
        TCPTransport._defaultReadTimeout = defaultReadTimeoutMillis_;
    }

    /**
     * Returns the default read timeout used for socket reads. A 0 value
     * means to wait forever for incoming data, or until an error occurs.
     *
     * @return The current default read timeout, in milliseconds.
     */
    public static int getDefaultReadTimeout()
    {
        return TCPTransport._defaultReadTimeout;
    }

    /**
     * Returns the default connect timeout used for new connections.
     *
     * @param defaultConnectTimeoutMillis_ The default connect timeout,
     *  in milliseconds. A 0 value means no timeout is specified, i.e. wait
     *  until the OS returns an error.
     */
    public static void setDefaultConnectTimeout(int defaultConnectTimeoutMillis_)
    {
        TCPTransport._defaultConnectTimeout = defaultConnectTimeoutMillis_;
    }

    /**
     * Returns the default connect timeout used for new connections.
     *
     * @return The default connect timeout in milliseconds. A 0 value means
     *       no timeout is specified, i.e. wait until the OS returns an error.
     */
    public static int getDefaultConnectTimeout()
    {
        return TCPTransport._defaultConnectTimeout;
    }

    public static TCPTransport createTransport(Protocol messageType)
    {
        return new TCPTransport(messageType);
    }

    public void setMessageHandler(MessageHandler ml)
    {
        this._impl.setMessageHandler(ml);
    }

    public void setThreadCreatedHandler(ThreadCreatedHandler tch_)
    {
        this._impl.setThreadCreatedHandler(tch_);
    }

    public void setDisconnectHandler(TransportDisconnectHandler dh)
    {
        this._impl.setDisconnectHandler(dh);
    }

    public void setExceptionListener(ExceptionListener exceptionListener)
    {
        this._impl.setExceptionListener(exceptionListener);
    }

    public void setTransportFilter(TransportFilter filter)
    {
        _impl.setTransportFilter(filter);
    }
    public void connect(URI uri) throws ConnectionRefusedException, AlreadyConnectedException, InvalidURIException
    {
        this._impl.connect(uri);
    }

    public void close() throws Exception
    {
        this._impl.disconnect();
    }

    public void disconnect()
    {
        this._impl.disconnect();
    }

    public void handleCloseEvent(int failedVersion_, String message, Exception e) throws DisconnectedException, RetryOperationException
    {
        this._impl.handleCloseEvent(failedVersion_, message, e);
    }

    public void sendWithoutRetry(Message message) throws DisconnectedException
    {
        this._sendLock.lock();
        try
        {
            _sendBuffer.clear();
            // Reserve space for a 4-byte int at the
            // beginning for the size of the message
            _sendBuffer.position(4);
            SerializationResult sr = message.serialize(_sendBuffer);
            if(sr == Message.SerializationResult.BufferTooSmall)
            {
                // Buffer was too small, let's resize and retry
                _sendBuffer = ByteBuffer.allocate(2 * _sendBuffer.capacity());
                sendWithoutRetry(message);
                return;
            }
            else if(sr == SerializationResult.OK)
            {
                // Write size integer now that we know the size
                _sendBuffer.putInt(0, _sendBuffer.position() - 4);
                // Flip buffer for reading
                _sendBuffer.flip();
                // Write buffer to socket
                this._impl.send(_sendBuffer);
            }
        }
        finally
        {
            this._sendLock.unlock();
        }
    }

    public void send(Message message) throws DisconnectedException
    {
        this._sendLock.lock();
        try
        {
            int currentVersion = getVersion();
            try
            {
                sendWithoutRetry(message);
            }
            catch(DisconnectedException ex)
            {
                try
                {
                    this.handleCloseEvent(currentVersion, "Exception occured while sending", ex);
                }
                catch(RetryOperationException r)
                {
                    ; // retry
                }
                throw ex;
            }

        }
        finally
        {
            this._sendLock.unlock();
        }
    }

    public Message allocateMessage()
    {
        return this._protocol.allocateMessage();
    }

    public long writeQueueSize() throws DisconnectedException
    {
        try
        {
            return this._impl.writeQueueSize();
        }
        catch(NullPointerException e)
        {
            throw new DisconnectedException("not connected", e);
        }
    }

    public long readQueueSize() throws DisconnectedException
    {
        try
        {
            return this._impl.writeQueueSize();
        }
        catch(NullPointerException e)
        {
            throw new DisconnectedException("not connected", e);
        }
    }

    public long flush() throws DisconnectedException
    {
        try
        {
            return this._impl.flush();
        }
        catch(NullPointerException e)
        {
            throw new DisconnectedException("not connected", e);
        }
    }

    public long flush(long timeout) throws DisconnectedException
    {
        try
        {
            return this._impl.flush(timeout);
        }
        catch(NullPointerException e)
        {
            throw new DisconnectedException("not connected", e);
        }
    }

    public Socket socket()
    {
        try
        {
            return this._impl.socket();
        }
        catch(Exception e)
        {
            return null;
        }
    }

    public int getVersion()
    {
        return this._impl._connectionVersion;
    }

    public void setReadTimeout(int readTimeout_)
    {
        this._impl.setReadTimeout(readTimeout_);
    }

    public void setIdleRunnable(AMPSRunnable runnable)
    {
      this._impl.setIdleRunnable(runnable);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy