package net.sf.colossus.util; import java.util.WeakHashMap; import java.util.logging.Level; import java.util.logging.Logger; /** * Keeps track of "viable entities", i.e. parts of the program * for which it makes sense to have them living on their own. * * Viable entities so far are : * - the game server part with it's subthreads, * - the user Client with MasterBoard (e.g. as remote client) * - the web server client * The reason is, earlier each of them may at some point do * System.exit(), even if one would have liked to keep one * other part open. (for example, 3 local players -- if one * was dead and you closed that MasterBoard, the whole application * did exit. * * Now, each of those tells the ViableEntityManager "I'm done", * and if the last one says so, THEN the System.exit() is * actually executed. Or rather, nowadays, the main() thread * can go on, come up with a menu again or something. * * @author Clemens Katzer */ public class ViableEntityManager { private static final Logger LOGGER = Logger .getLogger(ViableEntityManager.class.getName()); private static boolean debug = false; private static WeakHashMap<Object, String> viableEntities = new WeakHashMap<Object, String>(); private static int waiting = 0; private static Object mutex = new Object(); public static synchronized void register(Object viableEntity, String name) { viableEntities.put(viableEntity, name); LOGGER.log(Level.FINEST, "ViableEntityManager: now " + viableEntities.size() + " entities registered."); } public static synchronized void unregister(Object viableEntity) { if (viableEntities.containsKey(viableEntity)) { viableEntities.remove(viableEntity); if (viableEntities.isEmpty()) { LOGGER.log(Level.FINEST, "\n\nSystemExitManager: last viable entity is gone!!"); // notify that all gone: synchronized (mutex) { mutex.notify(); } } } if (debug) { int count = viableEntities.size(); String list = viableEntities.values().toString(); LOGGER.log(Level.FINEST, "ViableEntityManager: now " + count + " entities registered: " + list); } } public static int getWaitingCnt() { return waiting; } public static void waitUntilAllGone() { synchronized (viableEntities) { if (viableEntities.isEmpty()) { LOGGER.log(Level.FINEST, "waitUntilAllGone: viableEntities already empty! " + "- returning."); return; } } synchronized (mutex) { try { waiting++; mutex.wait(); waiting--; } catch (InterruptedException e) { LOGGER.log(Level.WARNING, "waitUntilAllGone(): interrupted!", e); } } } }