1 package uk.ac.vamsas.client.simpleclient;
3 import java.beans.PropertyChangeEvent;
4 import java.beans.PropertyChangeListener;
5 import java.beans.PropertyChangeSupport;
6 import java.util.Hashtable;
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
11 import uk.ac.vamsas.client.Events;
14 * monitors watcher objects and generates events.
16 public class EventGeneratorThread extends Thread implements Runnable {
17 private static Log log = LogFactory.getLog(EventGeneratorThread.class);
18 private SimpleClient client;
19 private Hashtable handlers; // manager object
20 private VamsasSession session;
23 * list with all the clientHandles for the session
25 protected FileWatcher clientfile=null;
27 * the session's vamsasDocument
29 protected FileWatcher vamsasfile=null;
31 * written to by client when its app calls storeDocument.
33 protected FileWatcher storeFile=null;
35 private boolean watch=false;
38 EventGeneratorThread(VamsasSession s, SimpleClient _client, Hashtable eventhandlers) {
39 if (eventhandlers==null || s==null || _client==null)
40 throw new Error("Null arguments to EventGeneratorThread constructor.");
41 handlers = eventhandlers;
44 setName(s.sessionDir.getName());
48 private void initWatchers() {
50 clientfile = session.getClientWatcher();
51 if (vamsasfile ==null)
52 vamsasfile = session.getDocWatcher();
53 if (storeFile == null)
54 storeFile = session.getStoreWatcher();
55 clientfile.setState();
56 vamsasfile.setState();
59 boolean ownsf = false;
61 * scans all watchers and fires changeEvents if necessary
62 * @return number of events generated.
64 private int checkforEvents() {
66 //TODO : leave slog.info messages for the events that occur.
68 // could make this general - but for now keep simple
69 if ((watchlock=storeFile.getChangedState())!=null) {
70 // 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).
71 if (storeFile.exists) {
72 PropertyChangeSupport h = (PropertyChangeSupport) handlers.get(Events.DOCUMENT_FINALIZEAPPDATA);
74 log.debug("Triggering DOCUMENT_FINALIZEAPPDATA");
76 h.firePropertyChange(client.getSessionUrn(), null, client);
78 vamsasfile.setState();
82 if ((watchlock=clientfile.getChangedState())!=null) {
83 // see what happened to the clientfile - compare our internal version with the one in the file, or just send the updated list out...?
86 * Generated when a new vamsas client is attached to a session (Handle is
87 * passed) Note: the newly created client does not receive the event.
89 public static final String CLIENT_CREATION = "uk.ac.vamsas.client.events.clientCreateEvent";
92 * Generated when a vamsas client leaves a session (Handle is passed to all
94 public static final String CLIENT_FINALIZATION = "uk.ac.vamsas.client.events.clientFinalizationEvent";
95 */ // again - as the test.
98 if ((watchlock=vamsasfile.getChangedState())!=null) {
101 * Generated when a client has finished updating the document. Passes
102 * applicationHandle of client so the updating client can recognise its own
104 public static final String DOCUMENT_UPDATE = "uk.ac.vamsas.client.events.documentUpdateEvent";
106 // read apphandle from 'lastUpdate' session file.
107 // pass apphandle name to appHandler ?
111 * Generated when a new vamsas document is created (perhaps from some existing
112 * Vamsas data) so an application may do its own data space initialization.
113 * TODO: decide if this is called when an app is connected to a stored
115 public static final String DOCUMENT_CREATE = "uk.ac.vamsas.client.events.documentCreateEvent";
117 // check if this session's appInit flag is set - if not - generate event for this app.
118 // prolly don't need this at the moment - when an app does getDocument it can to the initing then.
122 * Generated prior to session Shutdown, after the last participating vamsas
123 * client has finalized.
124 * TODO: decide on purpose of this ? is this for benefit of multi-session Apps only ?
125 public static final String SESSION_SHUTDOWN = "uk.ac.vamsas.client.events.SessionShutdownEvent";
129 * Generated for all clients when any client calls IClient.storeDocument() to
130 * allow them to store any updates before an offline copy of the session is
131 * created. Any client that handles this should call the
132 * IClient.getDocument(), update and then IClient.updateDocument in the same
134 * EventName: <Vamsas-session URN>
135 * NewValue: uk.ac.vamsas.client.IClient for session.
137 public static final String DOCUMENT_FINALIZEAPPDATA = "uk.ac.vamsas.client.events.DocumentFinalizeAppData";
139 // watch for finalization semaphore (last finalised sessionFile).
142 * Generated by Vorba stub after the penultimate client makes a call to
143 * closeDocument(). Sequence is as follows : 1. All other vamsas clients have
144 * called closeDocument() 2. Final living client monitors closures, and
145 * realises that it is last. 3. Final client generates event to prompt
146 * associated application to inquire if the user wishes to save the document
147 * for future reference.
148 * * Any call to closeDocument in a thread other than the registered
149 * EventListener will block until the RequestToClose handler has exited.
152 // public static final String DOCUMENT_REQUESTTOCLOSE = "org.vamas.client.DocumentRequestToCloseEvent";
157 private void initEvents() {
161 * Events raised by IClient and propagated to others in session
165 * number of milliseconds between any file state check.
168 protected void wait(int u) {
171 long l = System.currentTimeMillis()+POLL_UNIT*u;
172 while (System.currentTimeMillis()<l)
177 private boolean block_document_updates=false;
178 int STORE_WAIT=5; // how many units before we decide all clients have finalized their appdatas
181 * client App requests offline storage of vamsas data.
182 * Call blocks whilst other apps do any appData finalizing
183 * and then returns (after locking the vamsasDocument in the session)
184 * Note - the calling app may also receive events through the EventGeneratorThread for document updates.
186 * @return Lock for session.vamArchive
187 * @param STORE_WAIT indicates how lock the call will block for when nothing appears to be happening to the session.
189 protected Lock want_to_store() {
190 log.debug("Setting flag for document_update requests to be ignored");
191 block_document_updates=true;
192 log.debug("Waiting for other apps to do FinalizeApp handling.");
194 session.addStoreDocumentRequest(client.getClientHandle(), client.getUserHandle());
195 } catch (Exception e) {
196 log.warn("Whilst writing StoreDocumentRequest for "+client.getClientHandle().getClientUrn()+" "+client.getUserHandle(),
198 log.info("trying to continue.");
200 // LATER: refine this semaphore process
201 // to make a robust signalling mechanism:
202 // app1 requests, app1..n do something (or don't - they may be dead),
203 // app1 realises all apps have done their thing, it then continues with synchronized data.
204 // this probably needs two files - a request file,
205 // and a response file which is acknowledged by the app1 requestor for each app.
206 // eventually, no more responses are received for the request, and the app can then only continue with its store.
208 while (units<STORE_WAIT) {
210 if (storeFile.hasChanged() || vamsasfile.hasChanged())
216 block_document_updates=false;
217 log.debug("Cleared flag for ignoring document_update requests");
218 // wait around again (until our own watcher has woken up and synchronized).
219 while (units<STORE_WAIT) {
221 if (storeFile.hasChanged() || vamsasfile.hasChanged())
228 log.debug("finished waiting.");
229 return session.vamArchive.getLock();
232 * count handlers for a particular vamsas event
233 * @param event string enumeration from uk.ac.vamsas.client.Events
234 * @return -1 for an invalid event, otherwise the number of handlers
236 protected int countHandlersFor(String event) {
237 if (handlers.containsKey(event)) {
238 PropertyChangeSupport handler = (PropertyChangeSupport) handlers.get(event);
239 PropertyChangeListener[] listeners;
241 return ((listeners=handler.getPropertyChangeListeners())==null)
242 ? -1 : listeners.length;
247 * probably don't need any of these below.
250 * @see java.lang.Thread#destroy()
252 public void destroy() {
256 * @see java.lang.Thread#interrupt()
258 public void interrupt() {
259 // TODO Auto-generated method stub
263 * @see java.lang.Thread#isInterrupted()
265 public boolean isInterrupted() {
266 // TODO Auto-generated method stub
267 return super.isInterrupted();
270 * @see java.lang.Thread#run()
273 // TODO Auto-generated method stub