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 org.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;
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.ApplicationData;
30 import org.vamsas.objects.core.Entry;
31 import org.vamsas.objects.core.LockFile;
32 import org.vamsas.objects.core.VamsasDocument;
33 import org.vamsas.objects.utils.AppDataReference;
34 import org.vamsas.objects.utils.ProvenanceStuff;
35 import org.vamsas.objects.utils.document.VersionEntries;
40 public class SimpleClient implements IClient {
42 private static Log log = LogFactory.getLog(SimpleClient.class);
44 protected UserHandle user = null;
46 protected SessionUrn session = null;
47 protected VamsasSession _session;
48 protected ClientHandle client = null;
49 protected EventGeneratorThread evgen = null;
50 protected ClientDocument cdocument = null;
52 * construct a transient IdFactory instance - this should last only as long as the
53 * SimpleClient object holds the lock on the vamsas document being created/manipulated.
56 private IdFactory makeVorbaIdFactory() {
57 return new IdFactory(getSessionHandle(), client, user);
61 * construct SimpleClient for user, client and VamsasSession directory
62 * use the SimpleClientFactory rather than this constructor directly.
67 protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess) throws InvalidSessionUrnException {
68 // TODO: validate user/client/session
73 session = new SessionUrn(_session);
74 } catch (MalformedURLException e) {
75 log.error("Couldn't form a valid SessionUrn object!",e);
76 throw new InvalidSessionUrnException(_session.toString());
80 * construct new session by importing objects from an existing vamsas document
84 * @param importingArchive
85 * @throws Exception IOExceptions for Session IO problems, and general Exception if importing document is invalid.
87 protected SimpleClient(UserHandle user, ClientHandle client, VamsasSession sess, File importingArchive) throws Exception {
88 this(user, client, sess);
89 VamsasArchive sessdoc = _session.getVamsasDocument();
91 VamsasArchiveReader odoc = new VamsasArchiveReader(importingArchive);
92 SimpleDocument sdoc = new SimpleDocument(makeVorbaIdFactory());
93 VamsasDocument doc = sdoc.getVamsasDocument(odoc);
94 sessdoc.putVamsasDocument(doc, sdoc.vorba);
95 sessdoc.closeArchive();
96 } catch (Exception e) {
97 sessdoc.cancelArchive();
98 // write a dummy archive
99 _session.slog.info("Exception when importing document data from "+importingArchive);
100 throw new Exception("Failed to import data from "+importingArchive, e);
106 * LATER: check that build substitution variables are correct
107 * @see org.vamsas.client.IClient#getAbout()
109 public String getAbout() {
110 return new String("VORBA SimpleClient version $version$ build $build$");
116 * @see org.vamsas.client.IClient#getSessionUrn()
118 public String getSessionUrn() {
119 return session.getSessionUrn();
125 * @see org.vamsas.client.IClient#getSessionHandle()
127 public SessionHandle getSessionHandle() {
128 // TODO: eliminate SessionHandle ? need to refactor interfaces.
129 SessionHandle sh = new SessionHandle(session.getSessionUrn());
136 * @see org.vamsas.client.IClient#getClientHandle()
138 public ClientHandle getClientHandle() {
145 * @see org.vamsas.client.IClient#getUserHandle()
147 public UserHandle getUserHandle() {
152 * @return user field for a provenance entry
154 protected String getProvenanceUser() {
155 return new String(user.getFullName()+" ["+client.getClientUrn()+"]");
158 * construct a provenance entry for this client with the specified action string.
160 * @return properly completed provenance entry
162 protected Entry getProvenanceEntry(String action) {
163 // VAMSAS: modify schema to allow referencing of user field (plus other issues, ClientUrn field, machine readable action, input parameters, additional data generated notes
164 Entry prov = ProvenanceStuff.newProvenanceEntry(getProvenanceUser(), action);
167 private Hashtable handlers = initHandlers();
169 private Vector listeners = new Vector();
172 * make all the PropertyChangeSupport objects for the
173 * events described in org.vamsas.client.Event
176 private static Hashtable initHandlers() {
177 Hashtable events = new Hashtable();
178 java.util.Iterator evt = Events.EventList.iterator();
179 while (evt.hasNext()) {
180 Object ths = evt.next();
181 events.put(ths, (Object) new PropertyChangeSupport(ths));
189 * @see org.vamsas.client.IClient#addDocumentUpdateHandler(java.util.EventListener)
191 public void addDocumentUpdateHandler(PropertyChangeListener evt) {
192 if (handlers.containsKey(Events.DOCUMENT_UPDATE)) {
194 ((PropertyChangeSupport) (handler = handlers.get(Events.DOCUMENT_UPDATE)))
195 .addPropertyChangeListener(evt);
196 listeners.add(handler);
197 listeners.add((Object) evt);
200 boolean finalized=false;
204 * @see org.vamsas.client.IClient#finalizeClient()
206 public void finalizeClient() {
207 // TODO: determine if this is last client in session
208 // TODO: raise events like : ((lst_client && document.request.to.close), (client_finalization), (
210 // if (handlers.containsKey(Events.))
211 // if (handlers.containsKey(Events.CLIENT_FINALIZATION))
212 // deregister listeners.
213 // mark this instance as finalized
219 * @see org.vamsas.client.IClient#getClientDocument()
221 public IClientDocument getClientDocument() throws IOException {
222 if (cdocument!=null) {
223 // cdocument is non-nill if the ClientDocument.finalise() method hasn't been called.
226 VamsasArchive va = null;
228 // LATER: bail out if it takes too long to get the lock ?
229 va = _session.getVamsasDocument();
231 catch (IOException e) {
232 throw new IOException("Failed to get lock on session document");
234 VamsasDocument doc=null;
235 IdFactory vorba = null;
236 // TODO: reduce size of vorba ids generated from these parameters to IdFactory (mainly sessionHandle rationalization ?)
238 va.setVorba(vorba=makeVorbaIdFactory());
239 // if session currently holds data - read it in - or get a dummy
240 _session.slog.debug("Accessing document");
242 va.getVamsasDocument(getProvenanceUser(),
243 "created new session document.", null);
245 _session.slog.debug("Successfully retrieved document.");
247 log.error("Unexpectedly retrieved null document!");
249 catch (Exception e) {
250 log.error("Failed to get session document for session directory '"+_session.sessionDir+"'", e);
251 throw new IOException("Failed to get session document for session directory '"+_session.sessionDir+"'");
253 // Construct the IClientDocument instance
255 ClientDocument cdoc = new ClientDocument(doc, va, vorba, this);
261 * @throws Errors for invalid newdoc parameter
262 * @see org.vamsas.client.IClient#updateDocument(org.vamsas.client.IClientDocument)
264 public void updateDocument(IClientDocument newdoc) {
265 if (!(newdoc instanceof ClientDocument)) {
266 throw new Error("Invalid IClientDocument instance for SimpleClient.");
269 throw new Error("Client Error - updateDocument() called before getClientDocument().");
270 if (newdoc!=cdocument)
271 throw new Error("Client Error - SimpleClient.updateDocument() can only take the IClientDocument instance returned from SimpleClient.getClientDocument()");
272 if (!cdocument.isModified()) {
273 if (log.isDebugEnabled())
274 log.debug("updateDocument for "+session.getSessionUrn()+" with unmodified IClientDocument.");
276 if (cdocument.updateSessionDocument())
277 log.warn("Session document did not update properly for session directory "+_session.sessionDir);
279 // garbage collect the ClientDocument instance.
281 cdocument.finalize();
282 } catch (Throwable e) {
283 log.error("Exception when trying to garbage collect ClientDocument for "+session.getSessionUrn(), e);
291 * @see org.vamsas.client.IClient#storeDocument(java.io.File)
293 public void storeDocument(File location) {
295 // write storeDocument file to inform other clients that they should raise
296 Lock vamlock = evgen.want_to_store();
297 // Events.DOCUMENT_FINALIZEAPPDATA
299 _session.writeVamsasDocument(location, vamlock);
300 _session.clearUnsavedFlag();
301 } catch (Exception e) {
302 log.warn("Exception whilst trying to store document in "+location,e);
311 * @see org.vamsas.client.IClient#addVorbaEventHandler(java.lang.String,
312 * java.beans.PropertyChangeListener)
314 public void addVorbaEventHandler(String EventChain, PropertyChangeListener evt) {
315 if (handlers.containsKey(EventChain)) {
317 ((PropertyChangeSupport) (handler = handlers.get(EventChain)))
318 .addPropertyChangeListener(evt);
319 listeners.add(handler);
320 listeners.add((Object) evt);
325 * @see org.vamsas.client.IClient#pollUpdate()
327 public void pollUpdate() {
330 log.warn("pollUpdate called on incomplete SimpleClient object.");
334 if (!evgen.isAlive()) {
335 log.warn("pollUpdate called before joinSession()");
338 } catch (Exception e) {
339 log.error("Unexpected exception on default call to joinSession",e);
343 //TODO ensure event generator robustly handles these interrupts.
344 log.debug("interrrupting event generator.");
346 log.debug("interrrupted event generator.");
350 * @see org.vamsas.client.IClient#joinSession()
352 public void joinSession() throws Exception {
353 // start the EventGenerator thread.
355 log.warn("joinSession called on incomplete SimpleClient object.");
359 throw new Error("Join session called twice for the same SimpleClient (IClient instance).");
362 log.debug("Started EventGenerator thread.");
364 log.warn("Failed to start EventGenerator thread.");
365 throw new Exception("Failed to start event generator thread - client cannot be instantiated.");
367 if (evgen.countHandlersFor(Events.DOCUMENT_CREATE)>0) {
368 //TODO: is this application connecting to a newly created session document ?
369 //evgen.raise(Events.DOCUMENT_CREATE);
376 * @see org.vamsas.client.IClient#importDocument(java.io.File)
378 public void importDocument(File location) {
379 // TODO LATER: implement SimpleClient.importDocument()
380 log.error("importDocument is not implemented for a SimpleClient Session.");