2 * Created on 15-Sep-2005
4 * TODO To change the template for this generated file go to
5 * Window - Preferences - Java - Code Style - Code Templates
7 package uk.ac.vamsas.client.simpleclient;
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;
15 import java.io.IOException;
16 import java.net.MalformedURLException;
17 import java.util.Hashtable;
18 import java.util.Vector;
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
23 import uk.ac.vamsas.client.ClientHandle;
24 import uk.ac.vamsas.client.Events;
25 import uk.ac.vamsas.client.IClient;
26 import uk.ac.vamsas.client.IClientDocument;
27 import uk.ac.vamsas.client.IObjectUpdate;
28 import uk.ac.vamsas.client.InvalidSessionUrnException;
29 import uk.ac.vamsas.client.SessionHandle;
30 import uk.ac.vamsas.client.UserHandle;
31 import uk.ac.vamsas.objects.core.ApplicationData;
32 import uk.ac.vamsas.objects.core.Entry;
33 import uk.ac.vamsas.objects.core.LockFile;
34 import uk.ac.vamsas.objects.core.VamsasDocument;
35 import uk.ac.vamsas.objects.utils.AppDataReference;
36 import uk.ac.vamsas.objects.utils.ProvenanceStuff;
37 import uk.ac.vamsas.objects.utils.document.VersionEntries;
42 public class SimpleClient implements IClient {
44 private static Log log = LogFactory.getLog(SimpleClient.class);
46 protected UserHandle user = null;
48 protected SessionUrn session = null;
49 protected VamsasSession _session;
50 protected ClientHandle client = null;
51 protected EventGeneratorThread evgen = null;
52 protected ClientDocument cdocument = null;
54 * object hash table that persists in each client holding vorbaIds and hash values after a document write
56 protected Hashtable extantobjects=null;
58 * construct a transient IdFactory instance - this should last only as long as the
59 * SimpleClient object holds the lock on the vamsas document being created/manipulated.
62 private IdFactory makeVorbaIdFactory() {
63 return new IdFactory(getSessionHandle(), client, user);
67 * construct SimpleClient for user, client and VamsasSession directory
68 * use the SimpleClientFactory rather than this constructor directly.
73 protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess) throws InvalidSessionUrnException {
74 // TODO: validate user/client/session
79 session = new SessionUrn(_session);
80 } catch (MalformedURLException e) {
81 log.error("Couldn't form a valid SessionUrn object!",e);
82 throw new InvalidSessionUrnException(_session.toString());
86 * construct new session by importing objects from an existing vamsas document
90 * @param importingArchive
91 * @throws Exception IOExceptions for Session IO problems, and general Exception if importing document is invalid.
93 protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess, File importingArchive) throws Exception {
94 this(user, client, sess);
95 VamsasArchive sessdoc = _session.getVamsasDocument();
97 VamsasArchiveReader odoc = new VamsasArchiveReader(importingArchive);
98 SimpleDocument sdoc = new SimpleDocument(makeVorbaIdFactory());
99 VamsasDocument doc = sdoc.getVamsasDocument(odoc);
100 sessdoc.putVamsasDocument(doc, sdoc.vorba);
101 sessdoc.closeArchive();
102 } catch (Exception e) {
103 sessdoc.cancelArchive();
104 // write a dummy archive
105 _session.slog.info("Exception when importing document data from "+importingArchive);
106 throw new Exception("Failed to import data from "+importingArchive, e);
112 * LATER: check that build substitution variables are correct
113 * @see uk.ac.vamsas.client.IClient#getAbout()
115 public String getAbout() {
116 return new String("VORBA SimpleClient version $version$ build $build$");
122 * @see uk.ac.vamsas.client.IClient#getSessionUrn()
124 public String getSessionUrn() {
125 return session.getSessionUrn();
131 * @see uk.ac.vamsas.client.IClient#getSessionHandle()
133 public SessionHandle getSessionHandle() {
134 // TODO: eliminate SessionHandle ? need to refactor interfaces.
135 SessionHandle sh = new SessionHandle(session.getSessionUrn());
142 * @see uk.ac.vamsas.client.IClient#getClientHandle()
144 public ClientHandle getClientHandle() {
151 * @see uk.ac.vamsas.client.IClient#getUserHandle()
153 public UserHandle getUserHandle() {
158 * @return user field for a provenance entry
160 protected String getProvenanceUser() {
161 return new String(user.getFullName());
164 * construct a provenance entry for this client with the specified action string.
166 * @return properly completed provenance entry
168 protected Entry getProvenanceEntry(String action) {
169 Entry prov = ProvenanceStuff.newProvenanceEntry(client.getClientUrn(), getProvenanceUser(), action);
172 private Hashtable handlers = initHandlers();
174 private Vector listeners = new Vector();
177 * make all the PropertyChangeSupport objects for the
178 * events described in uk.ac.vamsas.client.Event
181 private static Hashtable initHandlers() {
182 Hashtable events = new Hashtable();
183 java.util.Iterator evt = Events.EventList.iterator();
184 while (evt.hasNext()) {
185 Object ths = evt.next();
186 events.put(ths, (Object) new PropertyChangeSupport(ths));
194 * @see uk.ac.vamsas.client.IClient#addDocumentUpdateHandler(java.util.EventListener)
196 public void addDocumentUpdateHandler(PropertyChangeListener evt) {
197 if (handlers.containsKey(Events.DOCUMENT_UPDATE)) {
199 ((PropertyChangeSupport) (handler = handlers.get(Events.DOCUMENT_UPDATE)))
200 .addPropertyChangeListener(evt);
201 listeners.add(handler);
202 listeners.add((Object) evt);
205 boolean finalized=false;
209 * @see uk.ac.vamsas.client.IClient#finalizeClient()
211 public void finalizeClient() {
212 // TODO: determine if this is last client in session
213 // TODO: raise events like : ((lst_client && document.request.to.close), (client_finalization), (
215 // if (handlers.containsKey(Events.))
216 // if (handlers.containsKey(Events.CLIENT_FINALIZATION))
217 // deregister listeners.
218 // mark this instance as finalized
224 * @see uk.ac.vamsas.client.IClient#getClientDocument()
226 public IClientDocument getClientDocument() throws IOException {
227 if (cdocument!=null) {
228 // cdocument is non-nill if the ClientDocument.finalise() method hasn't been called.
231 VamsasArchive va = null;
233 // LATER: bail out if it takes too long to get the lock ?
234 va = _session.getVamsasDocument();
236 catch (IOException e) {
237 throw new IOException("Failed to get lock on session document");
239 VamsasDocument doc=null;
240 IdFactory vorba = null;
241 // TODO: reduce size of vorba ids generated from these parameters to IdFactory (mainly sessionHandle rationalization ?)
243 va.setVorba(vorba=makeVorbaIdFactory());
244 // if session currently holds data - read it in - or get a dummy
245 _session.slog.debug("Accessing document");
247 va.getVamsasDocument(getProvenanceUser(),
248 "created new session document.", null);
250 _session.slog.debug("Successfully retrieved document.");
252 log.error("Unexpectedly retrieved null document!");
254 catch (Exception e) {
255 log.error("Failed to get session document for session directory '"+_session.sessionDir+"'", e);
256 throw new IOException("Failed to get session document for session directory '"+_session.sessionDir+"'");
258 // Construct the IClientDocument instance
260 ClientDocument cdoc = new ClientDocument(doc, va, vorba, this);
266 * @throws Errors for invalid newdoc parameter
267 * @see uk.ac.vamsas.client.IClient#updateDocument(uk.ac.vamsas.client.IClientDocument)
269 public void updateDocument(IClientDocument newdoc) {
270 if (!(newdoc instanceof ClientDocument)) {
271 throw new Error("Invalid IClientDocument instance for SimpleClient.");
274 throw new Error("Client Error - updateDocument() called before getClientDocument().");
275 if (newdoc!=cdocument)
276 throw new Error("Client Error - SimpleClient.updateDocument() can only take the IClientDocument instance returned from SimpleClient.getClientDocument()");
277 if (!cdocument.isModified()) {
278 if (log.isDebugEnabled())
279 log.debug("updateDocument for "+session.getSessionUrn()+" with unmodified IClientDocument.");
282 if (!cdocument.updateSessionDocument()) {
283 log.warn("Session document did not update properly for session directory "+_session.sessionDir);
284 // cdocument.archive.cancelArchive(); // LATER: could be done - would need to prevent updateSessionDocument closing the archive.
285 _session.slog.warn("Session Document updated but may not be valid (false return from org.vamsas.simpleclient.ClientDocument.updateSessionDocument()");
288 catch (IOException e) {
289 log.warn("IO Problems when updating document!",e);
290 _session.slog.error("IO problems when attempting to update document.");
293 // garbage collect the ClientDocument instance.
295 cdocument.finalize();
297 } catch (Throwable e) {
298 log.error("Exception when trying to garbage collect ClientDocument for "+session.getSessionUrn(), e);
300 cdocument = null; // this is probably done by finalize
306 * @see uk.ac.vamsas.client.IClient#storeDocument(java.io.File)
308 public void storeDocument(File location) {
310 // write storeDocument file to inform other clients that they should raise
311 Lock vamlock = evgen.want_to_store();
312 // Events.DOCUMENT_FINALIZEAPPDATA
314 _session.writeVamsasDocument(location, vamlock);
315 _session.clearUnsavedFlag();
316 } catch (Exception e) {
317 log.warn("Exception whilst trying to store document in "+location,e);
326 * @see uk.ac.vamsas.client.IClient#addVorbaEventHandler(java.lang.String,
327 * java.beans.PropertyChangeListener)
329 public void addVorbaEventHandler(String EventChain, PropertyChangeListener evt) {
330 if (handlers.containsKey(EventChain)) {
332 ((PropertyChangeSupport) (handler = handlers.get(EventChain)))
333 .addPropertyChangeListener(evt);
334 listeners.add(handler);
335 listeners.add((Object) evt);
340 * @see uk.ac.vamsas.client.IClient#pollUpdate()
342 public void pollUpdate() {
345 log.warn("pollUpdate called on incomplete SimpleClient object.");
349 if (!evgen.isAlive()) {
350 log.warn("pollUpdate called before joinSession() - trying to do this.");
353 } catch (Exception e) {
354 log.error("Unexpected exception on default call to joinSession",e);
358 //TODO ensure event generator robustly handles these interrupts.
359 log.debug("interrrupting event generator.");
361 log.debug("interrrupted event generator.");
365 * @see uk.ac.vamsas.client.IClient#joinSession()
367 public void joinSession() throws Exception {
368 // start the EventGenerator thread.
370 log.warn("joinSession called on incomplete SimpleClient object.");
374 throw new Error("Join session called twice for the same SimpleClient (IClient instance).");
377 log.debug("Started EventGenerator thread.");
379 log.warn("Failed to start EventGenerator thread.");
380 throw new Exception("Failed to start event generator thread - client cannot be instantiated.");
382 if (evgen.countHandlersFor(Events.DOCUMENT_CREATE)>0) {
383 //TODO: is this application connecting to a newly created session document ?
384 //evgen.raise(Events.DOCUMENT_CREATE);
391 * @see uk.ac.vamsas.client.IClient#importDocument(java.io.File)
393 public void importDocument(File location) {
394 // TODO LATER: implement SimpleClient.importDocument()
395 log.error("importDocument is not yet implemented for a SimpleClient Session.");
398 public IObjectUpdate getUpdateHandler(Class rootObject) {
399 // TODO Auto-generated method stub
403 public IObjectUpdate[] getUpdateHandlers() {
404 // TODO Auto-generated method stub
408 public void removeUpdateHandler(Class rootObject) {
409 // TODO Auto-generated method stub
413 public void setUpdateHandler(IObjectUpdate handler) {
414 // TODO Auto-generated method stub