JAL-2629 update spike branch to latest
[jalview.git] / src / jalview / gui / Jalview2XML.java
index 3840597..aed73d6 100644 (file)
@@ -30,6 +30,7 @@ import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.GraphLine;
+import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.RnaViewerModel;
 import jalview.datamodel.SequenceFeature;
@@ -45,6 +46,7 @@ import jalview.ext.varna.RnaModel;
 import jalview.gui.StructureViewer.ViewerType;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
+import jalview.io.HMMFile;
 import jalview.renderer.ResidueShaderI;
 import jalview.schemabinding.version2.AlcodMap;
 import jalview.schemabinding.version2.AlcodonFrame;
@@ -52,7 +54,6 @@ import jalview.schemabinding.version2.Annotation;
 import jalview.schemabinding.version2.AnnotationColours;
 import jalview.schemabinding.version2.AnnotationElement;
 import jalview.schemabinding.version2.CalcIdParam;
-import jalview.schemabinding.version2.Colour;
 import jalview.schemabinding.version2.CompoundMatcher;
 import jalview.schemabinding.version2.DBRef;
 import jalview.schemabinding.version2.Features;
@@ -167,6 +168,8 @@ public class Jalview2XML
 
   private static final String RNA_PREFIX = "rna_";
 
+  private static final String HMMER_PREFIX = "hmmer_";
+
   private static final String UTF_8 = "UTF-8";
 
   // use this with nextCounter() to make unique names for entities
@@ -867,73 +870,28 @@ public class Jalview2XML
         }
       }
 
-      // TODO: omit sequence features from each alignment view's XML dump if we
-      // are storing dataset
-      List<jalview.datamodel.SequenceFeature> sfs = jds
-              .getSequenceFeatures();
+      /*
+       * save sequence features
+       * TODO: omit sequence features from each alignment view's 
+       * XML dump if we are storing dataset
+       */
+      List<SequenceFeature> sfs = jds.getSequenceFeatures();
       for (SequenceFeature sf : sfs)
       {
-        Features features = new Features();
-
-        features.setBegin(sf.getBegin());
-        features.setEnd(sf.getEnd());
-        features.setDescription(sf.getDescription());
-        features.setType(sf.getType());
-        features.setFeatureGroup(sf.getFeatureGroup());
-        features.setScore(sf.getScore());
-        if (sf.links != null)
-        {
-          for (int l = 0; l < sf.links.size(); l++)
-          {
-            OtherData keyValue = new OtherData();
-            keyValue.setKey("LINK_" + l);
-            keyValue.setValue(sf.links.elementAt(l).toString());
-            features.addOtherData(keyValue);
-          }
-        }
-        if (sf.otherDetails != null)
-        {
-          /*
-           * save feature attributes, which may be simple strings or
-           * map valued (have sub-attributes)
-           */
-          for (Entry<String, Object> entry : sf.otherDetails.entrySet())
-          {
-            String key = entry.getKey();
-            Object value = entry.getValue();
-            if (value instanceof Map<?, ?>)
-            {
-              for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
-                      .entrySet())
-              {
-                OtherData otherData = new OtherData();
-                otherData.setKey(key);
-                otherData.setKey2(subAttribute.getKey());
-                otherData.setValue(subAttribute.getValue().toString());
-                features.addOtherData(otherData);
-              }
-            }
-            else
-            {
-              OtherData otherData = new OtherData();
-              otherData.setKey(key);
-              otherData.setValue(value.toString());
-              features.addOtherData(otherData);
-            }
-          }
-        }
-
+        Features features = saveFeature(sf);
         jseq.addFeatures(features);
       }
 
