JAL-2629 partial refactoring of Hmmer command classes
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 19 Feb 2018 17:03:07 +0000 (17:03 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Mon, 19 Feb 2018 17:03:07 +0000 (17:03 +0000)
src/jalview/gui/WsJobParameters.java
src/jalview/hmmer/HMMAlignThread.java
src/jalview/hmmer/HMMBuildThread.java
src/jalview/hmmer/HMMERParamStore.java
src/jalview/hmmer/HMMSearchThread.java
src/jalview/hmmer/HmmerCommand.java [moved from src/jalview/hmmer/HMMERCommands.java with 72% similarity]

index addda39..af52d43 100644 (file)
@@ -1362,8 +1362,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
     if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
     {
       final String setname = (String) setName.getSelectedItem();
-      System.out.println("Item state changed for " + setname
-              + " (handling ? " + !settingDialog + ")");
+      // System.out.println("Item state changed for " + setname
+      // + " (handling ? " + !settingDialog + ")");
       if (settingDialog)
       {
         // ignore event
index 168e3f9..fadbdb1 100644 (file)
@@ -1,5 +1,7 @@
 package jalview.hmmer;
 
+import jalview.analysis.AlignmentSorter;
+import jalview.analysis.SeqsetUtils;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -11,7 +13,6 @@ 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;
@@ -23,25 +24,18 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import javax.swing.JInternalFrame;
 
-public class HMMAlignThread implements Runnable
+public class HMMAlignThread extends HmmerCommand implements Runnable
 {
+  static final String HMMALIGN = "hmmalign";
 
-  /**
+  /*
    * feature settings from view that job was associated with
    */
   protected FeatureRendererSettings featureSettings = null;
 
-  /**
-   * Object containing frequently used commands.
-   */
-  HMMERCommands cmds = new HMMERCommands();
-
-  AlignFrame af;
-
   AlignmentI alignment;
 
   AlignmentI dataset;
@@ -58,8 +52,6 @@ public class HMMAlignThread implements Runnable
 
   long barID;
 
-  Map<Integer, SequenceI> hmmSeqs;
-
   File hmmTemp = null;
 
   File outTemp = null;
@@ -106,7 +98,6 @@ public class HMMAlignThread implements Runnable
     barID = System.currentTimeMillis();
     af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
             barID);
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
     prepareAlignment();
     SequenceI[][] subAlignments = msa.getVisibleContigs('-');
     allOrders = new ArrayList<>();
@@ -114,7 +105,7 @@ public class HMMAlignThread implements Runnable
     int job = 0;
     for (SequenceI[] seqs : subAlignments)
     {
-      cmds.uniquifySequences(seqs);
+      uniquifySequences(seqs);
       try
       {
         createTemporaryFiles();
@@ -124,7 +115,7 @@ public class HMMAlignThread implements Runnable
       }
       try
       {
-        cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
+        exportData(seqs, outTemp.getAbsoluteFile(), hmm,
                 hmmTemp.getAbsoluteFile(), null);
       } catch (IOException e1)
       {
@@ -156,8 +147,7 @@ public class HMMAlignThread implements Runnable
 
     displayResults(newFrame);
 
-    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
+    af.setProgressBar("", barID);
 
   }
 
@@ -183,7 +173,7 @@ public class HMMAlignThread implements Runnable
   }
 
   /**
-   * Executes the hmmalign command in the command line.
+   * Executes the hmmalign command in the command line
    * 
    * @return
    * @throws IOException
@@ -191,22 +181,16 @@ public class HMMAlignThread implements Runnable
    */
   private boolean runCommand() throws IOException, InterruptedException
   {
-    File file = new File(cmds.HMMERFOLDER + "/hmmalign");
-    if (!file.canExecute())
-    {
-      file = new File(cmds.HMMERFOLDER + "/hmmalign.exe");
-      {
-        if (!file.canExecute())
-        {
-          return false;
-        }
-      }
+    String binaryPath = getCommandRoot(HMMALIGN);
+    if (binaryPath == null) {
+      return false;
     }
-    String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
+    String command = binaryPath + SPACE;
+    // todo parse version from ./hmmerbuild -h
     String version = Cache.getProperty("HMMER_VERSION");
     if (!"3.1b2".equals(version))
     {
-      command += cmds.ALLCOL;
+      // command += ALLCOL; // todo obsolete option?
     }
     if (args != null)
     {
@@ -220,10 +204,10 @@ public class HMMAlignThread implements Runnable
         }
       }
     }
-    command += " -o " + inputTemp.getAbsolutePath() + cmds.SPACE
-            + hmmTemp.getAbsolutePath() + cmds.SPACE
+    command += " -o " + inputTemp.getAbsolutePath() + SPACE
+            + hmmTemp.getAbsolutePath() + SPACE
             + outTemp.getAbsolutePath();
-    return cmds.runCommand(command);
+    return runCommand(command);
   }
 
   /**
@@ -242,8 +226,8 @@ public class HMMAlignThread implements Runnable
             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);
+    SeqsetUtils.deuniquify(hash, result);
     allOrders.add(msaorder);
     allResults[index] = result;
     hmmTemp.delete();
index 2262bae..4e3dc2e 100644 (file)
@@ -1,15 +1,13 @@
 package jalview.hmmer;
 
-import jalview.bin.Cache;
+import jalview.analysis.SeqsetUtils;
 import jalview.datamodel.AlignmentI;
-import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.AlignViewport;
 import jalview.gui.JvOptionPane;
-import jalview.gui.Preferences;
 import jalview.io.DataSourceType;
 import jalview.io.FileParse;
 import jalview.io.HMMFile;
@@ -24,12 +22,8 @@ import java.util.List;
 
 import javax.swing.JOptionPane;
 
-public class HMMBuildThread implements Runnable
+public class HMMBuildThread extends HmmerCommand implements Runnable
 {
-  HMMERCommands cmds = new HMMERCommands();
-
-  AlignFrame af;
-
   AlignViewport viewport;
 
   boolean multiJob = false;
@@ -78,7 +72,6 @@ public class HMMBuildThread implements Runnable
       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
               barID);
     }
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
 
     List<SequenceGroup> groups = new ArrayList<>();
     if (params != null)
@@ -167,8 +160,7 @@ public class HMMBuildThread implements Runnable
 
     if (af != null)
     {
-      af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
-              barID);
+      af.setProgressBar("", barID);
     }
   }
 
@@ -215,8 +207,6 @@ public class HMMBuildThread implements Runnable
           array = alignment.getSequencesArray();
         }
 
-        cmds.setHmmSeqs(seqs);
-
         if (array.length < 1)
         {
           if (af != null)
@@ -234,18 +224,18 @@ public class HMMBuildThread implements Runnable
           index++;
         }
 
-        cmds.uniquifySequences(newArr);
+        uniquifySequences(newArr);
 
         if (forGroup)
         {
-          cmds.exportData(newArr, stoTemp, null, null, group);
+          exportData(newArr, stoTemp, null, null, group);
         }
         else
         {
-          cmds.exportData(newArr, stoTemp, null, null, alignment);
+          exportData(newArr, stoTemp, null, null, alignment);
         }
 
-        jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, array);
+        SeqsetUtils.deuniquify(hash, array);
 
       } catch (FileNotFoundException e)
       {
@@ -289,23 +279,12 @@ public class HMMBuildThread implements Runnable
    */
   private boolean runCommand() throws IOException, InterruptedException
   {
-    File file = new File(cmds.HMMERFOLDER + "/hmmbuild");
-    if (!file.canExecute())
+    String binaryPath = getCommandRoot(HMMBUILD);
+    if (binaryPath == null)
     {
-      file = new File(cmds.HMMERFOLDER + "/hmmbuild.exe");
-      {
-        if (!file.canExecute())
-        {
-          if (af != null)
-          {
-            JvOptionPane.showInternalMessageDialog(af,
-                    MessageManager.getString("warn.hmmbuild_failed"));
-          }
-          return false;
-        }
-      }
+      return false;
     }
-    String command = cmds.HMMERFOLDER + cmds.HMMBUILD + cmds.SPACE;
+    String command = binaryPath + SPACE;
     String name = null;
 
     if (params != null)
@@ -348,19 +327,19 @@ public class HMMBuildThread implements Runnable
 
     }
 
-    command += "-n " + name.replace(' ', '_') + cmds.SPACE;
+    command += "-n " + name.replace(' ', '_') + SPACE;
     if (!alignment.isNucleotide())
     {
-      command += cmds.FORCEAMINO; // TODO check for rna
+      command += FORCEAMINO; // TODO check for rna
     }
     else
     {
-      command += cmds.FORCEDNA;
+      command += FORCEDNA;
     }
 
-    command += hmmTemp.getAbsolutePath() + cmds.SPACE
-            + stoTemp.getAbsolutePath() + cmds.SPACE;
-    return cmds.runCommand(command);
+    command += hmmTemp.getAbsolutePath() + SPACE + stoTemp.getAbsolutePath()
+            + SPACE;
+    return runCommand(command);
   }
 
   /**
@@ -376,7 +355,6 @@ public class HMMBuildThread implements Runnable
     SequenceI[] seqs = file.getSeqsAsArray();
     SequenceI seq = seqs[0];
     seq.createDatasetSequence();
-    HiddenMarkovModel hmm = file.getHMM();
     if (group != null)
     {
       seq.insertCharAt(0, group.getStartRes(), '-');
index c23fe02..af55dab 100644 (file)
@@ -140,8 +140,7 @@ public class HMMERParamStore implements ParamDatastoreI
   {
     args.add(new BooleanOption(
             MessageManager.getString("label.trim_termini"),
-            MessageManager.getString(
-                    "label.trim_termini = Trim Non-Matching Termini_desc"),
+            MessageManager.getString("label.trim_termini_desc"),
             false, false, true, null));
   }
 
index d5baedf..16c7c68 100644 (file)
@@ -1,6 +1,5 @@
 package jalview.hmmer;
 
-import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -9,7 +8,6 @@ import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.JvOptionPane;
-import jalview.gui.Preferences;
 import jalview.io.DataSourceType;
 import jalview.io.FileParse;
 import jalview.io.StockholmFile;
@@ -29,23 +27,22 @@ import java.util.Scanner;
 
 import javax.swing.JOptionPane;
 
-public class HMMSearchThread implements Runnable
+public class HMMSearchThread extends HmmerCommand implements Runnable
 {
-  /**
+  static final String HMMSEARCH = "hmmsearch";
+
+  /*
    * feature settings from view that job was associated with
    */
   protected FeatureRendererSettings featureSettings = null;
 
-  /**
-   * Object containing frequently used commands.
-   */
-  HMMERCommands cmds = new HMMERCommands();
+  HiddenMarkovModel hmm;
 
-  AlignFrame af;
+  boolean newFrame;
 
-  HiddenMarkovModel hmm;
+  boolean realign = false;
 
-  boolean newFrame, realign = false, trim = false;
+  boolean trim = false;
 
   Integer numberOfSequences = null;
 
@@ -104,7 +101,6 @@ public class HMMSearchThread implements Runnable
     barID = System.currentTimeMillis();
     af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
             barID);
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
 
     try
     {
@@ -115,7 +111,7 @@ public class HMMSearchThread implements Runnable
     }
     try
     {
-      cmds.exportData(null, null, hmm, hmmTemp.getAbsoluteFile(), null);
+      exportData(null, null, hmm, hmmTemp.getAbsoluteFile(), null);
     } catch (IOException e1)
     {
       e1.printStackTrace();
@@ -142,8 +138,7 @@ public class HMMSearchThread implements Runnable
       e.printStackTrace();
     }
 
