JAL-2103 extracted result processing code to allow mocking
authorJim Procter <jprocter@issues.jalview.org>
Tue, 10 May 2016 15:25:23 +0000 (16:25 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Tue, 10 May 2016 15:25:23 +0000 (16:25 +0100)
src/jalview/ws/jws1/JPredThread.java
src/jalview/ws/jws1/JPredWSUtils.java [new file with mode: 0644]
test/jalview/ws/jws1/JPredWSUtilsTest.java [new file with mode: 0644]

index bb09af3..da53ef5 100644 (file)
@@ -23,7 +23,6 @@ package jalview.ws.jws1;
 import jalview.analysis.AlignSeq;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
@@ -31,6 +30,7 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.WebserviceInfo;
+import jalview.io.FileParse;
 import jalview.io.FormatAdapter;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
@@ -38,8 +38,8 @@ import jalview.ws.AWsJob;
 import jalview.ws.JobStateSummary;
 import jalview.ws.WSClientI;
 
+import java.io.IOException;
 import java.util.Hashtable;
-import java.util.List;
 
 import vamsas.objects.simple.JpredResult;
 
@@ -61,11 +61,6 @@ class JPredThread extends JWS1Thread implements WSClientI
 
     java.util.Hashtable SequenceInfo = null;
 
-    int msaIndex = 0; // the position of the original sequence in the array of
-
-    // Sequences in the input object that this job holds a
-    // prediction for
-
     /**
      * 
      * @return true if getResultSet will return a valid alignment and prediction
@@ -106,261 +101,26 @@ class JPredThread extends JWS1Thread implements WSClientI
       {
         return null;
       }
-      AlignmentI al = null;
-      ColumnSelection alcsel = null;
-      int FirstSeq = -1; // the position of the query sequence in Alignment al
 
       JpredResult result = (JpredResult) this.result;
 
       jalview.bin.Cache.log.debug("Parsing output from JNet job.");
-      // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt",
-      // "File");
-      jalview.io.JPredFile prediction = new jalview.io.JPredFile(
-              result.getPredfile(), "Paste");
-      SequenceI[] preds = prediction.getSeqsAsArray();
-      jalview.bin.Cache.log.debug("Got prediction profile.");
-
-      if ((this.msa != null) && (result.getAligfile() != null))
-      {
-        jalview.bin.Cache.log.debug("Getting associated alignment.");
-        // we ignore the returned alignment if we only predicted on a single
-        // sequence
-        String format = new jalview.io.IdentifyFile().identify(
-                result.getAligfile(), "Paste");
-
-        if (jalview.io.FormatAdapter.isValidFormat(format))
-        {
-          SequenceI sqs[];
-          if (predMap != null)
-          {
-            Object[] alandcolsel = input
-                    .getAlignmentAndColumnSelection(getGapChar());
-            sqs = (SequenceI[]) alandcolsel[0];
-            al = new Alignment(sqs);
-            alcsel = (ColumnSelection) alandcolsel[1];
-          }
-          else
-          {
-            al = new FormatAdapter().readFile(result.getAligfile(),
-                    "Paste", format);
-            sqs = new SequenceI[al.getHeight()];
-
-            for (int i = 0, j = al.getHeight(); i < j; i++)
-            {
-              sqs[i] = al.getSequenceAt(i);
-            }
-            if (!jalview.analysis.SeqsetUtils.deuniquify(SequenceInfo, sqs))
-            {
-              throw (new Exception(
-                      MessageManager
-                              .getString("exception.couldnt_recover_sequence_properties_for_alignment")));
-            }
-          }
-          FirstSeq = 0;
-          if (currentView.getDataset() != null)
-          {
-            al.setDataset(currentView.getDataset());
-
-          }
-          else
-          {
-            al.setDataset(null);
-          }
-          jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
-                  FirstSeq, false, predMap);
-
-        }
-        else
-        {
-          throw (new Exception(MessageManager.formatMessage(
-                  "exception.unknown_format_for_file", new String[] {
-                      format, result.getAligfile() })));
-        }
-      }
-      else
-      {
-        AlignmentI fullAlignment = null;
-        try
-        {
-          // locate full alignment
-          // http://www.compbio.dundee.ac.uk/jpred/results/jp_GuygEzV/jp_GuygEzV.full_MSA.fasta
-          String jobid = getJobId().substring(
-                  getJobId().lastIndexOf("/") + 1);
-          String job_alignment = "http://www.compbio.dundee.ac.uk/jpred/results/"
-                  + jobid + "/" + jobid + ".full_MSA.fasta";
-          fullAlignment = new FormatAdapter().readFile(job_alignment,
-                  FormatAdapter.URL, "FASTA");
-        } catch (Exception q)
-        {
-
-        } finally
-        {
-          if (fullAlignment != null)
-          {
-            al = fullAlignment;
-            FirstSeq = 0;
-          }
-          else
-          {
-            al = new Alignment(preds);
-            FirstSeq = prediction.getQuerySeqPosition();
-          }
-        }
-
-        if (predMap != null)
-        {
-          // map the prediction onto the query sequence, excluding positions
-          // corresponding to hidden regions in the original input.
-          char gc = getGapChar();
-          SequenceI[] sqs = (SequenceI[]) input
-                  .getAlignmentAndColumnSelection(gc)[0];
-          if (this.msaIndex >= sqs.length)
-          {
-            throw new Error(
-                    MessageManager
-                            .getString("error.implementation_error_invalid_msa_index_for_job"));
-          }
-          if (fullAlignment == null)
-          {
-            // //
-            // Uses RemoveGapsCommand
-            // //
-            new jalview.commands.RemoveGapsCommand(
-                    MessageManager.getString("label.remove_gaps"),
-                    new SequenceI[] { sqs[msaIndex] }, currentView);
-
-            SequenceI profileseq = al.getSequenceAt(FirstSeq);
-            profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
-          }
-        }
-
-        if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
-                al.getSequenceAt(FirstSeq), SequenceInfo))
-        {
-          throw (new Exception(
-                  MessageManager
-                          .getString("exception.couldnt_recover_sequence_props_for_jnet_query")));
-        }
-        else
-        {
-          if (currentView.getDataset() != null)
-          {
-            al.setDataset(currentView.getDataset());
-
-          }
-          else
-          {
-            al.setDataset(null);
-          }
-          jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
-                  FirstSeq, true, predMap);
-          SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
-          if (fullAlignment == null)
-          {
-            alignToProfileSeq(al, profileseq);
-          }
-          if (fullAlignment == null && predMap != null)
-          {
-            // Adjust input view for gaps
-            // propagate insertions into profile
-            alcsel = ColumnSelection.propagateInsertions(profileseq, al,
-                    input);
-          }
-        }
-      }
-      // transfer to dataset
-      for (AlignmentAnnotation alant : al.getAlignmentAnnotation())
-      {
-        if (alant.sequenceRef != null)
-        {
-          replaceAnnotationOnAlignmentWith(alant, alant.label,
-                  "jalview.jws1.Jpred" + (this.msa == null ? "" : "MSA"),
-                  alant.sequenceRef);
-        }
-      }
-      return new Object[] { al, alcsel }; // , FirstSeq, noMsa};
-    }
-
-    /**
-     * copied from JabawsCalcWorker
-     * 
-     * @param newAnnot
-     * @param typeName
-     * @param calcId
-     * @param aSeq
-     */
-    protected void replaceAnnotationOnAlignmentWith(
-            AlignmentAnnotation newAnnot, String typeName, String calcId,
-            SequenceI aSeq)
-    {
-      SequenceI dsseq = aSeq.getDatasetSequence();
-      while (dsseq.getDatasetSequence() != null)
-      {
-        dsseq = dsseq.getDatasetSequence();
-      }
-      // look for same annotation on dataset and lift this one over
-      List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(
-              calcId, typeName);
-      if (dsan != null && dsan.size() > 0)
-      {
-        for (AlignmentAnnotation dssan : dsan)
-        {
-          dsseq.removeAlignmentAnnotation(dssan);
-        }
-      }
-      AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
-      dsseq.addAlignmentAnnotation(dssan);
-      dssan.adjustForAlignment();
+      Object[] resview = JPredWSUtils.processJnetResult(currentView, input,
+              getGapChar(), SequenceInfo, this.msa != null,
+              this.predMap,
+              result.getPredfile(), result.getAligfile(),
+              getFullAlignmentSource());
+      return resview; // Alignment, ColumnSelection
     }
 
-    /**
-     * Given an alignment where all other sequences except profileseq are
-     * aligned to the ungapped profileseq, insert gaps in the other sequences to
-     * realign them with the residues in profileseq
-     * 
-     * @param al
-     * @param profileseq
-     */
-    private void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
+    public FileParse getFullAlignmentSource() throws IOException
     {
-      char gc = al.getGapCharacter();
-      int[] gapMap = profileseq.gapMap();
-      // insert gaps into profile
-      for (int lp = 0, r = 0; r < gapMap.length; r++)
-      {
-        if (gapMap[r] - lp > 1)
-        {
-          StringBuffer sb = new StringBuffer();
-          for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
-          {
-            sb.append(gc);
-          }
-          for (int s = 1, ns = al.getHeight(); s < ns; s++)
-          {
-            String sq = al.getSequenceAt(s).getSequenceAsString();
-            int diff = gapMap[r] - sq.length();
-            if (diff > 0)
-            {
-              // pad gaps
-              sq = sq + sb;
-              while ((diff = gapMap[r] - sq.length()) > 0)
-              {
-                sq = sq
-                        + ((diff >= sb.length()) ? sb.toString() : sb
-                                .substring(0, diff));
-              }
-              al.getSequenceAt(s).setSequence(sq);
-            }
-            else
-            {
-              al.getSequenceAt(s).setSequence(
-                      sq.substring(0, gapMap[r]) + sb.toString()
-                              + sq.substring(gapMap[r]));
-            }
-          }
-        }
-        lp = gapMap[r];
-      }
+      // locate full alignment
+      // http://www.compbio.dundee.ac.uk/jpred/results/jp_GuygEzV/jp_GuygEzV.full_MSA.fasta
+      String jobid = getJobId().substring(getJobId().lastIndexOf("/") + 1);
+      String job_alignment = "http://www.compbio.dundee.ac.uk/jpred/results/"
+              + jobid + "/" + jobid + ".full_MSA.fasta";
+      return new FileParse(job_alignment, FormatAdapter.URL);
     }
 
     public JPredJob(Hashtable SequenceInfo, SequenceI seq, int[] delMap)
diff --git a/src/jalview/ws/jws1/JPredWSUtils.java b/src/jalview/ws/jws1/JPredWSUtils.java
new file mode 100644 (file)
index 0000000..7b74e2a
--- /dev/null
@@ -0,0 +1,317 @@
+package jalview.ws.jws1;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.SequenceI;
+import jalview.io.FileParse;
+import jalview.io.FormatAdapter;
+import jalview.util.MessageManager;
+
+import java.util.Hashtable;
+import java.util.List;
+
+
+/**
+ * extraction of processing routines to allow mocking
+ * 
+ * @author jprocter
+ *
+ */
+public class JPredWSUtils
+{
+  /**
+   * Process data extracted from service result set to generate a JPred result
+   * view.
+   * 
+   * @param currentView
+   * 
+   * @param input
+   *          - original input alignment
+   * @param gapChar
+   *          - character to use for reconstructing alignment used for
+   *          prediction
+   * @param SequenceInfo
+   *          - from SeqHash
+   * @param msaPred
+   *          - true if a prediction based on existing MSA
+   * @param predMap
+   *          - position
+   * @param result_PredFile
+   * @param result_Aligfile
+   * @param full_alignment
+   * @return { Alignment, ColumnSelection }
+   * @throws Exception
+   */
+  public static Object[] processJnetResult(AlignmentI currentView,
+          AlignmentView input,
+          char gapChar, Hashtable SequenceInfo,
+          boolean msaPred, int[] predMap, String result_PredFile,
+          String result_Aligfile, FileParse full_alignment)
+          throws Exception
+  {
+
+    AlignmentI al = null;
+    ColumnSelection alcsel = null;
+
+    // the position of the query sequence in Alignment al
+    int FirstSeq = -1;
+
+    // the position of the original sequence in the array of
+    // Sequences in the input object that this job holds a
+    // prediction for
+    int msaIndex = 0;
+
+    // JPredFile prediction = new JPredFile("C:/JalviewX/files/jpred.txt",
+    // "File");
+    jalview.io.JPredFile prediction = new jalview.io.JPredFile(
+            result_PredFile, "Paste");
+    SequenceI[] preds = prediction.getSeqsAsArray();
+    jalview.bin.Cache.log.debug("Got prediction profile.");
+
+    if (msaPred && (result_Aligfile != null))
+    {
+      jalview.bin.Cache.log.debug("Getting associated alignment.");
+      // we ignore the returned alignment if we only predicted on a single
+      // sequence
+      String format = new jalview.io.IdentifyFile().identify(
+              result_Aligfile, "Paste");
+
+      if (jalview.io.FormatAdapter.isValidFormat(format))
+      {
+        SequenceI sqs[];
+        if (predMap != null)
+        {
+          Object[] alandcolsel = input
+                  .getAlignmentAndColumnSelection(gapChar);
+          sqs = (SequenceI[]) alandcolsel[0];
+          al = new Alignment(sqs);
+          alcsel = (ColumnSelection) alandcolsel[1];
+        }
+        else
+        {
+          al = new FormatAdapter().readFile(result_Aligfile, "Paste",
+                  format);
+          sqs = new SequenceI[al.getHeight()];
+
+          for (int i = 0, j = al.getHeight(); i < j; i++)
+          {
+            sqs[i] = al.getSequenceAt(i);
+          }
+          if (!jalview.analysis.SeqsetUtils.deuniquify(SequenceInfo, sqs))
+          {
+            throw (new Exception(
+                    MessageManager
+                            .getString("exception.couldnt_recover_sequence_properties_for_alignment")));
+          }
+        }
+        FirstSeq = 0;
+        if (currentView.getDataset() != null)
+        {
+          al.setDataset(currentView.getDataset());
+
+        }
+        else
+        {
+          al.setDataset(null);
+        }
+        jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
+                FirstSeq, false, predMap);
+
+      }
+      else
+      {
+        throw (new Exception(MessageManager.formatMessage(
+                "exception.unknown_format_for_file", new String[] { format,
+                    result_Aligfile })));
+      }
+    }
+    else
+    {
+      AlignmentI fullAlignment = null;
+      try
+      {
+        // read full alignment if present.
+        if (full_alignment != null)
+        {
+        fullAlignment = new FormatAdapter().readFromFile(full_alignment,
+                "FASTA");
+        }
+      } catch (Exception q)
+      {
+
+      } finally
+      {
+        if (fullAlignment != null)
+        {
+          al = fullAlignment;
+          FirstSeq = 0;
+        }
+        else
+        {
+          al = new Alignment(preds);
+          FirstSeq = prediction.getQuerySeqPosition();
+        }
+      }
+
+      if (predMap != null)
+      {
+        // map the prediction onto the query sequence, excluding positions
+        // corresponding to hidden regions in the original input.
+        char gc = gapChar;
+        SequenceI[] sqs = (SequenceI[]) input
+                .getAlignmentAndColumnSelection(gc)[0];
+        if (msaIndex >= sqs.length)
+        {
+          throw new Error(
+                  MessageManager
+                          .getString("error.implementation_error_invalid_msa_index_for_job"));
+        }
+        if (fullAlignment == null)
+        {
+          // //
+          // Uses RemoveGapsCommand
+          // //
+          new jalview.commands.RemoveGapsCommand(
+                  MessageManager.getString("label.remove_gaps"),
+                  new SequenceI[] { sqs[msaIndex] }, currentView);
+
+          SequenceI profileseq = al.getSequenceAt(FirstSeq);
+          profileseq.setSequence(sqs[msaIndex].getSequenceAsString());
+        }
+      }
+
+      if (!jalview.analysis.SeqsetUtils.SeqCharacterUnhash(
+              al.getSequenceAt(FirstSeq), SequenceInfo))
+      {
+        throw (new Exception(
+                MessageManager
+                        .getString("exception.couldnt_recover_sequence_props_for_jnet_query")));
+      }
+      else
+      {
+        if (currentView.getDataset() != null)
+        {
+          al.setDataset(currentView.getDataset());
+
+        }
+        else
+        {
+          al.setDataset(null);
+        }
+        jalview.io.JnetAnnotationMaker.add_annotation(prediction, al,
+                FirstSeq, true, predMap);
+        SequenceI profileseq = al.getSequenceAt(0); // this includes any gaps.
+        if (fullAlignment == null)
+        {
+          alignToProfileSeq(al, profileseq);
+        }
+        if (fullAlignment == null && predMap != null)
+        {
+          // Adjust input view for gaps
+          // propagate insertions into profile
+          alcsel = ColumnSelection.propagateInsertions(profileseq, al,
+                  input);
+        }
+      }
+    }
+
+    // transfer to dataset
+    for (AlignmentAnnotation alant : al.getAlignmentAnnotation())
+    {
+      if (alant.sequenceRef != null)
+      {
+        replaceAnnotationOnAlignmentWith(alant, alant.label,
+                "jalview.jws1.Jpred" + (msaPred ? "MSA" : ""),
+                alant.sequenceRef);
+      }
+    }
+
+    return new Object[] { al, alcsel }; // , FirstSeq, noMsa};
+  }
+
+  /**
+   * copied from JabawsCalcWorker
+   * 
+   * @param newAnnot
+   * @param typeName
+   * @param calcId
+   * @param aSeq
+   */
+  public static void replaceAnnotationOnAlignmentWith(
+          AlignmentAnnotation newAnnot, String typeName, String calcId,
+          SequenceI aSeq)
+  {
+    SequenceI dsseq = aSeq.getDatasetSequence();
+    while (dsseq.getDatasetSequence() != null)
+    {
+      dsseq = dsseq.getDatasetSequence();
+    }
+    // look for same annotation on dataset and lift this one over
+    List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
+            typeName);
+    if (dsan != null && dsan.size() > 0)
+    {
+      for (AlignmentAnnotation dssan : dsan)
+      {
+        dsseq.removeAlignmentAnnotation(dssan);
+      }
+    }
+    AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
+    dsseq.addAlignmentAnnotation(dssan);
+    dssan.adjustForAlignment();
+  }
+
+  /**
+   * Given an alignment where all other sequences except profileseq are aligned
+   * to the ungapped profileseq, insert gaps in the other sequences to realign
+   * them with the residues in profileseq
+   * 
+   * @param al
+   * @param profileseq
+   */
+  public static void alignToProfileSeq(AlignmentI al, SequenceI profileseq)
+  {
+    char gc = al.getGapCharacter();
+    int[] gapMap = profileseq.gapMap();
+    // insert gaps into profile
+    for (int lp = 0, r = 0; r < gapMap.length; r++)
+    {
+      if (gapMap[r] - lp > 1)
+      {
+        StringBuffer sb = new StringBuffer();
+        for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
+        {
+          sb.append(gc);
+        }
+        for (int s = 1, ns = al.getHeight(); s < ns; s++)
+        {
+          String sq = al.getSequenceAt(s).getSequenceAsString();
+          int diff = gapMap[r] - sq.length();
+          if (diff > 0)
+          {
+            // pad gaps
+            sq = sq + sb;
+            while ((diff = gapMap[r] - sq.length()) > 0)
+            {
+              sq = sq
+                      + ((diff >= sb.length()) ? sb.toString() : sb
+                              .substring(0, diff));
+            }
+            al.getSequenceAt(s).setSequence(sq);
+          }
+          else
+          {
+            al.getSequenceAt(s).setSequence(
+                    sq.substring(0, gapMap[r]) + sb.toString()
+                            + sq.substring(gapMap[r]));
+          }
+        }
+      }
+      lp = gapMap[r];
+    }
+  }
+
+}
diff --git a/test/jalview/ws/jws1/JPredWSUtilsTest.java b/test/jalview/ws/jws1/JPredWSUtilsTest.java
new file mode 100644 (file)
index 0000000..0563647
--- /dev/null
@@ -0,0 +1,31 @@
+package jalview.ws.jws1;
+
+import org.testng.annotations.Test;
+
+public class JPredWSUtilsTest
+{
+  @Test(groups = { "Functional" })
+  public void testSingleSeqPrediction()
+  {
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testSingleSeqPredictionHiddenRegion()
+  {
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMsaPrediction()
+  {
+
+  }
+
+  @Test(groups = { "Functional" })
+  public void testMsaPredictionHiddenRegion()
+  {
+
+  }
+
+}