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

org.bidib.jbidibc.gateway.GatewayNetMessageHandler Maven / Gradle / Ivy

package org.bidib.jbidibc.gateway;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.bidib.jbidibc.core.BidibLibrary;
import org.bidib.jbidibc.core.BidibMessageProcessor;
import org.bidib.jbidibc.core.CRC8;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.net.BidibNetAddress;
import org.bidib.jbidibc.net.DataPacket;
import org.bidib.jbidibc.net.NetBidibPort;
import org.bidib.jbidibc.net.NetMessageHandler;
import org.bidib.jbidibc.net.exception.ClientNotAcceptedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

    private BidibMessageProcessor messageReceiverDelegate;

    private List knownBidibHosts = new LinkedList();

    public GatewayNetMessageHandler(BidibMessageProcessor messageReceiverDelegate) {
        this.messageReceiverDelegate = messageReceiverDelegate;
    }

    @Override
    public void receive(final DataPacket packet) {
        // a data packet was received ... process the envelope and extract the message
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Received a packet from address: {}, port: {}, data: {}", packet.getAddress(),
                packet.getPort(), ByteUtils.bytesToHex(packet.getData()));
        }

        BidibNetAddress current = new BidibNetAddress(packet.getAddress(), packet.getPort());
        if (!knownBidibHosts.contains(current)) {

            LOGGER.info("Adding new known Bidib host: {}", current);
            knownBidibHosts.add(current);
        }

        // TODO for the first magic response we need special processing because we need to keep the session key
        try {

            // remove the UDP paket wrapper data and forward to the MessageReceiver
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            output.write(packet.getData());

            LOGGER.info("Forward received message to messageReceiverDelegate: {}", messageReceiverDelegate);
            messageReceiverDelegate.receive(output);
        }
        catch (Exception ex) {
            LOGGER.warn("Process messages failed.", ex);
            throw new RuntimeException(ex);
        }
    }

    @Override
    public void send(NetBidibPort port, byte[] message) {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Send message to port: {}, message: {}", port, ByteUtils.bytesToHex(message));
        }

        if (port != null) {

            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();

                // send the message to every known host
                for (BidibNetAddress host : knownBidibHosts) {
                    bos.reset();

                    addDelimiter(bos);

                    byte length = message[0];

                    escape(bos, length);

                    int txCrc = CRC8.getCrcValue(length);

                    for (int i = 1; i <= length; i++) {
                        escape(bos, message[i]);
                        txCrc = CRC8.getCrcValue((message[i] ^ txCrc) & 0xFF);
                    }
                    escape(bos, (byte) txCrc);
                    addDelimiter(bos);

                    LOGGER.info("Send message to address: {}, port: {}", host.getAddress(), host.getPortNumber());

                    // send the data to the host
                    port.send(bos.toByteArray(), host.getAddress(), host.getPortNumber());
                }
            }
            catch (IOException ex) {
                LOGGER.warn("Send message to port failed.", ex);
                throw new RuntimeException("Send message to datagram socket failed.", ex);
            }
        }
        else {
            LOGGER.warn("Send not possible, the port is closed.");
        }
    }

    private void addDelimiter(ByteArrayOutputStream output) {
        output.write((byte) BidibLibrary.BIDIB_PKT_MAGIC);
    }

    private void escape(ByteArrayOutputStream output, byte c) {
        if ((c == (byte) BidibLibrary.BIDIB_PKT_MAGIC) || (c == (byte) BidibLibrary.BIDIB_PKT_ESCAPE)) {
            output.write((byte) BidibLibrary.BIDIB_PKT_ESCAPE);
            c = (byte) (c ^ 0x20);
        }
        output.write(c);
    }

    @Override
    public void acceptClient(String remoteHost) {
        LOGGER.info("Accept client with address: {}", remoteHost);

        if (knownBidibHosts.isEmpty()) {
            LOGGER.info("Check if we can accept the client: {}", remoteHost);
        }
        else {
            LOGGER.warn("Deny access for more than 1 client!");

            throw new ClientNotAcceptedException("Only a single client is currently supported.");
        }

    }

    @Override
    public void cleanup(final String remoteHost) {
        LOGGER.info("Cleanup client with address: {}", remoteHost);

        BidibNetAddress foundHost = IterableUtils.find(knownBidibHosts, new Predicate() {

            @Override
            public boolean evaluate(BidibNetAddress other) {
                return remoteHost.equals(other.getAddress().getHostAddress());
            }
        });

        if (foundHost != null) {
            LOGGER.info("Remove client from knownBidibHosts: {}", foundHost);
            knownBidibHosts.remove(foundHost);
        }
        else {
            LOGGER.warn("No client found in knownBidibHosts with address: {}", remoteHost);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy