3bebe6d98742e830531665756a7b6fe2074618ef
[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.DataInput;
14 import java.io.DataInputStream;
15 import java.io.DataOutputStream;
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.ObjectInputStream;
20 import java.io.ObjectOutputStream;
21 import java.io.OutputStream;
22 import java.util.Vector;
23
24 /**
25  * Toy vamsas command line client application demonstrating the API. 
26  * Currently runs with one argument: ExampleApplication.main(new String("watch"))
27  * Test: Start up at least two of these processes independently and they will 
28  * successively modify and handle update events from the document model.
29  * 
30  * Behaviour of each client:
31  * Event handlers are registered for documentUpdate.
32  * - every document update:
33  *   * the vamsas document will be dumped to standard out using uk.ac.vamsas.test.simpleclient.ArchiveReports
34  *   * 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. 
35  * 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).
36  * A new vamsas root generated from uk.ac.vamsas.test.objects.Core.getDemoVamsas is added to the document.
37  * Then a while loop waits around for events until shutdown:
38  *  - currently it will shutdown after 9 updates (totalUpdates)
39  *  - an update will be made after every other update that is detected.
40  *  
41  * 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).
42  * 
43  * TODO: test
44  * appData get/set methods 
45  * 
46  * TODO: verify and test pickManager and interaction
47  * between it and other session events 
48  * 
49  * TODO: add more session interaction events
50  * 
51  * TODO: test client add/leave events - currently library generates exceptions for sessionlist and clientlist modifications.
52  * 
53  * @author jimp
54  */
55
56 public class ExampleApplication
57 {
58   private ClientHandle app;
59
60   private UserHandle user; // TODO: make this something defined by the
61   // api
62
63   private IClientFactory clientfactory;
64
65   private IClient vorbaclient;
66
67   private byte[] mydata;
68
69   private Vector vamsasObjects;
70
71   private boolean isUpdated = false;
72
73   private boolean isShuttingdown = false;
74
75   private boolean isFinalizing = false;
76   private int totalUpdates = 9;
77   private uk.ac.vamsas.client.VorbaId recover = null;
78   private int calls=0;
79   private long mdatahash = 0;
80   private long muserdatahash = 0;
81   
82   private void processVamsasDocument(IClientDocument doc)
83   {
84     if (doc.getVamsasRoots().length<4) {
85       doc.addVamsasRoot(Core.getDemoVamsas());
86     } else {
87       try {
88         uk.ac.vamsas.objects.core.DataSet ds = doc.getVamsasRoots()[1].getDataSet(0);
89         uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
90         if (recover==null)
91         {
92           recover = alsq.getVorbaId();
93         } else {
94           Vobject recoverd = doc.getObject(recover);
95           System.out.println("Recovery of "+recover+" was "+((recoverd==null) ? "A FAILURE" : "SUCCESSFUL"));
96         }
97         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
98         alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
99         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
100         System.out.println("Modified Sequence:\n"+alsq.getSequence());
101         doc.setVamsasRoots(doc.getVamsasRoots());
102       } catch (Exception ee) {
103         
104       }
105     }
106     // get this apps 'mydata' if it hasn't got it already.
107     System.out.println("Trying to get appdata and modify it.....");
108     try {
109       processAppData(doc);
110       System.out.println(".....Finished.");
111     } catch (Exception e)
112     {
113       System.err.println("Failed to process appdata for our application.");
114       e.printStackTrace(System.err);
115     }
116     
117     
118     // .. access this application's 'public' mydata' if there is any.
119     vorbaclient.updateDocument(doc);
120     // merge vamsasObjects with vamsas objects in document
121     
122   }
123   private int appdatareads=0;
124   private void processAppData(IClientDocument doc) throws Exception {
125     appdatareads++;
126     boolean writtenonce=false;
127     if (doc!=null)
128     {
129       uk.ac.vamsas.client.IClientAppdata appd = doc.getClientAppdata();
130       if (appd.hasClientAppdata() && !(appdatareads % 2==0))
131       {
132         //byte[] cappd = appd.getClientAppdata();
133         //if (cappd!=null)
134         //  System.out.println("Client appdata\n"+cappd.toString()+"\nEnd of Appdata\n");
135         System.out.println("Testing read from inputstream");
136         String cappds = readData(appd.getClientInputStream());
137         System.out.println("Client appdata\n"+cappds+"\nEnd of Appdata\n");
138       } else {
139         if (!writtenonce)
140         {  
141           writtenonce=true;
142           // appd.setClientAppdata(makeappData("Client Appdata for "+user.toString()+" written"));
143           writeData(appd.getClientOutputStream(), "Client Appdata for all users written on "+appdatareads+" read by "+vorbaclient.getUserHandle());
144           System.out.println("Written to ClientAppdata stream.");
145         }
146       }
147       if (appd.hasUserAppdata() && !(appdatareads % 2==0))
148       {
149         byte[] cappd = appd.getUserAppdata();
150         if (cappd!=null)
151           System.out.println("User appdata\n"+new String(cappd)+"\nEnd of Users' Appdata\n");
152         else
153         {
154           System.out.println("No user appdata.");
155           appd.setUserAppdata(("no default - overwritten null byte set on "+appdatareads+" read by "+vorbaclient.getUserHandle()+"").getBytes());
156         }
157       } else
158         if (!writtenonce)
159       {  
160         writtenonce=true;
161         byte[] bts = makeappData("User Appdata for "+user+" written on "+appdatareads+" read at ");
162         System.out.println("Setting appData bytes to\n"+new String(bts)+"\nEnd.");
163         appd.setUserAppdata(bts);
164         System.out.println("Written to UserAppdata stream.");
165       }
166     }
167   }
168   private byte[] makeappData(String message)
169   {
170     StringBuffer sb = new StringBuffer();
171     sb.append(message);
172     sb.append("on "+new java.util.Date());
173     return sb.toString().getBytes();
174   }
175   private boolean writeData(AppDataOutputStream os,  String message)
176   {
177     StringBuffer sb = new StringBuffer();
178     sb.append(message);
179     sb.append("on "+new java.util.Date());
180     try {
181       ObjectOutputStream oos = new ObjectOutputStream(os);
182       oos.writeObject(sb.toString());
183       oos.flush();
184       oos.close();
185     }
186     catch (Exception e) {
187       System.err.println("Problem serialising this message:\n"+sb);
188       e.printStackTrace(System.err);
189       return false;
190     }
191     return true;
192   }
193   private String readData(AppDataInputStream is)
194   {
195     try {
196       ObjectInputStream ois = new ObjectInputStream(is);
197       String rs = (String) ois.readObject();
198       return rs;
199     }
200     catch (Exception e)
201     {
202       System.err.println("Failed to read a string from input stream!");
203       e.printStackTrace(System.err);
204     }
205     return "";
206   }
207   private void addHandlers(IClient avorbaclient)
208   {
209     // make a non-volatile reference to the client instance.
210     final IClient vorbaclient = avorbaclient;
211     // register update handler
212     vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
213       public void propertyChange(PropertyChangeEvent evt)
214       {
215         System.out.println("Vamsas document update for "
216             + evt.getPropertyName() + ": " + evt.getOldValue()
217             + " to " + evt.getNewValue());
218         // merge new data into ours.
219         // example - output doc
220         try
221         {
222           IClientDocument cdoc = vorbaclient.getClientDocument();
223           if (calls>2 && cdoc.getVamsasRoots().length>0 && !cdoc.getVamsasRoots()[0].is__stored_in_document())
224           {
225             System.err.println("Pathological Update Detected - Document is zeroed!");
226           }
227           calls++;
228           uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(
229               cdoc.getVamsasRoots(), true, System.out);
230           // Simple update
231           try {
232             if (cdoc.getVamsasRoots().length>2) {
233               uk.ac.vamsas.objects.core.DataSet ds = cdoc.getVamsasRoots()[1].getDataSet(0);
234               uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
235               if (alsq.isUpdated())
236                 System.out.println("Seqeuence was updated since last time.");
237               alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
238               System.out.println("Newly Modified Sequence:\n"+alsq.getSequence());
239               cdoc.setVamsasRoots(cdoc.getVamsasRoots());
240             }
241           } catch (Exception ee) {
242             System.err.println("Exception whilst updating :");
243             ee.printStackTrace(System.err);
244           }
245           vorbaclient.updateDocument(cdoc);
246         }
247         catch (Exception e)
248         {
249           System.err
250           .println("Exception whilst dumping document tree after an update.");
251           e.printStackTrace(System.err);
252         }
253         isUpdated = true; // tell main thread to reflect change...
254       }
255     });
256     // register close handler
257     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE,
258         new PropertyChangeListener() {
259       public void propertyChange(PropertyChangeEvent evt)
260       {
261         System.out
262         .println("Received request to close vamsas document.");
263         // ask user for a filename to save it to.
264         // Then pass it to the vorba object...
265         vorbaclient.storeDocument(new java.io.File(
266         "UserLocation"));
267       }
268     });
269
270     // register some more handlers to monitor the session :
271
272     vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION,
273         new PropertyChangeListener() {
274       public void propertyChange(PropertyChangeEvent evt)
275       {
276         System.out.println("New Vamsas client for "
277             + evt.getPropertyName() + ": "
278             + evt.getOldValue() + " to "
279             + evt.getNewValue());
280         // tell app add new client to its list of clients.
281       }
282     });
283     vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION,
284         new PropertyChangeListener() {
285       public void propertyChange(PropertyChangeEvent evt)
286       {
287         System.out.println("Vamsas client finalizing for "
288             + evt.getPropertyName() + ": "
289             + evt.getOldValue() + " to "
290             + evt.getNewValue());
291         // tell app to update its list of clients to communicate
292         // with.
293       }
294     });
295     vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN,
296         new PropertyChangeListener() {
297       public void propertyChange(PropertyChangeEvent evt)
298       {
299         System.out.println("Session " + evt.getPropertyName()
300             + " is shutting down.");
301         // tell app to finalize its session data before
302         // shutdown.
303       }
304     });
305     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA,
306         new PropertyChangeListener() {
307       public void propertyChange(PropertyChangeEvent evt)
308       {
309         System.out
310         .println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
311         // tell app to finalize its session data prior to the
312         // storage of the current session as an archive.
313       }
314     });
315
316   }
317
318   public String Usage = "ExampleApplication :/n [-arena <vamsasFileDirectory>][-session <vamsasSessionURN>] <action> [+<arguments>]\n"
319     + "<action> is one of :\n\tsave,update,close,watch";
320
321   String sess = null;
322   String importFile=null;
323   String outputFile=null;
324   private boolean parseArgs(String args[])
325   {
326     if (args.length == 0)
327     {
328       return false;
329     }
330     int cpos=0;
331     boolean parsed=false;
332     while (!parsed && cpos<args.length)
333     {
334       if (args[cpos].toLowerCase().equals("load") && cpos+1<args.length)
335       {
336         importFile=args[cpos+1];
337         cpos+=2;
338         continue;
339       }
340       if (args[cpos].toLowerCase().equals("save") && cpos+1<args.length)
341       {
342         outputFile=args[cpos+1];
343         cpos+=2;
344         continue;
345       }
346       // default behaviour - if not anything else its probably a session urn
347       if (!args[cpos].toLowerCase().equals("watch"))
348       {
349         sess = args[cpos];
350       }
351       cpos++;
352     }
353     return true;
354   }
355   
356   class ExamplePicker extends Thread
357   {
358     String me = null;
359
360     public IPickManager pm = null;
361
362     ExamplePicker(String me, IPickManager pm)
363     {
364       this.me = me;
365       this.pm = pm;
366     }
367
368     public void run()
369     {
370       int mcount = 1;
371       while (pm != null)
372       {
373         try { Thread.sleep(1000 + (long) Math.random() * 10000); }
374         catch (Exception e) {}
375
376         if (pm != null)
377         {
378           pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage("Message " + mcount++ + " from " + me));
379         }
380       }
381     }
382
383   }
384   long shutdown = -1;
385   public void runMe(String[] args)
386   {
387     if (!parseArgs(args))
388     {
389       System.err.print(Usage);
390     }
391     // get IClientFactory
392     try
393     {
394       clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
395     }
396     catch (IOException e)
397     {
398       System.err.println(e + "\n" + Usage);
399       System.exit(1);
400     }
401
402     // get an Iclient with session data
403     app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication", "0.1");
404     user = new UserHandle("arnolduser", "deathsdoor");
405     try
406     {
407       if (sess!=null)
408       {
409         System.out.println("Connecting to "+sess);
410         vorbaclient = clientfactory.getIClient(app, user, sess);
411       }
412       else
413       {
414         vorbaclient = clientfactory.getIClient(app, user);
415       }
416     }
417     catch (NoDefaultSessionException e)
418     {
419       System.err
420       .println("There appear to be several sessions to choose from :");
421       String[] sessions = clientfactory.getCurrentSessions();
422       for (int s = 0; s < sessions.length; s++)
423         System.err.println(sessions[s]);
424       System.exit(2);
425     }
426     addHandlers(vorbaclient);
427     try
428     {
429       vorbaclient.joinSession();
430     }
431     catch (Exception se)
432     {
433       se.printStackTrace();
434       System.err.println(se + " when joining session.\n" + Usage);
435       System.exit(1);
436     }
437     // register an update listener and a close listener.
438     // import any data if requested to
439     if (importFile!=null)
440     {
441       File vfile = new File(importFile);
442       try
443       { 
444         vorbaclient.importDocument(vfile);
445       }
446       catch (Exception e)
447       {
448         System.err.println("Failed to import file "+importFile);
449         System.err.println("Exception received was "+e);
450         e.printStackTrace(System.err);
451       }
452       
453     }
454    // Write out any data if requested to
455     if (outputFile!=null)
456     {
457       File vfile = new File(outputFile);
458       try
459       { 
460         vorbaclient.storeDocument(vfile);
461       }
462       catch (Exception e)
463       {
464         System.err.println("Failed to export session as file "+outputFile);
465         System.err.println("Exception received was "+e);
466         e.printStackTrace(System.err);
467       }
468     }
469     // get document data
470     try
471     {
472       IClientDocument cdoc = vorbaclient.getClientDocument();
473       processVamsasDocument(cdoc);
474     }
475     catch (Exception e)
476     {
477       System.err
478       .println("Unexpected exception when retrieving the client document for the first time!");
479       e.printStackTrace(System.err);
480       System.exit(1);
481     }
482     int update = 0;
483     ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle()
484         .getClientUrn(), vorbaclient.getPickManager());
485
486     picker.start();
487     if (picker.pm!=null) {
488       picker.pm.registerMessageHandler(new IMessageHandler() {
489
490         public void handleMessage(Message message)
491         {
492           System.out
493           .println("Received |" + message.getRawMessage() + "|");
494           shutdown +=100; // hang around for 5 seconds or so before dying naturally. 
495           
496         }
497
498       });
499     }
500     shutdown = System.currentTimeMillis()+10000; // hang around for 10 seconds or so before dying naturally. 
501     while (!isShuttingdown && update < totalUpdates)
502     {
503       // do something with data
504       // , update document, or something.
505       // ..
506       if (isUpdated)
507       {
508         System.out.println("Update handler called " + (++update)
509             + " times");
510         System.out
511         .println("******************************************");
512         isUpdated = false; // TODO: saner update det method.
513         shutdown = System.currentTimeMillis()+10000;
514         if (update % 2 == 1)
515         {
516           try
517           {
518             IClientDocument cdoc = vorbaclient.getClientDocument();
519             processVamsasDocument(cdoc);
520           }
521           catch (Exception e)
522           {
523             System.err
524             .println("Error when updating document after an even numbered update.");
525             e.printStackTrace(System.err);
526           }
527         }
528       } else {
529         if (System.currentTimeMillis()>shutdown)
530         {
531           isShuttingdown=true;
532         }
533       }
534
535       try       { Thread.sleep(50); }
536       catch (Exception e) {}
537
538     }
539     System.out.println("Finalizing.");
540     // call finalizeClient
541     vorbaclient.finalizeClient();
542     System.out.println("Shutting down picker.");
543     picker.pm = null;
544     while (picker.isAlive())
545     {
546       System.out.println("Waiting for picker to die...");
547       try
548       {
549         Thread.sleep(1000);
550       }
551       catch (Exception e)
552       {
553       }
554       ;
555     }
556
557     // { meanwhile, eventHandlers are called to do any saves if need be }
558     // and all registered listeners will be deregistered to avoid deadlock.
559
560     // finish
561     System.out.println("Byee!");
562   }
563   public static void main(String[] args)
564   {
565     ExampleApplication example = new ExampleApplication();
566     example.runMe(args);
567   }
568 }