--- /dev/null
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+\r
+/**\r
+ * Element of the VamsasFileWatcherThread event generator chain.\r
+ * Keep a reference to this element before adding it to the chain \r
+ * in order to control the generation of events with halt and enable.\r
+ * \r
+ * doWatch will do nothing if the element is not enabled.\r
+ * \r
+ */\r
+public class SessionFileWatcherElement extends WatcherElement {\r
+ SessionFile watched=null;\r
+ /**\r
+ * create a new, enabled watch element\r
+ * @param watcher file being watched\r
+ * @param handler handler to call on state change\r
+ */\r
+ public SessionFileWatcherElement(SessionFile watcher, WatcherCallBack handler) {\r
+ this(watcher, handler, true);\r
+ }\r
+ protected void initWatch() {\r
+ if (watched==null)\r
+ return;\r
+ if (watcher==null || !watcher.getSubject().equals(watched.sessionFile)) \r
+ watcher=new FileWatcher(watched.sessionFile);\r
+ else\r
+ watcher.setState();\r
+ }\r
+ protected void endWatch() {\r
+ // leaves watcher in state its in.\r
+ }\r
+ /**\r
+ * new watcher with flag to initially skip watching this sessionfile\r
+ * @param watcher\r
+ * @param handler\r
+ * @param enableWatching\r
+ */\r
+ public SessionFileWatcherElement(SessionFile watcher, WatcherCallBack handler, boolean enableWatching) {\r
+ super(handler);\r
+ this.watched = watcher;\r
+ if (enableWatching)\r
+ enableWatch();\r
+ else\r
+ haltWatch();\r
+ }\r
+ /**\r
+ * @return the watched\r
+ */\r
+ public SessionFile getWatched() {\r
+ return watched;\r
+ }\r
+ protected String getSubject() {\r
+ return watched.sessionFile.toString();\r
+ }\r
+}\r
--- /dev/null
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+\r
+/**\r
+ * Element of the VamsasFileWatcherThread event generator chain.\r
+ * Keep a reference to this element before adding it to the chain \r
+ * in order to control the generation of events with halt and enable.\r
+ * \r
+ * doWatch will do nothing if the element is not enabled.\r
+ * \r
+ */\r
+public class VamsasFileWatcherElement extends WatcherElement {\r
+ VamsasFile watched=null;\r
+ /**\r
+ * create a new, enabled watch element\r
+ * @param watcher file being watched\r
+ * @param handler handler to call on state change\r
+ */\r
+ public VamsasFileWatcherElement(VamsasFile watcher, WatcherCallBack handler) {\r
+ this(watcher, handler, true);\r
+ }\r
+ protected void initWatch() {\r
+ if (watched==null)\r
+ return;\r
+ watched.unLock(); // very very essential!\r
+ watcher = new FileWatcher(watched.getVamsasFile());\r
+ }\r
+ protected void endWatch() {\r
+ // leaves watcher in state its in.\r
+ }\r
+ /**\r
+ * new watcher with flag to initially skip watching this sessionfile\r
+ * @param watcher\r
+ * @param handler\r
+ * @param enableWatching\r
+ */\r
+ public VamsasFileWatcherElement(VamsasFile watcher, WatcherCallBack handler, boolean enableWatching) {\r
+ super(handler);\r
+ this.watched = watcher;\r
+ if (enableWatching)\r
+ enableWatch();\r
+ else\r
+ haltWatch();\r
+ }\r
+ /**\r
+ * @return the watched\r
+ */\r
+ public VamsasFile getWatched() {\r
+ return watched;\r
+ }\r
+ protected String getSubject() {\r
+ return watched.getVamsasFile().toString();\r
+ }\r
+}\r
--- /dev/null
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+import java.util.Iterator;\r
+import java.util.Vector;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+\r
+/**\r
+ * Watches a bunch of VamsasFile states, calling \r
+ * the associated event handler when anything changes.\r
+ * @author JimP\r
+ *\r
+ */\r
+public class VamsasFileWatcherThread extends Thread {\r
+ private Log log = LogFactory.getLog(VamsasFileWatcherThread.class); \r
+ /* (non-Javadoc)\r
+ * @see java.lang.Thread#run()\r
+ */\r
+ EventGeneratorThread client=null;\r
+ private Vector elements=null;\r
+ public VamsasFileWatcherThread(EventGeneratorThread client) {\r
+ this.client = client;\r
+ elements=new Vector();\r
+ }\r
+ public void addElement(WatcherElement welement) {\r
+ elements.addElement(welement);\r
+ }\r
+ public void removeElemenet(WatcherElement welement) {\r
+ elements.removeElement(welement);\r
+ }\r
+ public void clearElements() {\r
+ elements.clear();\r
+ }\r
+ /**\r
+ * true if the thread is running\r
+ */\r
+ boolean running=false;\r
+ /**\r
+ * true if the watcher loop is in progress\r
+ */\r
+ boolean watching=false;\r
+ public void haltWatchers() {\r
+ if (!watching)\r
+ return;\r
+ watching=false;\r
+ // wait arount for WATCH_SLEEP milliseconds before returning\r
+ // in the hope that the watcher loop has stopped\r
+ try {\r
+ long time = System.currentTimeMillis()+WATCH_SLEEP;\r
+ interrupt();\r
+ while (running && time>System.currentTimeMillis()) {\r
+ Thread.sleep(1);\r
+ }\r
+ } catch (Exception e) {};\r
+ if (running)\r
+ log.warn("haltWatchers returning whilst thread is still running.");\r
+ }\r
+ \r
+ /**\r
+ * time between checks for changes of state on the file\r
+ */\r
+ public int WATCH_SLEEP=30; \r
+ /**\r
+ * check each watcher in sequence, monitoring any events generated.\r
+ * Then wait WATCH_SLEEP milliseconds before checking all again (if there were no events)\r
+ */\r
+ public void run() {\r
+ running=true;\r
+ watching=true;\r
+ log.debug("Starting WatcherThread poll loop");\r
+ while (watching) {\r
+ boolean wait=true;\r
+ Iterator watchers=elements.iterator();\r
+ while (watching && watchers.hasNext()) {\r
+ WatcherElement watch = (WatcherElement) watchers.next();\r
+ if (watch.doWatch()) {\r
+ wait=false;\r
+ log.debug("Event generated for watcher on "+watch.getWatcher().getSubject());\r
+ }\r
+ }\r
+ if (watching && wait) {\r
+ try {\r
+ Thread.sleep(WATCH_SLEEP);\r
+ }\r
+ catch (InterruptedException e) {};\r
+ }\r
+ }\r
+ log.debug("Finishing WatcherThread poll loop");\r
+ running=false;\r
+ }\r
+}\r
--- /dev/null
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+/**\r
+ * Interface for VamsasFileWatcherElement call back events generated by the VamsasFileWatcherThread.\r
+ */\r
+public interface WatcherCallBack {\r
+ /**\r
+ * \r
+ * @return true to enable watcher, or false to disable it in future WatcherThread cycles.\r
+ */\r
+ public boolean handleWatchEvent(WatcherElement watcher, Lock lock);\r
+}\r
--- /dev/null
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+\r
+\r
+public abstract class WatcherElement {\r
+\r
+ private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(VamsasFileWatcherElement.class);\r
+ protected FileWatcher watcher = null;\r
+ protected WatcherCallBack handler = null;\r
+ /**\r
+ * set this to false to stop the thread\r
+ */\r
+ private boolean watchForChange = true;\r
+ /**\r
+ * true when the handler is being called for this watcher\r
+ */\r
+ protected boolean handlerCalled = false;\r
+\r
+ public WatcherElement(WatcherCallBack handler) {\r
+ this.handler = handler;\r
+ }\r
+ /**\r
+ * will instruct watcher to stop and wait around for one WATCH_SLEEP\r
+ * before returning. If no thread is running then it returns immediately.\r
+ */\r
+ public void haltWatch() {\r
+ if (log.isDebugEnabled())\r
+ log.debug("haltWatch on "+watcher.getSubject());\r
+ // set the flag to skip this watch element.\r
+ watchForChange=false;\r
+ endWatch();\r
+ // watcher=null;\r
+ \r
+ }\r
+ /**\r
+ * called by haltWatch before \r
+ * clearing the FileWatcher reference.\r
+ *\r
+ */\r
+ protected abstract void endWatch();\r
+ /**\r
+ * called to generate the watcher object\r
+ * by enableWatch and in doWatch\r
+ *\r
+ */\r
+ protected abstract void initWatch();\r
+ /**\r
+ * implemented for debug information purposes.\r
+ * @return Informative string about what the watcher is watching\r
+ */\r
+ protected abstract String getSubject();\r
+ /**\r
+ * must be called by implementations of \r
+ * enablewatch\r
+ */\r
+ protected void enableWatch() {\r
+ watchForChange=true;\r
+ initWatch();\r
+ if (log.isDebugEnabled())\r
+ log.debug("enableWatch returning on "+getSubject());\r
+ }\r
+\r
+ /**\r
+ * Originally from the uk.ac.vamsas.test.simpleclient.ArchiveClient method\r
+ * @return true if the handler was called for a changeEvent\r
+ */\r
+ public boolean doWatch() {\r
+ if (!watchForChange || handler==null)\r
+ return false;\r
+ if (watcher==null)\r
+ initWatch(); // somehow not done the first time\r
+ handlerCalled=false;\r
+ Lock doclock=null;\r
+ try {\r
+ doclock=watcher.getChangedState();\r
+ } catch (Exception e) {\r
+ log.error("Whilst watching "+watcher.getSubject(), e);\r
+ }\r
+ if (doclock==null)\r
+ return false;\r
+ handlerCalled=true;\r
+ if (log.isDebugEnabled())\r
+ log.debug("Triggering watchEvent for change on "+watcher.getSubject());\r
+ boolean finish=!handler.handleWatchEvent(this, doclock);\r
+ doclock=null; // TODO: check that lock should really be released rather than dereferenced\r
+ if (finish)\r
+ haltWatch();\r
+ else\r
+ enableWatch();\r
+ handlerCalled=false;\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * @return the handler\r
+ */\r
+ public WatcherCallBack getHandler() {\r
+ return handler;\r
+ }\r
+ /**\r
+ * @return the handlerCalled\r
+ */\r
+ public boolean isHandlerCalled() {\r
+ return handlerCalled;\r
+ }\r
+ /**\r
+ * \r
+ * @return true if watcher is enabled\r
+ */\r
+ public boolean isWatchEnabled() {\r
+ return watchForChange;\r
+ }\r
+ /**\r
+ * @param handler the handler to set\r
+ */\r
+ public void setHandler(WatcherCallBack handler) {\r
+ this.handler = handler;\r
+ }\r
+ /**\r
+ * @return the watcher\r
+ */\r
+ public FileWatcher getWatcher() {\r
+ return watcher;\r
+ }\r
+}\r