rearranged some todos and preparing to implement SimpleClient and ClientDocument...
[vamsas.git] / src / org / vamsas / client / simpleclient / SimpleClient.java
1 /*
2  * Created on 15-Sep-2005
3  *
4  * TODO To change the template for this generated file go to
5  * Window - Preferences - Java - Code Style - Code Templates
6  */
7 package org.vamsas.client.simpleclient;
8
9 import java.beans.EventHandler;
10 import java.beans.PropertyChangeEvent;
11 import java.beans.PropertyChangeListener;
12 import java.beans.PropertyChangeSupport;
13 import java.io.BufferedReader;
14 import java.io.File;
15 import java.io.IOException;
16 import java.net.MalformedURLException;
17 import java.util.Hashtable;
18 import java.util.Vector;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.vamsas.client.ClientHandle;
23 import org.vamsas.client.Events;
24 import org.vamsas.client.IClient;
25 import org.vamsas.client.IClientDocument;
26 import org.vamsas.client.InvalidSessionUrnException;
27 import org.vamsas.client.SessionHandle;
28 import org.vamsas.client.UserHandle;
29 import org.vamsas.objects.core.LockFile;
30 import org.vamsas.objects.core.VamsasDocument;
31 import org.vamsas.objects.utils.ProvenanceStuff;
32 import org.vamsas.objects.utils.document.VersionEntries;
33
34 /**
35  * @author jimp
36  */
37 public class SimpleClient implements IClient {
38   
39   private static Log log = LogFactory.getLog(SimpleClient.class);
40   
41   protected UserHandle user = null;
42   
43   protected SessionUrn session = null;
44   protected VamsasSession _session;
45   protected ClientHandle client = null;
46   protected EventGeneratorThread evgen = null;
47   protected ClientDocument cdocument = null;
48   /**
49    * construct a transient IdFactory instance - this should last only as long as the 
50    * SimpleClient object holds the lock on the vamsas document being created/manipulated.
51    * @return
52    */
53   private IdFactory makeVorbaIdFactory() {
54     return new IdFactory(getSessionHandle(), client, user);
55   }
56   
57   /**
58    * construct SimpleClient for user, client and VamsasSession directory
59    * use the SimpleClientFactory rather than this constructor directly. 
60    * @param user
61    * @param client
62    * @param sess
63    */
64   protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess) throws InvalidSessionUrnException {
65     // TODO: validate user/client/session
66     _session = sess;
67     this.user = user;
68     this.client = client;
69     try {
70       session = new SessionUrn(_session);
71     } catch (MalformedURLException e) {
72       log.error("Couldn't form a valid SessionUrn object!",e);
73       throw new InvalidSessionUrnException(_session.toString());
74     }
75   }
76   /**
77    * construct new session by importing objects from an existing vamsas document
78    * @param user
79    * @param client
80    * @param sess
81    * @param importingArchive
82    * @throws Exception IOExceptions for Session IO problems, and general Exception if importing document is invalid.
83    */
84   protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess, File importingArchive) throws Exception {
85     this(user, client, sess);
86     VamsasArchive sessdoc = _session.getVamsasDocument();
87     try {
88       VamsasArchiveReader odoc = new VamsasArchiveReader(importingArchive);
89       SimpleDocument sdoc = new SimpleDocument(makeVorbaIdFactory());
90       VamsasDocument doc = sdoc.getVamsasDocument(odoc);
91       sessdoc.putVamsasDocument(doc, sdoc.vorba);
92       sessdoc.closeArchive();
93     } catch (Exception e) {
94       sessdoc.cancelArchive();
95       // write a dummy archive
96       _session.slog.info("Exception when importing document data from "+importingArchive);
97       throw new Exception("Failed to import data from "+importingArchive, e);
98     }
99   }
100
101   /*
102    * (non-Javadoc)
103    * LATER: check that build substitution variables are correct
104    * @see org.vamsas.client.IClient#getAbout()
105    */
106   public String getAbout() {
107     return new String("VORBA SimpleClient version $version$ build $build$");
108   }
109   
110   /*
111    * (non-Javadoc)
112    * 
113    * @see org.vamsas.client.IClient#getSessionUrn()
114    */
115   public String getSessionUrn() {
116     return session.getSessionUrn();
117   }
118   
119   /*
120    * (non-Javadoc)
121    * 
122    * @see org.vamsas.client.IClient#getSessionHandle()
123    */
124   public SessionHandle getSessionHandle() {
125     // TODO: eliminate SessionHandle ? need to refactor interfaces.
126     SessionHandle sh = new SessionHandle(session.getSessionUrn());
127     return sh;
128   }
129   
130   /*
131    * (non-Javadoc)
132    * 
133    * @see org.vamsas.client.IClient#getClientHandle()
134    */
135   public ClientHandle getClientHandle() {
136     return client;
137   }
138   
139   /*
140    * (non-Javadoc)
141    * 
142    * @see org.vamsas.client.IClient#getUserHandle()
143    */
144   public UserHandle getUserHandle() {
145     return user;
146   }
147   
148   private Hashtable handlers = initHandlers();
149   
150   private Vector listeners = new Vector();
151   
152   /**
153    * make all the PropertyChangeSupport objects for the
154    * events described in org.vamsas.client.Event
155    * @return
156    */
157   private static Hashtable initHandlers() {
158     Hashtable events = new Hashtable();
159     java.util.Iterator evt = Events.EventList.iterator();
160     while (evt.hasNext()) {
161       Object ths = evt.next();
162       events.put(ths, (Object) new PropertyChangeSupport(ths));
163     }
164     return events;
165   }
166   
167   /*
168    * (non-Javadoc)
169    * 
170    * @see org.vamsas.client.IClient#addDocumentUpdateHandler(java.util.EventListener)
171    */
172   public void addDocumentUpdateHandler(PropertyChangeListener evt) {
173     if (handlers.containsKey(Events.DOCUMENT_UPDATE)) {
174       Object handler;
175       ((PropertyChangeSupport) (handler = handlers.get(Events.DOCUMENT_UPDATE)))
176       .addPropertyChangeListener(evt);
177       listeners.add(handler);
178       listeners.add((Object) evt);
179     }
180   }
181   boolean finalized=false;
182   /*
183    * (non-Javadoc)
184    * 
185    * @see org.vamsas.client.IClient#finalizeClient()
186    */
187   public void finalizeClient() {
188     // TODO: determine if this is last client in session
189     // TODO: raise events like : ((lst_client && document.request.to.close), (client_finalization), (
190     
191     // if (handlers.containsKey(Events.))
192     // if (handlers.containsKey(Events.CLIENT_FINALIZATION))
193     // deregister listeners.
194     // mark this instance as finalized
195   }
196   
197   /*
198    * (non-Javadoc)
199    * 
200    * @see org.vamsas.client.IClient#getClientDocument()
201    */
202   public IClientDocument getClientDocument() throws IOException {
203     if (cdocument!=null) {
204       // cdocument is non-nill if the ClientDocument.finalise() method hasn't been called.
205       return cdocument;
206     }
207     VamsasArchive va = null;
208     try {
209       // LATER: bail out if it takes too long to get the lock ?
210       va = _session.getVamsasDocument();
211     }
212     catch (IOException e) {
213       throw new IOException("Failed to get lock on session document");
214     }
215     VamsasDocument doc=null;
216     IdFactory vorba = null;
217     // TODO: reduce size of vorba ids generated from these parameters to IdFactory (mainly sessionHandle rationalization ?)
218     try {
219       va.setVorba(vorba=makeVorbaIdFactory());
220       // if session currently holds data - read it in - or get a dummy
221       _session.slog.debug("Accessing document");
222       doc = 
223         va.getVamsasDocument(user.getFullName()+" using "+client.getClientName(),
224             "created new session document.", null);
225       if (doc!=null)
226         _session.slog.debug("Successfully retrieved document.");
227       else
228         log.error("Unexpectedly retrieved null document!");
229     }
230     catch (Exception e) {
231       log.error("Failed to get session document for session directory '"+_session.sessionDir+"'", e);
232       throw new IOException("Failed to get session document for session directory '"+_session.sessionDir+"'");
233     }
234     // Construct the IClientDocument instance
235     
236     ClientDocument cdoc = new ClientDocument(doc, va, vorba, this);
237     return cdoc;
238   }
239   
240   /*
241    * (non-Javadoc)
242    * 
243    * @see org.vamsas.client.IClient#updateDocument(org.vamsas.client.IClientDocument)
244    */
245   public void updateDocument(IClientDocument newdoc) {
246     if (!(newdoc instanceof ClientDocument)) {
247       throw new Error("Invalid IClientDocument instance for SimpleClient.");
248     }
249     
250     // try to update the sessionFile
251     
252     // write the appHandle to the lastupdate file.
253     
254   }
255   
256   /*
257    * (non-Javadoc)
258    * 
259    * @see org.vamsas.client.IClient#storeDocument(java.io.File)
260    */
261   public void storeDocument(File location) {
262     
263     // write storeDocument file to inform other clients that they should raise
264     Lock vamlock = evgen.want_to_store();
265     // Events.DOCUMENT_FINALIZEAPPDATA
266     try {
267       _session.writeVamsasDocument(location, vamlock);
268       _session.clearUnsavedFlag();
269     } catch (Exception e) {
270       log.warn("Exception whilst trying to store document in "+location,e);
271     }
272     
273     vamlock.release();
274   }
275   
276   /*
277    * (non-Javadoc)
278    * 
279    * @see org.vamsas.client.IClient#addVorbaEventHandler(java.lang.String,
280    *      java.beans.PropertyChangeListener)
281    */
282   public void addVorbaEventHandler(String EventChain, PropertyChangeListener evt) {
283     if (handlers.containsKey(EventChain)) {
284       Object handler;
285       ((PropertyChangeSupport) (handler = handlers.get(EventChain)))
286       .addPropertyChangeListener(evt);
287       listeners.add(handler);
288       listeners.add((Object) evt);
289     }
290   }
291   
292   /* (non-Javadoc)
293    * @see org.vamsas.client.IClient#pollUpdate()
294    */
295   public void pollUpdate() {
296     
297     if (evgen==null) {
298       log.warn("pollUpdate called on incomplete SimpleClient object.");
299       return;
300     }
301     
302     if (!evgen.isAlive()) {
303       log.warn("pollUpdate called before joinSession()");
304       try {
305         joinSession();
306       } catch (Exception e) {
307         log.error("Unexpected exception on default call to joinSession",e);
308       }
309     }
310     
311     //TODO ensure event generator robustly handles these interrupts.
312     log.debug("interrrupting event generator.");
313     evgen.interrupt();
314     log.debug("interrrupted event generator.");
315   }
316   
317   /* (non-Javadoc)
318    * @see org.vamsas.client.IClient#joinSession()
319    */
320   public void joinSession() throws Exception {
321     // start the EventGenerator thread.
322     if (evgen==null) {
323       log.warn("joinSession called on incomplete SimpleClient object.");
324       return;
325     }
326     if (evgen.isAlive())
327       throw new Error("Join session called twice for the same SimpleClient (IClient instance).");
328     evgen.start();
329     if (evgen.isAlive())
330       log.debug("Started EventGenerator thread.");
331     else {
332       log.warn("Failed to start EventGenerator thread.");
333       throw new Exception("Failed to start event generator thread - client cannot be instantiated.");
334     }
335     if (evgen.countHandlersFor(Events.DOCUMENT_CREATE)>0) {
336       //TODO: is this application connecting to a newly created session document ?
337       //evgen.raise(Events.DOCUMENT_CREATE);
338     }
339   }
340   
341   
342   
343   /* (non-Javadoc)
344    * @see org.vamsas.client.IClient#importDocument(java.io.File)
345    */
346   public void importDocument(File location) {
347     // TODO LATER: implement SimpleClient.importDocument()
348     log.error("importDocument is not implemented for a SimpleClient Session.");
349   }
350 }