package org.myrobotlab.net; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.URI; import java.util.HashMap; import java.util.Map; import org.myrobotlab.framework.Message; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; import org.myrobotlab.service.RemoteAdapter; import org.slf4j.Logger; public class TcpServer implements Runnable { public final static Logger log = LoggerFactory.getLogger(TcpServer.class); /** * list of active tcp connections tcp connections need a new thread for a * listener - to recv messages and maintain the connection udp does not - it * requires a single server on a single port */ transient private HashMap<URI, TcpThread> tcpClientList = new HashMap<URI, TcpThread>(); transient RemoteAdapter myService = null; transient ServerSocket serverSocket = null; transient ObjectOutputStream out; transient ObjectInputStream in; Integer serverPort; boolean isRunning = false; transient Thread serverThread = null; public TcpServer(RemoteAdapter s) { myService = s; } public void start(int serverPort){ this.serverPort = serverPort; if (serverThread != null){ stop(); } serverThread = new Thread(this, String.format("%s.tcp.%d", myService.getName(), this.serverPort)); serverThread.start(); } public void stop() { if (serverThread != null) { serverThread.interrupt(); } } @Override public void run() { try { serverSocket = new ServerSocket(serverPort, 10); myService.info(String.format("TcpServer listening on %s", serverSocket.getLocalSocketAddress())); isRunning = true; while (isRunning) { // FIXME - on contact register the "environment" regardless // if a service registers !!! java.net.Socket clientSocket = serverSocket.accept(); // inbound connection FIXME - all keys constructed in // Encoder // TODO reduce these 2 methods to an interface // addTcpClient(clientSocket, myService); // ADD TCP CLIENT BEGIN ! - probably should not be in RemoteAdapter - as this is a detail for tcp String clientKey = String.format("tcp://%s:%d", clientSocket.getInetAddress().getHostAddress(), clientSocket.getPort()); URI uri = new URI(clientKey); // HELP PROTOKEY VS MRL KEY ?? TcpThread tcp = new TcpThread(myService, uri, clientSocket); tcpClientList.put(uri, tcp); myService.connections.put(uri, tcp.data); // ADD TCP CLIENT END ! - probably should not be in RemoteAdapter - as this is a detail for tcp myService.broadcastState(); } serverSocket.close(); } catch (Exception e) { log.error("tcp server socket threw", e); } isRunning = false; } public void shutdown() { if ((serverSocket != null) && (!serverSocket.isClosed())) { try { serverSocket.close(); } catch (IOException e) { // dont care } } serverSocket = null; } public boolean isReady() { if (serverSocket != null) { return serverSocket.isBound(); } return false; } // FIXME - add to Gateway interfaceS public HashMap<URI, Connection> broadcastHeartbeat() { for (Map.Entry<URI, Connection> entry : myService.connections.entrySet()) { URI uri = entry.getKey(); // Connection value = entry.getValue(); // roll through send a set of transactions off & start a // IOCompletion like // array of status ... // if timeout is reached - write the rest with timeout (those that // did not // get an asynch response if (uri.getScheme().equals("tcp")) { TcpThread tcp = tcpClientList.get(uri); log.info("" + tcp); // check socket connectivity // attempt to re-connect if disconnected myService.broadcastState(); } } // FIXME - refactor out return myService.connections; } public void sendTcp(URI uri, Message msg) { TcpThread tcp = null; try { if (tcpClientList.containsKey(uri)) { tcp = tcpClientList.get(uri); } else { // constructor will throw if can not connect -> new Socket(host, // port) tcp = new TcpThread(myService, uri, null); tcpClientList.put(uri, tcp); // FIXME - refactor out myService.connections.put(uri, tcp.data); myService.broadcastState(); } tcp.send(msg); myService.connections.get(uri).tx++; } catch (Exception e) { Logging.logError(e); } } }