refactored to propery separate addToDocument,addFromDocument, updateToDocument, updat...
authorjprocter <Jim Procter>
Wed, 12 Nov 2008 17:05:58 +0000 (17:05 +0000)
committerjprocter <Jim Procter>
Wed, 12 Nov 2008 17:05:58 +0000 (17:05 +0000)
src/jalview/io/vamsas/Datasetsequence.java [new file with mode: 0644]
src/jalview/io/vamsas/DatastoreItem.java
src/jalview/io/vamsas/Dbref.java
src/jalview/io/vamsas/LocalDocSyncObject.java
src/jalview/io/vamsas/Rangetype.java
src/jalview/io/vamsas/Sequencefeature.java [new file with mode: 0644]
src/jalview/io/vamsas/Sequencemapping.java
src/jalview/io/vamsas/Tree.java

diff --git a/src/jalview/io/vamsas/Datasetsequence.java b/src/jalview/io/vamsas/Datasetsequence.java
new file mode 100644 (file)
index 0000000..85a228e
--- /dev/null
@@ -0,0 +1,185 @@
+package jalview.io.vamsas;\r
+\r
+import jalview.datamodel.AlignmentI;\r
+import jalview.datamodel.DBRefEntry;\r
+import jalview.datamodel.SequenceI;\r
+import jalview.io.VamsasAppDatastore;\r
+import uk.ac.vamsas.objects.core.DataSet;\r
+import uk.ac.vamsas.objects.core.Sequence;\r
+\r
+/**\r
+ * synchronize a vamsas dataset sequence with a jalview dataset sequence.\r
+ * This class deals with all sequence features and database references associated with\r
+ * the jalview sequence.\r
+ * @author JimP\r
+ *\r
+ */\r
+public class Datasetsequence extends DatastoreItem\r
+{\r
+  String dict;\r
+  private DataSet dataset;\r
+  // private AlignmentI jvdset;\r
+\r
+  public Datasetsequence(VamsasAppDatastore vamsasAppDatastore,\r
+          SequenceI sq, String dict, DataSet dataset)\r
+  {\r
+    super(vamsasAppDatastore, sq, uk.ac.vamsas.objects.core.Sequence.class);\r
+    this.dataset = dataset;\r
+    // this.jvdset = jvdset;\r
+    this.dict = dict;\r
+    doSync();\r
+  }\r
+\r
+  public Datasetsequence(VamsasAppDatastore vamsasAppDatastore,\r
+          Sequence vdseq)\r
+  {\r
+    super(vamsasAppDatastore, vdseq, SequenceI.class);\r
+    doJvUpdate();\r
+  }\r
+\r
+  public void addFromDocument()\r
+  {\r
+    Sequence vseq = (Sequence) vobj;\r
+    SequenceI dsseq = new jalview.datamodel.Sequence(vseq.getName(), \r
+            vseq.getSequence(),\r
+            (int) vseq.getStart(), (int) vseq.getEnd());\r
+    dsseq.setDescription(vseq.getDescription());\r
+    bindjvvobj(dsseq, vseq);\r
+    dsseq.setVamsasId(vseq.getVorbaId().getId());\r
+    jvobj = dsseq;\r
+    modified=true;\r
+  }\r
+  public void updateFromDoc()\r
+  {\r
+    Sequence sq = (Sequence) vobj;\r
+    SequenceI sequence = (SequenceI) jvobj;\r
+    if (!sequence.getSequenceAsString().equals(sq.getSequence()))\r
+    {\r
+      log.warn("Potential Client Error ! - mismatch of dataset sequence: and jalview internal dataset sequence.");\r
+    } else {\r
+      // verify and update principal attributes.\r
+      if (sequence.getDescription() != null\r
+              && (sequence.getDescription() == null || !sequence\r
+                      .getDescription().equals(sq.getDescription())))\r
+      {\r
+        sequence.setDescription(sq.getDescription());\r
+        modified = true;\r
+      }\r
+      if (sequence.getSequence() == null\r
+              || !sequence.getSequenceAsString().equals(\r
+                      sq.getSequence()))\r
+      {\r
+        if (sequence.getStart() != sq.getStart()\r
+                || sequence.getEnd() != sq.getEnd())\r
+        {\r
+          // update modified sequence.\r
+          sequence.setSequence(sq.getSequence());\r
+          sequence.setStart((int)sq.getStart());\r
+          sequence.setEnd((int)sq.getEnd());\r
+          modified = true;\r
+        }\r
+      }\r
+      if (!sequence.getName().equals(sq.getName()))\r
+      {\r
+        sequence.setName(sq.getName());\r
+        modified = true;\r
+      }\r
+    }    \r
+  }\r
+\r
+\r
+  public void addToDocument()\r
+  {\r
+    SequenceI sq = (SequenceI) jvobj;\r
+    Sequence sequence = new Sequence();\r
+    bindjvvobj(sq, sequence);\r
+    sq.setVamsasId(sequence.getVorbaId().getId());\r
+    sequence.setSequence(sq.getSequenceAsString());\r
+    sequence.setDictionary(dict);\r
+    sequence.setName(sq.getName());\r
+    sequence.setStart(sq.getStart());\r
+    sequence.setEnd(sq.getEnd());\r
+    sequence.setDescription(sq.getDescription());\r
+    dataset.addSequence(sequence);\r
+    vobj = sequence;\r
+    // add or update any new features/references on dataset sequence\r
+    if (sq.getSequenceFeatures() != null)\r
+    {\r
+      int sfSize = sq.getSequenceFeatures().length;\r
+\r
+      for (int sf = 0; sf < sfSize; sf++)\r
+      {\r
+        new jalview.io.vamsas.Sequencefeature(datastore, (jalview.datamodel.SequenceFeature) sq\r
+                .getSequenceFeatures()[sf], dataset, (Sequence) vobj);\r
+      }\r
+    }\r
+    if (sq.getDatasetSequence() == null && sq.getDBRef() != null)\r
+    {\r
+      // only sync database references for dataset sequences\r
+      DBRefEntry[] entries = sq.getDBRef();\r
+      jalview.datamodel.DBRefEntry dbentry;\r
+      for (int db = 0; db < entries.length; db++)\r
+      {\r
+        Rangetype dbr = new jalview.io.vamsas.Dbref(datastore,\r
+                dbentry = entries[db], sq, (Sequence) vobj, dataset);\r
+      }\r
+\r
+    }\r
+    \r
+  }\r
+\r
+  public void conflict()\r
+  {\r
+    log.warn("Conflict in dataset sequence update to document. Overwriting document");\r
+    // TODO: could try to import from document data to jalview first. and then\r
+    updateToDoc();\r
+  }\r
+  boolean modified = false;\r
+  public void updateToDoc()\r
+  {\r
+    SequenceI sq = (SequenceI) jvobj;\r
+    Sequence sequence = (Sequence) vobj;\r
+    // verify and update principal attributes.\r
+    if (sequence.getDescription() != null\r
+            && (sequence.getDescription() == null || !sequence\r
+                    .getDescription().equals(sq.getDescription())))\r
+    {\r
+      sequence.setDescription(sq.getDescription());\r
+      modified = true;\r
+    }\r
+    if (sequence.getSequence() == null\r
+            || !sequence.getSequence().equals(\r
+                    sq.getSequenceAsString()))\r
+    {\r
+      if (sequence.getStart() != sq.getStart()\r
+              || sequence.getEnd() != sq.getEnd())\r
+      {\r
+        // update modified sequence.\r
+        sequence.setSequence(sq.getSequenceAsString());\r
+        sequence.setStart(sq.getStart());\r
+        sequence.setEnd(sq.getEnd());\r
+        modified = true;\r
+      }\r
+    }\r
+    if (!dict.equals(sequence.getDictionary()))\r
+    {\r
+      sequence.setDictionary(dict);\r
+      modified = true;\r
+    }\r
+    if (!sequence.getName().equals(sq.getName()))\r
+    {\r
+      sequence.setName(sq.getName());\r
+      modified = true;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * (probably could just do vobj.isModified(), but..)\r
+   * @return true if document's dataset sequence was modified\r
+   */\r
+  public boolean getModified()\r
+  {\r
+    return modified;\r
+  }\r
+\r
+}\r
index 42e494f..ce5acd3 100644 (file)
@@ -19,6 +19,7 @@
 package jalview.io.vamsas;
 
 import jalview.bin.Cache;
+import jalview.datamodel.DBRefEntry;
 import jalview.gui.TreePanel;
 import jalview.io.VamsasAppDatastore;
 
@@ -27,9 +28,12 @@ import java.util.Hashtable;
 import java.util.IdentityHashMap;
 import java.util.Vector;
 
+import org.apache.commons.logging.Log;
+
 import uk.ac.vamsas.client.IClientDocument;
 import uk.ac.vamsas.client.Vobject;
 import uk.ac.vamsas.client.VorbaId;
+import uk.ac.vamsas.objects.core.DbRef;
 import uk.ac.vamsas.objects.core.Entry;
 import uk.ac.vamsas.objects.core.Provenance;
 import uk.ac.vamsas.objects.core.Seg;
@@ -40,7 +44,7 @@ import uk.ac.vamsas.objects.core.Seg;
  * @author JimP
  * 
  */
-public class DatastoreItem
+public abstract class DatastoreItem
 {
   /**
    * 
@@ -52,8 +56,14 @@ public class DatastoreItem
   Hashtable vobj2jv;
 
   IdentityHashMap jv2vobj;
-
+  
+  boolean tojalview=false;
+  /**
+   * shared log instance
+   */
+  protected static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(DatastoreItem.class);
   /**
+   * note: this is taken verbatim from jalview.io.VamsasAppDatastore
    * @return the Vobject bound to Jalview datamodel object
    */
   protected Vobject getjv2vObj(Object jvobj)
@@ -94,6 +104,12 @@ public class DatastoreItem
     return null;
   }
 
+  /**
+   * note: this is taken verbatim from jalview.io.VamsasAppDatastore
+
+   * @param jvobj
+   * @param vobj
+   */
   protected void bindjvvobj(Object jvobj, uk.ac.vamsas.client.Vobject vobj)
   {
     VorbaId id = vobj.getVorbaId();
@@ -137,6 +153,29 @@ public class DatastoreItem
     // JBPNote - better implementing a hybrid invertible hash.
     jv2vobj.put(jvobj, vobj.getVorbaId());
   }
+  /**
+   * replaces oldjvobject with newjvobject in the Jalview Object <> VorbaID
+   * binding tables
+   * note: this is taken verbatim from jalview.io.VamsasAppDatastore
+   * @param oldjvobject
+   * @param newjvobject (may be null to forget the oldjvobject's document mapping)
+   * 
+   */
+  protected void replaceJvObjMapping(Object oldjvobject, Object newjvobject)
+  {
+    Object vobject = jv2vobj.remove(oldjvobject);
+    if (vobject == null)
+    {
+      throw new Error(
+              "IMPLEMENTATION ERROR: old jalview object is not bound ! ("
+                      + oldjvobject + ")");
+    }
+    if (newjvobject!=null)
+    {
+      jv2vobj.put(newjvobject, vobject);
+      vobj2jv.put(vobject, newjvobject);
+    }
+  }
 
   public DatastoreItem()
   {
@@ -149,8 +188,137 @@ public class DatastoreItem
     initDatastoreItem(datastore);
     // TODO Auto-generated constructor stub
   }
+  /**
+   * construct and initialise datastore object and retrieve object bound to vobj2 and validate it against boundType
+   * @param datastore2
+   * @param vobj2
+   * @param boundType
+   */
+  public DatastoreItem(VamsasAppDatastore datastore2, Vobject vobj2, Class boundType)
+  {
+    this(datastore2);
+    vobj = vobj2;
+    jvobj = getvObj2jv(vobj2);
+    tojalview=true;
+    if (jvobj!=null && !(boundType.isAssignableFrom(jvobj.getClass())))
+    {
+      throw new Error("Implementation Error: Vamsas Document Class "+vobj.getClass()+" should bind to a "+boundType+" (found a "+jvobj.getClass()+")");
+    }
+  }
+  /**
+   * construct and initialise datastore object and retrieve document object bound to Jalview object jvobj2 and validate it against boundType
+   * @param datastore2 the datastore
+   * @param jvobj2 the jalview object
+   * @param boundToType - the document object class that the bound object should be assignable from
+   */
+  public DatastoreItem(VamsasAppDatastore datastore2, Object jvobj2, Class boundToType)
+  {
+    this(datastore2);
+    jvobj = jvobj2;
+    tojalview=false;
+    vobj = getjv2vObj(jvobj);
+    if (vobj!=null && !(boundToType.isAssignableFrom(vobj.getClass())))
+    {
+      throw new Error("Implementation Error: Jalview Class "+jvobj2.getClass()+" should bind to a "+boundToType+" (found a "+vobj.getClass()+")");
+    }
+  }
+  /**
+   * create a new vobj to be added to the document 
+   * for the jalview object jvobj
+   * (jvobj!=null, vobj==null)
+   */
+  public abstract void addToDocument();
+  /**
+   * handle a conflict where both an existing vobj has been updated
+   *  and a local jalview object has been updated. This method
+   *  is only called from doSync, when an incoming update from the vamsas
+   *  session conflicts with local modifications made by the Jalview user. 
+   *  (jvobj!=null, vobj!=null)
+   */
+  public abstract void conflict();
+  /**
+   * update an existing vobj in the document with the data and settings from jvobj
+   * (jvobj!=null, vobj!=null) 
+   */
+  public abstract void updateToDoc();
+  /**
+   * update the local jalview object with the data from an existing vobj in the document 
+   * (jvobj!=null, vobj!=null) 
+   */
+  public abstract void updateFromDoc();
+  /**
+   * create a new local jvobj bound to the vobj in the document.
+   * (jvobj==null, vobj!=null)
+   */
+  public abstract void addFromDocument();
+  boolean addtodoc=false, conflicted=false,updated=false,addfromdoc=false,success=false;
+
+  private boolean updatedtodoc;
+
+  private boolean updatedfromdoc;
+  /**
+   * Sync jalview to document. Enact addToDocument, conflict or update dependent on
+   * existence of a vobj bound to the local jvobj. 
+   */
+  protected void doSync()
+  {
+    
+    if (vobj == null)
+    {
+      log.debug("adding new vobject to document.");
+      addtodoc=true;
+      addToDocument();
+    }
+    else
+    {
+      if (vobj.isUpdated())
+      {
+        log.debug("Handling update conflict for existing bound vobject.");
+        conflicted=true;
+        conflict();
+      }
+      else
+      {
+        log.debug("updating existing vobject in document.");
+        updatedtodoc=true;
+        updateToDoc();
+      }
+    }
+    // no exceptions were encountered...
+    success=true;
+  }
+  /**
+   * Update jalview from document. enact addFromDocument if no local jvobj exists, or update iff jvobj
+   * exists and the vobj.isUpdated() flag is set. 
+   */
+  protected void doJvUpdate()
+  {
+    if (jvobj == null)
+    {
+      log.debug("adding new vobject to Jalview from Document");
+      addfromdoc=true;
+      addFromDocument();
+    }
+    else
+    {
+      if (vobj.isUpdated())
+      {
+        log.debug("updating Jalview from existing bound vObject");
+        updatedfromdoc=true;
+        updateFromDoc();
+      }
+    }
+  }
 
   VamsasAppDatastore datastore = null;
+  /**
+   * object in vamsas document
+   */
+  protected Vobject vobj = null;
+  /**
+   * local jalview object
+   */
+  protected Object jvobj = null;
 
   public void initDatastoreItem(VamsasAppDatastore ds)
   {
@@ -270,4 +438,77 @@ public class DatastoreItem
   {
     p.addEntry(dummyPEntry(action));
   }
+
+
+  /**
+   * @return true if jalview was being updated from the vamsas document
+   */
+  public boolean isTojalview()
+  {
+    return tojalview;
+  }
+
+  /**
+   * @return true if addToDocument() was called.
+   */
+  public boolean isAddtodoc()
+  {
+    return addtodoc;
+  }
+
+  /**
+   * @return true if conflict() was called
+   */
+  public boolean isConflicted()
+  {
+    return conflicted;
+  }
+
+  /**
+   * @return true if updateFromDoc() was called
+   */
+  public boolean isUpdatedFromDoc()
+  {
+    return updatedfromdoc;
+  }
+  /**
+   * @return true if updateToDoc() was called
+   */
+  public boolean isUpdatedToDoc()
+  {
+    return updatedtodoc;
+  }
+
+  /**
+   * @return true if addFromDocument() was called.
+   */
+  public boolean isAddfromdoc()
+  {
+    return addfromdoc;
+  }
+
+  /**
+   * @return true if object sync logic completed normally.
+   */
+  public boolean isSuccess()
+  {
+    return success;
+  }
+
+  /**
+   * @return the vobj
+   */
+  public Vobject getVobj()
+  {
+    return vobj;
+  }
+
+  /**
+   * @return the jvobj
+   */
+  public Object getJvobj()
+  {
+    return jvobj;
+  }
+
 }
index e8fedac..c27bc9a 100644 (file)
@@ -20,6 +20,7 @@ package jalview.io.vamsas;
 
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.SequenceI;
+import uk.ac.vamsas.objects.core.DataSet;
 import uk.ac.vamsas.objects.core.DbRef;
 import uk.ac.vamsas.objects.core.Map;
 import uk.ac.vamsas.objects.core.Sequence;
@@ -31,115 +32,170 @@ public class Dbref extends Rangetype
 
   uk.ac.vamsas.objects.core.Sequence sequence = null;
 
-  DbRef dbref = null;
-
-  DBRefEntry dbentry = null;
+  DataSet ds;
 
   public Dbref(VamsasAppDatastore datastore, DBRefEntry dbentry,
           jalview.datamodel.SequenceI sq2,
-          uk.ac.vamsas.objects.core.Sequence sequence2)
+          uk.ac.vamsas.objects.core.Sequence sequence2, DataSet dataset)
   {
-    super(datastore);
-    dbref = (DbRef) getjv2vObj(dbentry);
+    super(datastore, dbentry, DbRef.class);
+    // initialise object specific attributes
     sq = sq2;
     sequence = sequence2;
-    this.dbentry = dbentry;
-    if (dbref == null)
-    {
-      add();
-    }
-    else
-    {
-      if (dbref.isUpdated())
-      {
-        conflict();
-      }
-      else
-      {
-        update();
-      }
-
-    }
-
+    this.jvobj = dbentry;
+    ds = dataset;
+    // call the accessors
+    doSync();
   }
 
   public Dbref(VamsasAppDatastore datastore, DbRef ref, Sequence vdseq,
           SequenceI dsseq)
   {
-    super(datastore);
-    dbref = ref;
+    super(datastore, ref, jalview.datamodel.DBRefEntry.class);
     sequence = vdseq;
     sq = dsseq;
-    dbentry = (jalview.datamodel.DBRefEntry) getvObj2jv(dbref);
-    if (dbentry == null)
+    ds = (DataSet) vdseq.getV_parent();
+    doJvUpdate();
+  }
+
+  public void updateToDoc()
+  {
+    DbRef dbref = (DbRef) this.vobj;
+    DBRefEntry jvobj = (DBRefEntry) this.jvobj;
+    dbref.setAccessionId(jvobj.getAccessionId());
+    dbref.setSource(jvobj.getSource());
+    dbref.setVersion(jvobj.getVersion());
+    if (jvobj.getMap() != null)
     {
-      addFromDocument();
+      // Record mapping to external database coordinate system.
+      jalview.datamodel.Mapping mp = jvobj.getMap();
+      if (mp.getMap() != null)
+      {
+        Map vMap = null;
+        if (dbref.getMapCount() == 0)
+        {
+          vMap = new Map();
+          initMapType(vMap, mp.getMap(), true);
+          dbref.addMap(vMap);
+        }
+        else
+        {
+          // we just update the data anyway.
+          vMap = dbref.getMap(0);
+          initMapType(vMap, mp.getMap(), true);
+        }
+        updateMapTo(mp);
+      }
     }
-    else
+      else
+      {
+        jalview.bin.Cache.log.debug("Ignoring mapless DbRef.Map "
+                + jvobj.getSrcAccString());
+      }
+    
+  }
+  /**
+   * ugly hack to try to get the embedded sequences within a database reference to be stored in the document's dataset.
+   * @param mp
+   */
+  private void updateMapTo(jalview.datamodel.Mapping mp)
+  {
+    log.info("Performing updateMapTo remove this message when we know what we're doing.");
+    // TODO determine how sequences associated with database mappings are stored in the document
+    if (mp!=null && mp.getTo() != null)
     {
-      if (dbref.isUpdated())
+      if (mp.getTo().getDatasetSequence() == null)
       {
-        update();
+        // sync the dataset sequence, if it hasn't been done already.
+        Datasetsequence dssync = new Datasetsequence(
+                datastore, mp.getTo(),
+                (mp.getMappedWidth() == mp.getWidth()) ? sequence
+                        .getDictionary()
+                        : ((mp.getMappedWidth() == 3) ? uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_AA
+                                : uk.ac.vamsas.objects.utils.SymbolDictionary.STANDARD_NA),
+                ds);
+        // add a mapping between new dataset sequence and sequence associated with the database reference
+        
+      } else {
+        log.debug("Ignoring non-dataset sequence mapping.");
       }
     }
   }
-
-  private void update()
+  public void updateFromDoc()
   {
-    // TODO: verify and update dbrefs in vamsas document
-    // there will be trouble when a dataset sequence is modified to
-    // contain more residues than were originally referenced - we must
-    // then make a number of dataset sequence entries - this info is already
-    // stored
-    jalview.bin.Cache.log
-            .debug("TODO verify update of dataset sequence database references.");
+    DbRef vobj = (DbRef) this.vobj;
+    DBRefEntry jvobj = (DBRefEntry) this.jvobj;
+    jvobj.setAccessionId(vobj.getAccessionId());
+    jvobj.setSource(vobj.getSource());
+    jvobj.setVersion(vobj.getVersion());
+    // add new dbref
+    if (vobj.getMapCount() > 0)
+    {
+      // TODO: Jalview ignores all the other maps
+      if (vobj.getMapCount() > 1)
+      {
+        jalview.bin.Cache.log
+                .debug("Ignoring additional mappings on DbRef: "
+                        + jvobj.getSource() + ":" + jvobj.getAccessionId());
+      }
+      jalview.datamodel.Mapping mp = new jalview.datamodel.Mapping(
+              parsemapType(vobj.getMap(0)));
+      if (jvobj.getMap()==null || !mp.equals(jvobj.getMap()))
+      {
+        jvobj.setMap(mp);
+      }
+    }
   }
-
-  private void conflict()
+  
+  public void conflict()
   {
+    DbRef vobj = (DbRef) this.vobj;
+    DBRefEntry jvobj = (DBRefEntry) this.jvobj;
     jalview.bin.Cache.log.debug("Conflict in dbentry update for "
-            + dbref.getAccessionId() + dbref.getSource() + " "
-            + dbref.getVorbaId());
+            + vobj.getAccessionId() + vobj.getSource() + " "
+            + vobj.getVorbaId());
     // TODO Auto-generated method stub
 
   }
 
