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

org.bidib.jbidibc.netbidib.client.NetBidibClientPort Maven / Gradle / Ivy

package org.bidib.jbidibc.netbidib.client;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;

import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.messages.utils.ThreadFactoryBuilder;
import org.bidib.jbidibc.netbidib.client.listener.NetBidibPortConnectionStatusListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NetBidibClientPort implements NetBidibPort {
    private static final Logger LOGGER = LoggerFactory.getLogger(NetBidibClientPort.class);

    private final NetMessageHandler netMessageHandler;

    private Socket socket;

    private final Set connectionStatusListeners = new HashSet<>();

    private final ScheduledExecutorService socketWorker;

    private String targetAddress;

    public NetBidibClientPort(InetAddress address, int portNumber, NetMessageHandler netMessageHandler)
        throws IOException {

        if (address == null) {
            throw new IllegalArgumentException("address must not be null!");
        }

        this.netMessageHandler = netMessageHandler;
        this.targetAddress = address.toString() + ":" + portNumber;

        this.socketWorker =
            Executors
                .newScheduledThreadPool(1,
                    new ThreadFactoryBuilder().setNameFormat("netBidibClientSocketWorkers-thread-%d").build());

        final int connectTimeout = 10 * 1000;

        LOGGER
            .info("Created TCP socket for address: {}, port number: {}, connectTimeout: {}", address, portNumber,
                connectTimeout);

        // create the client socket
        this.socket = new Socket();
        this.socket.setTcpNoDelay(true);

        // connect the socket with the provided connect timeout
        this.socket.connect(new InetSocketAddress(address, portNumber), connectTimeout);

        LOGGER.info("Create TCP socket passed for address: {}, port number: {}", address, portNumber);
    }

    @Override
    public void addConnectionStatusListener(final NetBidibPortConnectionStatusListener listener) {
        synchronized (connectionStatusListeners) {
            connectionStatusListeners.add(listener);
        }
    }

    @Override
    public void removeConnectionStatusListener(final NetBidibPortConnectionStatusListener listener) {
        synchronized (connectionStatusListeners) {
            connectionStatusListeners.remove(listener);
        }
    }

    private AtomicBoolean acceptorRunEnabled = new AtomicBoolean();

    private NetBidibClientSocketHandler netBidibClientSocketHandler;

    @Override
    public void run() {

        processSocketTraffic(socket);
    }

    protected void processSocketTraffic(final Socket socket) {
        LOGGER.info("Start processing the TCP socket.");

        LOGGER.info("Start client receiver handler.");

        // add a task to the worker to let the node process the send queue

        try {
            final InputStream socketInputStream = socket.getInputStream();
            final InetAddress remoteAddress = socket.getInetAddress();
            final int portNumber = socket.getPort();

            this.netBidibClientSocketHandler =
                new NetBidibClientSocketHandler(socketInputStream, remoteAddress, portNumber, netMessageHandler);
            // the NetBidibClientSocketHandler handles the messages from the socket
            socketWorker.submit(this.netBidibClientSocketHandler);

            LOGGER.info("Start client receiver handler has passed.");

            // signal connection opened to the UI
            synchronized (connectionStatusListeners) {
                for (NetBidibPortConnectionStatusListener listener : connectionStatusListeners) {
                    listener.opened();
                }
            }
        }
        catch (IOException ex) {
            LOGGER.warn("Get the inputStream of the socket failed.", ex);
            // TODO: handle exception
        }
    }

    @Override
    public void stop() {
        LOGGER.info("Stop the TCP packet receiver, socket: {}", socket);

        acceptorRunEnabled.set(false);

        if (this.netBidibClientSocketHandler != null) {
            try {
                this.netBidibClientSocketHandler.stop();
            }
            catch (Exception ex) {
                LOGGER.warn("Stop the netBidibClientSocketHandler failed.", ex);
            }
            this.netBidibClientSocketHandler = null;
        }

        if (socket != null) {
            LOGGER.info("Close the client socket.");
            try {
                socket.close();
            }
            catch (IOException ex) {
                LOGGER.warn("Close socket failed.", ex);
            }
            socket = null;
        }

        synchronized (connectionStatusListeners) {
            for (NetBidibPortConnectionStatusListener listener : connectionStatusListeners) {
                listener.closed();
            }
        }
    }

    private static final Logger MSG_RAW_LOGGER = LoggerFactory.getLogger("RAW");

    /**
     * Send the data to the host.
     * 
     * @param sendData
     *            the data to send
     * @param address
     *            the receiving address of the host
     * @param portNumber
     *            the receiving port number of the host
     * @throws IOException
     */
    @Override
    public void send(byte[] sendData, InetAddress address, int portNumber) throws IOException {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Send data to socket, port: {}, bytes: {}", portNumber, ByteUtils.bytesToHex(sendData));
        }

        if (MSG_RAW_LOGGER.isInfoEnabled()) {
            MSG_RAW_LOGGER.info(">> {}", ByteUtils.bytesToHex(sendData));
        }

        socket.getOutputStream().write(sendData);
        socket.getOutputStream().flush();
    }

    @Override
    public String toString() {
        return "NetBidibPlainTcpPort[" + targetAddress + "]";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy