vamsas-client-1.2 schema (mappings and Treenodes) and begun refactoring object bindin...
authorjprocter <Jim Procter>
Sun, 17 Jun 2007 13:11:18 +0000 (13:11 +0000)
committerjprocter <Jim Procter>
Sun, 17 Jun 2007 13:11:18 +0000 (13:11 +0000)
src/jalview/io/VamsasAppDatastore.java
src/jalview/io/vamsas/DatastoreItem.java [new file with mode: 0644]
src/jalview/io/vamsas/Tree.java [new file with mode: 0644]

index d799a6c..427f5b5 100644 (file)
@@ -30,7 +30,9 @@ import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
 import jalview.gui.Desktop;
 import jalview.gui.TreePanel;
+import jalview.io.vamsas.DatastoreItem;
 
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.IdentityHashMap;
@@ -49,12 +51,11 @@ import uk.ac.vamsas.objects.core.*;
 
 public class VamsasAppDatastore
 {
-  Entry provEntry = null;
+  public static final String JALVIEW_ANNOTATION_ROW = "jalview:AnnotationRow";
 
-  // AlignViewport av;
+  public static final String JALVIEW_GRAPH_TYPE = "jalview:graphType";
 
-  org.exolab.castor.types.Date date = new org.exolab.castor.types.Date(
-      new java.util.Date());
+  Entry provEntry = null;
 
   IClientDocument cdoc;
 
@@ -70,23 +71,6 @@ public class VamsasAppDatastore
     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
    */
@@ -441,116 +425,26 @@ public class VamsasAppDatastore
           }
           if (aa[i].sequenceRef != null)
           {
-            uk.ac.vamsas.objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
-                objects.core.AlignmentSequence) getjv2vObj(aa[i].sequenceRef);
-            uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.
-                vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(aa[
-                i]);
-            int[] gapMap = null;
-            if (AlSeqMaps.containsKey(aa[i].sequenceRef))
-            {
-              gapMap = (int[]) AlSeqMaps.get(aa[i].sequenceRef);
-            }
-            else
+            // Deal with sequence associated annotation
+            Vobject sref = getjv2vObj(aa[i].sequenceRef);
+            if (sref instanceof uk.ac.vamsas.objects.core.AlignmentSequence)
             {
-              gapMap = new int[aa[i].sequenceRef.getLength()];
-              // map from alignment position to sequence position.
-              int[] sgapMap = aa[i].sequenceRef.gapMap();
-              for (int a = 0; a < sgapMap.length; a++)
-              {
-                gapMap[sgapMap[a]] = a;
-              }
-            }
-            if (an == null)
+              saveAlignmentSequenceAnnotation(AlSeqMaps, (AlignmentSequence) sref, aa[i]);
+            } else
             {
-              an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
-              Seg vSeg = new Seg();
-              vSeg.setStart(1);
-              vSeg.setInclusive(true);
-              vSeg.setEnd(gapMap.length);
-              an.addSeg(vSeg);
-              an.setType("jalview:SecondaryStructurePrediction"); // TODO: better fix this rough guess ;)
-              alsref.addAlignmentSequenceAnnotation(an);
-              bindjvvobj(aa[i], an);
-              // LATER: much of this is verbatim from the alignmentAnnotation
-              // method below. suggests refactoring to make rangeAnnotation the
-              // base class
-              an.setDescription(aa[i].description);
-              if (aa[i].graph > 0)
+              // first find the alignment sequence to associate this with.
+              SequenceI jvalsq=null;
+              Enumeration jval = av.getAlignment().getSequences().elements();
+              while (jval.hasMoreElements())
               {
-                an.setGraph(true); // aa[i].graph);
-              }
-              else
-              {
-                an.setGraph(false);
-              }
-              an.setLabel(aa[i].label);
-              an.setProvenance(dummyProvenance()); // get provenance as user
-              // created, or jnet, or
-              // something else.
-              an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
-              // originally we
-              // were going to
-              // store
-              // graphGroup in
-              // the Jalview
-              // specific
-              // bits.
-              AnnotationElement ae;
-              for (int a = 0; a < aa[i].annotations.length; a++)
-              {
-                if (aa[i].annotations[a] == null)
-                {
-                  continue;
-                }
-
-                ae = new AnnotationElement();
-                ae.setDescription(aa[i].annotations[a].description);
-                ae.addGlyph(new Glyph());
-                ae.getGlyph(0)
-                    .setContent(aa[i].annotations[a].displayCharacter); // assume
-                // jax-b
-                // takes
-                // care
-                // of
-                // utf8
-                // translation
-                if (aa[i].graph !=
-                    jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+                jvalsq = (SequenceI) jval.nextElement();
+                //saveDatasetSequenceAnnotation(AlSeqMaps,(uk.ac.vamsas.objects.core.Sequence) sref, aa[i]);
+                if (jvalsq.getDatasetSequence() == aa[i].sequenceRef)
                 {
-                  ae.addValue(aa[i].annotations[a].value);
-                }
-                ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
-                // symbols
-                if (aa[i].annotations[a].secondaryStructure != ' ')
-                {
-                  // we only write an annotation where it really exists.
-                  Glyph ss = new Glyph();
-                  ss
-                      .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.
-                               PROTEIN_SS_3STATE);
-                  ss.setContent(String
-                                .valueOf(aa[i].annotations[a].
-                                         secondaryStructure));
-                  ae.addGlyph(ss);
-                }
-                an.addAnnotationElement(ae);
-              }
-            }
-            else
-            {
-              // update reference sequence Annotation
-              if (an.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
-              {
-                // verify existing alignment sequence annotation is up to date
-                System.out.println("update alignment sequence annotation.");
-              }
-              else
-              {
-                // verify existing alignment sequence annotation is up to date
-                System.out
-                    .println(
-                    "make new alignment sequence annotation if modification has happened.");
+                  Vobject alsref = getjv2vObj(jvalsq);
+                  saveAlignmentSequenceAnnotation(AlSeqMaps, (AlignmentSequence) alsref, aa[i]);
+                  break;
+                };
               }
             }
           }
