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

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

package org.bidib.jbidibc.gateway;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.bidib.jbidib.pi.BiDiBPiConnector;
import org.bidib.jbidibc.core.AbstractBidib;
import org.bidib.jbidibc.core.BidibInterface;
import org.bidib.jbidibc.core.BidibMessageProcessor;
import org.bidib.jbidibc.core.ConnectionListener;
import org.bidib.jbidibc.core.MessageListener;
import org.bidib.jbidibc.core.MessageReceiver;
import org.bidib.jbidibc.core.NodeListener;
import org.bidib.jbidibc.core.exception.PortNotFoundException;
import org.bidib.jbidibc.core.exception.PortNotOpenedException;
import org.bidib.jbidibc.core.helpers.Context;
import org.bidib.jbidibc.core.node.NodeRegistry;
import org.bidib.jbidibc.core.node.listener.TransferListener;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.gateway.event.PortEvent;
import org.bidib.jbidibc.gateway.event.PortEventListener;
import org.bidib.jbidibc.net.NetBidib;
import org.bidib.jbidibc.net.NetBidibPort;
import org.bidib.jbidibc.net.NetBidibServerTcpPort;
import org.bidib.jbidibc.net.NetBidibUdpPort;
import org.bidib.jbidibc.net.NetMessageHandler;
import org.bidib.jbidibc.net.exception.ClientNotAcceptedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.eventbus.EventBus;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioProvider;

public class GatewayBidib extends AbstractBidib {

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

    private NetBidibPort port;

    private Thread portWorker;

    private NetMessageHandler netMessageHandler;

    private String connectedPortName;

    private InetAddress address;

    private int portNumber;

    private String protocol;

    private BiDiBPiConnector piConnector;

    private ConnectionListener localConnectionListener;

    private PortEventListener portEventListener;

    private EventBus eventBus;

    /**
     * Get a new initialized instance of GatewayBidib.
     *
     * @return the instance of GatewayBidib
     */
    public static BidibInterface createInstance() {
        LOGGER.info("Create new instance of GatewayBidib.");

        GatewayBidib instance = new GatewayBidib();
        instance.initialize();

        return instance;
    }

    private GatewayBidib() {

    }

    @Override
    protected void initialize() {

        portEventListener = new PortEventListener() {
            @Override
            protected void handlePortEvent(PortEvent event) {
                // TODO Auto-generated method stub
                super.handlePortEvent(event);
            }
        };

        eventBus = new EventBus(GatewayBidib.class.getSimpleName());
        eventBus.register(portEventListener);

        try {
            GpioProvider gpioProvider = GpioFactory.getDefaultProvider();
            if (gpioProvider != null) {
                LOGGER.info("Found GpioProvider. Prepare the BiDiBPiConnector.");
                piConnector = new BiDiBPiConnector();
                piConnector.connect();
            }
            else {
                LOGGER.info("No GpioProvider found. Cannot prepare the BiDiBPiConnector.");
            }
        }
        catch (Exception ex) {
            LOGGER.warn("Get GPIO provider failed.", ex);
        }
        catch (UnsatisfiedLinkError ex) {
            LOGGER.warn("Get GPIO provider failed.", ex);
        }

        // call base class
        super.initialize();
    }

    @Override
    protected BidibMessageProcessor createMessageReceiver(NodeRegistry nodeFactory) {
        return new GatewayMessageReceiver(nodeFactory);
    }

    private MessageReceiver getNetMessageReceiver() {
        return (MessageReceiver) getMessageReceiver();
    }

    @Override
    public void setConnectionListener(final ConnectionListener connectionListener) {
        // TODO Auto-generated method stub

        localConnectionListener = new ConnectionListener() {

            @Override
            public void status(String messageKey) {
                LOGGER.info("Status was signaled: {}", messageKey);
                // TODO Auto-generated method stub

                // forward to original connection listener
                connectionListener.status(messageKey);
            }

            @Override
            public void opened(String port) {
                LOGGER.info("Port was opened: {}", port);
                // TODO Auto-generated method stub

                eventBus.post(new PortEvent("Port was opened: " + port));

                // forward to original connection listener
                connectionListener.opened(port);
            }

            @Override
            public void closed(String port) {
                LOGGER.info("Port was closed: {}", port);
                // TODO Auto-generated method stub

                eventBus.post(new PortEvent("Port was closed: " + port));

                // forward to original connection listener
                connectionListener.closed(port);
            }
        };

        super.setConnectionListener(localConnectionListener);
    }

    @Override
    public void open(
        String portName, ConnectionListener connectionListener, Set nodeListeners,
        Set messageListeners, Set transferListeners, Context context)
        throws PortNotFoundException, PortNotOpenedException {

        LOGGER.info("Open port: {}", portName);

        try {
            close();
        }
        catch (Exception ex) {
            LOGGER.warn("Make sure port is closed before open port and send magic failed.", ex);
        }

        setConnectionListener(connectionListener);

        // register the listeners
        registerListeners(nodeListeners, messageListeners, transferListeners);

        if (port == null) {
            LOGGER.info("Open port with name: {}", portName);
            if (portName == null || portName.trim().isEmpty()) {
                throw new PortNotFoundException("");
            }

            if (portName.indexOf(":") < 0) {
                portName += ":" + NetBidib.BIDIB_UDP_PORT_NUMBER;
                LOGGER.info("Added portnumber to portName: {}", portName);
            }

            try {
                // close();
                port = internalOpen(portName, context);
                connectedPortName = portName;

                LOGGER.info("Port is opened, send the magic. The connected port is: {}", connectedPortName);
                // sendMagic();
                getRootNode();
            }
            catch (Exception ex) {
                LOGGER.warn("Open port and send magic failed.", ex);

                throw new PortNotOpenedException(portName, PortNotOpenedException.UNKNOWN);
            }
        }
        else {
            LOGGER.warn("Port is already opened.");
        }
    }

