org.bidib.wizard.tracer.service.DefaultBidibTracerService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bidibwizard-tracer Show documentation
Show all versions of bidibwizard-tracer Show documentation
jBiDiB BiDiB Wizard Tracer POM
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.");
}
}
}