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

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

package org.bidib.jbidibc.netbidib.client;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

import org.bidib.jbidibc.messages.exception.ProtocolException;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class is the handler for TCP client connections. Every client connection is handled with its own handler
 * instance.
 */
public class NetBidibClientSocketHandler implements Callable {

    private static final Logger LOGGER = LoggerFactory.getLogger(NetBidibClientSocketHandler.class);

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

    private final InputStream socketInputStream;

    private final NetMessageHandler netMessageHandler;

    private AtomicBoolean runEnabled = new AtomicBoolean();

    private ByteArrayOutputStream receiveBuffer = new ByteArrayOutputStream(2048);

    private final InetAddress remoteAddress;

    private final int portNumber;

    public NetBidibClientSocketHandler(final InputStream socketInputStream, final InetAddress remoteAddress,
        final int portNumber, final NetMessageHandler netMessageHandler) {
        this.socketInputStream = socketInputStream;
        this.netMessageHandler = netMessageHandler;

        this.remoteAddress = remoteAddress;
        this.portNumber = portNumber;
    }

    @Override
    public Void call() {
        runEnabled.set(true);

        byte[] receiveData = new byte[1024];
        try (BufferedInputStream in = new BufferedInputStream(socketInputStream)) {
            int receivedCount = 0;

            // wait for client sending data
            while ((receivedCount = in.read(receiveData)) > 0 && runEnabled.get()) {

                // forward processing to handler
                if (netMessageHandler != null) {
                    // LOGGER.info("Received a packet. Forward packet to messageReveiver: {}", messageReceiver);

                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Received data: {}", ByteUtils.bytesToHex(receiveData, receivedCount));
                    }

                    // append the received data to the buffer
                    receiveBuffer.write(receiveData, 0, receivedCount);

                    // the received data can contain more than a single packet !!!!

                    // 11:36:23.529 [INFO] org.bidib.jbidibc.net.NetBidibTcpPort [pool-26-thread-1] - Received data:
                    // 00 01 00 09 FE 05 00 05 90 01 01 D8 FE 00 01 00 0A FE 05 00 06 90 02 01 05 FE 00 01 00 0B FE
                    // 05 00 07 90 03 64 14 FE
                    try {
                        parsePackets(receiveBuffer, netMessageHandler, remoteAddress, portNumber);
                    }
                    catch (Exception pex) {
                        LOGGER.warn("Receive message failed.", pex);
                    }
                    finally {
                        receiveBuffer.reset();
                    }
                }
                else {
                    LOGGER
                        .warn("No message receiver configured, data: {}",
                            ByteUtils.bytesToHex(receiveData, receivedCount));
                }
            }
        }
        catch (IOException ex) {
            if (runEnabled.get()) {
                LOGGER.warn("--- Interrupt NetBidibTcpPort-run", ex);
            }
            else {
                LOGGER.info("The NetBidibTcpPort worker is terminating.");
            }
        }
        finally {
            LOGGER.info("The socket connection was closed.");
            // if (socketInputStream != null) {
            // try {
            // socketInputStream.close();
            // }
            // catch (IOException ex) {
            // LOGGER.warn("Close socket failed.", ex);
            // }
            // socketInputStream = null;
            // }

            if (netMessageHandler != null) {
                LOGGER.info("Cleanup the messageReceiver.");

                // say goodbye to the message receiver to cleanup resources
                String remoteHost = remoteAddress.getHostAddress() + ":" + portNumber;

                netMessageHandler.cleanup(remoteHost);
            }
            LOGGER.info("Cleanup work after close socked has finished.");
        }
        return null;
    }

    protected void parsePackets(
        final ByteArrayOutputStream output, final NetMessageHandler netMessageHandler, InetAddress address,
        int portNumber) throws ProtocolException {

        // iterate over the data and find the packets and strip out all serial encoding
        try {

            parseInput(output, netMessageHandler, address, portNumber);
        }
        catch (RuntimeException pex) {
            LOGGER.warn("Receive message failed, reason: {}", pex.getMessage());
        }
        finally {
            // append the remaining data
            output.reset();
        }
    }

    private void processMessages(
        final ByteArrayOutputStream output, final NetMessageHandler netMessageHandler, InetAddress address,
        int portNumber) throws ProtocolException {

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Process messages will put data into DataPacket: {}", ByteUtils.bytesToHex(output));
        }
        // publish the packet

        // do not add the CRC to the data packet
        final DataPacket receivedPacket =
            new DataPacket(output.toByteArray(), 0, output.size() /*- 1*/, address, portNumber);
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Received data: {}", ByteUtils.bytesToHex(receivedPacket.getData()));
        }
        netMessageHandler.receive(receivedPacket);

    }

    private ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(100);

    /**
     * Parse the received data to process the received bidib packets.
     * 
     * @param receiveData
     *            the receive data stream
     * @param netMessageHandler
     *            the message receiver
     * @param address
     *            the address from where the data was received
     * @param portNumber
     *            the port number
     * @throws ProtocolException
     */
    protected void parseInput(
        final ByteArrayOutputStream receiveData, final NetMessageHandler netMessageHandler, InetAddress address,
        int portNumber) throws ProtocolException {
        if (receiveData != null) {

            int receivedCount = receiveData.size();
            byte[] receivedData = receiveData.toByteArray();

            MSG_RAW_LOGGER.info("<<<< len: {}, data: {}", receivedCount, ByteUtils.bytesToHex(receiveData));

            try {
                outputBuffer.write(receivedData);
            }
            catch (IOException ex) {
                LOGGER.warn("Copy received data to output buffer failed.", ex);
                throw new ProtocolException("Copy received data to output buffer failed.");
            }

            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Received raw message: {}", ByteUtils.bytesToHex(outputBuffer));
            }

            if (MSG_RAW_LOGGER.isInfoEnabled()) {
                MSG_RAW_LOGGER.info("<< [{}] - {}", outputBuffer.size(), ByteUtils.bytesToHex(outputBuffer));
            }

            // if a CRC error is detected in splitMessages the reading loop will terminate ...
            try {
                processMessages(outputBuffer, netMessageHandler, address, portNumber);

                outputBuffer.reset();
            }
            catch (ProtocolException ex) {
                LOGGER.warn("Process messages failed.", ex);

                // TODO handle this error
            }

        }
        else {
            LOGGER.error("No input available.");
        }

    }

    public void stop() {
        LOGGER.info("Stop the socket handler.");
        this.runEnabled.set(false);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy