package org.reldb.rel.v0.server; import java.io.*; import java.util.*; import java.net.*; import org.reldb.rel.v0.interpreter.*; /** A Server listens on a port for incoming connection requests, and spawns * SessionS to handle each connection. * * @author scat070 * */ public class Server { private final static int shutdownAttempts = 10; private int portNumber; private boolean running; private ServerSocket serverSocket; private HashMap<Long, Session> sessions; private Thread daemon; private Instance rel; public Server(Instance rel, int portNumber) { this.rel = rel; this.portNumber = portNumber; serverSocket = null; startup(); } public Instance getInstance() { return rel; } /** Start up server. */ void startup() { if (serverSocket != null) return; sessions = new HashMap<Long, Session>(); try { serverSocket = new ServerSocket(portNumber); } catch (IOException ioe) { System.out.println("Server: " + ioe); return; } daemon = new Thread() { public void run() { running = true; InetAddress ip = serverSocket.getInetAddress(); System.out.println("Server: Listening for connections on " + ip + ":" + portNumber + " (" + rel.getHost() + ")"); while (running) { try { new Session(Server.this, serverSocket.accept()); } catch (IOException ioe) { System.out.println("Server: " + ioe.getMessage()); running = false; break; } } System.out.println("Server: Turned off."); } }; daemon.start(); } /** Shut down server. */ public void shutdown() { System.out.println("Server: Shutting down..."); if (serverSocket != null) { int i; // Make multiple attempts to shut down server for (i=0; i<shutdownAttempts && running; i++) { try { try { // Delay 1 second Thread.sleep(1000); } catch (InterruptedException ie) { } // Close the server socket serverSocket.close(); // Kill all sessions killAllSessions(); } catch (IOException ioe) { System.out.println("Server: " + ioe); } } // If all attempts have failed, forcibly terminate daemon if (i == shutdownAttempts) { System.out.println("Server: Forcing shutdown after " + shutdownAttempts + " attempts."); daemon.interrupt(); } serverSocket = null; } } /* This is invoked by a Session when it terminates, to advise the * Server that the Session should be removed. */ synchronized void removeSession(Session s) { sessions.remove(new Long(s.getId())); } /* This is invoked by a Session when it successfully starts, to advise the * Server that it is managing the Session. */ synchronized void addSession(Session s) { sessions.put(new Long(s.getId()), s); } /** Kill all SessionS. */ void killAllSessions() { Session[] s = sessions.values().toArray(new Session[0]); // prevent concurrent modification exception for (Session session: s) session.kill(); } }