@@ -562,10 +456,10 @@ public class VamsasAppDatastore
             if (an == null)
             {
               an = new uk.ac.vamsas.objects.core.AlignmentAnnotation();
-              an.setType("jalview:AnnotationRow");
+              an.setType(JALVIEW_ANNOTATION_ROW);
               an.setDescription(aa[i].description);
               alignment.addAlignmentAnnotation(an);
-              Seg vSeg = new Seg();
+              Seg vSeg = new Seg(); // TODO: refactor to have a default rangeAnnotationType initer/updater that takes a set of int ranges.
               vSeg.setStart(1);
               vSeg.setInclusive(true);
               vSeg.setEnd(jal.getWidth());
@@ -576,7 +470,7 @@ public class VamsasAppDatastore
               }
               an.setLabel(aa[i].label);
               an.setProvenance(dummyProvenance());
-              if (aa[i].graph != aa[i].NO_GRAPH)
+              if (aa[i].graph != AlignmentAnnotation.NO_GRAPH)
               {
                 an.setGroup(Integer.toString(aa[i].graphGroup)); // // JBPNote -
                 // originally we
@@ -636,7 +530,7 @@ public class VamsasAppDatastore
               {
                 an.setGraph(true);
                 an.setGroup(Integer.toString(aa[i].graphGroup));
-                an.addProperty(newProperty("jalview:graphType", null,
+                an.addProperty(newProperty(JALVIEW_GRAPH_TYPE, null,
                                            ( (aa[i].graph ==
                                               jalview.datamodel.AlignmentAnnotation.
                                               BAR_GRAPH) ? "BAR_GRAPH" :
@@ -685,34 +579,7 @@ public class VamsasAppDatastore
 
             if (tp.getAlignment() == jal)
             {
-              Tree tree = (Tree) getjv2vObj(tp);
-              if (tree == null)
-              {
-                tree = new Tree();
-                bindjvvobj(tp, tree);
-                tree.setTitle(tp.getTitle());
-                Newick newick = new Newick();
-                // TODO: translate sequenceI to leaf mappings to vamsas
-                // references - see tree specification in schema.
-                newick.setContent(tp.getTree().toString());
-                newick.setTitle(tp.getTitle());
-                tree.addNewick(newick);
-                tree.setProvenance(makeTreeProvenance(jal, tp));
-                alignment.addTree(tree);
-              }
-              else
-              {
-                if (tree.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
-                {
-                  // verify any changes.
-                  System.out.println("Update tree in document.");
-                }
-                else
-                {
-                  System.out
-                      .println("Add modified tree as new tree in document.");
-                }
-              }
+              DatastoreItem vtree = new jalview.io.vamsas.Tree(this, tp, jal, alignment);
             }
           }
         }
@@ -727,7 +594,191 @@ public class VamsasAppDatastore
     }
 
   }
+  private void initRangeAnnotationType(RangeAnnotation an, AlignmentAnnotation alan, int[] gapMap)
+  {
+    Seg vSeg = new Seg();
+    vSeg.setStart(1);
+    vSeg.setInclusive(true);
+    vSeg.setEnd(gapMap.length);
+    an.addSeg(vSeg);
+    
+    // LATER: much of this is verbatim from the alignmentAnnotation
+    // method below. suggests refactoring to make rangeAnnotation the
+    // base class
+    an.setDescription(alan.description);
+    an.setLabel(alan.label);
+    an.setGroup(Integer.toString(alan.graphGroup)); 
+    // // JBPNote -
+    // originally we
+    // were going to
+    // store
+    // graphGroup in
+    // the Jalview
+    // specific
+    // bits.
+   AnnotationElement ae;
+    for (int a = 0; a < alan.annotations.length; a++)
+    {
+      if (alan.annotations[a] == null)
+      {
+        continue;
+      }
+
+      ae = new AnnotationElement();
+      ae.setDescription(alan.annotations[a].description);
+      ae.addGlyph(new Glyph());
+      ae.getGlyph(0)
+          .setContent(alan.annotations[a].displayCharacter); // assume
+      // jax-b
+      // takes
+      // care
+      // of
+      // utf8
+      // translation
+      if (alan.graph !=
+          jalview.datamodel.AlignmentAnnotation.NO_GRAPH)
+      {
+        ae.addValue(alan.annotations[a].value);
+      }
+      ae.setPosition(gapMap[a] + 1); // position w.r.t. AlignmentSequence
+      // symbols
+      if (alan.annotations[a].secondaryStructure != ' ')
+      {
+        // we only write an annotation where it really exists.
+        Glyph ss = new Glyph();
+        ss
+            .setDict(uk.ac.vamsas.objects.utils.GlyphDictionary.
+                     PROTEIN_SS_3STATE);
+        ss.setContent(String
+                      .valueOf(alan.annotations[a].
+                               secondaryStructure));
+        ae.addGlyph(ss);
+      }
+      an.addAnnotationElement(ae);
+    }
 
+  }
+  private void saveDatasetSequenceAnnotation(HashMap AlSeqMaps, uk.ac.vamsas.objects.core.Sequence sref, AlignmentAnnotation alan)
+  {
+    //{
+    //  uk.ac.vamsas.
+    //  objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
+    //  objects.core.AlignmentSequence) sref;
+    uk.ac.vamsas.objects.core.DataSetAnnotations an = (uk.ac.
+            vamsas.objects.core.DataSetAnnotations) getjv2vObj(alan);
+    int[] gapMap = getGapMap(AlSeqMaps, alan);
+    if (an == null)
+    {
+      an = new uk.ac.vamsas.objects.core.DataSetAnnotations();
+      initRangeAnnotationType(an, alan, gapMap);
+      an.setProvenance(dummyProvenance()); // get provenance as user
+      // created, or jnet, or
+      // something else.
+      an.setType("jalview:SecondaryStructurePrediction"); // TODO: better fix this rough guess ;)
+      // The properties below don't fit into the DataSet Sequence Annotation as it currently is defined.
+      if (alan.graph > 0)
+      {
+        an.addProperty(newProperty("jalview:displayAsGraph", "boolean", "true"));
+      }
+      an.setGroup(Integer.toString(alan.graphGroup)); // // JBPNote -
+      // originally we
+      // were going to
+      // store
+      // graphGroup in
+      // the Jalview
+      // specific
+      // bits.
+      ((DataSet) sref.getV_parent()).addDataSetAnnotations(an);
+      bindjvvobj(alan, an);
+    }
+    else
+    {
+      // update reference sequence Annotation
+      if (an.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out.println("update dataset sequence annotation.");
+      }
+      else
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out
+            .println(
+            "make new alignment dataset sequence annotation if modification has happened.");
+      }
+    }
+    
+  }
+  private int[] getGapMap(HashMap AlSeqMaps, AlignmentAnnotation alan)
+  {
+    int[] gapMap;
+    if (AlSeqMaps.containsKey(alan.sequenceRef))
+    {
+      gapMap = (int[]) AlSeqMaps.get(alan.sequenceRef);
+    }
+    else
+    {
+      gapMap = new int[alan.sequenceRef.getLength()];
+      // map from alignment position to sequence position.
+      int[] sgapMap = alan.sequenceRef.gapMap();
+      for (int a = 0; a < sgapMap.length; a++)
+      {
+        gapMap[sgapMap[a]] = a;
+      }
+    }
+    return gapMap;
+  }
+  
+  private void saveAlignmentSequenceAnnotation(HashMap AlSeqMaps, AlignmentSequence alsref, AlignmentAnnotation alan)
+  {
+    //{
+    //  uk.ac.vamsas.
+    //  objects.core.AlignmentSequence alsref = (uk.ac.vamsas.
+    //  objects.core.AlignmentSequence) sref;
+    uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation an = (uk.ac.
+            vamsas.objects.core.AlignmentSequenceAnnotation) getjv2vObj(alan);
+    int[] gapMap = getGapMap(AlSeqMaps, alan);
+    if (an == null)
+    {
+      an = new uk.ac.vamsas.objects.core.AlignmentSequenceAnnotation();
+      initRangeAnnotationType(an, alan, gapMap);
+      /**
+       * I mean here that we don't actually have a semantic 'type' for the annotation (this might be - score, intrinsic property, measurement, something extracted from another program, etc)
+       */
+      an.setType("jalview:SecondaryStructurePrediction"); // TODO: better fix this rough guess ;) 
+      alsref.addAlignmentSequenceAnnotation(an);
+      bindjvvobj(alan, an);
+      // These properties are directly supported by the AlignmentSequenceAnnotation type.
+      if (alan.graph != AlignmentAnnotation.NO_GRAPH)
+      {
+        an.setGraph(true);
+        an.addProperty(newProperty(JALVIEW_GRAPH_TYPE, "integer", ""+alan.graph));
+      }
+      else
+      {
+        an.setGraph(false);
+      }
+      an.setProvenance(dummyProvenance()); // get provenance as user
+      // created, or jnet, or
+      // something else.
+    }
+    else
+    {
+      // update reference sequence Annotation
+      if (an.getModifiable()==null) // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out.println("update alignment sequence annotation.");
+      }
+      else
+      {
+        // verify existing alignment sequence annotation is up to date
+        System.out
+            .println(
+            "make new alignment sequence annotation if modification has happened.");
+      }
+    }
+  }
   private Property newProperty(String name, String type, String content)
   {
     Property vProperty = new Property();
@@ -791,53 +842,6 @@ public class VamsasAppDatastore
   }
 
   /**
-   * correctly creates provenance for trees calculated on an alignment by
-   * jalview.
-   *
-   * @param jal
-   * @param tp
-   * @return
-   */
-  private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)
-  {
-    Provenance prov = new Provenance();
-    prov.addEntry(new Entry());
-    prov.getEntry(0).setAction("imported " + tp.getTitle());
-    prov.getEntry(0).setUser(provEntry.getUser());
-    prov.getEntry(0).setApp(provEntry.getApp());
-    prov.getEntry(0).setDate(provEntry.getDate());
-    if (tp.getTree().hasOriginalSequenceData())
-    {
-      Input vInput = new Input();
-      // LATER: check to see if tree input data is contained in this alignment -
-      // or just correctly resolve the tree's seqData to the correct alignment in
-      // the document.
-      // vInput.setObjRef(getjv2vObj(jal));
-      vInput.setObjRef(new Object[] { getjv2vObj(tp.getViewPort())});
-      prov.getEntry(0).setAction("created " + tp.getTitle());
-      prov.getEntry(0).addInput(vInput);
-      vInput.setName("jalview:seqdist");
-      prov.getEntry(0).addParam(new Param());
-      prov.getEntry(0).getParam(0).setName("treeType");
-      prov.getEntry(0).getParam(0).setType("utf8");
-      prov.getEntry(0).getParam(0).setContent("NJ");
-
-      int ranges[] = tp.getTree().seqData.getVisibleContigs();
-      // VisibleContigs are with respect to alignment coordinates. Still need offsets
-      int start = tp.getTree().seqData.getAlignmentOrigin();
-      for (int r = 0; r < ranges.length; r += 2)
-      {
-        Seg visSeg = new Seg();
-        visSeg.setStart(1 + start + ranges[r]);
-        visSeg.setEnd(start + ranges[r + 1]);
-        visSeg.setInclusive(true);
-        vInput.addSeg(visSeg);
-      }
-    }
-    return prov;
-  }
-
-  /**
    *
    * @param tp
    * @return Object[] { AlignmentView, AlignmentI - reference alignment for
@@ -1559,7 +1563,6 @@ public class VamsasAppDatastore
     {
       Cache.log.debug(
           "Inserting empty annotation row elements for a whole-alignment annotation.");
-
     }
     else
     {
@@ -1659,7 +1662,7 @@ public class VamsasAppDatastore
         uk.ac.vamsas.objects.core.Property[] props = annotation.getProperty();
         for (int p = 0; p < props.length; p++)
         {
-          if (props[p].getName().equalsIgnoreCase("jalview:graphType"))
+          if (props[p].getName().equalsIgnoreCase(JALVIEW_GRAPH_TYPE))
           {
             try
             {
@@ -1916,4 +1919,22 @@ public class VamsasAppDatastore
     p.addEntry(dummyPEntry(action));
   }
 
+  public Entry getProvEntry()
+  {
+    return provEntry;
+  }
+
+  public IClientDocument getClientDocument()
+  {
+    return cdoc;
+  }
+
+  public IdentityHashMap getJvObjectBinding()
+  {
+    return jv2vobj;
+  }
+  public Hashtable getVamsasObjectBinding() {
+    return vobj2jv;
+  }
+
 }
diff --git a/src/jalview/io/vamsas/DatastoreItem.java b/src/jalview/io/vamsas/DatastoreItem.java
new file mode 100644 (file)
index 0000000..b77cc8c
--- /dev/null
@@ -0,0 +1,146 @@
+package jalview.io.vamsas;\r
+\r
+import jalview.bin.Cache;\r
+import jalview.gui.TreePanel;\r
+import jalview.io.VamsasAppDatastore;\r
+\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.IdentityHashMap;\r
+import java.util.Vector;\r
+\r
+import uk.ac.vamsas.client.IClientDocument;\r
+import uk.ac.vamsas.client.Vobject;\r
+import uk.ac.vamsas.client.VorbaId;\r
+import uk.ac.vamsas.objects.core.Entry;\r
+\r
+/**\r
+ * Holds all the common machinery for binding objects to vamsas objects\r
+ * @author JimP\r
+ *\r
+ */\r
+public class DatastoreItem\r
+{\r
+  /**\r
+   * \r
+   */\r
+  Entry provEntry = null;\r
+\r
+  IClientDocument cdoc;\r
+\r
+  Hashtable vobj2jv;\r
+\r
+  IdentityHashMap jv2vobj;\r
+  /**\r
+   * @return the Vobject bound to Jalview datamodel object\r
+   */\r
+  protected Vobject getjv2vObj(Object jvobj)\r
+  {\r
+    if (jv2vobj.containsKey(jvobj))\r
+    {\r
+      return cdoc.getObject( (VorbaId) jv2vobj.get(jvobj));\r
+    }\r
+    if (Cache.log.isDebugEnabled())\r
+    {\r
+      Cache.log.debug("Returning null VorbaID binding for jalview object "+jvobj);\r
+    }\r
+    return null;\r
+  }\r
+\r
+  /**\r
+   *\r
+   * @param vobj\r
+   * @return Jalview datamodel object bound to the vamsas document object\r
+   */\r
+  protected Object getvObj2jv(uk.ac.vamsas.client.Vobject vobj)\r
+  {\r
+    VorbaId id = vobj.getVorbaId();\r
+    if (id == null)\r
+    {\r
+      id = cdoc.registerObject(vobj);\r
+      Cache.log\r
+          .debug("Registering new object and returning null for getvObj2jv");\r
+      return null;\r
+    }\r
+    if (vobj2jv.containsKey(vobj.getVorbaId()))\r
+    {\r
+      return vobj2jv.get(vobj.getVorbaId());\r
+    }\r
+    return null;\r
+  }\r
+\r
+  protected void bindjvvobj(Object jvobj, uk.ac.vamsas.client.Vobject vobj)\r
+  {\r
+    VorbaId id = vobj.getVorbaId();\r
+    if (id == null)\r
+    {\r
+      id = cdoc.registerObject(vobj);\r
+      if (id == null || vobj.getVorbaId() == null || cdoc.getObject(id)!=vobj)\r
+      {\r
+        Cache.log.error("Failed to get id for " +\r
+                        (vobj.isRegisterable() ? "registerable" :\r
+                         "unregisterable") + " object " + vobj);\r
+      }\r
+    }\r
+\r
+    if (vobj2jv.containsKey(vobj.getVorbaId()) &&\r
+        ! ( (VorbaId) vobj2jv.get(vobj.getVorbaId())).equals(jvobj))\r
+    {\r
+      Cache.log.debug("Warning? Overwriting existing vamsas id binding for " +\r
+                      vobj.getVorbaId(),\r
+                      new Exception("Overwriting vamsas id binding."));\r
+    }\r
+    else if (jv2vobj.containsKey(jvobj) &&\r
+             ! ( (VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId()))\r
+    {\r
+      Cache.log.debug(\r
+          "Warning? Overwriting existing jalview object binding for " + jvobj,\r
+          new Exception("Overwriting jalview object binding."));\r
+    }\r
+    /* Cache.log.error("Attempt to make conflicting object binding! "+vobj+" id " +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+" already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to bindjvvobj"));\r
+         }*/\r
+    // we just update the hash's regardless!\r
+    Cache.log.debug("Binding "+vobj.getVorbaId()+" to "+jvobj);\r
+    vobj2jv.put(vobj.getVorbaId(), jvobj);\r
+    // JBPNote - better implementing a hybrid invertible hash.\r
+    jv2vobj.put(jvobj, vobj.getVorbaId());\r
+  }\r
+\r
+  public DatastoreItem() {\r
+    super();\r
+  }\r
+  public DatastoreItem(VamsasAppDatastore datastore)\r
+  {\r
+    this();\r
+    initDatastoreItem(datastore);\r
+    // TODO Auto-generated constructor stub\r
+  }\r
+\r
+  public void initDatastoreItem(VamsasAppDatastore ds)\r
+  {\r
+    initDatastoreItem(ds.getProvEntry(), ds.getClientDocument(), ds.getVamsasObjectBinding(), ds.getJvObjectBinding());\r
+  }\r
+  public void initDatastoreItem(Entry provEntry, IClientDocument cdoc, Hashtable vobj2jv, IdentityHashMap jv2vobj)\r
+  {\r
+    this.provEntry = provEntry;\r
+    this.cdoc = cdoc;\r
+    this.vobj2jv = vobj2jv;\r
+    this.jv2vobj = jv2vobj;\r
+  }\r
+\r
+  protected boolean isModifiable(String modifiable)\r
+  {\r
+    return modifiable==null; // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS)\r
+  }\r
+\r
+  protected Vector getjv2vObjs(Vector alsq)\r
+  {\r
+    Vector vObjs = new Vector();\r
+    Enumeration elm = alsq.elements();\r
+    while (elm.hasMoreElements())\r
+    {\r
+      vObjs.addElement(getjv2vObj(elm.nextElement()));\r
+    }\r
+    return vObjs;\r
+  }\r
+}\r
diff --git a/src/jalview/io/vamsas/Tree.java b/src/jalview/io/vamsas/Tree.java
new file mode 100644 (file)
index 0000000..3946a98
--- /dev/null
@@ -0,0 +1,239 @@
+package jalview.io.vamsas;\r
+\r
+import java.util.Enumeration;\r
+import java.util.Hashtable;\r
+import java.util.Vector;\r
+\r
+import jalview.analysis.NJTree;\r
+import jalview.datamodel.AlignmentI;\r
+import jalview.datamodel.SeqCigar;\r
+import jalview.datamodel.SequenceI;\r
+import jalview.gui.TreePanel;\r
+import jalview.io.VamsasAppDatastore;\r
+import uk.ac.vamsas.client.Vobject;\r
+import uk.ac.vamsas.objects.core.Entry;\r
+import uk.ac.vamsas.objects.core.Input;\r
+import uk.ac.vamsas.objects.core.Newick;\r
+import uk.ac.vamsas.objects.core.Param;\r
+import uk.ac.vamsas.objects.core.Provenance;\r
+import uk.ac.vamsas.objects.core.Seg;\r
+import uk.ac.vamsas.objects.core.Treenode;\r
+import uk.ac.vamsas.objects.core.Vref;\r
+\r
+public class Tree extends DatastoreItem\r
+{\r
+  AlignmentI jal;\r
+  TreePanel tp;\r
+  uk.ac.vamsas.objects.core.Tree tree;\r
+  uk.ac.vamsas.objects.core.Alignment alignment; // may be null => dataset or other kind of tree\r
+  public Tree(VamsasAppDatastore datastore, TreePanel tp2, AlignmentI jal2, uk.ac.vamsas.objects.core.Alignment alignment2)\r
+  {\r
+    super(datastore);\r
+\r
+    jal = jal2;\r
+    tp = tp2;\r
+    alignment = alignment2;\r
+    \r
+    tree = (uk.ac.vamsas.objects.core.Tree) getjv2vObj(tp);\r
+    if (tree == null)\r
+    {\r
+      add();\r
+    }\r
+    else\r
+    {\r
+      if (isModifiable(tree.getModifiable()))\r
+      {\r
+        // synchronize(); // update();\r
+        // verify any changes.\r
+        System.out.println("Update tree in document.");\r
+      }\r
+      else\r
+      {\r
+        // handle conflict\r
+        System.out\r
+            .println("Add modified tree as new tree in document.");\r
+      }\r
+    }\r
+  }\r
+  /**\r
+   * correctly creates provenance for trees calculated on an alignment by\r
+   * jalview.\r
+   *\r
+   * @param jal\r
+   * @param tp\r
+   * @return\r
+   */\r
+  private Provenance makeTreeProvenance(AlignmentI jal, TreePanel tp)\r
+  {\r
+    Provenance prov = new Provenance();\r
+    prov.addEntry(new Entry());\r
+    prov.getEntry(0).setAction("imported " + tp.getTitle());\r
+    prov.getEntry(0).setUser(provEntry.getUser());\r
+    prov.getEntry(0).setApp(provEntry.getApp());\r
+    prov.getEntry(0).setDate(provEntry.getDate());\r
+    if (tp.getTree().hasOriginalSequenceData())\r
+    {\r
+      Input vInput = new Input();\r
+      // LATER: check to see if tree input data is contained in this alignment -\r
+      // or just correctly resolve the tree's seqData to the correct alignment in\r
+      // the document.\r
+      Vector alsqrefs = getjv2vObjs(findAlignmentSequences(jal, tp.getTree().seqData.getSequences()));\r
+      Object[] alsqs = new Object[alsqrefs.size()];\r
+      alsqrefs.copyInto(alsqs);\r
+      vInput.setObjRef(alsqs);\r
+      // now create main provenance data\r
+      prov.getEntry(0).setAction("created " + tp.getTitle());\r
+      prov.getEntry(0).addInput(vInput);\r
+      // jalview's special input parameter for distance matrix calculations\r
+      vInput.setName("jalview:seqdist");\r
+      prov.getEntry(0).addParam(new Param());\r
+      prov.getEntry(0).getParam(0).setName("treeType");\r
+      prov.getEntry(0).getParam(0).setType("utf8");\r
+      prov.getEntry(0).getParam(0).setContent("NJ");\r
+      int ranges[] = tp.getTree().seqData.getVisibleContigs();\r
+      // VisibleContigs are with respect to alignment coordinates. Still need offsets\r
+      int start = tp.getTree().seqData.getAlignmentOrigin();\r
+      for (int r = 0; r < ranges.length; r += 2)\r
+      {\r
+        Seg visSeg = new Seg();\r
+        visSeg.setStart(1 + start + ranges[r]);\r
+        visSeg.setEnd(start + ranges[r + 1]);\r
+        visSeg.setInclusive(true);\r
+        vInput.addSeg(visSeg);\r
+      }\r
+    }\r
+    return prov;\r
+  }\r
+  /**\r
+   * look up SeqCigars in an existing alignment.\r
+   * @param jal\r
+   * @param sequences\r
+   * @return vector of alignment sequences in order of SeqCigar array (but missing unfound seqcigars)\r
+   */\r
+  private Vector findAlignmentSequences(AlignmentI jal, SeqCigar[] sequences)\r
+  {\r
+    SeqCigar[] tseqs = new SeqCigar[sequences.length];\r
+    System.arraycopy(sequences, 0, tseqs, 0, sequences.length);\r
+    Vector alsq = new Vector();\r
+    Enumeration as = jal.getSequences().elements();\r
+    while (as.hasMoreElements())\r
+    {\r
+      SequenceI asq = (SequenceI) as.nextElement();\r
+      for (int t = 0; t<sequences.length; t++)\r
+      {\r
+        if (tseqs[t]!=null \r
+                && (tseqs[t].getRefSeq()==asq || tseqs[t].getRefSeq() == asq.getDatasetSequence())\r
+                && tseqs[t].getStart()>=asq.getStart() && tseqs[t].getEnd()<=asq.getEnd())\r
+        {\r
+          tseqs[t] = null;\r
+          alsq.add(asq);\r
+        }\r
+      }\r
+    }\r
+    return alsq;\r
+  }\r
+  public Treenode[] makeTreeNodes(NJTree ntree) {\r
+    Vector leaves = new Vector();\r
+    ntree.findLeaves(ntree.getTopNode(), leaves);\r
+    Vector tnv = new Vector();\r
+    Enumeration l = leaves.elements();\r
+    int i=0;\r
+    Hashtable nodespecs = new Hashtable();\r
+    while (l.hasMoreElements())\r
+    {\r
+      jalview.datamodel.BinaryNode tnode = (jalview.datamodel.BinaryNode) l.nextElement();\r
+      if (tnode instanceof jalview.datamodel.SequenceNode)\r
+      {\r
+        if (!((jalview.datamodel.SequenceNode) tnode).isPlaceholder())\r
+        {\r
+          Object assocseq = ((jalview.datamodel.SequenceNode) tnode).element();\r
+          if (assocseq instanceof SequenceI)\r
+          {\r
+            Vobject vobj = this.getjv2vObj(assocseq);\r
+            if (vobj!=null)\r
+            {\r
+              Treenode node = new Treenode();\r
+              node.setNodespec(makeNodeSpec(nodespecs, tnode));\r
+              node.setName(tnode.getName());\r
+              Vref vr = new Vref();\r
+              vr.addRefs(vobj);\r
+              node.addVref(vr);\r
+              tnv.addElement(node);\r
+            }\r
+            else\r
+            {\r
+              System.err.println("WARNING: Unassociated treeNode "+tnode.element().toString()+" "\r
+                      +((tnode.getName()!=null) ? " label "+tnode.getName() : ""));\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    if (tnv.size()>0)\r
+    {\r
+      Treenode[] tn = new Treenode[tnv.size()];\r
+      tnv.copyInto(tn);  \r
+      return tn;\r
+    }\r
+    return new Treenode[] {};\r
+  }\r
+  private String makeNodeSpec(Hashtable nodespecs, jalview.datamodel.BinaryNode tnode)\r
+  { \r
+    String nname = new String(tnode.getName());\r
+    Integer nindx = (Integer) nodespecs.get(nname);\r
+    if (nindx==null)\r
+    {\r
+      nindx = new Integer(1);\r
+    }\r
+    nname = nindx.toString()+" "+nname;\r
+    return nname;\r
+  }\r
+  /**\r
+   * call to match up Treenode specs to NJTree parsed from document object.\r
+   * @param nodespec\r
+   * @param leaves as returned from NJTree.findLeaves( .., ..) .. \r
+   * @return\r
+   */\r
+  private jalview.datamodel.BinaryNode findNodeSpec(String nodespec, Vector leaves)\r
+  {\r
+    int occurence=-1;\r
+    String nspec = nodespec.substring(nodespec.indexOf(' ')+1);\r
+    String oval = nodespec.substring(0, nodespec.indexOf(' '));\r
+    try {\r
+      occurence = new Integer(oval).intValue();\r
+    }\r
+    catch (Exception e)\r
+    {\r
+      System.err.println("Invalid nodespec '"+nodespec+"'");\r
+      return null;\r
+    }\r
+    jalview.datamodel.BinaryNode bn = null;\r
+    \r
+    int nocc = 0;\r
+    Enumeration en = leaves.elements();\r
+    while (en.hasMoreElements() && nocc<occurence)\r
+    {\r
+      bn = (jalview.datamodel.BinaryNode) en.nextElement();\r
+      if (bn instanceof jalview.datamodel.SequenceNode && bn.getName().equals(nspec))\r
+      {\r
+         --occurence;\r
+      } else \r
+        bn=null;\r
+    }\r
+    return bn;\r
+  }\r
+  \r
+  public void add() {\r
+    tree = new uk.ac.vamsas.objects.core.Tree();\r
+    bindjvvobj(tp, tree);\r
+    tree.setTitle(tp.getTitle());\r
+    Newick newick = new Newick();\r
+    newick.setContent(tp.getTree().toString());\r
+    newick.setTitle(tp.getTitle());\r
+    tree.addNewick(newick);\r
+    tree.setProvenance(makeTreeProvenance(jal, tp));\r
+    tree.setTreenode(makeTreeNodes(tp.getTree()));\r
+    \r
+    alignment.addTree(tree);\r
+  }\r
+}\r