package geniusweb.partiesserver; import java.util.logging.Level; import geniusweb.partiesserver.repository.RunningPartiesRepo; import geniusweb.partiesserver.repository.RunningParty; import geniusweb.party.Party; import tudelft.utilities.logging.ReportToLogger; import tudelft.utilities.logging.Reporter; /** * * This object keeps the {@link RunningPartiesRepo} up to date. Main job is to * remove parties that have been timed out. When a party times out, it calls * {@link Party#terminate()} but that might fail to stop a party. In the end, * the protocol should close the connection after the deadline. Start and run * only once. */ public class RunningPartiesUpdater implements Runnable { private final long period; private final Reporter log = new ReportToLogger("partiesserver"); private final RunningPartiesRepo running; /** * when a negotiation runs out of time, the protocol may want to inform all * parties about the failed session. If the parties are all killed at that * moment, this is impossible. Therefore we wait KILL_DELAY extra time * before really killing the parties. */ private static final long KILL_DELAY = 2000; /** * @param repo the {@link RunningPartiesRepo} that must be updated * automatically * @param period the period with which to check time-out (ms). Recommended * 1000. After constructing you can run this in separate * thread or just call {@link #run()} * */ public RunningPartiesUpdater(RunningPartiesRepo repo, final long period) { this.running = repo; this.period = period; } /** * * run the updater. Please run only one of this to avoid neeedless CPU load. */ @Override public void run() { try { while (true) { Thread.sleep(period); update(); } } catch (InterruptedException e) { System.err .println("ERROR: RunningPartiesUpdater was interrupted!"); } } /** * Removes parties when they ran out of time. Called when some file that may * be relevant has changed, and periodically every {@link #period}. * Synchronized to avoid weird states if filesystem changes rapidly. We * ignore everything but jar files. */ void update() { for (RunningParty party : running.list()) { long now = System.currentTimeMillis(); if (now >= party.getEndDate().getTime() + KILL_DELAY) { log.log(Level.WARNING, "party " + party.getID() + " still running " + KILL_DELAY / 1000 + "s after deadline. Removed now."); running.remove(party.getID()); try { Thread.sleep(20); } catch (InterruptedException e) { } } } } }