-    af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
-            barID);
+    af.setProgressBar("", barID);
 
   }
 
@@ -171,23 +166,18 @@ public class HMMSearchThread implements Runnable
    */
   private boolean runCommand() throws IOException, InterruptedException
   {
-    Boolean dbFound = false;
-    String dbPath = "";
-    File file = new File(cmds.HMMERFOLDER + "/hmmsearch");
-    if (!file.canExecute())
+    String binaryPath = getCommandRoot(HMMSEARCH);
+    if (binaryPath == null)
     {
-      file = new File(cmds.HMMERFOLDER + "/hmmsearch.exe");
-      {
-        if (!file.canExecute())
-        {
-          return false;
-        }
-      }
+      return false;
     }
 
-    String command = cmds.HMMERFOLDER + "/hmmsearch -o "
+    String command = binaryPath + " -o "
             + inputTableTemp.getAbsolutePath() + " -A "
-            + inputAlignmentTemp.getAbsolutePath() + cmds.SPACE;
+            + inputAlignmentTemp.getAbsolutePath() + SPACE;
+
+    boolean dbFound = false;
+    String dbPath = "";
     if (params != null)
     {
       for (ArgumentI arg : params)
@@ -212,16 +202,16 @@ public class HMMSearchThread implements Runnable
           }
           break;
         case "Sequence E-value Cutoff":
-          command += "--incE " + arg.getValue() + cmds.SPACE;
+          command += "--incE " + arg.getValue() + SPACE;
           break;
         case "Sequence Score Threshold":
-          command += "-incT " + arg.getValue() + cmds.SPACE;
+          command += "-incT " + arg.getValue() + SPACE;
           break;
         case "Domain E-value Threshold":
-          command += "--incdomE " + arg.getValue() + cmds.SPACE;
+          command += "--incdomE " + arg.getValue() + SPACE;
           break;
         case "Domain Score Threshold":
-          command += "--incdomT " + arg.getValue() + cmds.SPACE;
+          command += "--incdomT " + arg.getValue() + SPACE;
           break;
         case "Trim Non-Matching Termini":
           trim = true;
@@ -239,7 +229,7 @@ public class HMMSearchThread implements Runnable
       }
     }
 
