JAL-2629 simplifying method signatures in Hmmer command classes
[jalview.git] / src / jalview / hmmer / HMMAlignThread.java
index 303b58b..582dc06 100644 (file)
@@ -1,6 +1,6 @@
 package jalview.hmmer;
 
-import jalview.bin.Cache;
+import jalview.analysis.AlignmentSorter;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
@@ -11,34 +11,31 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
-import jalview.gui.Preferences;
 import jalview.gui.SplitFrame;
 import jalview.io.DataSourceType;
 import jalview.io.StockholmFile;
 import jalview.util.MessageManager;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
+import jalview.ws.params.ArgumentI;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import javax.swing.JInternalFrame;
-import javax.swing.JOptionPane;
 
-public class HMMAlignThread implements Runnable
+public class HMMAlignThread extends HmmerCommand implements Runnable
 {
+  static final String HMMALIGN = "hmmalign";
 
-  /**
+  static final String ARG_TRIM = "--trim";
+
+  /*
    * feature settings from view that job was associated with
    */
   protected FeatureRendererSettings featureSettings = null;
 
-  HMMERCommands cmds = new HMMERCommands();
-
-  AlignFrame af;
-
   AlignmentI alignment;
 
   AlignmentI dataset;
@@ -49,205 +46,201 @@ public class HMMAlignThread implements Runnable
 
   HiddenMarkovModel hmm;
 
-  boolean newFrame;
-
-  long barID;
-
-  Map<Integer, SequenceI> hmmSeqs;
-
-  File hmmTemp = null;
-
-  File outTemp = null;
-
-  File inputTemp = null;
-
-  List<AlignmentOrder> allOrders;
-
   SequenceI[][] allResults;
 
-  public HMMAlignThread(AlignFrame af, boolean createNewFrame)
+  /**
+   * Constructor for the HMMAlignThread
+   * 
+   * @param af
+   * @param args
+   */
+  public HMMAlignThread(AlignFrame af, List<ArgumentI> args)
   {
-    this.af = af;
+    super(af, args);
     alignment = af.getViewport().getAlignment();
     if (alignment.getDataset() != null)
     {
       dataset = alignment.getDataset();
     }
-    newFrame = createNewFrame;
     featureSettings = af.getFeatureRenderer().getSettings();
   }
 
+  /**
+   * Runs the HMMAlignThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame (if true). The command is executed
+   * for each segemtn of the alignment.
+   */
   @Override
   public void run()
   {
-    if (af.getSelectedHMM() == null)
-    {
-      JOptionPane.showMessageDialog(af,
-              MessageManager.getString("warn.no_selected_hmm"));
-      return;
-    }
-    else
-    {
-      hmm = af.getSelectedHMM();
-    }
-    barID = System.currentTimeMillis();
-    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
+    hmm = af.getSelectedHMM();
 
-    // if (!alignment.isAligned())
-    // {
-    // alignment.padGaps();
-    // }
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
+            msgId);
     prepareAlignment();
     SequenceI[][] subAlignments = msa.getVisibleContigs('-');
-    allOrders = new ArrayList<>();
+
+    List<AlignmentOrder> allOrders = new ArrayList<>();
     allResults = new SequenceI[subAlignments.length][];
     int job = 0;
     for (SequenceI[] seqs : subAlignments)
     {
-      cmds.uniquifySequences(seqs);
-      try
-      {
-        createTemporaryFiles();
-      } catch (IOException e2)
-      {
-        e2.printStackTrace();
-      }
-      try
-      {
-        cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
-                hmmTemp.getAbsoluteFile());
-      } catch (IOException e1)
-      {
-        e1.printStackTrace();
-      }
+      stashSequences(seqs);
       try
       {
-        boolean ran = runCommand();
+        File modelFile = createTempFile("hmm", ".hmm");
+        File alignmentFile = createTempFile("output", ".sto");
+        File resultFile = createTempFile("input", ".sto");
+
+        exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null);
+        exportHmm(hmm, modelFile.getAbsoluteFile());
+
+        boolean ran = runCommand(modelFile, alignmentFile, resultFile);
         if (!ran)
         {
           JvOptionPane.showInternalMessageDialog(af,
                   MessageManager.getString("warn.hmmalign_failed"));
           return;
         }
-      } catch (IOException | InterruptedException e)
-      {
-        e.printStackTrace();
-      }
-      try
-      {
-        importData(job);
-      } catch (IOException | InterruptedException e)
+
+        SequenceI[] result = importData(resultFile, allOrders);
+        allResults[job] = result;
+        modelFile.delete();
+        alignmentFile.delete();
+        resultFile.delete();
+      } catch (IOException e)
       {
-        // TODO Auto-generated catch block
         e.printStackTrace();
       }
       job++;
     }
 
