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