    private NetBidibPort internalOpen(String portName, final Context context) throws IOException {
        LOGGER.info("Internal open port: {}", portName);

        String[] hostAndPort = portName.split(":");

        if (hostAndPort.length > 2) {
            // protocol provided
            protocol = hostAndPort[0];
            address = InetAddress.getByName(hostAndPort[1]);
            portNumber = Integer.parseInt(hostAndPort[2]);
        }
        else {
            protocol = "tcp";
            address = InetAddress.getByName(hostAndPort[0]);
            portNumber = Integer.parseInt(hostAndPort[1]);
        }

        LOGGER.info("Configured address: {}, portNumber: {}, protocol: {}", address, portNumber, protocol);

        final BidibMessageProcessor messageReceiver = getMessageReceiver();

        if (context != null) {
            Boolean ignoreWrongMessageNumber = context.get("ignoreWrongMessageNumber", Boolean.class, Boolean.FALSE);
            messageReceiver.setIgnoreWrongMessageNumber(ignoreWrongMessageNumber);
        }

        // enable the message receiver before the event listener is added
        getNetMessageReceiver().enable();

        netMessageHandler = new GatewayNetMessageHandler(messageReceiver) {
            @Override
            public void acceptClient(String remoteHost) {
                LOGGER.info("A new client applied for a connection: {}", remoteHost);

                // TODO check if we accept the client or not

                if (piConnector != null) {
                    boolean pairingAllowed = piConnector.acceptClient(remoteHost);
                    if (!pairingAllowed) {
                        LOGGER.warn("Pairing is not allowed! Current remoteHost: {}", remoteHost);

                        throw new ClientNotAcceptedException("Pairing is not allowed for remoteHost: " + remoteHost);
                    }
                    else {
                        LOGGER.info("Pairing is allowed!");
                    }

                }
                else {

                    super.acceptClient(remoteHost);
                }
            }
        };

        // open the port
        NetBidibPort netBidibPort = null;

        if ("tcp".equalsIgnoreCase(protocol)) {
            LOGGER.info("Create a NetBidibTcpPort with the portnumber: {}", NetBidib.BIDIB_UDP_PORT_NUMBER);
            netBidibPort = new NetBidibServerTcpPort(NetBidib.BIDIB_UDP_PORT_NUMBER, null, netMessageHandler);
        }
        else {
            LOGGER.info("Create a NetBidibUdpPort with the portnumber: {}", NetBidib.BIDIB_UDP_PORT_NUMBER);
            netBidibPort = new NetBidibUdpPort(NetBidib.BIDIB_UDP_PORT_NUMBER, netMessageHandler);
        }
        LOGGER.info("Prepare and start the port worker for netBidibPort: {}", netBidibPort);

        startReceiverAndQueues(messageReceiver, context);

        portWorker = new Thread(netBidibPort);
        portWorker.start();

        return netBidibPort;
    }

    @Override
    public boolean isOpened() {
        return port != null;
    }

    @Override
    public void close() {
        LOGGER.info("Close the port.");

        if (!isOpened()) {
            LOGGER.info("The port is not opened. Skip close processing.");
            return;
        }

        if (port != null) {
            LOGGER.info("Stop the port.");
            port.stop();

            if (portWorker != null) {
                synchronized (portWorker) {
                    try {
                        portWorker.join(5000L);
                    }
                    catch (InterruptedException ex) {
                        LOGGER.warn("Wait for termination of port worker failed.", ex);
                    }
                    portWorker = null;
                }
            }

            port = null;
        }

        stopReceiverAndQueues(null);

        if (getConnectionListener() != null) {
            getConnectionListener().closed(connectedPortName);
        }

        // clear the connectedPortName
        connectedPortName = null;

        // TODO close is currently called to often
        if (piConnector != null) {
            LOGGER.info("Disconnect the piConnector.");

            try {
                piConnector.disconnect();
            }
            catch (Exception ex) {
                LOGGER.warn("Disconnect the piConnector failed.", ex);
            }

            piConnector = null;
            LOGGER.info("Released the piConnector.");
        }

        LOGGER.info("Close the port finished.");
    }

    @Override
    public List getPortIdentifiers() {
        return Collections.emptyList();
    }

    @Override
    protected void sendData(ByteArrayOutputStream data) {
        LOGGER.info("Send data to host/client: {}, netMessageHandler: {}", ByteUtils.bytesToHex(data.toByteArray()),
            netMessageHandler);
        netMessageHandler.send(port, data.toByteArray());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy