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

org.bidib.wizard.tracer.service.DefaultBidibTracerService Maven / Gradle / Ivy

There is a newer version: 2.0.29
Show newest version
package org.bidib.wizard.tracer.service;

import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.bidib.jbidibc.debug.DebugInterface;
import org.bidib.jbidibc.debug.DebugMessageProcessor;
import org.bidib.jbidibc.debug.DebugMessageReceiver;
import org.bidib.jbidibc.debug.DebugReaderFactory;
import org.bidib.jbidibc.debug.DebugReaderFactory.SerialImpl;
import org.bidib.jbidibc.messages.ConnectionListener;
import org.bidib.jbidibc.messages.base.BidibPortStatusListener;
import org.bidib.jbidibc.messages.exception.PortNotFoundException;
import org.bidib.jbidibc.messages.exception.PortNotOpenedException;
import org.bidib.jbidibc.messages.helpers.Context;
import org.bidib.jbidibc.messages.helpers.DefaultContext;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.serial.SerialMessageParser;
import org.bidib.wizard.common.model.settings.TracerServiceSettingsInterface;
import org.bidib.wizard.tracer.event.TracerMessageEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.MessageFormatter;

import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Action;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.schedulers.Schedulers;
import io.reactivex.rxjava3.subjects.PublishSubject;

public class DefaultBidibTracerService implements BidibTracerService {

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

    public static final String VALID_HOSTNAME_REGEX =
        "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$";

    private final TracerServiceSettingsInterface tracerServiceSettings;

    private ConnectionListener upstreamConnectionListener;

    private ConnectionListener downstreamConnectionListener;

    private DebugInterface upstreamPort;

    private DebugInterface downstreamPort;

    private UpstreamTracerMessageProcessor upstreamTracerMessageProcessor;

    private DownstreamTracerMessageProcessor downstreamTracerMessageProcessor;

    private PublishSubject subjectMessageEvents;

    public DefaultBidibTracerService(final TracerServiceSettingsInterface tracerServiceSettings) {
        LOGGER.info("Create new instance of DefaultBidibTracerService.");

        this.tracerServiceSettings = tracerServiceSettings;

        this.subjectMessageEvents = PublishSubject.create();
    }

    @Override
    public Disposable subscribeMessageEvents(
        Consumer onNext, Consumer onError, Action onComplete) {
        LOGGER.info("Subscribe to tracer message events.");
        return subjectMessageEvents.observeOn(Schedulers.computation()).subscribe(onNext, onError, onComplete);
    }

    @Override
    public void start(final BidibPortStatusListener bidibPortStatusListener) {

        final Context context = new DefaultContext();

        String upstreamPortName = this.tracerServiceSettings.getUpstreamPort();
        String downstreamPortName = this.tracerServiceSettings.getDownstreamPort();

        String serialPortProvider = this.tracerServiceSettings.getSerialPortProvider();

        LOGGER
            .info("Configured serialPortProvider: {}, upstreamPortName: {}, downstreamPortName: {}", serialPortProvider,
                upstreamPortName, downstreamPortName);

        SerialImpl serialImpl = SerialImpl.SCM;
        if (StringUtils.isNotBlank(serialPortProvider)) {
            switch (serialPortProvider) {
                case "RXTX":
                    serialImpl = SerialImpl.RXTX;

                    LOGGER
                        .info("Set the system property: gnu.io.rxtx.SerialPorts, value: {}",
                            downstreamPortName + ":" + upstreamPortName);

                    // TODO
                    // System.setProperty("gnu.io.rxtx.SerialPorts", downstreamPortName + ":" + upstreamPortName);

                    break;
                case "PUREJAVACOMM":
                    serialImpl = SerialImpl.PUREJAVACOMM;
                    break;
                default:
                    break;
            }
        }
        LOGGER.info("Use the serial port provider impl: {}", serialImpl);

        this.upstreamConnectionListener = new ConnectionListener() {

            @Override
            public void status(String messageKey, final Context context) {
                LOGGER.info("The status of the upstream port has changed: {}, context: {}", messageKey, context);

            }

            @Override
            public void opened(String port) {
                LOGGER.info("The upstream port was opened: {}", port);

                bidibPortStatusListener.statusChanged("upstream", BidibPortStatusListener.PortStatus.CONNECTED);

                // openProxyPort(context, proxyPortName, serialImpl);
            }

            @Override
            public void closed(String port) {
                LOGGER.info("The interface port was closed: {}", port);

                bidibPortStatusListener.statusChanged("upstream", BidibPortStatusListener.PortStatus.DISCONNECTED);

                // closeProxyPort();
            }

            @Override
            public void stall(boolean stall) {
                // TODO Auto-generated method stub
            }
        };

        this.downstreamConnectionListener = new ConnectionListener() {

            @Override
            public void status(String messageKey, final Context context) {
                LOGGER.info("The status of the downstream port has changed: {}, context: {}", messageKey, context);

            }

            @Override
            public void opened(String port) {
                LOGGER.info("The downstream port was opened: {}", port);

                bidibPortStatusListener.statusChanged("downstream", BidibPortStatusListener.PortStatus.CONNECTED);

                // for (BidibPortStatusListener listener : statusListeners) {
                // listener.statusChanged(PortStatus.CONNECTED);
                // }
            }

            @Override
            public void closed(String port) {
                LOGGER.info("The downstream port was closed: {}", port);

                bidibPortStatusListener.statusChanged("downstream", BidibPortStatusListener.PortStatus.DISCONNECTED);

                // make sure the resources are cleaned up
                // closeProxyPort();
                //
                // for (BidibPortStatusListener listener : statusListeners) {
                // listener.statusChanged(PortStatus.DISCONNECTED);
                // }
            }

            @Override
            public void stall(boolean stall) {
                // TODO Auto-generated method stub
            }
        };

        openUpstreamPort(context, upstreamPortName, serialImpl);
        openDownstreamPort(context, downstreamPortName, serialImpl);

    }

    private void openUpstreamPort(final Context context, final String upstreamPortName, SerialImpl serialImpl) {

        LOGGER.info("Begin open the upstream port: {}", upstreamPortName);

        final org.bidib.jbidibc.messages.logger.Logger messageLogger = new org.bidib.jbidibc.messages.logger.Logger() {

            @Override
            public void debug(String format, Object... arguments) {
                LOGGER.debug(format, arguments);
            }

            @Override
            public void info(String format, Object... arguments) {
                LOGGER.info(format, arguments);

                final TracerMessageEvent event =
                    new TracerMessageEvent("upstream", LocalDateTime.now(),
                        MessageFormatter.arrayFormat(format, arguments).getMessage());
                subjectMessageEvents.onNext(event);
            }

            @Override
            public void warn(String format, Object... arguments) {
                LOGGER.warn(format, arguments);
            }

            @Override
            public void error(String format, Object... arguments) {
                LOGGER.error(format, arguments);
            }
        };

        int baudRate = 115200;

        // create the message parser for upstream messages
        final SerialMessageParser upstreamMessageParser = new SerialMessageParser();

        upstreamTracerMessageProcessor = new UpstreamTracerMessageProcessor(messageLogger, true);

        final DebugMessageProcessor messageReceiver = new DebugMessageReceiver() {

            @Override
            public void processMessages(ByteArrayOutputStream output) {
                try {

                    LOGGER.info("<< Received data from interface: {}", ByteUtils.bytesToHex(output));

                    try {
                        upstreamMessageParser
                            .parseInput(upstreamTracerMessageProcessor, output.toByteArray(), output.size());
                    }
                    catch (Exception ex1) {
                        LOGGER.warn("Prepare messages to send to proxy failed.", ex1);
                    }

                }
                catch (Exception ex) {
                    LOGGER.warn("Send message from interface to proxy failed.", ex);
                }
                finally {
                    output.reset();
                }
            }
        };

        // support remote interface ports
        if (upstreamPortName.contains(":")) {
            String[] splited = upstreamPortName.split(":");

            if (InetAddressValidator.getInstance().isValid(splited[0])) {
                LOGGER.info("Valid IP address detected: {}", splited[0]);
                serialImpl = SerialImpl.SPSW_NET;
            }
            else if (Pattern.matches(VALID_HOSTNAME_REGEX, splited[0])) {
                LOGGER.info("Valid hostname detected: {}", splited[0]);
                serialImpl = SerialImpl.SPSW_NET;
            }
        }

        try {
            upstreamPort = DebugReaderFactory.getDebugReader(serialImpl, messageReceiver);
            upstreamPort.open(upstreamPortName, baudRate, upstreamConnectionListener, context);

            LOGGER.info("Open the upstream port passed.");
        }
        catch (PortNotFoundException ex) {
            LOGGER.warn("Selected upstream port is not available.", ex);

            throw new RuntimeException("Selected upstream port for is not available: " + ex.getMessage());
        }
        catch (PortNotOpenedException ex) {
            LOGGER.warn("Open upstream reader port failed.", ex);

            throw new RuntimeException("Open upstream reader port failed: " + ex.getMessage());
        }
        catch (Exception ex) {
            LOGGER.warn("Create upstream reader failed.", ex);

            throw new RuntimeException("Create upstream reader failed.");
        }

    }