-    displayResults(newFrame);
-
-    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
-
-  }
+    displayResults(allOrders);
 
-  private void createTemporaryFiles() throws IOException
-  {
-    hmmTemp = File.createTempFile("hmm", ".hmm");
-    hmmTemp.deleteOnExit();
-    outTemp = File.createTempFile("output", ".sto");
-    outTemp.deleteOnExit();
-    inputTemp = File.createTempFile("input", ".sto");
-    inputTemp.deleteOnExit();
+    af.setProgressBar("", msgId);
   }
 
-  private boolean runCommand() throws IOException, InterruptedException
+  /**
+   * Executes the hmmalign command and returns true if successful, false if an
+   * error is detected
+   * 
+   * @param modelFile
+   *          the HMM to align to
+   * @param alignmentFile
+   *          the sequences to align
+   * @param resultFile
+   *          the file to hold the results of alignment
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File modelFile, File alignmentFile,
+          File resultFile)
+          throws IOException
   {
-    File file = new File(cmds.HMMERFOLDER + "/binaries/hmmalign");
-    if (!file.canExecute())
+    String command = getCommandPath(HMMALIGN);
+    if (command == null)
     {
       return false;
     }
-    String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
-    String version = Cache.getProperty("HMMER_VERSION");
-    if (!"3.1b2".equals(version))
-    {
-      command += cmds.ALLCOL;
-    }
-    boolean trim = true;
-    String bool = Cache.getProperty("TRIM_TERMINI");
-    if ("false".equals(bool))
-    {
-      trim = false;
-    }
-    if (trim)
+    List<String> args = new ArrayList<>();
+    args.add(command);
+
+    if (params != null)
     {
-      command += cmds.TRIM;
+      for (ArgumentI arg : params)
+      {
+        String name = arg.getName();
+        if (MessageManager.getString("label.trim_termini").equals(name))
+        {
+          args.add(ARG_TRIM);
+        }
+      }
     }
-    command += " -o " + inputTemp.getAbsolutePath() + cmds.SPACE
-            + hmmTemp.getAbsolutePath() + cmds.SPACE
-            + outTemp.getAbsolutePath();
-    return cmds.runCommand(command);
+    args.add("-o");
+    args.add(resultFile.getAbsolutePath());
+    args.add(modelFile.getAbsolutePath());
+    args.add(alignmentFile.getAbsolutePath());
+    
+    return runCommand(args);
   }
 
-  private void importData(int index)
-          throws IOException, InterruptedException
+  /**
+   * Imports the data from the file holding the output of hmmalign
+   * 
+   * @param resultFile
+   * @param allOrders
+   *          a list of alignment orders to add to
+   * 
+   * @return
+   * @throws IOException
+   */
+  private SequenceI[] importData(File resultFile,
+          List<AlignmentOrder> allOrders) throws IOException
   {
-    StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(),
+    StockholmFile file = new StockholmFile(resultFile.getAbsolutePath(),
             DataSourceType.FILE);
     SequenceI[] result = file.getSeqsAsArray();
     AlignmentOrder msaorder = new AlignmentOrder(result);
-    jalview.analysis.AlignmentSorter.recoverOrder(result);
-    jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
+    AlignmentSorter.recoverOrder(result);
+    recoverSequences(result);
     allOrders.add(msaorder);
-    allResults[index] = result;
-    hmmTemp.delete();
-    outTemp.delete();
-    inputTemp.delete();
+
+    return result;
   }
 
+  /**
+   * Gathers the sequences in preparation for the alignment.
+   */
   private void prepareAlignment()
   {
-    // hmmSeqs = alignment.getHMMConsensusSequences(true);
     msa = af.gatherSequencesForAlignment();
   }
 
