reprioritising TODOs and LATERs and fixing documentation typos.
[vamsas.git] / src / org / vamsas / client / simpleclient / EventGeneratorThread.java
1 package org.vamsas.client.simpleclient;
2
3 import java.beans.PropertyChangeEvent;
4 import java.beans.PropertyChangeSupport;
5 import java.util.Hashtable;
6
7 import org.apache.commons.logging.Log;
8 import org.apache.commons.logging.LogFactory;
9 import org.vamsas.client.Events;
10
11 /**
12  * monitors watcher objects and generates events.
13  */
14 public class EventGeneratorThread extends Thread implements Runnable {
15   private static Log log = LogFactory.getLog(EventGeneratorThread.class);
16   private SimpleClient client;
17   private Hashtable handlers; // manager object
18   private VamsasSession session;
19
20   /** 
21    * list with all the clientHandles for the session
22    */
23   protected FileWatcher clientfile=null;
24   /**
25    * the session's vamsasDocument
26    */
27   protected FileWatcher vamsasfile=null;
28   /**
29    * written to by client when its app calls storeDocument.
30    */
31   protected FileWatcher storeFile=null;
32   
33   private boolean watch=false;
34   
35   
36   EventGeneratorThread(VamsasSession s, SimpleClient _client, Hashtable eventhandlers) {
37     if (eventhandlers==null || s==null || _client==null)
38       throw new Error("Null arguments to EventGeneratorThread constructor.");
39     handlers = eventhandlers;
40     session = s;
41     client = _client;
42     setName(s.sessionDir.getName());
43     initWatchers();
44   }
45   
46   private void initWatchers() {
47     if (clientfile==null)
48       clientfile = session.getClientWatcher();
49     if (vamsasfile ==null)
50       vamsasfile = session.getDocWatcher();
51     if (storeFile == null)
52       storeFile = session.getStoreWatcher();
53     clientfile.setState();
54     vamsasfile.setState();
55     storeFile.setState();
56   }
57   boolean ownsf = false;
58   /**
59    * scans all watchers and fires changeEvents if necessary
60    * @return number of events generated.
61    */
62   private int checkforEvents() {
63     Lock watchlock;
64     //TODO : leave slog.info messages for the events that occur.
65     int raised=0;
66     // could make this general - but for now keep simple
67     if ((watchlock=storeFile.getChangedState())!=null) {
68       // 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).
69       if (storeFile.exists) { 
70         PropertyChangeSupport h = (PropertyChangeSupport) handlers.get(Events.DOCUMENT_FINALIZEAPPDATA);
71         if (h!=null) {
72           log.debug("Triggering DOCUMENT_FINALIZEAPPDATA");
73           raised++;
74           h.firePropertyChange(client.getSessionUrn(), null, client);
75           // expect client to 
76           vamsasfile.setState();
77         }
78       }
79     }
80     if ((watchlock=clientfile.getChangedState())!=null) {
81       // see what happened to the clientfile - compare our internal version with the one in the file, or just send the updated list out...?
82       //
83       /**
84        * Generated when a new vamsas client is attached to a session (Handle is
85        * passed) Note: the newly created client does not receive the event.
86        *
87       public static final String CLIENT_CREATION = "org.vamsas.client.events.clientCreateEvent";
88   */ // as the test
89       /**
90        * Generated when a vamsas client leaves a session (Handle is passed to all
91        * others).
92       public static final String CLIENT_FINALIZATION = "org.vamsas.client.events.clientFinalizationEvent";
93        */ // again - as the test.
94           raised++;
95     }
96     if ((watchlock=vamsasfile.getChangedState())!=null) {
97       
98       /**
99        * Generated when a client has finished updating the document. Passes
100        * applicationHandle of client so the updating client can recognise its own
101        * updates.
102       public static final String DOCUMENT_UPDATE = "org.vamsas.client.events.documentUpdateEvent";
103        */
104       // read apphandle from 'lastUpdate' session file.
105       // pass apphandle name to appHandler ?
106       
107     }
108     /**
109      * Generated when a new vamsas document is created (perhaps from some existing
110      * Vamsas data) so an application may do its own data space initialization.
111      * TODO: decide if this is called when an app is connected to a stored
112      * session...
113      public static final String DOCUMENT_CREATE = "org.vamsas.client.events.documentCreateEvent";
114     */
115     // check if this session's appInit flag is set - if not - generate event for this app.
116     // prolly don't need this at the moment - when an app does getDocument it can to the initing then.
117     
118
119     /**
120      * Generated prior to session Shutdown, after the last participating vamsas
121      * client has finalized.
122      *  TODO: decide on purpose of this ?  is this for benefit of multi-session Apps only ?
123     public static final String SESSION_SHUTDOWN = "org.vamsas.client.events.SessionShutdownEvent";
124      */
125
126     /**
127      * Generated for all clients when any client calls IClient.storeDocument() to
128      * allow them to store any updates before an offline copy of the session is
129      * created. Any client that handles this should call the
130      * IClient.getDocument(), update and then IClient.updateDocument in the same
131      * handler thread.
132      * EventName: <Vamsas-session URN>
133      * NewValue: org.vamsas.client.IClient for session.
134      *
135     public static final String DOCUMENT_FINALIZEAPPDATA = "org.vamsas.client.events.DocumentFinalizeAppData";
136 */
137     // watch for finalization semaphore (last finalised sessionFile).
138     
139     /**
140      * Generated by Vorba stub after the penultimate client makes a call to
141      * closeDocument(). Sequence is as follows : 1. All other vamsas clients have
142      * called closeDocument() 2. Final living client monitors closures, and
143      * realises that it is last. 3. Final client generates event to prompt
144      * associated application to inquire if the user wishes to save the document
145      * for future reference.
146      *  * Any call to closeDocument in a thread other than the registered
147      * EventListener will block until the RequestToClose handler has exited.
148      * 
149      */
150     //    public static final String DOCUMENT_REQUESTTOCLOSE = "org.vamas.client.DocumentRequestToCloseEvent";
151
152     return raised;
153   }
154   
155   private void initEvents() {
156     
157   }
158   /**
159    * Events raised by IClient and propagated to others in session
160    */
161   
162   /**
163    * number of milliseconds between any file state check.
164    */
165   long POLL_UNIT = 20;
166   protected void wait(int u) {
167     if (u<=0)
168       u=1;
169     long l = System.currentTimeMillis()+POLL_UNIT*u;
170       while (System.currentTimeMillis()<l)
171         ;
172   }
173     
174   
175   
176   int STORE_WAIT=5; // how many units before we decide all clients have finalized their appdatas
177   
178   /**
179    * client App requests offline storage of vamsas data. 
180    * Call blocks whilst other apps do any appData finalizing
181    * and then returns (after locking the vamsasDocument in the session)
182    * @return Lock for session.vamArchive 
183    * @param STORE_WAIT indicates how lock the call will block for when nothing appears to be happening to the session.
184    */
185   protected Lock want_to_store() {
186     log.debug("Waiting for other apps to do FinalizeApp handling.");
187     try {
188       session.addStoreDocumentRequest(client.getClientHandle(), client.getUserHandle());
189     } catch (Exception e) {
190       log.warn("Whilst writing StoreDocumentRequest for "+client.getClientHandle().getClientUrn()+" "+client.getUserHandle(),
191           e);
192       log.info("trying to continue.");
193     }
194     
195     int units = 0;
196     while (units<STORE_WAIT) {
197       wait(1);
198       if (storeFile.hasChanged() || vamsasfile.hasChanged())
199         units=0;
200       else
201         units++;
202     }  
203     log.debug("finished waiting.");
204     return session.vamArchive.getLock();
205   }
206   
207   /**
208    * probably don't need any of these below.
209    */
210   /* (non-Javadoc)
211    * @see java.lang.Thread#destroy()
212    */
213   public void destroy() {
214     super.destroy();
215   }
216   /* (non-Javadoc)
217    * @see java.lang.Thread#interrupt()
218    */
219   public void interrupt() {
220     // TODO Auto-generated method stub
221     super.interrupt();
222   }
223   /* (non-Javadoc)
224    * @see java.lang.Thread#isInterrupted()
225    */
226   public boolean isInterrupted() {
227     // TODO Auto-generated method stub
228     return super.isInterrupted();
229   }
230   /* (non-Javadoc)
231    * @see java.lang.Thread#run()
232    */
233   public void run() {
234     // TODO Auto-generated method stub
235     super.run();
236   }
237   
238
239 }