package rescuecore2.connection; import java.net.ServerSocket; import java.net.Socket; import java.io.InterruptedIOException; import java.io.IOException; import java.util.Set; import java.util.HashSet; import rescuecore2.misc.WorkerThread; import rescuecore2.registry.Registry; import rescuecore2.log.Logger; /** A class for managing incoming connections. */ public class ConnectionManager { private Set<Reader> readers; private boolean shutdown; private final Object lock = new Object(); /** Construct a new ConnectionManager. */ public ConnectionManager() { readers = new HashSet<Reader>(); shutdown = false; } /** Listen for connections on a particular port. @param port The port to listen on. @param registry The registry to install in new connections. @param listener A ConnectionManagerListener that will be informed of new connections. @throws IOException If there is a problem listening on the port. */ public void listen(int port, Registry registry, ConnectionManagerListener listener) throws IOException { synchronized (lock) { if (shutdown) { throw new IOException("Connection manager has been shut down"); } Logger.info("Listening for connections on port " + port); ServerSocket socket = new ServerSocket(port); socket.setSoTimeout(1000); socket.setReuseAddress(true); Reader r = new Reader(socket, registry, listener); readers.add(r); r.start(); } } /** Shut down this ConnectionManager. */ public void shutdown() { synchronized (lock) { if (shutdown) { return; } shutdown = true; } for (Reader next : readers) { try { next.kill(); } catch (InterruptedException e) { Logger.error("ConnectionManager interrupted while shutting down read threads", e); } } } /** Find out if this ConnectionManager is alive. @return True if this manager has not been shut down. */ public boolean isAlive() { synchronized (lock) { return !shutdown; } } private class Reader extends WorkerThread { private ServerSocket socket; private Registry registry; private ConnectionManagerListener callback; public Reader(ServerSocket socket, Registry registry, ConnectionManagerListener callback) { this.socket = socket; this.registry = registry; this.callback = callback; } @Override protected boolean work() { try { Socket s = socket.accept(); TCPConnection conn = new TCPConnection(s); if (ConnectionManager.this.isAlive()) { conn.setRegistry(registry); callback.newConnection(conn); conn.startup(); } } // CHECKSTYLE:OFF:EmptyBlock OK here catch (InterruptedIOException e) { // Ignore } // CHECKSTYLE:ON:EmptyBlock catch (IOException e) { Logger.error("Error listening for connection", e); } return true; } @Override protected void cleanup() { try { socket.close(); } catch (IOException e) { Logger.error("Error closing server socket", e); } } } }