-  private void displayResults(boolean newFrame)
+  /**
+   * Displays the results of all 'jobs' in a new frame
+   * 
+   * @param allOrders
+   */
+  private void displayResults(List<AlignmentOrder> allOrders)
   {
     AlignmentOrder[] arrOrders = allOrders
             .toArray(new AlignmentOrder[allOrders.size()]);
-    Object[] newview = msa.getUpdatedView(allResults,
-            arrOrders, '-');
-    SequenceI[] alignment = (SequenceI[]) newview[0];
+    Object[] newview = msa.getUpdatedView(allResults, arrOrders, '-');
+    SequenceI[] seqs = (SequenceI[]) newview[0];
     HiddenColumns hidden = (HiddenColumns) newview[1];
-    Alignment al = new Alignment(alignment);
+    Alignment al = new Alignment(seqs);
     al.setProperty("Alignment Program", "hmmalign");
     if (dataset != null)
     {
       al.setDataset(dataset);
     }
 
-    if (newFrame)
-    {
-      displayInNewFrame(al, allOrders, hidden);
-    }
+    displayInNewFrame(al, allOrders, hidden);
   }
 
+  /**
+   * Displays the results in a new frame
+   * 
+   * @param al
+   *          The alignment containing the results
+   * @param alorders
+   *          The order of the sequences in the alignment on which the jobs were
+   *          run
+   * @param hidden
+   *          Hidden columns in the previous alignment
+   */
   private void displayInNewFrame(AlignmentI al,
           List<AlignmentOrder> alorders, HiddenColumns hidden)
   {
-    AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
+    AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
             AlignFrame.DEFAULT_HEIGHT);
 
     // initialise with same renderer settings as in parent alignframe.
-    af.getFeatureRenderer().transferSettings(this.featureSettings);
+    alignFrame.getFeatureRenderer().transferSettings(this.featureSettings);
 
-    if (allOrders.size() > 0)
-    {
-      addSortByMenuItems(af, allOrders);
-    }
+    addSortByMenuItems(alignFrame, alorders);
 
     // TODO: refactor retrieve and show as new splitFrame as Desktop method
 
@@ -274,14 +267,14 @@ public class HMMAlignThread implements Runnable
       copyComplement.alignAs(al);
       if (copyComplement.getHeight() > 0)
       {
-        af.setTitle(this.af.getTitle());
+        alignFrame.setTitle(this.af.getTitle());
         AlignFrame af2 = new AlignFrame(copyComplement,
                 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
         af2.setTitle(complementTitle);
         String linkedTitle = MessageManager
                 .getString("label.linked_view_title");
         JInternalFrame splitFrame = new SplitFrame(
-                al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af);
+                al.isNucleotide() ? alignFrame : af2, al.isNucleotide() ? af2 : alignFrame);
         Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
         return;
       }
@@ -290,23 +283,23 @@ public class HMMAlignThread implements Runnable
     /*
      * Not from SplitFrame, or failed to created a complementary alignment
      */
-    Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
+    Desktop.addInternalFrame(alignFrame, alignFrame.getTitle(), AlignFrame.DEFAULT_WIDTH,
             AlignFrame.DEFAULT_HEIGHT);
   }
 
   /**
-   * Add sort order options to the AlignFrame menus.
+   * Adds sort order options to the AlignFrame menus
    * 
-   * @param af
+   * @param alignFrame
    * @param alorders
    */
-  protected void addSortByMenuItems(AlignFrame af,
+  protected void addSortByMenuItems(AlignFrame alignFrame,
           List<AlignmentOrder> alorders)
   {
     // update orders
     if (alorders.size() == 1)
     {
-      af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
+      alignFrame.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
     }
     else
     {
@@ -342,12 +335,29 @@ public class HMMAlignThread implements Runnable
       }
       for (int i = 0, l = alorders.size(); i < l; i++)
       {
-        af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
+        alignFrame.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
                 alorders.get(i));
       }
     }
   }
 
-  }
+  /**
+   * Runs hmmalign, and waits for the results to be imported before continuing
+   */
+  public void hmmalignWaitTillComplete()
+  {
+    Thread loader = new Thread(this);
+    loader.start();
 
+    while (loader.isAlive())
+    {
+      try
+      {
+        Thread.sleep(500);
+      } catch (Exception ex)
+      {
+      }
+    }
 
+  }
+}