-  private void addFromDocument()
+  public void addFromDocument()
   {
+    DbRef vobj = (DbRef) this.vobj;
+    DBRefEntry jvobj = (DBRefEntry) this.jvobj;
     // add new dbref
-    sq.addDBRef(dbentry = new jalview.datamodel.DBRefEntry(dbref
-            .getSource().toString(), dbref.getVersion().toString(), dbref
+    sq.addDBRef(jvobj = new jalview.datamodel.DBRefEntry(vobj.getSource()
+            .toString(), vobj.getVersion().toString(), vobj
             .getAccessionId().toString()));
-    if (dbref.getMapCount() > 0)
+    if (vobj.getMapCount() > 0)
     {
       // TODO: Jalview ignores all the other maps
-      if (dbref.getMapCount() > 1)
+      if (vobj.getMapCount() > 1)
       {
         jalview.bin.Cache.log
                 .debug("Ignoring additional mappings on DbRef: "
-                        + dbentry.getSource() + ":"
-                        + dbentry.getAccessionId());
+                        + jvobj.getSource() + ":" + jvobj.getAccessionId());
       }
       jalview.datamodel.Mapping mp = new jalview.datamodel.Mapping(
-              parsemapType(dbref.getMap(0)));
-      dbentry.setMap(mp);
+              parsemapType(vobj.getMap(0)));
+      jvobj.setMap(mp);
     }
     // TODO: jalview ignores links and properties because it doesn't know what
     // to do with them.
 
-    bindjvvobj(dbentry, dbref);
+    bindjvvobj(jvobj, vobj);
   }
 
