001package jmri.jmrix.bidib.tcpserver;
002
003import java.io.ByteArrayOutputStream;
004import java.util.concurrent.atomic.AtomicBoolean;
005import jmri.jmrix.bidib.BiDiBTrafficController;
006
007import org.bidib.jbidibc.core.NodeListener;
008import org.bidib.jbidibc.messages.exception.ProtocolException;
009import org.bidib.jbidibc.net.serialovertcp.*;
010
011import org.slf4j.Logger;
012import org.slf4j.LoggerFactory;
013
014/**
015 * This is the BiDiB controller of the BiDiB over TCP server.
016 * The class starts and stops the receiver on both sides,
017 * the incoming TCP server and the JMRI BiDiB connection.
018 * 
019 * @author Eckart Meyer Copyright (C) 2023
020 *
021 */
022public class NetPlainTcpBidib {
023
024    private final BiDiBTrafficController tc;
025    private Thread portWorker;
026    private NetMessageHandler netServerMessageHandler;
027    private NetBidibPort netBidibTcpPort;
028    private BiDiBMessageReceiver bidibMessageReveiver;
029    private final AtomicBoolean isStarted = new AtomicBoolean();
030    private final Object stopSync = new Object();
031    
032    public NetPlainTcpBidib(BiDiBTrafficController tc) {
033        this.tc = tc;
034    }
035    
036    public boolean isStarted() {
037        return isStarted.get();
038    }
039
040    //@Override
041    public void start(int portNumber) {
042        log.info("Start the TCP server.");
043
044        // create the server components
045        try {
046
047            // create the message receiver that handles incoming commands from the host and forward the commands to the
048            // simulators
049            netServerMessageHandler = createServerMessageHandler();
050
051            //LOGGER.info("Create simulator for protocol: {}", protocol);
052
053            // open the port that simulates the interface device
054            log.info("Create a NetBidibTcpPort with the portnumber: {}", portNumber);
055            netBidibTcpPort =
056                new NetBidibServerPlainTcpPort(portNumber, null, netServerMessageHandler);
057
058            log.info("Prepare and start the port worker for netBidibPortSimulator: {}", netBidibTcpPort);
059
060            portWorker = new Thread(netBidibTcpPort);
061            portWorker.start();
062
063            // create the BiDiB connection receiver
064            //BiDiBTrafficController tc = InstanceManager.getDefault(BiDiBSystemConnectionMemo.class).getBiDiBTrafficController();
065            bidibMessageReveiver = new BiDiBMessageReceiver(netServerMessageHandler, netBidibTcpPort);
066            tc.addRawMessageListener(bidibMessageReveiver);
067            
068            isStarted.set(true);
069        }
070        catch (Exception ex) {
071            log.warn("Start the TCP server failed.", ex);
072            isStarted.set(false);
073        }
074        
075    }
076        
077    protected NetMessageHandler createServerMessageHandler() {
078        // create the message handler that delegates the incoming messages to the message receiver that has a
079        // simulator node configured
080        final ServerMessageReceiver serverMessageReceiver = new ServerMessageReceiver(tc) {
081            @Override
082            public void publishResponse(ByteArrayOutputStream output) throws ProtocolException {
083
084                // Publish the responses to the host
085                log.info("Publish the response. Prepare message to send to host using netSimulationMessageHandler: {}",
086                        netServerMessageHandler);
087                try {
088                    // send to handler
089                    ///// netServerMessageHandler.send(netBidibTcpPort, output.toByteArray());
090                }
091                catch (Exception ex) {
092                    log.warn("Process messages failed.", ex);
093                }
094            }
095
096            @Override
097            public void removeNodeListener(NodeListener nodeListener) {
098
099            }
100
101//            @Override
102//            public void setIgnoreWrongMessageNumber(boolean ignoreWrongMessageNumber) {
103//
104//            }
105        };
106        
107        TcpServerNetMessageHandler netMessageHandler = new TcpServerNetMessageHandler(serverMessageReceiver);
108        log.info("Created the server netMessageHandler: {}", netMessageHandler);
109        return netMessageHandler;
110        
111    }
112
113    //@Override
114    public void stop() {
115        log.info("Stop the TCP server.");
116
117        if (netBidibTcpPort != null) {
118            log.info("Stop the port.");
119            netBidibTcpPort.stop();
120
121            if (portWorker != null) {
122                synchronized (stopSync) {
123                    try {
124                        portWorker.join(5000L);
125                    }
126                    catch (InterruptedException ex) {
127                        log.warn("Wait for termination of port worker failed.", ex);
128                    }
129                    portWorker = null;
130                }
131            }
132
133            isStarted.set(false);
134            netBidibTcpPort = null;
135        }
136        
137        if (bidibMessageReveiver != null) {
138            //BiDiBTrafficController tc = InstanceManager.getDefault(BiDiBSystemConnectionMemo.class).getBiDiBTrafficController();
139            tc.removeRawMessageListener(bidibMessageReveiver);
140            bidibMessageReveiver = null;
141        }
142
143        log.info("Stop the TCP server finished.");
144    }
145
146    private final static Logger log = LoggerFactory.getLogger(NetPlainTcpBidib.class);
147    
148}