001package jmri.jmrix.ipocs; 002 003import java.io.DataInputStream; 004import java.io.DataOutputStream; 005import java.io.IOException; 006import java.net.InetSocketAddress; 007import java.net.StandardSocketOptions; 008import java.nio.channels.AsynchronousServerSocketChannel; 009import java.util.ArrayList; 010import java.util.HashMap; 011import java.util.List; 012import java.util.Map; 013 014 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018import jmri.jmrix.AbstractPortController; 019import jmri.jmrix.ipocs.protocol.Message; 020import jmri.util.zeroconf.ZeroConfService; 021 022/** 023 * 024 * @author Fredrik Elestedt Copyright (C) 2020 025 * @since 4.21.2 026 */ 027public class IpocsPortController extends AbstractPortController implements IpocsClientListener { 028 private final static Logger log = LoggerFactory.getLogger(IpocsPortController.class); 029 private static String INADDR_ANY = "0.0.0.0"; 030 private short port = 0; 031 private AsynchronousServerSocketChannel serverSocket = null; 032 private IpocsSocketAcceptor socketAcceptor; 033 private ZeroConfService zeroConfService = null; 034 private final List<IpocsClientListener> clientListeners = new ArrayList<IpocsClientListener>(); 035 private final Map<String, IpocsClientHandler> clients = new HashMap<>(); 036 private final Map<String, Message> lastMessage = new HashMap<>(); 037 038 public IpocsPortController(IpocsSystemConnectionMemo memo) { 039 super(memo); 040 super.setManufacturer(IpocsConnectionTypeList.IPOCSMR); 041 final Option o1 = new Option("Port", new String[]{"0"}, false, Option.Type.TEXT); 042 super.options.put(super.option1Name, o1); 043 } 044 045 @Override 046 public IpocsSystemConnectionMemo getSystemConnectionMemo() { 047 return (IpocsSystemConnectionMemo) super.getSystemConnectionMemo(); 048 } 049 050 @Override 051 public void configure() { 052 if (getSystemConnectionMemo().getPortController() == null) { 053 getSystemConnectionMemo().setPortController(this); 054 } 055 getSystemConnectionMemo().configureManagers(); 056 } 057 058 @Override 059 public void connect() throws IOException { 060 log.info("Setting up service"); 061 serverSocket = AsynchronousServerSocketChannel.open(); 062 socketAcceptor = new IpocsSocketAcceptor(this, serverSocket); 063 final InetSocketAddress address = new InetSocketAddress(INADDR_ANY, port); 064 serverSocket.bind(address); 065 serverSocket.setOption(StandardSocketOptions.SO_REUSEADDR, true); 066 serverSocket.accept(null, socketAcceptor); 067 int servicePort = ((InetSocketAddress)serverSocket.getLocalAddress()).getPort(); 068 log.info("Starting ZeroConfService _ipocs._tcp.local for port {}", servicePort); 069 zeroConfService = ZeroConfService.create("_ipocs._tcp.local.", "ipocs", servicePort, 0, 0, new HashMap<String, String>()); 070 zeroConfService.publish(); 071 } 072 073 @Override 074 public DataInputStream getInputStream() { 075 throw new UnsupportedOperationException(); 076 } 077 078 @Override 079 public DataOutputStream getOutputStream() { 080 throw new UnsupportedOperationException(); 081 } 082 083 @Override 084 public String getCurrentPortName() { 085 return "IPOCSMR"; 086 } 087 088 public void addListener(IpocsClientListener clientListener) { 089 clientListeners.add(clientListener); 090 } 091 092 public void removeListener(IpocsClientListener clientListener) { 093 clientListeners.remove(clientListener); 094 } 095 096 @Override 097 public void clientConnected(IpocsClientHandler client) { 098 log.info("New client connected"); 099 } 100 101 @Override 102 public void clientDisconnected(IpocsClientHandler client) { 103 new HashMap<String, IpocsClientHandler>(clients).forEach((userName, storedClient) -> { 104 if (storedClient == client) { 105 clients.remove(userName); 106 lastMessage.remove(userName); 107 for (IpocsClientListener handler : clientListeners) { 108 if (userName.equals(handler.getUserName())) { 109 handler.clientDisconnected(client); 110 } 111 } 112 } 113 }); 114 } 115 116 @Override 117 public void onMessage(IpocsClientHandler client, Message msg) { 118 clients.put(msg.getObjectName(), client); 119 lastMessage.put(msg.getObjectName(), msg); 120 for (IpocsClientListener handler : clientListeners) { 121 if (handler.getUserName().equals(msg.getObjectName())) { 122 handler.onMessage(client, msg); 123 } 124 } 125 } 126 127 public void send(Message msg) { 128 IpocsClientHandler client = clients.get(msg.getObjectName()); 129 if (client != null) { 130 client.send(msg); 131 } 132 } 133 134 public Message getLastStatus(String userName) { 135 return lastMessage.get(userName); 136 } 137 138 public short getPort() { 139 return port; 140 } 141 142 public void setPort(short port) { 143 this.port = port; 144 } 145}