001package jmri.jmrix.bidib.tcpserver;
002
003import java.io.ByteArrayOutputStream;
004import java.util.ArrayList;
005import java.util.List;
006import java.util.concurrent.atomic.AtomicBoolean;
007
008import jmri.jmrix.bidib.BiDiBTrafficController;
009
010import org.apache.commons.collections4.CollectionUtils;
011
012import org.bidib.jbidibc.core.*;
013import org.bidib.jbidibc.messages.message.*;
014import org.bidib.jbidibc.messages.MessageReceiver;
015import org.bidib.jbidibc.messages.exception.ProtocolException;
016import org.bidib.jbidibc.messages.utils.ByteUtils;
017
018import org.slf4j.Logger;
019import org.slf4j.LoggerFactory;
020
021/**
022 * This is the server message receiver. Message from the network client will
023 * be received and then forwarded to the JMRI BiDiB connection via the
024 * traffic controler.
025 * 
026 * @author Eckart Meyer Copyright (C) 2023
027 *
028 */
029public abstract class ServerMessageReceiver implements ServerBidibMessageProcessor, MessageReceiver {
030
031    //private final BiDiBSystemConnectionMemo memo;
032    private final BiDiBTrafficController tc;
033    private BidibRequestFactory requestFactory;
034    protected AtomicBoolean running = new AtomicBoolean();
035    boolean escapeHot = false;
036    private final Object accessLock = new Object();
037
038    public ServerMessageReceiver(BiDiBTrafficController tc) {
039
040        //memo = InstanceManager.getDefault(BiDiBSystemConnectionMemo.class);
041        //log.info("Server connected to {}", memo.getUserName());
042        //tc = memo.getBiDiBTrafficController();
043        this.tc = tc;
044        log.info("Server connected to {}", tc.getUserName());
045        // enable the running flag
046        running.set(true);
047    }
048
049    private synchronized BidibRequestFactory getRequestFactory() {
050        if (requestFactory == null) {
051            requestFactory = new BidibRequestFactory();
052        }
053
054        return requestFactory;
055    }
056
057    @Override
058    public void enable() {
059        log.info("enable is called.");
060        synchronized (accessLock) {
061            escapeHot = false;
062        }
063
064        running.set(true);
065    }
066
067    @Override
068    public void disable() {
069        log.info("Disable is called.");
070
071        running.set(false);
072
073        synchronized (accessLock) {
074            escapeHot = false;
075        }
076    }
077    
078//    @Override
079//    public void purgeReceivedDataInBuffer() {
080//
081//    }
082
083/**
084 * Process data received from network. Forward to BiDiB connection
085 * Currently we split possible multi-message packets into a sequence of single messages.
086 * TODO: forward multi-message packets, this would require that the BiDiB traffic controller supports this
087 * 
088 * @param output data received
089 */
090    @Override
091    public void receive(final ByteArrayOutputStream output) {
092
093        if (!running.get()) {
094            log.warn("Receiver is not running. Discard messages.");
095
096            return;
097        }
098
099        log.info("Receive data: {}", ByteUtils.bytesToHex(output));
100
101        // if a CRC error is detected in splitMessages the reading loop will terminate ...
102        try {
103            List<BidibMessageInterface> commands = new ArrayList<>();
104            getRequestFactory().createFromRaw(output.toByteArray(), commands);
105
106            if (CollectionUtils.isNotEmpty(commands)) {
107
108                for (BidibMessageInterface bidibCommand : commands) {
109                    log.info("Process the current bidibCommand: {}", bidibCommand);
110
111                    //String nodeAddress = NodeUtils.formatAddress(bidibCommand.getAddr());
112                    //log.debug("node address: {}", tc.getNodeByAddr(bidibCommand.getAddr()));
113                    
114                    tc.sendBiDiBMessage((BidibCommandMessage)bidibCommand, tc.getNodeByAddr(bidibCommand.getAddr()));
115
116//                    SimulatorNode simulatorNode = simulatorRegistry.getSimulator(nodeAddress);
117//                    if (simulatorNode != null) {
118//                        simulatorNode.processRequest(bidibCommand);
119//                    }
120//                    else {
121//                        log.error("No simulator available for address: {}", nodeAddress);
122//                    }
123                }
124            }
125            else {
126                log.warn("No commands in packet received.");
127            }
128        }
129        catch (ProtocolException ex) {
130            log.warn("Create BiDiB message failed.", ex);
131        }
132
133    }
134
135    @Override
136    public abstract void publishResponse(ByteArrayOutputStream output) throws ProtocolException;
137
138    @Override
139    public void processMessages(ByteArrayOutputStream output) throws ProtocolException {
140        log.warn("processMessages() is not implemented in SimulationMessageReceiver.");
141    }
142
143    @Override
144    public String getErrorInformation() {
145        return null;
146    }
147
148    @Override
149    public void addMessageListener(MessageListener messageListener) {
150    }
151
152    @Override
153    public void removeMessageListener(MessageListener messageListener) {
154    }
155
156    @Override
157    public void addNodeListener(NodeListener nodeListener) {
158    }
159
160    @Override
161    public void cleanup() {
162    }
163
164    private final static Logger log = LoggerFactory.getLogger(ServerMessageReceiver.class);
165
166}