bfb14256c67d5abc650d4c9c7de7c4fff2513d99
[vamsas.git] / src / uk / ac / vamsas / test / ExampleApplication.java
1 package uk.ac.vamsas.test;
2
3 import uk.ac.vamsas.client.*;
4 import uk.ac.vamsas.client.picking.IMessageHandler;
5 import uk.ac.vamsas.client.picking.IPickManager;
6 import uk.ac.vamsas.client.picking.Message;
7 import uk.ac.vamsas.objects.core.VAMSAS;
8 import uk.ac.vamsas.test.objects.Core;
9
10 import java.awt.Event;
11 import java.beans.PropertyChangeEvent;
12 import java.beans.PropertyChangeListener;
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.Vector;
16
17 /**
18  * Toy vamsas command line client application demonstrating the API. 
19  * Currently runs with one argument: ExampleApplication.main(new String("watch"))
20  * Test: Start up at least two of these processes independently and they will 
21  * successively modify and handle update events from the document model.
22  * 
23  * Behaviour of each client:
24  * Event handlers are registered for documentUpdate.
25  * - every document update:
26  *   * the vamsas document will be dumped to standard out using uk.ac.vamsas.test.simpleclient.ArchiveReports
27  *   * if there are more than 4 vamsas roots, the first sequence in the first alignment of the first dataset of the second vamsas root will be appended with a single gap character and then written back to the session document. 
28  * A pick thread is started, which sends random CUSTOM pick events every so often (tuning: flooding the pick channel seems to affect the behaviour of other vamsasClient threads, suggesting some object lock contention).
29  * A new vamsas root generated from uk.ac.vamsas.test.objects.Core.getDemoVamsas is added to the document.
30  * Then a while loop waits around for events until shutdown:
31  *  - currently it will shutdown after 9 updates (totalUpdates)
32  *  - an update will be made after every other update that is detected.
33  *  
34  * Status: PickManager now shuts down correctly. Serial updates for two instances work correctly and are detected under j1.4 (need to test in 1.5 and 1.6).
35  * 
36  * TODO: test
37  * appData get/set methods 
38  * 
39  * TODO: verify and test pickManager and interaction
40  * between it and other session events 
41  * 
42  * TODO: add more session interaction events
43  * 
44  * TODO: test client add/leave events - currently library generates exceptions for sessionlist and clientlist modifications.
45  * 
46  * @author jimp
47  */
48
49 public class ExampleApplication
50 {
51   private ClientHandle app;
52
53   private UserHandle user; // TODO: make this something defined by the
54   // api
55
56   private IClientFactory clientfactory;
57
58   private IClient vorbaclient;
59
60   private byte[] mydata;
61
62   private Vector vamsasObjects;
63
64   private boolean isUpdated = false;
65
66   private boolean isShuttingdown = false;
67
68   private boolean isFinalizing = false;
69   private int totalUpdates = 9;
70   private uk.ac.vamsas.client.VorbaId recover = null;
71   private int calls=0;
72   private void processVamsasDocument(IClientDocument doc)
73   {
74     if (doc.getVamsasRoots().length<4) {
75       doc.addVamsasRoot(Core.getDemoVamsas());
76     } else {
77       try {
78         uk.ac.vamsas.objects.core.DataSet ds = doc.getVamsasRoots()[1].getDataSet(0);
79         uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
80         if (recover==null)
81         {
82           recover = alsq.getVorbaId();
83         } else {
84           Vobject recoverd = doc.getObject(recover);
85           System.out.println("Recovery of "+recover+" was "+((recoverd==null) ? "A FAILURE" : "SUCCESSFUL"));
86         }
87         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
88         alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
89         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
90         System.out.println("Modified Sequence:\n"+alsq.getSequence());
91         doc.setVamsasRoots(doc.getVamsasRoots());
92       } catch (Exception ee) {
93       
94       }
95     }
96     vorbaclient.updateDocument(doc);
97     // merge vamsasObjects with vamsas objects in document
98     // get this apps 'mydata' if it hasn't got it already.
99     // .. access this application's 'public' mydata' if there is any.
100   }
101
102   private void addHandlers(IClient avorbaclient)
103   {
104     // make a non-volatile reference to the client instance.
105     final IClient vorbaclient = avorbaclient;
106     // register update handler
107     vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
108       public void propertyChange(PropertyChangeEvent evt)
109       {
110         System.out.println("Vamsas document update for "
111             + evt.getPropertyName() + ": " + evt.getOldValue()
112             + " to " + evt.getNewValue());
113         // merge new data into ours.
114         // example - output doc
115         try
116         {
117           IClientDocument cdoc = vorbaclient.getClientDocument();
118           if (calls>2 && cdoc.getVamsasRoots().length>0 && !cdoc.getVamsasRoots()[0].is__stored_in_document())
119           {
120             System.err.println("Pathological Update Detected - Document is zeroed!");
121           }
122           calls++;
123           uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(
124               cdoc.getVamsasRoots(), true, System.out);
125           // Simple update
126           try {
127             if (cdoc.getVamsasRoots().length>2) {
128               uk.ac.vamsas.objects.core.DataSet ds = cdoc.getVamsasRoots()[1].getDataSet(0);
129               uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
130               if (alsq.isUpdated())
131                 System.out.println("Seqeuence was updated since last time.");
132               alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
133               System.out.println("Newly Modified Sequence:\n"+alsq.getSequence());
134               cdoc.setVamsasRoots(cdoc.getVamsasRoots());
135             }
136           } catch (Exception ee) {
137             System.err.println("Exception whilst updating :");
138             ee.printStackTrace(System.err);
139           }
140           vorbaclient.updateDocument(cdoc);
141         }
142         catch (Exception e)
143         {
144           System.err
145           .println("Exception whilst dumping document tree after an update.");
146           e.printStackTrace(System.err);
147         }
148         isUpdated = true; // tell main thread to reflect change...
149       }
150     });
151     // register close handler
152     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE,
153         new PropertyChangeListener() {
154       public void propertyChange(PropertyChangeEvent evt)
155       {
156         System.out
157         .println("Received request to close vamsas document.");
158         // ask user for a filename to save it to.
159         // Then pass it to the vorba object...
160         vorbaclient.storeDocument(new java.io.File(
161         "UserLocation"));
162       }
163     });
164
165     // register some more handlers to monitor the session :
166
167     vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION,
168         new PropertyChangeListener() {
169       public void propertyChange(PropertyChangeEvent evt)
170       {
171         System.out.println("New Vamsas client for "
172             + evt.getPropertyName() + ": "
173             + evt.getOldValue() + " to "
174             + evt.getNewValue());
175         // tell app add new client to its list of clients.
176       }
177     });
178     vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION,
179         new PropertyChangeListener() {
180       public void propertyChange(PropertyChangeEvent evt)
181       {
182         System.out.println("Vamsas client finalizing for "
183             + evt.getPropertyName() + ": "
184             + evt.getOldValue() + " to "
185             + evt.getNewValue());
186         // tell app to update its list of clients to communicate
187         // with.
188       }
189     });
190     vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN,
191         new PropertyChangeListener() {
192       public void propertyChange(PropertyChangeEvent evt)
193       {
194         System.out.println("Session " + evt.getPropertyName()
195             + " is shutting down.");
196         // tell app to finalize its session data before
197         // shutdown.
198       }
199     });
200     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA,
201         new PropertyChangeListener() {
202       public void propertyChange(PropertyChangeEvent evt)
203       {
204         System.out
205         .println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
206         // tell app to finalize its session data prior to the
207         // storage of the current session as an archive.
208       }
209     });
210
211   }
212
213   public String Usage = "ExampleApplication :/n [-arena <vamsasFileDirectory>][-session <vamsasSessionURN>] <action> [+<arguments>]\n"
214     + "<action> is one of :\n\tsave,update,close,watch";
215
216   String sess = null;
217   String importFile=null;
218   String outputFile=null;
219   private boolean parseArgs(String args[])
220   {
221     if (args.length == 0)
222     {
223       return false;
224     }
225     int cpos=0;
226     boolean parsed=false;
227     while (!parsed && cpos<args.length)
228     {
229       if (args[cpos].toLowerCase().equals("load") && cpos+1<args.length)
230       {
231         importFile=args[cpos+1];
232         cpos+=2;
233         continue;
234       }
235       if (args[cpos].toLowerCase().equals("save") && cpos+1<args.length)
236       {
237         outputFile=args[cpos+1];
238         cpos+=2;
239         continue;
240       }
241       // default behaviour - if not anything else its probably a session urn
242       if (!args[cpos].toLowerCase().equals("watch"))
243       {
244         sess = args[cpos];
245       }
246       cpos++;
247     }
248     return true;
249   }
250   
251   class ExamplePicker extends Thread
252   {
253     String me = null;
254
255     public IPickManager pm = null;
256
257     ExamplePicker(String me, IPickManager pm)
258     {
259       this.me = me;
260       this.pm = pm;
261     }
262
263     public void run()
264     {
265       int mcount = 1;
266       while (pm != null)
267       {
268         try { Thread.sleep(1000 + (long) Math.random() * 10000); }
269         catch (Exception e) {}
270
271         if (pm != null)
272         {
273           pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage("Message " + mcount++ + " from " + me));
274         }
275       }
276     }
277
278   }
279   long shutdown = -1;
280   public void runMe(String[] args)
281   {
282     if (!parseArgs(args))
283     {
284       System.err.print(Usage);
285     }
286     // get IClientFactory
287     try
288     {
289       clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
290     }
291     catch (IOException e)
292     {
293       System.err.println(e + "\n" + Usage);
294       System.exit(1);
295     }
296
297     // get an Iclient with session data
298     app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication", "0.1");
299     user = new UserHandle("arnolduser", "deathsdoor");
300     try
301     {
302       if (sess!=null)
303       {
304         System.out.println("Connecting to "+sess);
305         vorbaclient = clientfactory.getIClient(app, user, sess);
306       }
307       else
308       {
309         vorbaclient = clientfactory.getIClient(app, user);
310       }
311     }
312     catch (NoDefaultSessionException e)
313     {
314       System.err
315       .println("There appear to be several sessions to choose from :");
316       String[] sessions = clientfactory.getCurrentSessions();
317       for (int s = 0; s < sessions.length; s++)
318         System.err.println(sessions[s]);
319       System.exit(2);
320     }
321     addHandlers(vorbaclient);
322     try
323     {
324       vorbaclient.joinSession();
325     }
326     catch (Exception se)
327     {
328       se.printStackTrace();
329       System.err.println(se + " when joining session.\n" + Usage);
330       System.exit(1);
331     }
332     // register an update listener and a close listener.
333     // import any data if requested to
334     if (importFile!=null)
335     {
336       File vfile = new File(importFile);
337       try
338       { 
339         vorbaclient.importDocument(vfile);
340       }
341       catch (Exception e)
342       {
343         System.err.println("Failed to import file "+importFile);
344         System.err.println("Exception received was "+e);
345         e.printStackTrace(System.err);
346       }
347       
348     }
349    // Write out any data if requested to
350     if (outputFile!=null)
351     {
352       File vfile = new File(outputFile);
353       try
354       { 
355         vorbaclient.storeDocument(vfile);
356       }
357       catch (Exception e)
358       {
359         System.err.println("Failed to export session as file "+outputFile);
360         System.err.println("Exception received was "+e);
361         e.printStackTrace(System.err);
362       }
363     }
364     // get document data
365     try
366     {
367       IClientDocument cdoc = vorbaclient.getClientDocument();
368       processVamsasDocument(cdoc);
369     }
370     catch (Exception e)
371     {
372       System.err
373       .println("Unexpected exception when retrieving the client document for the first time!");
374       e.printStackTrace(System.err);
375       System.exit(1);
376     }
377     int update = 0;
378     ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle()
379         .getClientUrn(), vorbaclient.getPickManager());
380
381     picker.start();
382     if (picker.pm!=null) {
383       picker.pm.registerMessageHandler(new IMessageHandler() {
384
385         public void handleMessage(Message message)
386         {
387           System.out
388           .println("Received |" + message.getRawMessage() + "|");
389           shutdown +=100; // hang around for 5 seconds or so before dying naturally. 
390           
391         }
392
393       });
394     }
395     shutdown = System.currentTimeMillis()+10000; // hang around for 10 seconds or so before dying naturally. 
396     while (!isShuttingdown && update < totalUpdates)
397     {
398       // do something with data
399       // , update document, or something.
400       // ..
401       if (isUpdated)
402       {
403         System.out.println("Update handler called " + (++update)
404             + " times");
405         System.out
406         .println("******************************************");
407         isUpdated = false; // TODO: saner update det method.
408         shutdown = System.currentTimeMillis()+10000;
409         if (update % 2 == 1)
410         {
411           try
412           {
413             IClientDocument cdoc = vorbaclient.getClientDocument();
414             processVamsasDocument(cdoc);
415           }
416           catch (Exception e)
417           {
418             System.err
419             .println("Error when updating document after an even numbered update.");
420             e.printStackTrace(System.err);
421           }
422         }
423       } else {
424         if (System.currentTimeMillis()>shutdown)
425         {
426           isShuttingdown=true;
427         }
428       }
429
430       try       { Thread.sleep(50); }
431       catch (Exception e) {}
432
433     }
434     System.out.println("Finalizing.");
435     // call finalizeClient
436     vorbaclient.finalizeClient();
437     System.out.println("Shutting down picker.");
438     picker.pm = null;
439     while (picker.isAlive())
440     {
441       System.out.println("Waiting for picker to die...");
442       try
443       {
444         Thread.sleep(1000);
445       }
446       catch (Exception e)
447       {
448       }
449       ;
450     }
451
452     // { meanwhile, eventHandlers are called to do any saves if need be }
453     // and all registered listeners will be deregistered to avoid deadlock.
454
455     // finish
456     System.out.println("Byee!");
457   }
458   public static void main(String[] args)
459   {
460     ExampleApplication example = new ExampleApplication();
461     example.runMe(args);
462   }
463 }