better command line processing options (load, save) and slower update poll check.
[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 void processVamsasDocument(IClientDocument doc)
71   {
72     if (doc.getVamsasRoots().length<4) {
73     doc.addVamsasRoot(Core.getDemoVamsas());
74     } else {
75       try {
76         uk.ac.vamsas.objects.core.DataSet ds = doc.getVamsasRoots()[1].getDataSet(0);
77         uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
78         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
79         alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
80         System.out.println("Modifying Sequence:\n"+alsq.hashCode());
81         System.out.println("Modified Sequence:\n"+alsq.getSequence());
82         doc.setVamsasRoots(doc.getVamsasRoots());
83       } catch (Exception ee) {
84       
85       }
86     }
87     vorbaclient.updateDocument(doc);
88     // merge vamsasObjects with vamsas objects in document
89     // get this apps 'mydata' if it hasn't got it already.
90     // .. access this application's 'public' mydata' if there is any.
91   }
92
93   private void addHandlers(IClient avorbaclient)
94   {
95     // make a non-volatile reference to the client instance.
96     final IClient vorbaclient = avorbaclient;
97     // register update handler
98     vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() {
99       public void propertyChange(PropertyChangeEvent evt)
100       {
101         System.out.println("Vamsas document update for "
102             + evt.getPropertyName() + ": " + evt.getOldValue()
103             + " to " + evt.getNewValue());
104         // merge new data into ours.
105         // example - output doc
106         try
107         {
108           IClientDocument cdoc = vorbaclient.getClientDocument();
109           uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport(
110               cdoc.getVamsasRoots(), true, System.out);
111           // Simple update
112           try {
113             if (cdoc.getVamsasRoots().length>2) {
114               uk.ac.vamsas.objects.core.DataSet ds = cdoc.getVamsasRoots()[1].getDataSet(0);
115               uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0);
116               if (alsq.isUpdated())
117                 System.out.println("Seqeuence was updated since last time.");
118               alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar());
119               System.out.println("Newly Modified Sequence:\n"+alsq.getSequence());
120               cdoc.setVamsasRoots(cdoc.getVamsasRoots());
121             }
122           } catch (Exception ee) {
123             System.err.println("Exception whilst updating :");
124             ee.printStackTrace(System.err);
125           }
126           vorbaclient.updateDocument(cdoc);
127         }
128         catch (Exception e)
129         {
130           System.err
131           .println("Exception whilst dumping document tree after an update.");
132           e.printStackTrace(System.err);
133         }
134         isUpdated = true; // tell main thread to reflect change...
135       }
136     });
137     // register close handler
138     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE,
139         new PropertyChangeListener() {
140       public void propertyChange(PropertyChangeEvent evt)
141       {
142         System.out
143         .println("Received request to close vamsas document.");
144         // ask user for a filename to save it to.
145         // Then pass it to the vorba object...
146         vorbaclient.storeDocument(new java.io.File(
147         "UserLocation"));
148       }
149     });
150
151     // register some more handlers to monitor the session :
152
153     vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION,
154         new PropertyChangeListener() {
155       public void propertyChange(PropertyChangeEvent evt)
156       {
157         System.out.println("New Vamsas client for "
158             + evt.getPropertyName() + ": "
159             + evt.getOldValue() + " to "
160             + evt.getNewValue());
161         // tell app add new client to its list of clients.
162       }
163     });
164     vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION,
165         new PropertyChangeListener() {
166       public void propertyChange(PropertyChangeEvent evt)
167       {
168         System.out.println("Vamsas client finalizing for "
169             + evt.getPropertyName() + ": "
170             + evt.getOldValue() + " to "
171             + evt.getNewValue());
172         // tell app to update its list of clients to communicate
173         // with.
174       }
175     });
176     vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN,
177         new PropertyChangeListener() {
178       public void propertyChange(PropertyChangeEvent evt)
179       {
180         System.out.println("Session " + evt.getPropertyName()
181             + " is shutting down.");
182         // tell app to finalize its session data before
183         // shutdown.
184       }
185     });
186     vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA,
187         new PropertyChangeListener() {
188       public void propertyChange(PropertyChangeEvent evt)
189       {
190         System.out
191         .println("Application received a DOCUMENT_FINALIZEAPPDATA event.");
192         // tell app to finalize its session data prior to the
193         // storage of the current session as an archive.
194       }
195     });
196
197   }
198
199   public String Usage = "ExampleApplication :/n [-arena <vamsasFileDirectory>][-session <vamsasSessionURN>] <action> [+<arguments>]\n"
200     + "<action> is one of :\n\tsave,update,close,watch";
201
202   String sess = null;
203   String importFile=null;
204   String outputFile=null;
205   private boolean parseArgs(String args[])
206   {
207     if (args.length == 0)
208     {
209       return false;
210     }
211     int cpos=0;
212     boolean parsed=false;
213     while (!parsed && cpos<args.length)
214     {
215       if (args[cpos].toLowerCase().equals("load") && cpos+1<args.length)
216       {
217         importFile=args[cpos+1];
218         cpos+=2;
219         continue;
220       }
221       if (args[cpos].toLowerCase().equals("save") && cpos+1<args.length)
222       {
223         outputFile=args[cpos+1];
224         cpos+=2;
225         continue;
226       }
227       // default behaviour - if not anything else its probably a session urn
228       if (!args[cpos].toLowerCase().equals("watch"))
229       {
230         sess = args[cpos];
231       }
232       cpos++;
233     }
234     return true;
235   }
236   
237   class ExamplePicker extends Thread
238   {
239     String me = null;
240
241     public IPickManager pm = null;
242
243     ExamplePicker(String me, IPickManager pm)
244     {
245       this.me = me;
246       this.pm = pm;
247     }
248
249     public void run()
250     {
251       int mcount = 1;
252       while (pm != null)
253       {
254         try { Thread.sleep(1000 + (long) Math.random() * 10000); }
255         catch (Exception e) {}
256
257         if (pm != null)
258         {
259           pm.sendMessage(new uk.ac.vamsas.client.picking.CustomMessage("Message " + mcount++ + " from " + me));
260         }
261       }
262     }
263
264   }
265
266   public void runMe(String[] args)
267   {
268     if (!parseArgs(args))
269     {
270       System.err.print(Usage);
271     }
272     // get IClientFactory
273     try
274     {
275       clientfactory = new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
276     }
277     catch (IOException e)
278     {
279       System.err.println(e + "\n" + Usage);
280       System.exit(1);
281     }
282
283     // get an Iclient with session data
284     app = new ClientHandle("uk.ac.vamsas.test.ExampleApplication", "0.1");
285     user = new UserHandle("arnolduser", "deathsdoor");
286     try
287     {
288       if (sess!=null)
289       {
290         System.out.println("Connecting to "+sess);
291         vorbaclient = clientfactory.getIClient(app, user, sess);
292       }
293       else
294       {
295         vorbaclient = clientfactory.getIClient(app, user);
296       }
297     }
298     catch (NoDefaultSessionException e)
299     {
300       System.err
301       .println("There appear to be several sessions to choose from :");
302       String[] sessions = clientfactory.getCurrentSessions();
303       for (int s = 0; s < sessions.length; s++)
304         System.err.println(sessions[s]);
305       System.exit(2);
306     }
307     addHandlers(vorbaclient);
308     try
309     {
310       vorbaclient.joinSession();
311     }
312     catch (Exception se)
313     {
314       se.printStackTrace();
315       System.err.println(se + " when joining session.\n" + Usage);
316       System.exit(1);
317     }
318     // register an update listener and a close listener.
319     // import any data if requested to
320     if (importFile!=null)
321     {
322       File vfile = new File(importFile);
323       try
324       { 
325         vorbaclient.importDocument(vfile);
326       }
327       catch (Exception e)
328       {
329         System.err.println("Failed to import file "+importFile);
330         System.err.println("Exception received was "+e);
331         e.printStackTrace(System.err);
332       }
333       
334     }
335    // Write out any data if requested to
336     if (outputFile!=null)
337     {
338       File vfile = new File(outputFile);
339       try
340       { 
341         vorbaclient.storeDocument(vfile);
342       }
343       catch (Exception e)
344       {
345         System.err.println("Failed to export session as file "+outputFile);
346         System.err.println("Exception received was "+e);
347         e.printStackTrace(System.err);
348       }
349     }
350     // get document data
351     try
352     {
353       IClientDocument cdoc = vorbaclient.getClientDocument();
354       processVamsasDocument(cdoc);
355     }
356     catch (Exception e)
357     {
358       System.err
359       .println("Unexpected exception when retrieving the client document for the first time!");
360       e.printStackTrace(System.err);
361       System.exit(1);
362     }
363     int update = 0;
364     ExamplePicker picker = new ExamplePicker(vorbaclient.getClientHandle()
365         .getClientUrn(), vorbaclient.getPickManager());
366
367     picker.start();
368     if (picker.pm!=null) {
369       picker.pm.registerMessageHandler(new IMessageHandler() {
370
371         public void handleMessage(Message message)
372         {
373           System.out
374           .println("Received |" + message.getRawMessage() + "|");
375         }
376
377       });
378     }
379     while (!isShuttingdown && update < totalUpdates)
380     {
381       // do something with data
382       // , update document, or something.
383       // ..
384       if (isUpdated)
385       {
386         System.out.println("Update handler called " + (++update)
387             + " times");
388         System.out
389         .println("******************************************");
390         isUpdated = false; // TODO: saner update det method.
391         if (update % 2 == 1)
392         {
393           try
394           {
395             IClientDocument cdoc = vorbaclient.getClientDocument();
396             processVamsasDocument(cdoc);
397           }
398           catch (Exception e)
399           {
400             System.err
401             .println("Error when updating document after an even numbered update.");
402             e.printStackTrace(System.err);
403           }
404         }
405       }
406
407       try       { Thread.sleep(50); }
408       catch (Exception e) {}
409
410     }
411     System.out.println("Finalizing.");
412     // call finalizeClient
413     vorbaclient.finalizeClient();
414     System.out.println("Shutting down picker.");
415     picker.pm = null;
416     while (picker.isAlive())
417     {
418       System.out.println("Waiting for picker to die...");
419       try
420       {
421         Thread.sleep(1000);
422       }
423       catch (Exception e)
424       {
425       }
426       ;
427     }
428
429     // { meanwhile, eventHandlers are called to do any saves if need be }
430     // and all registered listeners will be deregistered to avoid deadlock.
431
432     // finish
433     System.out.println("Byee!");
434   }
435   public static void main(String[] args)
436   {
437     ExampleApplication example = new ExampleApplication();
438     example.runMe(args);
439   }
440 }