    private void openDownstreamPort(final Context context, final String downstreamPortName, SerialImpl serialImpl) {

        LOGGER.info("Begin open the downstream port: {}", downstreamPortName);

        final org.bidib.jbidibc.messages.logger.Logger messageLogger = new org.bidib.jbidibc.messages.logger.Logger() {

            @Override
            public void debug(String format, Object... arguments) {
                LOGGER.debug(format, arguments);
            }

            @Override
            public void info(String format, Object... arguments) {
                LOGGER.info(format, arguments);

                final TracerMessageEvent event =
                    new TracerMessageEvent("downstream", LocalDateTime.now(),
                        MessageFormatter.arrayFormat(format, arguments).getMessage());
                subjectMessageEvents.onNext(event);
            }

            @Override
            public void warn(String format, Object... arguments) {
                LOGGER.warn(format, arguments);
            }

            @Override
            public void error(String format, Object... arguments) {
                LOGGER.error(format, arguments);
            }
        };

        int baudRate = 115200;

        // create the message parser for downstream messages
        final SerialMessageParser downstreamMessageParser = new SerialMessageParser();

        downstreamTracerMessageProcessor = new DownstreamTracerMessageProcessor(messageLogger, true);

        final DebugMessageProcessor messageReceiver = new DebugMessageReceiver() {

            @Override
            public void processMessages(ByteArrayOutputStream output) {
                try {

                    LOGGER.info("<< Received data from interface: {}", ByteUtils.bytesToHex(output));

                    try {
                        downstreamMessageParser
                            .parseInput(downstreamTracerMessageProcessor, output.toByteArray(), output.size());
                    }
                    catch (Exception ex1) {
                        LOGGER.warn("Prepare messages to send to proxy failed.", ex1);
                    }

                }
                catch (Exception ex) {
                    LOGGER.warn("Send message from interface to proxy failed.", ex);
                }
                finally {
                    output.reset();
                }
            }
        };

        // support remote interface ports
        if (downstreamPortName.contains(":")) {
            String[] splited = downstreamPortName.split(":");

            if (InetAddressValidator.getInstance().isValid(splited[0])) {
                LOGGER.info("Valid IP address detected: {}", splited[0]);
                serialImpl = SerialImpl.SPSW_NET;
            }
            else if (Pattern.matches(VALID_HOSTNAME_REGEX, splited[0])) {
                LOGGER.info("Valid hostname detected: {}", splited[0]);
                serialImpl = SerialImpl.SPSW_NET;
            }
        }

        try {
            downstreamPort = DebugReaderFactory.getDebugReader(serialImpl, messageReceiver);
            downstreamPort.open(downstreamPortName, baudRate, downstreamConnectionListener, context);

            LOGGER.info("Open the downstream port passed.");
        }
        catch (PortNotFoundException ex) {
            LOGGER.warn("Selected downstream port is not available.", ex);

            throw new RuntimeException("Selected downstream port for is not available: " + ex.getMessage());
        }
        catch (PortNotOpenedException ex) {
            LOGGER.warn("Open downstream reader port failed.", ex);

            throw new RuntimeException("Open downstream reader port failed: " + ex.getMessage());
        }
        catch (Exception ex) {
            LOGGER.warn("Create downstream reader failed.", ex);

            throw new RuntimeException("Create downstream reader failed.");
        }

    }

    @Override
    public void shutdown() {
        LOGGER.info("Shutdown the bidib tracer service.");

        closeUpstreamPort();

        closeDownstreamPort();

    }

    private void closeUpstreamPort() {
        LOGGER.info("Close the upstream port.");

        if (upstreamPort != null) {
            LOGGER.info("Close the upstream port: {}", upstreamPort);
            upstreamPort.close();

            upstreamPort = null;
        }
        else {
            LOGGER.info("No upstream port to close available.");
        }
    }

    private void closeDownstreamPort() {
        LOGGER.info("Close the downstream port.");

        if (downstreamPort != null) {
            LOGGER.info("Close the downstream port: {}", downstreamPort);
            downstreamPort.close();

            downstreamPort = null;
        }
        else {
            LOGGER.info("No downstream port to close available.");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy