2 * This file is part of the Vamsas Client version 0.1.
3 * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite,
4 * Andrew Waterhouse and Dominik Lindner.
6 * Earlier versions have also been incorporated into Jalview version 2.4
7 * since 2008, and TOPALi version 2 since 2007.
9 * The Vamsas Client is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * The Vamsas Client is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with the Vamsas Client. If not, see <http://www.gnu.org/licenses/>.
22 package uk.ac.vamsas.test;
24 import uk.ac.vamsas.client.*;
25 import uk.ac.vamsas.client.picking.IMessageHandler;
26 import uk.ac.vamsas.client.picking.IPickManager;
27 import uk.ac.vamsas.client.picking.Message;
28 import uk.ac.vamsas.objects.core.VAMSAS;
29 import uk.ac.vamsas.test.objects.Core;
31 import java.awt.Event;
32 import java.beans.PropertyChangeEvent;
33 import java.beans.PropertyChangeListener;
34 import java.io.DataInput;
35 import java.io.DataInputStream;
36 import java.io.DataOutputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.io.ObjectInputStream;
41 import java.io.ObjectOutputStream;
42 import java.io.OutputStream;
43 import java.util.Vector;
46 * Toy vamsas command line client application demonstrating the API. Currently
47 * runs with one argument: ExampleApplication.main(new String("watch")) Test:
48 * Start up at least two of these processes independently and they will
49 * successively modify and handle update events from the document model.
51 * Behaviour of each client: Event handlers are registered for documentUpdate. -
52 * every document update: * the vamsas document will be dumped to standard out
53 * using uk.ac.vamsas.test.simpleclient.ArchiveReports * if there are more than
54 * 4 vamsas roots, the first sequence in the first alignment of the first
55 * dataset of the second vamsas root will be appended with a single gap
56 * character and then written back to the session document. A pick thread is
57 * started, which sends random CUSTOM pick events every so often (tuning:
58 * flooding the pick channel seems to affect the behaviour of other vamsasClient
59 * threads, suggesting some object lock contention). A new vamsas root generated
60 * from uk.ac.vamsas.test.objects.Core.getDemoVamsas is added to the document.
61 * Then a while loop waits around for events until shutdown: - currently it will
62 * shutdown after 9 updates (totalUpdates) - an update will be made after every
63 * other update that is detected.
65 * Status: PickManager now shuts down correctly. Serial updates for two
66 * instances work correctly and are detected under j1.4 (need to test in 1.5 and
69 * TODO: test appData get/set methods
71 * TODO: verify and test pickManager and interaction between it and other
74 * TODO: add more session interaction events
76 * TODO: test client add/leave events - currently library generates exceptions
77 * for sessionlist and clientlist modifications.
82 public class ExampleApplication {
83 private ClientHandle app;
85 private UserHandle user; // TODO: make this something defined by the
89 private IClientFactory clientfactory;
91 private IClient vorbaclient;
93 private byte[] mydata;
95 private Vector vamsasObjects;
97 private boolean isUpdated = false;
99 private boolean isShuttingdown = false;
101 private boolean isFinalizing = false;
103 private int totalUpdates = 9;
105 private uk.ac.vamsas.client.VorbaId recover = null;
107 private int calls = 0;
109 private long mdatahash = 0;
111 private long muserdatahash = 0;
113 private void processVamsasDocument(IClientDocument doc) {
114 if (doc.getVamsasRoots().length < 4) {
115 doc.addVamsasRoot(Core.getDemoVamsas());
118 uk.ac.vamsas.objects.core.DataSet ds = doc.getVamsasRoots()[1]
120 uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0)
121 .getAlignmentSequence(0);
122 if (recover == null) {
123 recover = alsq.getVorbaId();
125 Vobject recoverd = doc.getObject(recover);
126 System.out.println("Recovery of " + recover + " was "
127 + ((recoverd == null) ? "A FAILURE" : "SUCCESSFUL"));
129 System.out.println("Modifying Sequence:\n" + alsq.hashCode());
130 alsq.setSequence(alsq.getSequence() + ds.getAlignment(0).getGapChar());
131 System.out.println("Modifying Sequence:\n" + alsq.hashCode());
132 System.out.println("Modified Sequence:\n" + alsq.getSequence());
133 doc.setVamsasRoots(doc.getVamsasRoots());
134 } catch (Exception ee) {
138 // get this apps 'mydata' if it hasn't got it already.
139 System.out.println("Trying to get appdata and modify it.....");
142 System.out.println(".....Finished.");
143 } catch (Exception e) {
144 System.err.println("Failed to process appdata for our application.");
145 e.printStackTrace(System.err);
148 // .. access this application's 'public' mydata' if there is any.
149 vorbaclient.updateDocument(doc);
150 // merge vamsasObjects with vamsas objects in document
154 private int appdatareads = 0;
156 boolean clientappd = true;
158 boolean userappd = false;
160 private void processAppData(IClientDocument doc) throws Exception {
162 boolean writtenonce = false;
164 uk.ac.vamsas.client.IClientAppdata appd = doc.getClientAppdata();
166 if (appd.hasClientAppdata() && !(appdatareads % 2 == 0)) {
167 // byte[] cappd = appd.getClientAppdata();
169 // System.out.println("Client appdata\n"+cappd.toString()+"\nEnd of
171 System.out.println("Testing read from inputstream");
172 String cappds = readData(appd.getClientInputStream());
174 .println("Client appdata\n" + cappds + "\nEnd of Appdata\n");
177 String newapd = "Client Appdata:";
178 if (appd.hasClientAppdata()) {
179 AppDataInputStream is;
180 newapd = readData(is = appd.getClientInputStream());
184 // appd.setClientAppdata(makeappData("Client Appdata for
185 // "+user.toString()+" written"));
186 writeData(appd.getClientOutputStream(), newapd
187 + " : Client Appdata for all users written on " + appdatareads
188 + " read by " + vorbaclient.getUserHandle());
189 System.out.println("Written to ClientAppdata stream.");
194 if (appd.hasUserAppdata() && !(appdatareads % 2 == 0)) {
195 byte[] cappd = appd.getUserAppdata();
197 System.out.println("User appdata\n" + new String(cappd)
198 + "\nEnd of Users' Appdata\n");
200 System.out.println("No user appdata.");
202 .setUserAppdata(("no default - overwritten null byte set on "
203 + appdatareads + " read by " + vorbaclient.getUserHandle() + "")
206 } else if (!writtenonce) {
208 byte[] bts = makeappData("User Appdata for " + user + " written on "
209 + appdatareads + " read at ");
210 System.out.println("Setting appData bytes to\n" + new String(bts)
212 appd.setUserAppdata(bts);
213 System.out.println("Written to UserAppdata stream.");
219 private byte[] makeappData(String message) {
220 StringBuffer sb = new StringBuffer();
222 sb.append("on " + new java.util.Date());
223 return sb.toString().getBytes();
226 private boolean writeData(AppDataOutputStream os, String message) {
227 StringBuffer sb = new StringBuffer();
229 sb.append("on " + new java.util.Date());
231 ObjectOutputStream oos = new ObjectOutputStream(os);
232 oos.writeObject(sb.toString());
235 } catch (Exception e) {
236 System.err.println("Problem serialising this message:\n" + sb);
237 e.printStackTrace(System.err);
243 private String readData(AppDataInputStream is) {
246 if (is.available() > 0) {
247 ObjectInputStream ois = new ObjectInputStream(is);
248 String rs = (String) ois.readObject();
251 } catch (Exception e) {
252 System.err.println("Failed to read a string from input stream!");
253 e.printStackTrace(System.err);
259 private void addHandlers(IClient avorbaclient) {
260 final ExampleApplication me = this;
261 // make a non-volatile reference to the client instance.
262 final IClient vorbaclient = avorbaclient;
263 // register update handler
264 vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
265 public void propertyChange(PropertyChangeEvent evt) {
266 System.out.println("Vamsas document update for "
267 + evt.getPropertyName() + ": " + evt.getOldValue() + " to "
268 + evt.getNewValue());
269 // merge new data into ours.
270 // example - output doc
272 IClientDocument cdoc = vorbaclient.getClientDocument();
273 if (calls > 2 && cdoc.getVamsasRoots().length > 0
274 && !cdoc.getVamsasRoots()[0].is__stored_in_document()) {
276 .println("Pathological Update Detected - Document is zeroed!");
279 uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(cdoc
280 .getVamsasRoots(), true, System.out);
283 if (cdoc.getVamsasRoots().length > 2) {
284 uk.ac.vamsas.objects.core.DataSet ds = cdoc.getVamsasRoots()[1]
286 uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds
287 .getAlignment(0).getAlignmentSequence(0);
288 if (alsq.isUpdated())
289 System.out.println("Seqeuence was updated since last time.");
290 alsq.setSequence(alsq.getSequence()
291 + ds.getAlignment(0).getGapChar());
292 System.out.println("Newly Modified Sequence:\n"
293 + alsq.getSequence());
294 cdoc.setVamsasRoots(cdoc.getVamsasRoots());
296 } catch (Exception ee) {
297 System.err.println("Exception whilst updating :");
298 ee.printStackTrace(System.err);
300 vorbaclient.updateDocument(cdoc);
301 } catch (Exception e) {
303 .println("Exception whilst dumping document tree after an update.");
304 e.printStackTrace(System.err);
306 isUpdated = true; // tell main thread to reflect change...
309 // register close handler
310 vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE,
311 new PropertyChangeListener() {
312 public void propertyChange(PropertyChangeEvent evt) {
313 System.out.println("Received request to close vamsas document.");
314 // ask user for a filename to save it to.
315 // Then pass it to the vorba object...
316 vorbaclient.storeDocument(new java.io.File("UserLocation"));
320 // register some more handlers to monitor the session :
322 vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION,
323 new PropertyChangeListener() {
324 public void propertyChange(PropertyChangeEvent evt) {
325 System.out.println("New Vamsas client for " + evt.getPropertyName()
326 + ": " + evt.getOldValue() + " to " + evt.getNewValue());
327 // tell app add new client to its list of clients.
330 vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION,
331 new PropertyChangeListener() {
332 public void propertyChange(PropertyChangeEvent evt) {
333 System.out.println("Vamsas client finalizing for "
334 + evt.getPropertyName() + ": " + evt.getOldValue() + " to "
335 + evt.getNewValue());
336 // tell app to update its list of clients to communicate
340 vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN,
341 new PropertyChangeListener() {
342 public void propertyChange(PropertyChangeEvent evt) {
343 System.out.println("Session " + evt.getPropertyName()
344 + " is shutting down.");
345 // tell app to finalize its session data before
349 vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA,
350 new PropertyChangeListener() {
351 public void propertyChange(PropertyChangeEvent evt) {
352 boolean finalized = false;
354 .println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
355 IClientDocument cdoc = null;
357 cdoc = vorbaclient.getClientDocument();
359 IClientAppdata apd = cdoc.getClientAppdata();
362 if (apd.getUserAppdata() != null) {
363 userd = new String(apd.getUserAppdata());
365 String appdat = me.readData(apd.getClientInputStream());
366 me.writeData(apd.getClientOutputStream(), appdat
367 + "\nUser Data merged\n" + userd + "\n");
370 vorbaclient.updateDocument(cdoc);
372 // tell app to finalize its session data prior to the
373 // storage of the current session as an archive.
374 } catch (Exception e) {
377 .println("Probable library problem - exception when trying to update document after writing merged appdata.");
378 e.printStackTrace(System.err);
381 .println("Recovering from exception when writing merged appdata");
382 e.printStackTrace(System.err);
385 vorbaclient.updateDocument(cdoc);
387 } catch (Exception e2) {
389 .println("Probable library problem - exception when trying to update document after an exception when writing merged appdata.");
390 e2.printStackTrace(System.err);
395 System.out.println("Application finalized appdata successfuly.");
401 public String Usage = "ExampleApplication :/n [-arena <vamsasFileDirectory>][-session <vamsasSessionURN>] <action> [+<arguments>]\n"
402 + "<action> is one of :\n\tsave,new,watch\n"
403 + "-arena and -session are not yet supported"; // TODO for release
407 String importFile = null;
409 String outputFile = null;
411 boolean newSession = false;
413 boolean imported = false;
415 private boolean parseArgs(String args[]) {
416 if (args.length == 0) {
420 boolean parsed = false;
421 while (!parsed && cpos < args.length) {
422 // TODO: note importDocument not yet supported.
423 // if (args[cpos].toLowerCase().equals("load") && cpos + 1 < args.length)
425 // importFile = args[cpos + 1];
429 if (args[cpos].toLowerCase().equals("new") && cpos + 1 < args.length) {
430 importFile = args[cpos + 1];
435 if (args[cpos].toLowerCase().equals("save") && cpos + 1 < args.length) {
436 outputFile = args[cpos + 1];
440 // default behaviour - if not anything else its probably a session urn
441 if (!args[cpos].toLowerCase().equals("watch")) {
449 class ExamplePicker extends Thread {
452 public IPickManager pm = null;
454 ExamplePicker(String me, IPickManager pm) {
463 Thread.sleep(1000 + (long) Math.random() * 10000);
464 } catch (Exception e) {
468 pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage(
469 "Message " + mcount++ + " from " + me));
478 public void runMe(String[] args) {
479 if (!parseArgs(args)) {
480 System.err.print(Usage);
482 // get IClientFactory
484 clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
485 } catch (IOException e) {
486 System.err.println(e + "\n" + Usage);
490 // get an Iclient with session data
491 app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication", "0.1");
492 user = new UserHandle("arnolduser", "deathsdoor");
493 if (sess != null && importFile != null) {
495 .println("Import of an existing document into an existing session is not fully supported yet.");
500 System.out.println("Connecting to " + sess);
501 vorbaclient = clientfactory.getIClient(app, user, sess);
504 if (importFile == null) {
505 System.out.println("Connecting to a new VAMSAS Session.");
506 vorbaclient = clientfactory.getNewSessionIClient(app, user);
509 .println("Connecting to a new VAMSAS Session to share data in existing document:"
511 File vfile = new File(importFile);
512 vorbaclient = clientfactory.openAsNewSessionIClient(app, user,
515 .println("Succesfully imported document into new session.");
520 vorbaclient = clientfactory.getIClient(app, user);
523 } catch (InvalidSessionDocumentException e) {
524 System.err.println("Failed to create a session to share " + importFile);
525 System.err.println("Sorry it didn't work out. This is what went wrong:");
526 e.printStackTrace(System.err);
528 } catch (NoDefaultSessionException e) {
530 .println("There appear to be several sessions to choose from :");
531 String[] sessions = clientfactory.getCurrentSessions();
532 for (int s = 0; s < sessions.length; s++)
533 System.err.println(sessions[s]);
536 addHandlers(vorbaclient);
538 vorbaclient.joinSession();
539 } catch (Exception se) {
540 se.printStackTrace();
541 System.err.println(se + " when joining session.\n" + Usage);
544 // register an update listener and a close listener.
545 // import any data if requested to
546 if (importFile != null) {
547 File vfile = new File(importFile);
549 vorbaclient.importDocument(vfile);
551 } catch (Exception e) {
552 System.err.println("Failed to import file " + importFile);
553 System.err.println("Exception received was " + e);
554 e.printStackTrace(System.err);
558 // Write out any data if requested to
559 if (outputFile != null) {
560 File vfile = new File(outputFile);
562 vorbaclient.storeDocument(vfile);
563 } catch (Exception e) {
564 System.err.println("Failed to export session as file " + outputFile);
565 System.err.println("Exception received was " + e);
566 e.printStackTrace(System.err);
571 IClientDocument cdoc = vorbaclient.getClientDocument();
573 if (cdoc.getVamsasRoots() == null
574 || cdoc.getVamsasRoots()[0].getDataSetCount() < 1) {
576 .println("Imported an Empty vamsas document. Is this correct ?");
579 processVamsasDocument(cdoc);
580 } catch (Exception e) {
582 .println("Unexpected exception when retrieving the client document for the first time!");
583 e.printStackTrace(System.err);
587 ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle()
588 .getClientUrn(), vorbaclient.getPickManager());
591 if (picker.pm != null) {
592 picker.pm.registerMessageHandler(new IMessageHandler() {
594 public void handleMessage(Message message) {
595 System.out.println("Received |" + message.getRawMessage() + "|");
596 shutdown += 100; // hang around for 5 seconds or so before dying
603 shutdown = System.currentTimeMillis() + 10000; // hang around for 10
604 // seconds or so before
606 while (!isShuttingdown && update < totalUpdates) {
607 // do something with data
608 // , update document, or something.
611 System.out.println("Update handler called " + (++update) + " times");
612 System.out.println("******************************************");
613 isUpdated = false; // TODO: saner update det method.
614 shutdown = System.currentTimeMillis() + 10000;
615 if (update % 2 == 1) {
617 IClientDocument cdoc = vorbaclient.getClientDocument();
618 processVamsasDocument(cdoc);
619 } catch (Exception e) {
621 .println("Error when updating document after an even numbered update.");
622 e.printStackTrace(System.err);
626 } catch (Exception e) {
630 if (System.currentTimeMillis() > shutdown) {
631 isShuttingdown = true;
637 } catch (Exception e) {
641 System.out.println("Finalizing.");
642 // call finalizeClient
643 vorbaclient.finalizeClient();
644 System.out.println("Shutting down picker.");
646 while (picker.isAlive()) {
647 System.out.println("Waiting for picker to die...");
650 } catch (Exception e) {
655 // { meanwhile, eventHandlers are called to do any saves if need be }
656 // and all registered listeners will be deregistered to avoid deadlock.
660 clientfactory = null;
661 System.out.println("Byee!");
662 // try { Thread.sleep(100000); } catch (Exception e) {}
665 public static void main(String[] args) {
666 ExampleApplication example = new ExampleApplication();