-    if (dbFound == false || MessageManager.getString("label.this_alignment")
+    if (!dbFound || MessageManager.getString("label.this_alignment")
             .equals(dbPath))
     {
       AlignmentI alignment = af.getViewport().getAlignment();
@@ -255,9 +245,9 @@ public class HMMSearchThread implements Runnable
       writer.close();
     }
 
-    command += hmmTemp.getAbsolutePath() + cmds.SPACE
+    command += hmmTemp.getAbsolutePath() + SPACE
             + databaseFile.getAbsolutePath();
-    return cmds.runCommand(command);
+    return runCommand(command);
   }
 
   /**
@@ -268,55 +258,64 @@ public class HMMSearchThread implements Runnable
   {
     BufferedReader br = new BufferedReader(
             new FileReader(inputAlignmentTemp));
-    if (br.readLine() == null)
+    try
     {
-      JOptionPane.showMessageDialog(af,
-              MessageManager.getString("label.no_sequences_found"));
-      return;
-    }
-    StockholmFile file = new StockholmFile(new FileParse(
-            inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
-    seqs = file.getSeqsAsArray();
+      if (br.readLine() == null)
+      {
+        JOptionPane.showMessageDialog(af,
+                MessageManager.getString("label.no_sequences_found"));
+        return;
+      }
+      StockholmFile file = new StockholmFile(new FileParse(
+              inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+      seqs = file.getSeqsAsArray();
 
-    readTable();
+      readTable();
 
-    SequenceI[] hmmAndSeqs;
-    if (numberOfSequences != null && numberOfSequences < seqs.length)
-    {
-      hmmAndSeqs = new SequenceI[numberOfSequences + 1];
-    }
-    else
-    {
-      hmmAndSeqs = new SequenceI[seqs.length + 1];
-    }
-    hmmAndSeqs[0] = hmmSeq;
+      SequenceI[] hmmAndSeqs;
+      if (numberOfSequences != null && numberOfSequences < seqs.length)
+      {
+        hmmAndSeqs = new SequenceI[numberOfSequences + 1];
+      }
+      else
+      {
+        hmmAndSeqs = new SequenceI[seqs.length + 1];
+      }
+      hmmAndSeqs[0] = hmmSeq;
 
-    if (numberOfSequences != null && seqs.length > numberOfSequences)
-    {
-      System.arraycopy(seqs, 0, hmmAndSeqs, 1, numberOfSequences);
-    }
-    else
-    {
-      System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqs.length);
-    }
+      if (numberOfSequences != null && seqs.length > numberOfSequences)
+      {
+        System.arraycopy(seqs, 0, hmmAndSeqs, 1, numberOfSequences);
+      }
+      else
+      {
+        System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqs.length);
+      }
 
-    AlignmentI alignment = new Alignment(hmmAndSeqs);
-    AlignFrame frame = new AlignFrame(alignment, 1, 1);
-    frame.setSelectedHMMSequence(hmmSeq);
-    List<ArgumentI> alignArgs = new ArrayList<>();
-    if (trim)
+      AlignmentI alignment = new Alignment(hmmAndSeqs);
+      AlignFrame frame = new AlignFrame(alignment, 1, 1);
+      frame.setSelectedHMMSequence(hmmSeq);
+      List<ArgumentI> alignArgs = new ArrayList<>();
+      if (trim)
+      {
+        alignArgs.add(new BooleanOption(
+                MessageManager.getString("label.trim_termini"),
+                MessageManager.getString("label.trim_termini_desc"), true,
+                true, true, null));
+      }
+      HMMAlignThread hmmalign = new HMMAlignThread(frame, true, alignArgs);
+      hmmalign.hmmalignWaitTillComplete();
+      frame = null;
+      hmmTemp.delete();
+      inputAlignmentTemp.delete();
+      inputTableTemp.delete();
+    } finally
     {
-      alignArgs.add(new BooleanOption(
-              MessageManager.getString("label.trim_termini"),
-              MessageManager.getString("label.trim_termini_desc"), true,
-              true, true, null));
+      if (br != null)
+      {
+        br.close();
+      }
     }
-    HMMAlignThread hmmalign = new HMMAlignThread(frame, true, alignArgs);
-    hmmalign.hmmalignWaitTillComplete();
-    frame = null;
-    hmmTemp.delete();
-    inputAlignmentTemp.delete();
-    inputTableTemp.delete();
   }
 
   /**
@@ -339,7 +338,7 @@ public class HMMSearchThread implements Runnable
 
   }
 
-  public void readTable() throws IOException
+  void readTable() throws IOException
   {
     BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
     String line = "";
@@ -358,11 +357,13 @@ public class HMMSearchThread implements Runnable
     {
       Scanner scanner = new Scanner(line);
 
-      String str = scanner.next();
-      Annotation[] annots = new Annotation[seqs[index].getLength()];
-      for (Annotation an : annots)
+      String str = scanner.next(); // full sequence eValue score
+      float eValue = Float.parseFloat(str);
+      int seqLength = seqs[index].getLength();
+      Annotation[] annots = new Annotation[seqLength];
+      for (int j = 0; j < seqLength; j++)
       {
-        an = new Annotation(Float.parseFloat(str));
+        annots[j] = new Annotation(eValue);
       }
       AlignmentAnnotation annot = new AlignmentAnnotation("E-value",
               "Score", annots);
similarity index 72%
rename from src/jalview/hmmer/HMMERCommands.java
rename to src/jalview/hmmer/HmmerCommand.java
index 854f0c5..0f45184 100644 (file)
@@ -1,5 +1,6 @@
 package jalview.hmmer;
 
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
@@ -8,8 +9,11 @@ import jalview.datamodel.Annotation;
 import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.gui.Preferences;
 import jalview.io.HMMFile;
 import jalview.io.StockholmFile;
+import jalview.util.MessageManager;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -20,24 +24,17 @@ import java.util.Hashtable;
 import java.util.List;
 
 /**
- * Contains multiple commands and methods frequently used to run hmmbuild,
- * hmmalign and hmmsearch
+ * Base class for hmmbuild, hmmalign and hmmsearch
  * 
  * @author TZVanaalten
  *
  */
