From ef985efd6a509d94567170da164c57a65b3b11ee Mon Sep 17 00:00:00 2001 From: jprocter Date: Wed, 13 Sep 2006 14:25:32 +0000 Subject: [PATCH] jalview'esque vamsas session example for org.vamsas.test.simpleclient.ArchiveClient test model. git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@243 be28352e-c001-0410-b1a7-c7978e42abec --- .../test/simpleclient/simpleapp/VamsasClient.java | 186 +++++++++++ .../simpleclient/simpleapp/VamsasDatastore.java | 333 ++++++++++++++++++++ 2 files changed, 519 insertions(+) create mode 100644 src/org/vamsas/test/simpleclient/simpleapp/VamsasClient.java create mode 100644 src/org/vamsas/test/simpleclient/simpleapp/VamsasDatastore.java diff --git a/src/org/vamsas/test/simpleclient/simpleapp/VamsasClient.java b/src/org/vamsas/test/simpleclient/simpleapp/VamsasClient.java new file mode 100644 index 0000000..2b70a0a --- /dev/null +++ b/src/org/vamsas/test/simpleclient/simpleapp/VamsasClient.java @@ -0,0 +1,186 @@ +/** + * + */ +package org.vamsas.test.simpleclient.simpleapp; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Vector; +import java.util.jar.JarOutputStream; + +import javax.swing.JInternalFrame; + +import org.vamsas.client.UserHandle; +import org.vamsas.client.simpleclient.FileWatcher; +import org.vamsas.client.simpleclient.VamsasArchive; +import org.vamsas.client.simpleclient.VamsasFile; +import org.vamsas.objects.core.Entry; +import org.vamsas.objects.core.VamsasDocument; +import org.vamsas.test.simpleclient.ArchiveClient; +import org.vamsas.test.simpleclient.ClientDoc; + +/** + * @author jimp + * + */ +public class VamsasClient extends ArchiveClient { + org.apache.commons.logging.Log log=org.apache.commons.logging.LogFactory.getLog(VamsasClient.class); + /** + * create a new vamsas client session from the archive at sessionPath. + * @param sessionPath + */ + public VamsasClient(File sessionPath) { + super(System.getProperty("user.name"),System.getProperty("host.name"), "SimpleVamsasClientApp","0.1", + sessionPath); + } + /** + * Called by gui to read anything from the vamsas session into the apps datamodel + * after it has started up. + * + */ + public void initial_update() { + log.info("Jalview loading the Vamsas Session."); + // load in the vamsas archive for the first time + ClientDoc cdoc = this.getUpdateable(); + updateJalview(cdoc); + // TODO: flush any new VorbaIds to the document : updateVamsasClient may actually generate new Vamsas Document data in the form of vamsas element ids - these should be written back to the document. + //doUpdate(cdoc); // JBPNote: this should flush new VorbaIds but I've not tested it yet. + cdoc.closeDoc(); + // then tell app to update its display based on the datamodel changes. + } + VamsasClientWatcher watcher=null; + /** + * Called by app when internal datamodel should exported (syncrhonised outwards) to vamsas document + * + */ + public void push_update() { + + watchForChange=false; // this makes any watch(long) loops return. + // we should also wait arount for this.WATCH_SLEEP to really make sure the watcher thread has stopped. + try { + Thread.sleep(WATCH_SLEEP); + } catch (Exception e) { + + }; + + ClientDoc cdoc = getUpdateable(); + updateVamsasDocument(cdoc); + doUpdate(cdoc); + cdoc.closeDoc(); + cdoc=null; + watchForChange=true; + startWatcher(); + } + public void end_session() { + watchForChange=false; // this makes any watch(long) loops return. + // we should also wait arount for this.WATCH_SLEEP to really make sure the watcher thread has stopped. + try { + Thread.sleep(WATCH_SLEEP); + } catch (Exception e) { + + }; + + // stop any update/watcher thread. + log.info("VamsasClientApplication disconnecting from the Vamsas Session."); + } + public void updateJalview(ClientDoc cdoc) { + ensureVamsasBindings(); + VamsasDatastore vds = new VamsasDatastore(cdoc, vobj2jv, jv2vobj, baseProvEntry()); + vds.updateToJalview(); + } + private void ensureVamsasBindings() { + if (jv2vobj==null) { + jv2vobj = new IdentityHashMap(); + vobj2jv = new Hashtable(); + } + } + /** + * App's object binding to VorbaIds + */ + IdentityHashMap jv2vobj = null; + Hashtable vobj2jv = null; + /** + * called with a vamsas document which will be updated with new data from the app + * @param doc + */ + public void updateVamsasDocument(ClientDoc doc) { + ensureVamsasBindings(); + VamsasDatastore vds = new VamsasDatastore(doc, vobj2jv, jv2vobj, baseProvEntry()); + // wander through frames + vds.storeVAMSAS(new Object()); // Object is the apps datamodel ;) + } + /** + * + * @return a base provenance entry used by the VamsasDatastore object to get attributes from. this isn't particularly elegant either. + */ + private Entry baseProvEntry() { + org.vamsas.objects.core.Entry pentry = new org.vamsas.objects.core.Entry(); + pentry.setUser(this.getProvenanceUser()); + pentry.setApp(this.getClientHandle().getClientName()); + pentry.setDate(new org.exolab.castor.types.Date(new java.util.Date())); + pentry.setAction("created"); + return pentry; + } + protected class VamsasClientWatcher extends Thread implements Runnable { + /* (non-Javadoc) + * @see java.lang.Thread#run() + */ + VamsasClient client=null; + VamsasClientWatcher(VamsasClient client) { + this.client = client; + } + boolean running=false; + public void run() { + running=true; + while (client.watchForChange) { + ClientDoc docio = client.watch(0); + if (docio!=null) { + // VamsasClient GUI bits should be disabled whilst an update is in progress so the user doesn't screw anything up. + client.disableGui(true); + log.debug("Updating VamsasClient app from changed vamsas document."); + client.updateJalview(docio); + log.debug("Finished updating from document change."); + docio.closeDoc(); + docio=null; + client.disableGui(false); + } + } + running=false; + + } + + } + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + /** + * disable (if b is true) or enable (if b is true) the VamsasClient's vamsas session gui bits whilst a document change is being updated to the app. + * @param b + */ + public void disableGui(boolean b) { + // in jalview, we turn off the VAMSAS Session menu : Desktop.instance.setVamsasUpdate(b); + } + /** + * spawn a new thread to start the VamsasClientWatcher. + * + */ + public void startWatcher() { + if (watcher==null) + watcher=new VamsasClientWatcher(this); + Thread thr = new Thread() { + public void run() { + watcher.start(); + } + }; + thr.start(); + } + +} diff --git a/src/org/vamsas/test/simpleclient/simpleapp/VamsasDatastore.java b/src/org/vamsas/test/simpleclient/simpleapp/VamsasDatastore.java new file mode 100644 index 0000000..9114e88 --- /dev/null +++ b/src/org/vamsas/test/simpleclient/simpleapp/VamsasDatastore.java @@ -0,0 +1,333 @@ +/* + * VamsasClientSimpleApp - A framework for interoparable Sequence analysis + * Copyright (C) 2006 VAMSAS + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +package org.vamsas.test.simpleclient.simpleapp; + +import org.vamsas.client.Vobject; +import org.vamsas.client.VorbaId; +import org.vamsas.objects.core.*; +import org.vamsas.objects.utils.DocumentStuff; +import org.vamsas.test.simpleclient.ClientDoc; + + +import java.io.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.IdentityHashMap; +import java.util.Vector; +import java.util.jar.*; +import org.exolab.castor.xml.*; +import org.exolab.castor.mapping.Mapping; + +/* + * + * static { + * org.exolab.castor.util.LocalConfiguration.getInstance().getProperties().setProperty( + * "org.exolab.castor.serializer", "org.apache.xml.serialize.XMLSerilazizer"); } + * + */ + +public class VamsasDatastore { + org.apache.commons.logging.Log log=org.apache.commons.logging.LogFactory.getLog(VamsasDatastore.class); + Entry provEntry = null; + + + org.exolab.castor.types.Date date = new org.exolab.castor.types.Date( + new java.util.Date()); + + ClientDoc cdoc; + + Hashtable vobj2jv; + + IdentityHashMap jv2vobj; + + public VamsasDatastore(ClientDoc cdoc, Hashtable vobj2jv, + IdentityHashMap jv2vobj, Entry provEntry) { + this.cdoc = cdoc; + this.vobj2jv = vobj2jv; + this.jv2vobj = jv2vobj; + this.provEntry = provEntry; + } + + /* + * public void storeJalview(String file, AlignFrame af) { try { // 1. Load the + * mapping information from the file Mapping map = new + * Mapping(getClass().getClassLoader()); java.net.URL url = + * getClass().getResource("/jalview_mapping.xml"); map.loadMapping(url); // 2. + * Unmarshal the data // Unmarshaller unmar = new Unmarshaller(); + * //unmar.setIgnoreExtraElements(true); //unmar.setMapping(map); // uni = + * (UniprotFile) unmar.unmarshal(new FileReader(file)); // 3. marshal the data + * with the total price back and print the XML in the console Marshaller + * marshaller = new Marshaller( new FileWriter(file) ); + * + * marshaller.setMapping(map); marshaller.marshal(af); } catch (Exception e) { + * e.printStackTrace(); } } + * + * + */ + /** + * @return the Vobject bound to Jalview datamodel object + */ + protected Vobject getjv2vObj(Object jvobj) { + if (jv2vobj.containsKey(jvobj)) + return cdoc.getObject((VorbaId) jv2vobj.get(jvobj)); + return null; + } + + /** + * + * @param vobj + * @return Jalview datamodel object bound to the vamsas document object + */ + protected Object getvObj2jv(org.vamsas.client.Vobject vobj) { + VorbaId id = vobj.getVorbaId(); + if (id == null) + { + id = cdoc.registerObject(vobj); + log + .debug("Registering new object and returning null for getvObj2jv"); + return null; + } + if (vobj2jv.containsKey(vobj.getVorbaId())) + return vobj2jv.get(vobj.getVorbaId()); + return null; + } + + protected void bindjvvobj(Object jvobj, org.vamsas.client.Vobject vobj) { + VorbaId id = vobj.getVorbaId(); + if (id == null) + { + id = cdoc.registerObject(vobj); + if (id==null || vobj.getVorbaId()==null) + log.error("Failed to get id for "+(vobj.isRegisterable() ? "registerable" : "unregisterable") +" object "+vobj); + } + if (vobj2jv.containsKey(vobj.getVorbaId()) || jv2vobj.containsKey(jvobj)) + { + log.error("Duplicate object binding! "+vobj+" id " +vobj.getVorbaId().getId()+" to "+jvobj); + } + else + { + vobj2jv.put(vobj.getVorbaId(), jvobj);// JBPNote - better implementing a + // hybrid invertible hash. + jv2vobj.put(jvobj, vobj.getVorbaId()); + } + } + + /** + * put the alignment viewed by AlignViewport into cdoc. + * + * @param av + */ + public void storeVAMSAS(Object fromAppsDatamodel) { + boolean nw = false; + VAMSAS root = null; // will be resolved based on Dataset Parent. + DataSet dataset = (DataSet) getjv2vObj(fromAppsDatamodel); + if (dataset == null) + { + root = cdoc.getVamsasRoots()[0]; // default vamsas root for modifying. + dataset = new DataSet(); + root.addDataSet(dataset); + bindjvvobj(fromAppsDatamodel, dataset); + dataset.setProvenance(dummyProvenance()); + dataset.getProvenance().addEntry(provEntry); + nw = true; + } else { + root = (VAMSAS) dataset.getV_parent(); + } + // etc... + } + + private Property newProperty(String name, String type, String content) { + Property vProperty=new Property(); + vProperty.setName(name); + if (type!=null) + vProperty.setType(type); + vProperty.setContent(content); + return vProperty; + } + + /** + * get start0 && dseta.getPosCount()>0) + throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!"); + if (dseta.getSegCount() > 0) + { + se = getSegRange(dseta.getSeg(0),true); + for (int s = 1, sSize = dseta.getSegCount(); s < sSize; s++) + { + int nse[] = getSegRange(dseta.getSeg(s), true); + if (se[0] > nse[0]) + se[0] = nse[0]; + if (se[1] < nse[1]) + se[1] = nse[1]; + } + } + if (dseta.getPosCount() > 0) + { + // could do a polarity for pos range too. and pass back indication of discontinuities. + int pos = dseta.getPos(0).getI(); + se = new int[] { pos, pos }; + for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++) + { + pos = dseta.getPos(p).getI(); + if (se[0] > pos) + se[0] = pos; + if (se[1] < pos) + se[1] = pos; + } + } + return se; + } + return null; + } + /** + * map from a rangeType's internal frame to the referenced object's coordinate frame. + * @param dseta + * @return int [] { ref(pos)...} for all pos in rangeType's frame. + */ + private int[] getMapping(RangeType dseta) { + Vector posList=new Vector(); + if (dseta != null) + { + int[] se = null; + if (dseta.getSegCount()>0 && dseta.getPosCount()>0) + throw new Error("Invalid vamsas RangeType - cannot resolve both lists of Pos and Seg from choice!"); + if (dseta.getSegCount() > 0) + { + for (int s = 0, sSize = dseta.getSegCount(); s < sSize; s++) + { + se = getSegRange(dseta.getSeg(s), false); + int se_end=se[1-se[2]]+(se[2]==0 ? 1 : -1); + for (int p=se[se[2]]; p!=se_end; p+=se[2]==0 ? 1 : -1 ) { + posList.add(Integer.valueOf(p)); + } + } + } + else if (dseta.getPosCount() > 0) + { + int pos = dseta.getPos(0).getI(); + + for (int p = 0, pSize = dseta.getPosCount(); p < pSize; p++) + { + pos = dseta.getPos(p).getI(); + posList.add(Integer.valueOf(pos)); + } + } + } + if (posList!=null && posList.size()>0) { + int[] range=new int[posList.size()]; + for (int i=0; i