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;
}
}