+      /*
+       * save PDB entries for sequence
+       */
       if (jdatasq.getAllPDBEntries() != null)
       {
-        Enumeration en = jdatasq.getAllPDBEntries().elements();
+        Enumeration<PDBEntry> en = jdatasq.getAllPDBEntries().elements();
         while (en.hasMoreElements())
         {
           Pdbids pdb = new Pdbids();
-          jalview.datamodel.PDBEntry entry = (jalview.datamodel.PDBEntry) en
-                  .nextElement();
+          PDBEntry entry = en.nextElement();
 
           String pdbId = entry.getId();
           pdb.setId(pdbId);
@@ -1017,6 +975,11 @@ public class Jalview2XML
 
       saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
 
+      if (jds.hasHMMProfile())
+      {
+        saveHmmerProfile(jout, jseq, jds);
+      }
+
       jms.addJSeq(jseq);
     }
 
@@ -1508,6 +1471,98 @@ public class Jalview2XML
   }
 
   /**
+   * Saves the HMMER profile associated with the sequence as a file in the jar,
+   * in HMMER format, and saves the name of the file as a child element of the
+   * XML sequence element
+   * 
+   * @param jout
+   * @param xmlSeq
+   * @param seq
+   */
+  protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
+          SequenceI seq)
+  {
+    HiddenMarkovModel profile = seq.getHMM();
+    if (profile == null)
+    {
+      warn("Want to save HMM profile for " + seq.getName()
+              + " but none found");
+      return;
+    }
+    HMMFile hmmFile = new HMMFile(profile);
+    String hmmAsString = hmmFile.print();
+    String jarEntryName = HMMER_PREFIX + nextCounter();
+    try
+    {
+      writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
+      xmlSeq.setHmmerProfile(jarEntryName);
+    } catch (IOException e)
+    {
+      warn("Error saving HMM profile: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Converts a Jalview SequenceFeature into the XML model of it to save
+   * 
+   * @param sf
+   * @return
+   */
+  protected Features saveFeature(SequenceFeature sf)
+  {
+    Features features = new Features();
+
+    features.setBegin(sf.getBegin());
+    features.setEnd(sf.getEnd());
+    features.setDescription(sf.getDescription());
+    features.setType(sf.getType());
+    features.setFeatureGroup(sf.getFeatureGroup());
+    features.setScore(sf.getScore());
+    if (sf.links != null)
+    {
+      for (int l = 0; l < sf.links.size(); l++)
+      {
+        OtherData keyValue = new OtherData();
+        keyValue.setKey("LINK_" + l);
+        keyValue.setValue(sf.links.elementAt(l).toString());
+        features.addOtherData(keyValue);
+      }
+    }
+    if (sf.otherDetails != null)
+    {
+      /*
+       * save feature attributes, which may be simple strings or
+       * map valued (have sub-attributes)
+       */
+      for (Entry<String, Object> entry : sf.otherDetails.entrySet())
+      {
+        String key = entry.getKey();
+        Object value = entry.getValue();
+        if (value instanceof Map<?, ?>)
+        {
+          for (Entry<String, Object> subAttribute : ((Map<String, Object>) value)
+                  .entrySet())
+          {
+            OtherData otherData = new OtherData();
+            otherData.setKey(key);
+            otherData.setKey2(subAttribute.getKey());
+            otherData.setValue(subAttribute.getValue().toString());
+            features.addOtherData(otherData);
+          }
+        }
+        else
+        {
+          OtherData otherData = new OtherData();
+          otherData.setKey(key);
+          otherData.setValue(value.toString());
+          features.addOtherData(otherData);
+        }
+      }
+    }
+    return features;
+  }
+
+  /**
    * Save any Varna viewers linked to this sequence. Writes an rnaViewer element
    * for each viewer, with
    * <ul>
@@ -1708,9 +1763,8 @@ public class Jalview2XML
       }
       else if (!matchedFile.equals(pdbentry.getFile()))
       {
-        Cache.log.warn(
-                "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
-                        + pdbentry.getFile());
+        warn("Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+                + pdbentry.getFile());
       }
       // record the
       // file so we
@@ -2194,12 +2248,12 @@ public class Jalview2XML
         mpc.setDseqFor(jmpid);
         if (!seqRefIds.containsKey(mpc.getDseqFor()))
         {
-          jalview.bin.Cache.log.debug("creatign new DseqFor ID");
+          debug("creating new DseqFor ID");
           seqRefIds.put(mpc.getDseqFor(), ps);
         }
         else
         {
-          jalview.bin.Cache.log.debug("reusing DseqFor ID");
+          debug("reusing DseqFor ID");
         }
 
         mp.setMappingChoice(mpc);
@@ -3014,24 +3068,26 @@ public class Jalview2XML
       //
       for (int i = 0; i < vamsasSeq.length; i++)
       {
+        SequenceI alignmentSeq = al.getSequenceAt(i);
         if (jseqs[i].getFeaturesCount() > 0)
         {
           Features[] features = jseqs[i].getFeatures();
           for (int f = 0; f < features.length; f++)
           {
-            SequenceFeature sf = new SequenceFeature(features[f].getType(),
-                    features[f].getDescription(), features[f].getBegin(),
-                    features[f].getEnd(), features[f].getScore(),
-                    features[f].getFeatureGroup());
-            sf.setStatus(features[f].getStatus());
+            Features feature = features[f];
+            SequenceFeature sf = new SequenceFeature(feature.getType(),
+                    feature.getDescription(), feature.getBegin(),
+                    feature.getEnd(), feature.getScore(),
+                    feature.getFeatureGroup());
+            sf.setStatus(feature.getStatus());
 
             /*
              * load any feature attributes - include map-valued attributes
              */
             Map<String, Map<String, String>> mapAttributes = new HashMap<>();
-            for (int od = 0; od < features[f].getOtherDataCount(); od++)
+            for (int od = 0; od < feature.getOtherDataCount(); od++)
             {
-              OtherData keyValue = features[f].getOtherData(od);
+              OtherData keyValue = feature.getOtherData(od);
               String attributeName = keyValue.getKey();
               String attributeValue = keyValue.getValue();
               if (attributeName.startsWith("LINK"))
@@ -3065,16 +3121,15 @@ public class Jalview2XML
             }
 
             // adds feature to datasequence's feature set (since Jalview 2.10)
-            al.getSequenceAt(i).addSequenceFeature(sf);
+            alignmentSeq.addSequenceFeature(sf);
           }
         }
         if (vamsasSeq[i].getDBRefCount() > 0)
         {
           // adds dbrefs to datasequence's set (since Jalview 2.10)
           addDBRefs(
-                  al.getSequenceAt(i).getDatasetSequence() == null
-                          ? al.getSequenceAt(i)
-                          : al.getSequenceAt(i).getDatasetSequence(),
+                  alignmentSeq.getDatasetSequence() == null ? alignmentSeq
+                          : alignmentSeq.getDatasetSequence(),
                   vamsasSeq[i]);
         }
         if (jseqs[i].getPdbidsCount() > 0)
@@ -3122,16 +3177,25 @@ public class Jalview2XML
                     .getStructureSelectionManager(Desktop.instance)
                     .registerPDBEntry(entry);
             // adds PDBEntry to datasequence's set (since Jalview 2.10)
-            if (al.getSequenceAt(i).getDatasetSequence() != null)
+            if (alignmentSeq.getDatasetSequence() != null)
             {
-              al.getSequenceAt(i).getDatasetSequence().addPDBId(entry);
+              alignmentSeq.getDatasetSequence().addPDBId(entry);
             }
             else
             {
-              al.getSequenceAt(i).addPDBId(entry);
+              alignmentSeq.addPDBId(entry);
             }
           }
         }
