package ww10; import ww10.Table; import ww10.DataModel; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; public class PrologBotServer implements Runnable { public final int port; private boolean running = true; private ConcurrentHashMap<String,Table> tables; private ConcurrentHashMap<String, Long> lastRequestPerTable; private ServerSocket serverSocket; private static final int inactivityLimit = 20*60000; //20 minutes private static final int expirationLimit = 120*60000; //120 minutes private final GameParameters gameParam = new GameParameters(); public PrologBotServer() { this(20000); } public PrologBotServer(int port) { this.port = port; try { serverSocket = new ServerSocket(port); //hack around JRE bug? serverSocket.setSoTimeout(50); } catch (IOException e) { System.err.println(e.getMessage()); e.printStackTrace(); System.err.println("Could not listen on port: " + port); System.exit(-1); } tables = new ConcurrentHashMap<String,Table>(); lastRequestPerTable = new ConcurrentHashMap<String, Long>(); } public static void main(String[] args) { (new PrologBotServer() { }).run(); } public void stop() throws IOException { running = false; serverSocket.close(); } public void run() { long delay = 60000*10; //10 minutes long period = 60000; //1 minute Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { public void run(){ performMaintenance(); } } , delay, period); while (running) { Socket clientSocket = null; try { clientSocket = serverSocket.accept(); RequestHandler handler = new RequestHandler(clientSocket, this); Thread t = new Thread(handler); //Set to high priority t.setPriority(Thread.MAX_PRIORITY); t.start(); } catch (SocketTimeoutException excp) { try { Thread.sleep(600); } catch (InterruptedException e) { e.printStackTrace(); } // try again } catch (IOException e) { System.err.println(e.getMessage()); e.printStackTrace(); System.err.println("Accept failed: 4444"); //System.exit(-1); } } } protected synchronized Table getTable(String tableName){ return tables.get(tableName); } protected synchronized void addTable(String tableName, Table table){ tables.put(tableName, table); lastRequestPerTable.put(tableName, System.currentTimeMillis()); } protected synchronized void removeTable(String tableName){ tables.remove(tableName); lastRequestPerTable.remove(tableName); } protected synchronized Set<String> listTableNames(){ return tables.keySet(); } protected synchronized void tableReceivedRequest(String tableName){ lastRequestPerTable.put(tableName, System.currentTimeMillis()); } protected synchronized int getLastRequest(String tableName){ return (int) (System.currentTimeMillis() - lastRequestPerTable.get(tableName)); } /** * If a table has no new submits in a given period of time, temporary stop simulation. * If there have been no requests concerning a given table in a given period of time, * permanently remove it from the system. */ protected synchronized void performMaintenance() { for(Table table: tables.values()){ if(table.getDataModel().getLastSubmit() > inactivityLimit) table.stop(); } for(String tableName: lastRequestPerTable.keySet()){ if(getLastRequest(tableName) > expirationLimit) { Table table = tables.get(tableName); table.terminate(); removeTable(tableName); } } } public GameParameters getGameparameters(){ return gameParam; } }