-package uk.ac.vamsas.client.simpleclient;
-
-import java.beans.PropertyChangeListener;
-import java.beans.PropertyChangeSupport;
-import java.util.Hashtable;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import uk.ac.vamsas.client.Events;
-
-/**
- * monitors watcher objects and generates events.
- */
-public class EventGeneratorThread {
- private static Log log = LogFactory.getLog(EventGeneratorThread.class);
- private SimpleClient client;
- private Hashtable handlers; // manager object
- private VamsasSession session;
- /**
- * thread watching all the session's file objects
- */
- protected VamsasFileWatcherThread watchThread=null;
- /**
- * Watcher element for list of all the clientHandles for the session
- */
- protected SessionFileWatcherElement clientfile=null;
- /**
- * the session's vamsasDocument
- */
- protected VamsasFileWatcherElement vamsasfile=null;
- /**
- * written to by client when its app calls storeDocument.
- */
- protected SessionFileWatcherElement storeFile=null;
-
- EventGeneratorThread(VamsasSession s, SimpleClient _client, Hashtable eventhandlers) {
- if (eventhandlers==null || s==null || _client==null)
- throw new Error("Null arguments to EventGeneratorThread constructor.");
- handlers = eventhandlers;
- session = s;
- client = _client;
- log.debug("Creating VamsasFileWatcherThread.");
- watchThread = new VamsasFileWatcherThread(this);
- initWatchers();
- }
-
- private void initWatchers() {
- if (clientfile==null) {
- log.debug("Initializing clientfile Watcher");
- clientfile = session.getClientWatcherElement();
- // handler is set in the Vamsas session
-/* clientfile.setHandler(new WatcherCallBack() {
-
- public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {
- return clientListChanged(watcher, lock);
- }
- });*/
- watchThread.addElement(clientfile);
- }
- final EventGeneratorThread evgen=this;
-
- if (vamsasfile ==null) {
- log.debug("Initializing VamsasFileWatcher");
- vamsasfile = new VamsasFileWatcherElement(session.vamArchive,
- new WatcherCallBack() {
- public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {
- return evgen.documentChanged(lock);
- }
- });
- watchThread.addElement(vamsasfile);
- }
- if (storeFile == null) {
- storeFile = new SessionFileWatcherElement(session.getStoreDocFile(),
- new WatcherCallBack() {
- public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {
- return evgen.storeDocRequest(lock);
- }
- });
- log.debug("Initializing storeDocFile flag watcher");
- }
- /*
- */
- log.debug("Watchers inited.");
- }
- /**
- * Call registered handlers for a vamsas session event
- * @param handlerEvent a named event
- * @param property property name to pass to handler
- * @param oldval old value of property to pass
- * @param newval new value of property to pass
- * @return true if event generation did not raise any exceptions.
- */
- boolean _raise(String handlerEvent, String property, Object oldval, Object newval) {
- PropertyChangeSupport h = (PropertyChangeSupport) handlers.get(handlerEvent);
- if (h!=null) {
- log.debug("Triggering:"+handlerEvent);
- try {
- h.firePropertyChange(property, oldval, newval);
- } catch (Exception e) {
- log.warn("Client Exception during handling of "+handlerEvent, e);
- return false;
- }
- catch (Error e)
- {
- log.error("Serious! Client Error during handling of "+handlerEvent, e);
- return false;
- }
- log.debug("Finished :"+handlerEvent);
- } else
- log.debug("No handlers for raised "+handlerEvent);
- return true;
- }
- protected boolean storeDocRequest(Lock lock) {
- if (log.isDebugEnabled())
- log.debug("StoreDocRequest on "+(lock==null ? (lock.isLocked() ? "" : "Invalid ") : "Non-")+"Existing lock");
- // TODO: define the storeFile semaphore mechanism : file exists - all clients inform their apps, and then the client that wrote the file should delete the file (it should hold the lock to it).
- if (storeFile.getWatcher().exists) {
- _raise(Events.DOCUMENT_FINALIZEAPPDATA, client.getSessionUrn(), null, client);
- // expect client to write to document so update watcher state on return
- vamsasfile.getWatcher().setState();
- lock.release();
- }
- return true;
- }
-
- protected boolean documentChanged(Lock doclock) {
- boolean continueWatching=true;
- if (!block_document_updates) {
- session.vamArchive.fileLock=doclock;
- if (client.pickmanager!=null)
- client.pickmanager.setPassThru(false);
- if (log.isDebugEnabled()) {
- log.debug("Initiating a documentChanged event. Document is "+(client.cdocument==null ? "closed" : "open"));
- }
- // TODO: decide if individual object update handlers are called as well as overall event handler
- if (!_raise(Events.DOCUMENT_UPDATE, client.getSessionUrn(), null, client))
- {
- log.info("Recovering from errors or exceptions generated by client application");
- if (client.cdocument!=null)
- {
- try {
- client.tidyAwaySessionDocumentState();
- }
- catch (Exception e)
- {
- log.warn("Exception generated by vamsas library - when tidying away session document:",e);
- }
- catch (Error e)
- {
- log.error("LIBRARY Implementation error - when tidying away session document:",e);
- }
- }
-
- }
- if (client.pickmanager!=null)
- client.pickmanager.setPassThru(true);
- if (log.isDebugEnabled()) {
- log.debug("Finished handling a documentChanged event. Document is "+(client.cdocument==null ? "closed" : "open"));
- }
- if (client.cdocument!=null)
- {
- log.warn("Implementation Error ? ClientDocument instance has not been closed or updated by handler!");
- }
- /*try {
- client._session.getVamsasDocument().closeArchive();
- } catch (Exception e) {log.warn("Unexpected exception when closing document after update.",e);};
- */
- } else {
- // TODO: check documentChanged */
- log.debug("Ignoring documentChanged event for "+client.getSessionUrn());
- }
- return continueWatching;
- }
- boolean ownsf = false;
- /**
- * Moved to SimpleClientSessionManager
- * scans all watchers and fires changeEvents if necessary
- * @return number of events generated.
- */
- private boolean clientListChanged(WatcherElement clientfile, Lock watchlock) {
- log.debug("ClientListChanged handler called for "+clientfile.getWatcher().getSubject());
- // could make this general - but for now keep simple
- if (watchlock!=null) {
- // TODO: compare new client list to old list version. is it changed ?
- // see what happened to the clientfile - compare our internal version with the one in the file, or just send the updated list out...?
- //
- /**
- * Generated when a new vamsas client is attached to a session (Handle is
- * passed) Note: the newly created client does not receive the event.
- *
- public static final String CLIENT_CREATION = "uk.ac.vamsas.client.events.clientCreateEvent";
- */ // as the test
- /**
- * Generated when a vamsas client leaves a session (Handle is passed to all
- * others).
- public static final String CLIENT_FINALIZATION = "uk.ac.vamsas.client.events.clientFinalizationEvent";
- */ // again - as the test.
- watchlock.release();
- }
- return true;
- }
- /**
- * Events raised by IClient and propagated to others in session
- */
-
- /**
- * number of milliseconds between any file state check.
- */
- long POLL_UNIT = 20;
- protected void wait(int u) {
- if (u<=0)
- u=1;
- long l = System.currentTimeMillis()+POLL_UNIT*u;
- while (System.currentTimeMillis()<l)
- ;
- }
-
-
- private boolean block_document_updates=false;
- int STORE_WAIT=5; // how many units before we decide all clients have finalized their appdatas
- private boolean in_want_to_store_phase=false;
- /**
- * client App requests offline storage of vamsas data.
- * Call blocks whilst other apps do any appData finalizing
- * and then returns (after locking the vamsasDocument in the session)
- * Note - the calling app may also receive events through the EventGeneratorThread for document updates.
- *
- * @return Lock for session.vamArchive
- * @param STORE_WAIT indicates how lock the call will block for when nothing appears to be happening to the session.
- */
- protected Lock want_to_store() {
- if (in_want_to_store_phase) {
- log.error("client error: want_to_store called again before first call has completed.");
- return null;
- }
- in_want_to_store_phase=true;
- // TODO: test the storeDocumentRequest mechanism
- /*/ watchThread.haltWatchers();
- */
- log.debug("Stopping document_update watcher");
- vamsasfile.haltWatch();
- // block_document_updates=true;
- log.debug("Cleared flag for ignoring document_update requests");
-
- log.debug("Sending Store Document Request");
- try {
- session.addStoreDocumentRequest(client.getClientHandle(), client.getUserHandle());
- } catch (Exception e) {
- log.warn("Whilst writing StoreDocumentRequest for "+client.getClientHandle().getClientUrn()+" "+client.getUserHandle(),
- e);
- log.info("trying to continue after storeDocumentRequest exception.");
- }
- log.debug("Waiting for other apps to do FinalizeApp handling.");
- // LATER: refine this semaphore process
- // to make a robust signalling mechanism:
- // app1 requests, app1..n do something (or don't - they may be dead),
- // app1 realises all apps have done their thing, it then continues with synchronized data.
- // this probably needs two files - a request file,
- // and a response file which is acknowledged by the app1 requestor for each app.
- // eventually, no more responses are received for the request, and the app can then only continue with its store.
- FileWatcher sfwatcher=session.getStoreWatcher();
- FileWatcher vfwatcher=session.getDocWatcher();
- int units = 0; // zero if updates occured over a sleep period
- while (units<STORE_WAIT) {
- try {
- Thread.sleep(watchThread.WATCH_SLEEP);
- } catch (InterruptedException e) {
- log.debug("interrupted.");
- }
- if (sfwatcher.hasChanged() || vfwatcher.hasChanged()) {
- units=0;
- } else {
- units++;
- }
- }
-
- block_document_updates=false;
- vamsasfile.enableWatch();
- log.debug("Cleared flag for ignoring document_update requests");
- // wait around again (until our own watcher has woken up and synchronized).
- while (units<STORE_WAIT) {
- try {
- Thread.sleep(watchThread.WATCH_SLEEP);
- } catch (InterruptedException e) {
- log.debug("interrupted.");
- }
- if (sfwatcher.hasChanged() || vfwatcher.hasChanged())
- units=0;
- else
- units++;
- }
-
-
- log.debug("finished waiting.");
- in_want_to_store_phase=false;
- return session.vamArchive.getLock();
- }
- /**
- * count handlers for a particular vamsas event
- * @param event string enumeration from uk.ac.vamsas.client.Events
- * @return -1 for an invalid event, otherwise the number of handlers
- */
- protected int countHandlersFor(String event) {
- if (handlers.containsKey(event)) {
- PropertyChangeSupport handler = (PropertyChangeSupport) handlers.get(event);
- PropertyChangeListener[] listeners;
- if (handler!=null)
- return ((listeners=handler.getPropertyChangeListeners())==null)
- ? -1 : listeners.length;
- }
- return -1;
- }
-
- public void disableDocumentWatch() {
- vamsasfile.haltWatch();
- }
-
- public boolean isDocumentWatchEnabled() {
- return (vamsasfile!=null) && vamsasfile.isWatchEnabled();
- }
-
- public void enableDocumentWatch() {
- vamsasfile.enableWatch();
- }
-
- public boolean isWatcherAlive() {
- return watchThread!=null && watchThread.running && watchThread.isAlive();
- }
-
- public void interruptWatching() {
- if (watchThread!=null && watchThread.isAlive())
- {
- // TODO: find a way of interrupting watcher in a way that prevents file IO being interrupted
- watchThread.interrupt();
- }
-
- }
- /**
- * called to start the session watching thread which generates events
- */
- public void startWatching() {
- enableDocumentWatch();
- watchThread.start();
- while (!watchThread.running && watchThread.isAlive())
- log.debug("Waiting until watcher is really started.");
- }
-
- public void stopWatching() {
- interruptWatching();
- watchThread.haltWatchers();
-
- }
-
-
-}
+/*\r
+ * This file is part of the Vamsas Client version 0.1. \r
+ * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
+ * Andrew Waterhouse and Dominik Lindner.\r
+ * \r
+ * Earlier versions have also been incorporated into Jalview version 2.4 \r
+ * since 2008, and TOPALi version 2 since 2007.\r
+ * \r
+ * The Vamsas Client is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * The Vamsas Client is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with the Vamsas Client. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package uk.ac.vamsas.client.simpleclient;\r
+\r
+import java.beans.PropertyChangeListener;\r
+import java.beans.PropertyChangeSupport;\r
+import java.util.Hashtable;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+\r
+import uk.ac.vamsas.client.Events;\r
+\r
+/**\r
+ * monitors watcher objects and generates events.\r
+ */\r
+public class EventGeneratorThread {\r
+ private static Log log = LogFactory.getLog(EventGeneratorThread.class);\r
+\r
+ private SimpleClient client;\r
+\r
+ private Hashtable handlers; // manager object\r
+\r
+ private VamsasSession session;\r
+\r
+ /**\r
+ * thread watching all the session's file objects\r
+ */\r
+ protected VamsasFileWatcherThread watchThread = null;\r
+\r
+ /**\r
+ * Watcher element for list of all the clientHandles for the session\r
+ */\r
+ protected SessionFileWatcherElement clientfile = null;\r
+\r
+ /**\r
+ * the session's vamsasDocument\r
+ */\r
+ protected VamsasFileWatcherElement vamsasfile = null;\r
+\r
+ /**\r
+ * written to by client when its app calls storeDocument.\r
+ */\r
+ protected SessionFileWatcherElement storeFile = null;\r
+\r
+ EventGeneratorThread(VamsasSession s, SimpleClient _client,\r
+ Hashtable eventhandlers) {\r
+ if (eventhandlers == null || s == null || _client == null)\r
+ throw new Error("Null arguments to EventGeneratorThread constructor.");\r
+ handlers = eventhandlers;\r
+ session = s;\r
+ client = _client;\r
+ log.debug("Creating VamsasFileWatcherThread.");\r
+ watchThread = new VamsasFileWatcherThread(this);\r
+ initWatchers();\r
+ }\r
+\r
+ private void initWatchers() {\r
+ if (clientfile == null) {\r
+ log.debug("Initializing clientfile Watcher");\r
+ clientfile = session.getClientWatcherElement();\r
+ // handler is set in the Vamsas session\r
+ /*\r
+ * clientfile.setHandler(new WatcherCallBack() {\r
+ * \r
+ * public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {\r
+ * return clientListChanged(watcher, lock); } });\r
+ */\r
+ watchThread.addElement(clientfile);\r
+ }\r
+ final EventGeneratorThread evgen = this;\r
+\r
+ if (vamsasfile == null) {\r
+ log.debug("Initializing VamsasFileWatcher");\r
+ vamsasfile = new VamsasFileWatcherElement(session.vamArchive,\r
+ new WatcherCallBack() {\r
+ public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {\r
+ return evgen.documentChanged(lock);\r
+ }\r
+ });\r
+ watchThread.addElement(vamsasfile);\r
+ }\r
+ if (storeFile == null) {\r
+ storeFile = new SessionFileWatcherElement(session.getStoreDocFile(),\r
+ new WatcherCallBack() {\r
+ public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {\r
+ return evgen.storeDocRequest(lock);\r
+ }\r
+ });\r
+ log.debug("Initializing storeDocFile flag watcher");\r
+ }\r
+ /*\r
+ */\r
+ log.debug("Watchers inited.");\r
+ }\r
+\r
+ /**\r
+ * Call registered handlers for a vamsas session event\r
+ * \r
+ * @param handlerEvent\r
+ * a named event\r
+ * @param property\r
+ * property name to pass to handler\r
+ * @param oldval\r
+ * old value of property to pass\r
+ * @param newval\r
+ * new value of property to pass\r
+ * @return true if event generation did not raise any exceptions.\r
+ */\r
+ boolean _raise(String handlerEvent, String property, Object oldval,\r
+ Object newval) {\r
+ PropertyChangeSupport h = (PropertyChangeSupport) handlers\r
+ .get(handlerEvent);\r
+ if (h != null) {\r
+ log.debug("Triggering:" + handlerEvent);\r
+ try {\r
+ h.firePropertyChange(property, oldval, newval);\r
+ } catch (Exception e) {\r
+ log.warn("Client Exception during handling of " + handlerEvent, e);\r
+ return false;\r
+ } catch (Error e) {\r
+ log\r
+ .error("Serious! Client Error during handling of " + handlerEvent,\r
+ e);\r
+ return false;\r
+ }\r
+ log.debug("Finished :" + handlerEvent);\r
+ } else\r
+ log.debug("No handlers for raised " + handlerEvent);\r
+ return true;\r
+ }\r
+\r
+ protected boolean storeDocRequest(Lock lock) {\r
+ if (log.isDebugEnabled())\r
+ log.debug("StoreDocRequest on "\r
+ + (lock == null ? (lock.isLocked() ? "" : "Invalid ") : "Non-")\r
+ + "Existing lock");\r
+ // TODO: define the storeFile semaphore mechanism : file exists - all\r
+ // clients inform their apps, and then the client that wrote the file should\r
+ // delete the file (it should hold the lock to it).\r
+ if (storeFile.getWatcher().exists) {\r
+ _raise(Events.DOCUMENT_FINALIZEAPPDATA, client.getSessionUrn(), null,\r
+ client);\r
+ // expect client to write to document so update watcher state on return\r
+ vamsasfile.getWatcher().setState();\r
+ lock.release();\r
+ }\r
+ return true;\r
+ }\r
+\r
+ protected boolean documentChanged(Lock doclock) {\r
+ boolean continueWatching = true;\r
+ if (!block_document_updates) {\r
+ session.vamArchive.fileLock = doclock;\r
+ if (client.pickmanager != null)\r
+ client.pickmanager.setPassThru(false);\r
+ if (log.isDebugEnabled()) {\r
+ log.debug("Initiating a documentChanged event. Document is "\r
+ + (client.cdocument == null ? "closed" : "open"));\r
+ }\r
+ // TODO: decide if individual object update handlers are called as well as\r
+ // overall event handler\r
+ if (!_raise(Events.DOCUMENT_UPDATE, client.getSessionUrn(), null, client)) {\r
+ log\r
+ .info("Recovering from errors or exceptions generated by client application");\r
+ if (client.cdocument != null) {\r
+ try {\r
+ client.tidyAwaySessionDocumentState();\r
+ } catch (Exception e) {\r
+ log\r
+ .warn(\r
+ "Exception generated by vamsas library - when tidying away session document:",\r
+ e);\r
+ } catch (Error e) {\r
+ log\r
+ .error(\r
+ "LIBRARY Implementation error - when tidying away session document:",\r
+ e);\r
+ }\r
+ }\r
+\r
+ }\r
+ if (client.pickmanager != null)\r
+ client.pickmanager.setPassThru(true);\r
+ if (log.isDebugEnabled()) {\r
+ log.debug("Finished handling a documentChanged event. Document is "\r
+ + (client.cdocument == null ? "closed" : "open"));\r
+ }\r
+ if (client.cdocument != null) {\r
+ log\r
+ .warn("Implementation Error ? ClientDocument instance has not been closed or updated by handler!");\r
+ }\r
+ /*\r
+ * try { client._session.getVamsasDocument().closeArchive(); } catch\r
+ * (Exception e)\r
+ * {log.warn("Unexpected exception when closing document after update."\r
+ * ,e);};\r
+ */\r
+ } else {\r
+ // TODO: check documentChanged */\r
+ log.debug("Ignoring documentChanged event for " + client.getSessionUrn());\r
+ }\r
+ return continueWatching;\r
+ }\r
+\r
+ boolean ownsf = false;\r
+\r
+ /**\r
+ * Moved to SimpleClientSessionManager scans all watchers and fires\r
+ * changeEvents if necessary\r
+ * \r
+ * @return number of events generated.\r
+ */\r
+ private boolean clientListChanged(WatcherElement clientfile, Lock watchlock) {\r
+ log.debug("ClientListChanged handler called for "\r
+ + clientfile.getWatcher().getSubject());\r
+ // could make this general - but for now keep simple\r
+ if (watchlock != null) {\r
+ // TODO: compare new client list to old list version. is it changed ?\r
+ // see what happened to the clientfile - compare our internal version with\r
+ // the one in the file, or just send the updated list out...?\r
+ //\r
+ /**\r
+ * Generated when a new vamsas client is attached to a session (Handle is\r
+ * passed) Note: the newly created client does not receive the event.\r
+ * \r
+ * public static final String CLIENT_CREATION =\r
+ * "uk.ac.vamsas.client.events.clientCreateEvent";\r
+ */\r
+ // as the test\r
+ /**\r
+ * Generated when a vamsas client leaves a session (Handle is passed to\r
+ * all others). public static final String CLIENT_FINALIZATION =\r
+ * "uk.ac.vamsas.client.events.clientFinalizationEvent";\r
+ */\r
+ // again - as the test.\r
+ watchlock.release();\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Events raised by IClient and propagated to others in session\r
+ */\r
+\r
+ /**\r
+ * number of milliseconds between any file state check.\r
+ */\r
+ long POLL_UNIT = 20;\r
+\r
+ protected void wait(int u) {\r
+ if (u <= 0)\r
+ u = 1;\r
+ long l = System.currentTimeMillis() + POLL_UNIT * u;\r
+ while (System.currentTimeMillis() < l)\r
+ ;\r
+ }\r
+\r
+ private boolean block_document_updates = false;\r
+\r
+ int STORE_WAIT = 5; // how many units before we decide all clients have\r
+ // finalized their appdatas\r
+\r
+ private boolean in_want_to_store_phase = false;\r
+\r
+ /**\r
+ * client App requests offline storage of vamsas data. Call blocks whilst\r
+ * other apps do any appData finalizing and then returns (after locking the\r
+ * vamsasDocument in the session) Note - the calling app may also receive\r
+ * events through the EventGeneratorThread for document updates.\r
+ * \r
+ * @return Lock for session.vamArchive\r
+ * @param STORE_WAIT\r
+ * indicates how lock the call will block for when nothing appears to\r
+ * be happening to the session.\r
+ */\r
+ protected Lock want_to_store() {\r
+ if (in_want_to_store_phase) {\r
+ log\r
+ .error("client error: want_to_store called again before first call has completed.");\r
+ return null;\r
+ }\r
+ in_want_to_store_phase = true;\r
+ // TODO: test the storeDocumentRequest mechanism\r
+ /*\r
+ * / watchThread.haltWatchers();\r
+ */\r
+ log.debug("Stopping document_update watcher");\r
+ vamsasfile.haltWatch();\r
+ // block_document_updates=true;\r
+ log.debug("Cleared flag for ignoring document_update requests");\r
+\r
+ log.debug("Sending Store Document Request");\r
+ try {\r
+ session.addStoreDocumentRequest(client.getClientHandle(), client\r
+ .getUserHandle());\r
+ } catch (Exception e) {\r
+ log.warn("Whilst writing StoreDocumentRequest for "\r
+ + client.getClientHandle().getClientUrn() + " "\r
+ + client.getUserHandle(), e);\r
+ log.info("trying to continue after storeDocumentRequest exception.");\r
+ }\r
+ log.debug("Waiting for other apps to do FinalizeApp handling.");\r
+ // LATER: refine this semaphore process\r
+ // to make a robust signalling mechanism:\r
+ // app1 requests, app1..n do something (or don't - they may be dead),\r
+ // app1 realises all apps have done their thing, it then continues with\r
+ // synchronized data.\r
+ // this probably needs two files - a request file,\r
+ // and a response file which is acknowledged by the app1 requestor for each\r
+ // app.\r
+ // eventually, no more responses are received for the request, and the app\r
+ // can then only continue with its store.\r
+ FileWatcher sfwatcher = session.getStoreWatcher();\r
+ FileWatcher vfwatcher = session.getDocWatcher();\r
+ int units = 0; // zero if updates occured over a sleep period\r
+ while (units < STORE_WAIT) {\r
+ try {\r
+ Thread.sleep(watchThread.WATCH_SLEEP);\r
+ } catch (InterruptedException e) {\r
+ log.debug("interrupted.");\r
+ }\r
+ if (sfwatcher.hasChanged() || vfwatcher.hasChanged()) {\r
+ units = 0;\r
+ } else {\r
+ units++;\r
+ }\r
+ }\r
+\r
+ block_document_updates = false;\r
+ vamsasfile.enableWatch();\r
+ log.debug("Cleared flag for ignoring document_update requests");\r
+ // wait around again (until our own watcher has woken up and synchronized).\r
+ while (units < STORE_WAIT) {\r
+ try {\r
+ Thread.sleep(watchThread.WATCH_SLEEP);\r
+ } catch (InterruptedException e) {\r
+ log.debug("interrupted.");\r
+ }\r
+ if (sfwatcher.hasChanged() || vfwatcher.hasChanged())\r
+ units = 0;\r
+ else\r
+ units++;\r
+ }\r
+\r
+ log.debug("finished waiting.");\r
+ in_want_to_store_phase = false;\r
+ return session.vamArchive.getLock();\r
+ }\r
+\r
+ /**\r
+ * count handlers for a particular vamsas event\r
+ * \r
+ * @param event\r
+ * string enumeration from uk.ac.vamsas.client.Events\r
+ * @return -1 for an invalid event, otherwise the number of handlers\r
+ */\r
+ protected int countHandlersFor(String event) {\r
+ if (handlers.containsKey(event)) {\r
+ PropertyChangeSupport handler = (PropertyChangeSupport) handlers\r
+ .get(event);\r
+ PropertyChangeListener[] listeners;\r
+ if (handler != null)\r
+ return ((listeners = handler.getPropertyChangeListeners()) == null) ? -1\r
+ : listeners.length;\r
+ }\r
+ return -1;\r
+ }\r
+\r
+ public void disableDocumentWatch() {\r
+ vamsasfile.haltWatch();\r
+ }\r
+\r
+ public boolean isDocumentWatchEnabled() {\r
+ return (vamsasfile != null) && vamsasfile.isWatchEnabled();\r
+ }\r
+\r
+ public void enableDocumentWatch() {\r
+ vamsasfile.enableWatch();\r
+ }\r
+\r
+ public boolean isWatcherAlive() {\r
+ return watchThread != null && watchThread.running && watchThread.isAlive();\r
+ }\r
+\r
+ public void interruptWatching() {\r
+ if (watchThread != null && watchThread.isAlive()) {\r
+ // TODO: find a way of interrupting watcher in a way that prevents file IO\r
+ // being interrupted\r
+ watchThread.interrupt();\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * called to start the session watching thread which generates events\r
+ */\r
+ public void startWatching() {\r
+ enableDocumentWatch();\r
+ watchThread.start();\r
+ while (!watchThread.running && watchThread.isAlive())\r
+ log.debug("Waiting until watcher is really started.");\r
+ }\r
+\r
+ public void stopWatching() {\r
+ interruptWatching();\r
+ watchThread.haltWatchers();\r
+\r
+ }\r
+\r
+}\r