-public class HMMERCommands
+public class HmmerCommand
 {
-  // Path of hmmer binaries directory
-  String HMMERFOLDER = "/Documents/";
+  public static final String HMMBUILD = "hmmbuild";
 
-  public String JALVIEWDIRECTORY = System.getProperty("user.dir") + "/";
-
-  public final String HMMALIGN = "/hmmalign ";
-
-  public final String HMMBUILD = "/hmmbuild ";
-
-  public final String HMMSEARCH = "/hmmsearch ";
+  public String JALVIEWDIRECTORY = System.getProperty("user.dir")
+          + File.separator;
 
   public String OUTPUTALIGNMENT;
 
@@ -57,6 +54,14 @@ public class HMMERCommands
 
   List<SequenceI> hmmSeqs;
 
+  protected AlignFrame af;
+
+  public static boolean isHmmerAvailable()
+  {
+    File exec = getExecutable(HMMBUILD, Cache.getProperty(Preferences.HMMER_PATH));
+    return exec != null;
+  }
+
   /**
    * Uniquifies the sequences when exporting and stores their details in a
    * hashtable.
@@ -136,7 +141,7 @@ public class HMMERCommands
     if (seqs != null)
     {
       AlignmentI newAl = new Alignment(seqs);
-      if (stoLocation != null)
+      if (stoLocation != null && al != null)
       {
         for (AlignmentAnnotation annot : al.getAlignmentAnnotation())
         {
@@ -219,4 +224,52 @@ public class HMMERCommands
   {
     this.hmmSeqs = hmmSeqs;
   }
+
+  /**
+   * Answers the full path to the given hmmer executable, or null if file cannot
+   * be found or is not executable
+   * 
+   * @param cmd
+   *          command short name e.g. hmmalign
+   * @return
+   */
+  protected String getCommandRoot(String cmd)
+  {
+    String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH);
+    File file = getExecutable(cmd, binariesFolder);
+    if (file == null && af != null)
+    {
+        JvOptionPane.showInternalMessageDialog(af,
+                MessageManager.getString("warn.hmm_command_failed"));
+    }
+
+    return file == null ? null : file.getAbsolutePath();
+  }
+
+  /**
+   * Answers the executable file for the given hmmer command, or null if not
+   * found or not executable. The path to the executable is the command name
+   * prefixed by the hmmer binaries folder path, optionally with .exe appended.
+   * 
+   * @param cmd
+   *          hmmer command short name, for example hmmbuild
+   * @param binaryPath
+   *          parent folder containing hmmer executables
+   * @return
+   */
+  public static File getExecutable(String cmd, String binaryPath)
+  {
+    File file = new File(binaryPath, cmd);
+    if (!file.canExecute())
+    {
+      file = new File(binaryPath, cmd + ".exe");
+      {
+        if (!file.canExecute())
+        {
+          file = null;
+        }
+      }
+    }
+    return file;
+  }
 }