+
+        /*
+         * load any HMMER profile
+         */
+        String hmmJarFile = jseqs[i].getHmmerProfile();
+        if (hmmJarFile != null)
+        {
+          loadHmmerProfile(jprovider, hmmJarFile, alignmentSeq);
+        }
       }
     } // end !multipleview
 
@@ -3629,6 +3693,31 @@ public class Jalview2XML
   }
 
   /**
+   * Loads a HMMER profile from a file stored in the project, and associates it
+   * with the specified sequence
+   * 
+   * @param jprovider
+   * @param hmmJarFile
+   * @param seq
+   */
+  protected void loadHmmerProfile(jarInputStreamProvider jprovider,
+          String hmmJarFile, SequenceI seq)
+  {
+    try
+    {
+      String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
+      HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
+      HiddenMarkovModel hmmModel = parser.getHMM();
+      hmmModel = new HiddenMarkovModel(hmmModel, seq);
+      seq.setHMM(hmmModel);
+    } catch (IOException e)
+    {
+      warn("Error loading HMM profile for " + seq.getName() + ": "
+              + e.getMessage());
+    }
+  }
+
+  /**
    * Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
    * panel is restored from separate jar entries, two (gapped and trimmed) per
    * sequence and secondary structure.
@@ -5055,10 +5144,7 @@ public class Jalview2XML
             id = object.getJalviewModelSequence().getViewport()[0]
                     .getSequenceSetId()))
     {
-      if (Cache.log != null && Cache.log.isDebugEnabled())
-      {
-        Cache.log.debug("Skipping seuqence set id " + id);
-      }
+      debug("Skipping sequence set id " + id);
       return true;
     }
     return false;
@@ -5432,7 +5518,7 @@ public class Jalview2XML
           seqRefIds.put(sqid, djs);
 
         }
-        jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
+        debug("about to recurse on addDBRefs.");
         addDBRefs(djs, ms);
 
       }
@@ -5610,7 +5696,7 @@ public class Jalview2XML
       }
       else
       {
-        Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
+        debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
       }
     }
   }
@@ -5942,7 +6028,10 @@ public class Jalview2XML
         maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
       } catch (Exception e)
       {
-        Cache.log.warn("Couldn't parse out graduated feature color.", e);
+        if (Cache.log != null)
+        {
+          Cache.log.warn("Couldn't parse out graduated feature color.", e);
+        }
       }
   
       NoValueColour noCol = colourModel.getNoValueColour();