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