-  private void add()
+  public void addToDocument()
   {
+    DBRefEntry jvobj = (DBRefEntry) this.jvobj;
     DbRef dbref = new DbRef();
-    bindjvvobj(dbentry, dbref);
-    dbref.setAccessionId(dbentry.getAccessionId());
-    dbref.setSource(dbentry.getSource());
-    dbref.setVersion(dbentry.getVersion());
-    if (dbentry.getMap() != null)
+    bindjvvobj(jvobj, dbref);
+    dbref.setAccessionId(jvobj.getAccessionId());
+    dbref.setSource(jvobj.getSource());
+    dbref.setVersion(jvobj.getVersion());
+    if (jvobj.getMap() != null)
     {
-      jalview.datamodel.Mapping mp = dbentry.getMap();
+      jalview.datamodel.Mapping mp = jvobj.getMap();
       if (mp.getMap() != null)
       {
         Map vMap = new Map();
@@ -149,7 +205,7 @@ public class Dbref extends Rangetype
       else
       {
         jalview.bin.Cache.log.debug("Ignoring mapless DbRef.Map "
-                + dbentry.getSrcAccString());
+                + jvobj.getSrcAccString());
       }
     }
     sequence.addDbRef(dbref);
index 2c9eddc..50b0cdb 100644 (file)
@@ -22,8 +22,9 @@ import uk.ac.vamsas.client.Vobject;
 
 /**
  * Implement the basic logic for synchronising changes to or from the Vamsas
- * Document
- * 
+ * Document. This is a more generic and normalised framework than the one implemented in DatastoreItem,
+ * but probably more tedious to implement.
+ * .. abandoned. Nov 2008 
  * @author JimP
  */
 public abstract class LocalDocSyncObject extends DatastoreItem
@@ -48,14 +49,14 @@ public abstract class LocalDocSyncObject extends DatastoreItem
   /**
    * called if the local object can be safely updated from the bound document
    * object.
+  public abstract void updateToDoc();
    */
-  public abstract void updateFromDoc();
 
   /**
    * called if the associated document object can be safely updated with the
    * local changes
-   */
   public abstract void updateToDoc();
+   */
 
   /**
    * @return true if the local object is modified
index 2686e85..8c8b7d7 100644 (file)
@@ -20,16 +20,22 @@ package jalview.io.vamsas;
 
 import java.util.Vector;
 
+import uk.ac.vamsas.client.Vobject;
 import uk.ac.vamsas.objects.core.Local;
 import uk.ac.vamsas.objects.core.Map;
 import uk.ac.vamsas.objects.core.MapType;
 import uk.ac.vamsas.objects.core.Mapped;
 import uk.ac.vamsas.objects.core.RangeType;
 import uk.ac.vamsas.objects.core.Seg;
+import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.Mapping;
 import jalview.io.VamsasAppDatastore;
-
-public class Rangetype extends DatastoreItem
+/**
+ * Enhances DatastoreItem objects with additional functions to do with RangeType objects
+ * @author JimP
+ *
+ */
+public abstract class Rangetype extends DatastoreItem
 {
 
   public Rangetype()
@@ -41,6 +47,15 @@ public class Rangetype extends DatastoreItem
   {
     super(datastore);
   }
+  
+  public Rangetype(VamsasAppDatastore datastore, Vobject vobj, Class jvClass)
+  {
+    super(datastore, vobj, jvClass);
+  }
+  public Rangetype(VamsasAppDatastore datastore, Object jvobj, Class vClass)
+  {
+    super(datastore, jvobj, vClass);
+  }
 
   /**
    * get real bounds of a RangeType's specification. start and end are an
diff --git a/src/jalview/io/vamsas/Sequencefeature.java b/src/jalview/io/vamsas/Sequencefeature.java
new file mode 100644 (file)
index 0000000..0ddfc6f
--- /dev/null
@@ -0,0 +1,326 @@
+/**\r
+ * \r
+ */\r
+package jalview.io.vamsas;\r
+\r
+import java.util.Enumeration;\r
+import java.util.Vector;\r
+\r
+import uk.ac.vamsas.objects.core.DataSet;\r
+import uk.ac.vamsas.objects.core.DataSetAnnotations;\r
+import uk.ac.vamsas.objects.core.Link;\r
+import uk.ac.vamsas.objects.core.Property;\r
+import uk.ac.vamsas.objects.core.Provenance;\r
+import uk.ac.vamsas.objects.core.RangeAnnotation;\r
+import uk.ac.vamsas.objects.core.Score;\r
+import uk.ac.vamsas.objects.core.Seg;\r
+import uk.ac.vamsas.objects.core.Sequence;\r
+import uk.ac.vamsas.objects.utils.Properties;\r
+import jalview.bin.Cache;\r
+import jalview.datamodel.SequenceFeature;\r
+import jalview.datamodel.SequenceI;\r
+import jalview.io.VamsasAppDatastore;\r
+import jalview.util.UrlLink;\r
+\r
+/**\r
+ * @author JimP\r
+ * \r
+ */\r
+public class Sequencefeature extends Rangetype\r
+{\r
+\r
+  uk.ac.vamsas.objects.core.DataSet dataset;\r
+\r
+  uk.ac.vamsas.objects.core.Sequence sequence;\r
+\r
+  private SequenceI dsSeq;\r
+\r
+  public Sequencefeature(VamsasAppDatastore vamsasAppDatastore,\r
+          SequenceFeature sequenceFeature,\r
+          uk.ac.vamsas.objects.core.DataSet dataset,\r
+          uk.ac.vamsas.objects.core.Sequence sequence)\r
+  {\r
+    super(vamsasAppDatastore, sequenceFeature, DataSetAnnotations.class);\r
+    this.dataset = dataset;\r
+    this.sequence = sequence;\r
+    doSync();\r
+  }\r
+\r
+  public Sequencefeature(VamsasAppDatastore vamsasAppDatastore,\r
+          DataSetAnnotations dseta, SequenceI dsSeq)\r
+  {\r
+    super(vamsasAppDatastore, dseta, jalview.datamodel.SequenceFeature.class);\r
+    this.dsSeq = dsSeq;\r
+    doJvUpdate();\r
+  }\r
+\r
+  public void addToDocument()\r
+  {\r
+    DataSetAnnotations dsa = (DataSetAnnotations) vobj;\r
+    jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;\r
+    dsa = (DataSetAnnotations) getDSAnnotationFromJalview(\r
+            new DataSetAnnotations(), feature);\r
+    if (dsa.getProvenance() == null)\r
+    {\r
+      dsa.setProvenance(new Provenance());\r
+    }\r
+    addProvenance(dsa.getProvenance(), "created"); // JBPNote - need\r
+    // to update\r
+    dsa.addSeqRef(sequence); // we have just created this annotation\r
+    // - so safe to use this\r
+    bindjvvobj(feature, dsa);\r
+    dataset.addDataSetAnnotations(dsa);\r
+  }\r
+\r
+  public void addFromDocument()\r
+  {\r
+    DataSetAnnotations dsa = (DataSetAnnotations) vobj;\r
+    if (dsa.getSeqRefCount()!=1)\r
+    {\r
+      Cache.log.warn("Not binding "+dsa.getVorbaId()+" to Sequence Feature - has multiple dataset sequence references.");\r
+      return;\r
+    }\r
+    jalview.datamodel.SequenceFeature sf = (jalview.datamodel.SequenceFeature) jvobj;\r
+    dsSeq.addSequenceFeature(sf = getJalviewSeqFeature(dsa));\r
+    jvobj = sf;\r
+    bindjvvobj(sf, dsa);\r
+  }\r
+\r
+  public void conflict()\r
+  {\r
+    log.warn("Untested sequencefeature conflict code");\r
+    DataSetAnnotations dsa = (DataSetAnnotations) vobj;\r
+    jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;\r
+    jalview.datamodel.SequenceFeature sf = getJalviewSeqFeature(dsa);\r
+    replaceJvObjMapping(feature, sf); // switch binding of dsa from old feature to newly created feature\r
+    dsSeq.addSequenceFeature(sf); // add new imported feature\r
+    addToDocument(); // and create a new feature in the document        \r
+  }\r
+\r
+  public void updateToDoc()\r
+  {\r
+    DataSetAnnotations dsa = (DataSetAnnotations) vobj;\r
+    jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;\r
+    if (dsa.getSeqRefCount() != 1)\r
+    {\r
+      replaceJvObjMapping(feature, null);\r
+      Cache.log\r
+              .warn("Binding of annotation to jalview feature has changed. Removing binding and recreating.");\r
+      doSync(); // re-verify bindings.\r
+    }\r
+    else\r
+    {\r
+      // Sync the features from Jalview\r
+      long oldref = dsa.get__last_hash();\r
+      getDSAnnotationFromJalview(dsa, feature);\r
+      if (oldref != dsa.hashCode())\r
+      {\r
+        Cache.log\r
+                .debug("Updated dataset sequence annotation from feature.");\r
+        addProvenance(dsa.getProvenance(), "modified");\r
+      }\r
+    }\r
+\r
+  }\r
+  public void updateFromDoc()\r
+  {\r
+    DataSetAnnotations dsa = (DataSetAnnotations) vobj;\r
+    jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj;\r
+    if (dsa.getSeqRefCount() != 1)\r
+    {\r
+      // conflicting update from document - we cannot map this feature anymore.\r
+      replaceJvObjMapping(feature, null);\r
+      Cache.log\r
+              .warn("annotation ("+dsa.getVorbaId()+" bound to jalview feature cannot be mapped. Removing binding, deleting feature, and deleting feature.");\r
+       // - consider deleting the feature ?\r
+      dsSeq.deleteFeature(feature);\r
+      // doSync();\r
+    }\r
+    else\r
+    {\r
+      // Sync the features to Jalview - easiest to delete and add the feature again\r
+      jalview.datamodel.SequenceFeature newsf = getJalviewSeqFeature(dsa);\r
+      dsSeq.deleteFeature(feature);\r
+      replaceJvObjMapping(feature, newsf);\r
+      dsSeq.addSequenceFeature(newsf);\r
+      feature.otherDetails.clear();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * correctly create/update a RangeAnnotation from a jalview sequence feature\r
+   * TODO: refactor to a method in jalview.io.vamsas.RangeAnnotation class\r
+   * \r
+   * @param dsa\r
+   *                (typically DataSetAnnotations or\r
+   *                AlignmentSequenceAnnotation)\r
+   * @param feature\r
+   *                (the feature to be mapped from)\r
+   * @return\r
+   */\r
+  private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa,\r
+          jalview.datamodel.SequenceFeature feature)\r
+  {\r
+    dsa.setType(feature.getType());\r
+    Seg vSeg = new Seg();\r
+    vSeg.setStart(feature.getBegin());\r
+    vSeg.setEnd(feature.getEnd());\r
+    vSeg.setInclusive(true);\r
+    if (dsa.getSegCount() > 1)\r
+    {\r
+      Cache.log\r
+              .debug("About to destroy complex annotation in vamsas document mapped to sequence feature ("\r
+                      + dsa.getVorbaId() + ")");\r
+    }\r
+    dsa.setSeg(new Seg[]\r
+    { vSeg });\r
+    dsa.setDescription(feature.getDescription());\r
+    dsa.setStatus(feature.getStatus());\r
+    if (feature.links != null && feature.links.size() > 0)\r
+    {\r
+      for (int i = 0, iSize = feature.links.size(); i < iSize; i++)\r
+      {\r
+        String link = (String) feature.links.elementAt(i);\r
+        UrlLink ulink = new UrlLink(link);\r
+        /*\r
+         * int sep = link.indexOf('|'); if (sep > -1) { Link vLink = new Link();\r
+         * if (sep > 0) { vLink.setContent(link.substring(0, sep - 1)); } else {\r
+         * vLink.setContent(""); } vLink.setHref(link.substring(sep + 1)); //\r
+         * TODO: validate href. dsa.addLink(vLink); }\r
+         */\r
+        Link vLink = new Link();\r
+        vLink.setContent(ulink.getLabel());\r
+        vLink.setHref(ulink.getUrl_prefix());\r
+      }\r
+    }\r
+    dsa.setGroup(feature.getFeatureGroup());\r
+    if (feature.getScore() != Float.NaN)\r
+    {\r
+      Score fscore = new Score();\r
+      dsa.setScore(new Score[]\r
+      { fscore });\r
+      fscore.setContent(feature.getScore());\r
+      fscore.setName(feature.getType());\r
+    }\r
+    if (feature.otherDetails != null)\r
+    {\r
+      Enumeration iter = feature.otherDetails.keys();\r
+      Vector props = dsa.getPropertyAsReference();\r
+      while (iter.hasMoreElements())\r
+      {\r
+        String key = (String) iter.nextElement();\r
+        if (!key.equalsIgnoreCase("score")\r
+                && !key.equalsIgnoreCase("status"))\r
+        {\r
+          Property nprop = new Property();\r
+          nprop.setName(key);\r
+          Object vlu = feature.getValue(key);\r
+          nprop.setContent(feature.getValue(key).toString());\r
+          boolean valid = false;\r
+          if (vlu instanceof String)\r
+          {\r
+            nprop.setType(uk.ac.vamsas.objects.utils.Properties.STRINGTYPE);\r
+            valid = true;\r
+          }\r
+          else if (vlu instanceof Integer)\r
+          {\r
+            valid = true;\r
+            nprop\r
+                    .setType(uk.ac.vamsas.objects.utils.Properties.INTEGERTYPE);\r
+          }\r
+          else if (vlu instanceof Float)\r
+          {\r
+            nprop.setType(uk.ac.vamsas.objects.utils.Properties.FLOATTYPE);\r
+            valid = true;\r
+          }\r
+          if (valid)\r
+          {\r
+            if (props != null)\r
+            {\r
+              uk.ac.vamsas.objects.utils.Properties.addOrReplace(props,\r
+                      nprop);\r
+            }\r
+            else\r
+            {\r
+              dsa.addProperty(nprop);\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    return dsa;\r
+  }\r
+  private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta)\r
+  {\r
+    int[] se = getBounds(dseta);\r
+    SequenceFeature sf = new jalview.datamodel.SequenceFeature(dseta\r
+            .getType(), dseta.getDescription(), dseta.getStatus(), se[0],\r
+            se[1], dseta.getGroup());\r
+    if (dseta.getLinkCount() > 0)\r
+    {\r
+      Link[] links = dseta.getLink();\r
+      for (int i = 0; i < links.length; i++)\r
+      {\r
+        sf.addLink(links[i].getContent() + "|" + links[i].getHref());\r
+      }\r
+    }\r
+    if (dseta.getScoreCount()>0)\r
+    {\r
+      Enumeration scr = dseta.enumerateScore();\r
+      while (scr.hasMoreElements())\r
+      {\r
+        Score score = (Score) scr.nextElement();\r
+        if (score.getName().equals(sf.getType()))\r
+        {\r
+          sf.setScore(score.getContent());\r
+        } else {\r
+          sf.setValue(score.getName(), ""+score.getContent());\r
+        }\r
+      }\r
+    }\r
+    // other details\r
+    Enumeration props = dseta.enumerateProperty();\r
+    while (props.hasMoreElements())\r
+    {\r
+      Property p = (Property) props.nextElement();\r
+      Object val = null;\r
+      if (Properties.isValid(p)) \r
+      {\r
+        if (Properties.isString(p))\r
+        {\r
+        val = p.getContent();\r
+        }\r
+        if (Properties.isBoolean(p))\r
+        {\r
+          try {\r
+            val = new Boolean(p.getContent());\r
+          } catch (Exception e) {}\r
+        }\r
+        if (Properties.isFloat(p))\r
+        {\r
+          try {\r
+              val = new Float(p.getContent());\r
+              \r
+            } catch (Exception e)\r
+            {\r
+            }\r
+          }\r
+        if(Properties.isInteger(p))\r
+        {\r
+          try {\r
+                val = new Integer(p.getContent());\r
+          } catch (Exception e)\r
+          {\r
+              } \r
+        }\r
+        if (val!=null)\r
+        {\r
+          sf.setValue(p.getName(), val);\r
+        }\r
+      }\r
+    }\r
+\r
+    return sf;\r
+  }\r
+\r
+}\r
index de4a01e..2e8d31b 100644 (file)
@@ -34,26 +34,29 @@ import uk.ac.vamsas.objects.core.Sequence;
 import uk.ac.vamsas.objects.core.SequenceMapping;
 import uk.ac.vamsas.objects.core.SequenceType;
 
+/**
+ * binds a vamsas sequence mapping object from the vamsas document to
+ * a maplist object associated with a mapping in the Jalview model.
+ * We use the maplist object because these are referred to both in
+ * the Mapping object associated with a jalview.datamodel.DBRefEntry
+ * and in the array of jalview.datamodel.AlCodonFrame objects that
+ * Jalview uses to propagate sequence mapping position highlighting
+ * across the views.
+ * @author JimP
+ *
+ */
 public class Sequencemapping extends Rangetype
 {
   public Sequencemapping(VamsasAppDatastore datastore,
           SequenceMapping sequenceMapping)
   {
-    super(datastore);
-    Object mjvmapping = getvObj2jv(sequenceMapping);
-    if (mjvmapping == null)
-    {
-      add(sequenceMapping);
-    }
-    else
-    {
-      if (sequenceMapping.isUpdated())
-      {
-        update((jalview.util.MapList) mjvmapping, sequenceMapping);
-      }
-    }
+    super(datastore, sequenceMapping, jalview.util.MapList.class);
+    doJvUpdate();
   }
-
+  private SequenceType from;
+  private DataSet ds;
+  private Mapping mjvmapping;
+  
   /**
    * create or update a vamsas sequence mapping corresponding to a jalview
    * Mapping between two dataset sequences
@@ -68,38 +71,64 @@ public class Sequencemapping extends Rangetype
           uk.ac.vamsas.objects.core.SequenceType from,
           uk.ac.vamsas.objects.core.DataSet ds)
   {
-    super(datastore);
-    SequenceMapping sequenceMapping = (SequenceMapping) getjv2vObj(mjvmapping);
-    if (sequenceMapping == null)
+    super(datastore, mjvmapping.getMap(), SequenceMapping.class);
+    this.from = from;
+    this.ds = ds;
+    this.mjvmapping = mjvmapping;
+    validate();
+    doSync();
+  }
+  /**
+   * local check that extant mapping context is valid
+   */
+  public void validate()
+  {
+    
+    SequenceMapping sequenceMapping = (SequenceMapping) vobj;
+    if (sequenceMapping==null)
     {
-      add(mjvmapping, from, ds);
+      return;
     }
-    else
+    if (from != null && sequenceMapping.getLoc() != from)
     {
-      if (from != null && sequenceMapping.getLoc() != from)
-      {
-        jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from
-                + " doesn't match the local mapping sequence.");
-      }
-      if (ds != null && sequenceMapping.is__stored_in_document()
-              && sequenceMapping.getV_parent() != ds)
-      {
-        jalview.bin.Cache.log
-                .warn("Probable IMPLEMENTATION ERROR: "
-                        + ds
-                        + " doesn't match the parent of the bound sequence mapping object.");
-      }
-      if (sequenceMapping.isUpdated())
-      {
-        conflict(mjvmapping, sequenceMapping);
-      }
-      else
-      {
-        update(mjvmapping, sequenceMapping);
-      }
+      jalview.bin.Cache.log.warn("Probable IMPLEMENTATION ERROR: " + from
+              + " doesn't match the local mapping sequence.");
     }
+    if (ds != null && sequenceMapping.is__stored_in_document()
+            && sequenceMapping.getV_parent() != ds)
+    {
+      jalview.bin.Cache.log
+              .warn("Probable IMPLEMENTATION ERROR: "
+                      + ds
+                      + " doesn't match the parent of the bound sequence mapping object.");
+    }
+  }    
+
+  public void addToDocument()
+  {
+    add(mjvmapping, from, ds);
   }
 
+  public void addFromDocument()
+  {
+    add((SequenceMapping) vobj);
+  }
+
+  public void conflict()
+  {
+    conflict(mjvmapping, (SequenceMapping) vobj);
+    
+  }
+
+  public void updateToDoc()
+  {
+    update(mjvmapping, (SequenceMapping) vobj);
+  }
+  public void updateFromDoc()
+  {
+    update((SequenceMapping) vobj, (jalview.datamodel.Mapping) jvobj);
+  }
+  
   private void conflict(Mapping mjvmapping, SequenceMapping sequenceMapping)
   {
     System.err.println("Conflict in update of sequenceMapping "
@@ -118,7 +147,7 @@ public class Sequencemapping extends Rangetype
     if (to == null)
     {
       jalview.bin.Cache.log
-              .warn("NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
+              .warn("FIXME NONFATAL - do a second update: Ignoring Forward Reference to seuqence not yet bound to vamsas seuqence object");
       return;
     }
     SequenceMapping sequenceMapping = new SequenceMapping();
@@ -186,19 +215,25 @@ public class Sequencemapping extends Rangetype
     // source
     // of
     // mapping
-    bindjvvobj(mjvmapping, sequenceMapping);
+    bindjvvobj(mjvmapping.getMap(), sequenceMapping);
 
     jalview.bin.Cache.log.debug("Successfully created mapping "
             + sequenceMapping.getVorbaId());
   }
 
-  private void update(jalview.util.MapList mjvmapping,
-          SequenceMapping sequenceMapping)
+  // private void update(jalview.util.MapList mjvmapping,
+     //     SequenceMapping sequenceMapping)
   {
     jalview.bin.Cache.log
             .error("Not implemented: Jalview Update Alcodon Mapping:TODO!");
   }
 
+  private void update(SequenceMapping sequenceMapping,
+          jalview.datamodel.Mapping mjvmapping)
+  {
+    jalview.bin.Cache.log
+            .error("Not implemented: Update DBRef Mapping from Jalview");
+  }
   private void update(jalview.datamodel.Mapping mjvmapping,
           SequenceMapping sequenceMapping)
   {
@@ -207,6 +242,7 @@ public class Sequencemapping extends Rangetype
   }
 
   /**
+   * bind a SequenceMapping to a live AlCodonFrame element
    * limitations: Currently, jalview only deals with mappings between dataset
    * sequences, and even then, only between those that map from DNA to Protein.
    * 
@@ -300,17 +336,23 @@ public class Sequencemapping extends Rangetype
     // create and add the new mapping to (each) dataset's codonFrame
 
     jalview.util.MapList mapping = null;
-    if (!sense)
-    {
-      mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense
-      mapping = new jalview.util.MapList(mapping.getToRanges(), mapping
-              .getFromRanges(), mapping.getToRatio(), mapping
-              .getFromRatio());
-      afc.addMap(to, from, mapping);
-    }
-    else
+    if (dnaToProt)
     {
-      mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense
+      if (!sense)
+      {
+        mapping = this.parsemapType(sequenceMapping, 1, 3); // invert sense
+        mapping = new jalview.util.MapList(mapping.getToRanges(), mapping
+                .getFromRanges(), mapping.getToRatio(), mapping
+                .getFromRatio());
+        afc.addMap(to, from, mapping);
+      }
+      else
+      {
+        mapping = this.parsemapType(sequenceMapping, 3, 1); // correct sense
+        afc.addMap(from, to, mapping);
+      }
+    } else {
+      mapping = this.parsemapType(sequenceMapping, 1, 1); // correct sense
       afc.addMap(from, to, mapping);
     }
     bindjvvobj(mapping, sequenceMapping);
index fd9294b..1866336 100644 (file)
@@ -71,46 +71,14 @@ public class Tree extends DatastoreItem
           uk.ac.vamsas.objects.core.Tree vtree)
   {
     Tree toTree = new Tree(datastore, alignFrame, vtree);
-
   }
 
   public Tree(VamsasAppDatastore datastore,
           jalview.gui.AlignFrame alignFrame,
           uk.ac.vamsas.objects.core.Tree vtree)
   {
-    super(datastore);
-    tree = vtree;
-    TreePanel tp = (TreePanel) getvObj2jv(tree);
-    if (tp != null)
-    {
-      if (tree.isUpdated())
-      {
-        Cache.log
-                .info("Update from vamsas document to alignment associated tree not implemented yet.");
-      }
-    }
-    else
-    {
-      // make a new tree
-      Object[] idata = recoverInputData(tree.getProvenance());
-      try
-      {
-        if (idata != null && idata[0] != null)
-        {
-          inputData = (AlignmentView) idata[0];
-        }
-        ntree = getNtree();
-        title = tree.getNewick(0).getTitle();
-        if (title == null || title.length() == 0)
-        {
-          title = tree.getTitle(); // hack!!!!
-        }
-      } catch (Exception e)
-      {
-        Cache.log.warn("Problems parsing treefile '"
-                + tree.getNewick(0).getContent() + "'", e);
-      }
-    }
+    super(datastore, vtree, TreePanel.class);
+    doJvUpdate();
   }
 
   private NewickFile getNtree() throws IOException
@@ -121,30 +89,111 @@ public class Tree extends DatastoreItem
   public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2,
           uk.ac.vamsas.objects.core.Alignment alignment2)
   {
-    super(datastore);
+    super(datastore, tp2, uk.ac.vamsas.objects.core.Tree.class);
 
     jal = jal2;
-    tp = tp2;
+    tp = (TreePanel) jvobj;
     alignment = alignment2;
 
-    tree = (uk.ac.vamsas.objects.core.Tree) getjv2vObj(tp);
-    if (tree == null)
+    tree = (uk.ac.vamsas.objects.core.Tree) vobj;
+    doSync();
+  }
+  
+  /* (non-Javadoc)
+   * @see jalview.io.vamsas.DatastoreItem#addFromDocument()
+   */
+  public void addFromDocument()
+  {
+    tree = (uk.ac.vamsas.objects.core.Tree) vobj; // vtree;
+    TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
+    // make a new tree
+    Object[] idata = recoverInputData(tree.getProvenance());
+    try
+    {
+      if (idata != null && idata[0] != null)
+      {
+        inputData = (AlignmentView) idata[0];
+      }
+      ntree = getNtree();
+      title = tree.getNewick(0).getTitle();
+      if (title == null || title.length() == 0)
+      {
+        title = tree.getTitle(); // hack!!!!
+      }
+    } catch (Exception e)
     {
-      add();
+      Cache.log.warn("Problems parsing treefile '"
+              + tree.getNewick(0).getContent() + "'", e);
+    }
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.io.vamsas.DatastoreItem#conflict()
+   */
+  public void conflict()
+  {
+    Cache.log
+    .info("Update (with conflict) from vamsas document to alignment associated tree not implemented yet.");
+  }
+
+  /* (non-Javadoc)
+   * @see jalview.io.vamsas.DatastoreItem#update()
+   */
+  public void updateToDoc()
+  {
+    if (isModifiable(tree.getModifiable()))
+    {
+      // synchronize(); // update();
+      // verify any changes.
+      log.info("TODO: Update tree in document from jalview.");
     }
     else
     {
-      if (isModifiable(tree.getModifiable()))
+      // handle conflict
+      log.info("TODO: Add the locally modified tree in Jalview as a new tree in document, leaving locked tree unchanged.");
+    }
+  }
+  /* (non-Javadoc)
+   * @see jalview.io.vamsas.DatastoreItem#updateFromDoc()
+   */
+  public void updateFromDoc()
+  {
+    // should probably just open a new tree panel in the same place as the old one
+    // TODO: Tree.updateFromDoc
+    /*
+    TreePanel tp = (TreePanel) jvobj; // getvObj2jv(tree);
+    
+    // make a new tree
+    Object[] idata = recoverInputData(tree.getProvenance());
+    try
+    {
+      if (idata != null && idata[0] != null)
       {
-        // synchronize(); // update();
-        // verify any changes.
-        System.out.println("Update tree in document.");
+        inputData = (AlignmentView) idata[0];
       }
-      else
+      ntree = getNtree();
+      title = tree.getNewick(0).getTitle();
+      if (title == null || title.length() == 0)
       {
-        // handle conflict
-        System.out.println("Add modified tree as new tree in document.");
+        title = tree.getTitle(); // hack!!!!
       }
+    } catch (Exception e)
+    {
+      Cache.log.warn("Problems parsing treefile '"
+              + tree.getNewick(0).getContent() + "'", e);
+    }*/
+    log.debug("Update the local tree in jalview from the document.");
+
+    if (isModifiable(tree.getModifiable()))
+    {
+      // synchronize(); // update();
+      // verify any changes.
+      log.debug("Update tree in document from jalview.");
+    }
+    else
+    {
+      // handle conflict
+      log.debug("Add modified jalview tree as new tree in document.");
     }
   }
 
@@ -430,7 +479,7 @@ public class Tree extends DatastoreItem
    * add jalview object to vamsas document
    * 
    */
-  public void add()
+  public void addToDocument()
   {
     tree = new uk.ac.vamsas.objects.core.Tree();
     bindjvvobj(tp, tree);