package uk.ac.vamsas.test; import uk.ac.vamsas.client.*; import uk.ac.vamsas.client.picking.IMessageHandler; import uk.ac.vamsas.client.picking.IPickManager; import uk.ac.vamsas.client.picking.Message; import uk.ac.vamsas.objects.core.VAMSAS; import uk.ac.vamsas.test.objects.Core; import java.awt.Event; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.DataInput; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.Vector; /** * Toy vamsas command line client application demonstrating the API. * Currently runs with one argument: ExampleApplication.main(new String("watch")) * Test: Start up at least two of these processes independently and they will * successively modify and handle update events from the document model. * * Behaviour of each client: * Event handlers are registered for documentUpdate. * - every document update: * * the vamsas document will be dumped to standard out using uk.ac.vamsas.test.simpleclient.ArchiveReports * * 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. * 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). * A new vamsas root generated from uk.ac.vamsas.test.objects.Core.getDemoVamsas is added to the document. * Then a while loop waits around for events until shutdown: * - currently it will shutdown after 9 updates (totalUpdates) * - an update will be made after every other update that is detected. * * 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). * * TODO: test * appData get/set methods * * TODO: verify and test pickManager and interaction * between it and other session events * * TODO: add more session interaction events * * TODO: test client add/leave events - currently library generates exceptions for sessionlist and clientlist modifications. * * @author jimp */ public class ExampleApplication { private ClientHandle app; private UserHandle user; // TODO: make this something defined by the // api private IClientFactory clientfactory; private IClient vorbaclient; private byte[] mydata; private Vector vamsasObjects; private boolean isUpdated = false; private boolean isShuttingdown = false; private boolean isFinalizing = false; private int totalUpdates = 9; private uk.ac.vamsas.client.VorbaId recover = null; private int calls=0; private long mdatahash = 0; private long muserdatahash = 0; private void processVamsasDocument(IClientDocument doc) { if (doc.getVamsasRoots().length<4) { doc.addVamsasRoot(Core.getDemoVamsas()); } else { try { uk.ac.vamsas.objects.core.DataSet ds = doc.getVamsasRoots()[1].getDataSet(0); uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0); if (recover==null) { recover = alsq.getVorbaId(); } else { Vobject recoverd = doc.getObject(recover); System.out.println("Recovery of "+recover+" was "+((recoverd==null) ? "A FAILURE" : "SUCCESSFUL")); } System.out.println("Modifying Sequence:\n"+alsq.hashCode()); alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar()); System.out.println("Modifying Sequence:\n"+alsq.hashCode()); System.out.println("Modified Sequence:\n"+alsq.getSequence()); doc.setVamsasRoots(doc.getVamsasRoots()); } catch (Exception ee) { } } // get this apps 'mydata' if it hasn't got it already. System.out.println("Trying to get appdata and modify it....."); try { processAppData(doc); System.out.println(".....Finished."); } catch (Exception e) { System.err.println("Failed to process appdata for our application."); e.printStackTrace(System.err); } // .. access this application's 'public' mydata' if there is any. vorbaclient.updateDocument(doc); // merge vamsasObjects with vamsas objects in document } private int appdatareads=0; private void processAppData(IClientDocument doc) throws Exception { appdatareads++; boolean writtenonce=false; if (doc!=null) { uk.ac.vamsas.client.IClientAppdata appd = doc.getClientAppdata(); if (appd.hasClientAppdata() && !(appdatareads % 2==0)) { //byte[] cappd = appd.getClientAppdata(); //if (cappd!=null) // System.out.println("Client appdata\n"+cappd.toString()+"\nEnd of Appdata\n"); System.out.println("Testing read from inputstream"); String cappds = readData(appd.getClientInputStream()); System.out.println("Client appdata\n"+cappds+"\nEnd of Appdata\n"); } else { if (!writtenonce) { writtenonce=true; // appd.setClientAppdata(makeappData("Client Appdata for "+user.toString()+" written")); writeData(appd.getClientOutputStream(), "Client Appdata for all users written on "+appdatareads+" read by "+vorbaclient.getUserHandle()); System.out.println("Written to ClientAppdata stream."); } } if (appd.hasUserAppdata() && !(appdatareads % 2==0)) { byte[] cappd = appd.getUserAppdata(); if (cappd!=null) System.out.println("User appdata\n"+new String(cappd)+"\nEnd of Users' Appdata\n"); else { System.out.println("No user appdata."); appd.setUserAppdata(("no default - overwritten null byte set on "+appdatareads+" read by "+vorbaclient.getUserHandle()+"").getBytes()); } } else if (!writtenonce) { writtenonce=true; byte[] bts = makeappData("User Appdata for "+user+" written on "+appdatareads+" read at "); System.out.println("Setting appData bytes to\n"+new String(bts)+"\nEnd."); appd.setUserAppdata(bts); System.out.println("Written to UserAppdata stream."); } } } private byte[] makeappData(String message) { StringBuffer sb = new StringBuffer(); sb.append(message); sb.append("on "+new java.util.Date()); return sb.toString().getBytes(); } private boolean writeData(AppDataOutputStream os, String message) { StringBuffer sb = new StringBuffer(); sb.append(message); sb.append("on "+new java.util.Date()); try { ObjectOutputStream oos = new ObjectOutputStream(os); oos.writeObject(sb.toString()); oos.flush(); oos.close(); } catch (Exception e) { System.err.println("Problem serialising this message:\n"+sb); e.printStackTrace(System.err); return false; } return true; } private String readData(AppDataInputStream is) { try { ObjectInputStream ois = new ObjectInputStream(is); String rs = (String) ois.readObject(); return rs; } catch (Exception e) { System.err.println("Failed to read a string from input stream!"); e.printStackTrace(System.err); } return ""; } private void addHandlers(IClient avorbaclient) { // make a non-volatile reference to the client instance. final IClient vorbaclient = avorbaclient; // register update handler vorbaclient.addDocumentUpdateHandler(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out.println("Vamsas document update for " + evt.getPropertyName() + ": " + evt.getOldValue() + " to " + evt.getNewValue()); // merge new data into ours. // example - output doc try { IClientDocument cdoc = vorbaclient.getClientDocument(); if (calls>2 && cdoc.getVamsasRoots().length>0 && !cdoc.getVamsasRoots()[0].is__stored_in_document()) { System.err.println("Pathological Update Detected - Document is zeroed!"); } calls++; uk.ac.vamsas.test.simpleclient.ArchiveReports.rootReport( cdoc.getVamsasRoots(), true, System.out); // Simple update try { if (cdoc.getVamsasRoots().length>2) { uk.ac.vamsas.objects.core.DataSet ds = cdoc.getVamsasRoots()[1].getDataSet(0); uk.ac.vamsas.objects.core.AlignmentSequence alsq = ds.getAlignment(0).getAlignmentSequence(0); if (alsq.isUpdated()) System.out.println("Seqeuence was updated since last time."); alsq.setSequence(alsq.getSequence()+ds.getAlignment(0).getGapChar()); System.out.println("Newly Modified Sequence:\n"+alsq.getSequence()); cdoc.setVamsasRoots(cdoc.getVamsasRoots()); } } catch (Exception ee) { System.err.println("Exception whilst updating :"); ee.printStackTrace(System.err); } vorbaclient.updateDocument(cdoc); } catch (Exception e) { System.err .println("Exception whilst dumping document tree after an update."); e.printStackTrace(System.err); } isUpdated = true; // tell main thread to reflect change... } }); // register close handler vorbaclient.addVorbaEventHandler(Events.DOCUMENT_REQUESTTOCLOSE, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out .println("Received request to close vamsas document."); // ask user for a filename to save it to. // Then pass it to the vorba object... vorbaclient.storeDocument(new java.io.File( "UserLocation")); } }); // register some more handlers to monitor the session : vorbaclient.addVorbaEventHandler(Events.CLIENT_CREATION, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out.println("New Vamsas client for " + evt.getPropertyName() + ": " + evt.getOldValue() + " to " + evt.getNewValue()); // tell app add new client to its list of clients. } }); vorbaclient.addVorbaEventHandler(Events.CLIENT_FINALIZATION, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out.println("Vamsas client finalizing for " + evt.getPropertyName() + ": " + evt.getOldValue() + " to " + evt.getNewValue()); // tell app to update its list of clients to communicate // with. } }); vorbaclient.addVorbaEventHandler(Events.SESSION_SHUTDOWN, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out.println("Session " + evt.getPropertyName() + " is shutting down."); // tell app to finalize its session data before // shutdown. } }); vorbaclient.addVorbaEventHandler(Events.DOCUMENT_FINALIZEAPPDATA, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { System.out .println("Application received a DOCUMENT_FINALIZEAPPDATA event."); // tell app to finalize its session data prior to the // storage of the current session as an archive. } }); } public String Usage = "ExampleApplication :/n [-arena ][-session ] [+]\n" + " is one of :\n\tsave,update,close,watch"; String sess = null; String importFile=null; String outputFile=null; private boolean parseArgs(String args[]) { if (args.length == 0) { return false; } int cpos=0; boolean parsed=false; while (!parsed && cposshutdown) { isShuttingdown=true; } } try { Thread.sleep(50); } catch (Exception e) {} } System.out.println("Finalizing."); // call finalizeClient vorbaclient.finalizeClient(); System.out.println("Shutting down picker."); picker.pm = null; while (picker.isAlive()) { System.out.println("Waiting for picker to die..."); try { Thread.sleep(1000); } catch (Exception e) { } ; } // { meanwhile, eventHandlers are called to do any saves if need be } // and all registered listeners will be deregistered to avoid deadlock. // finish System.out.println("Byee!"); } public static void main(String[] args) { ExampleApplication example = new ExampleApplication(); example.runMe(args); } }