JAL-3954 Implement proxy ws client for phmmer
authorMateusz Warowny <mmzwarowny@dundee.ac.uk>
Mon, 8 May 2023 14:28:02 +0000 (16:28 +0200)
committerMateusz Warowny <mmzwarowny@dundee.ac.uk>
Mon, 8 May 2023 14:28:02 +0000 (16:28 +0200)
src/jalview/ws2/client/ebi/PhmmerWSClient.java [new file with mode: 0644]

diff --git a/src/jalview/ws2/client/ebi/PhmmerWSClient.java b/src/jalview/ws2/client/ebi/PhmmerWSClient.java
new file mode 100644 (file)
index 0000000..b796618
--- /dev/null
@@ -0,0 +1,232 @@
+package jalview.ws2.client.ebi;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+
+import jalview.datamodel.SequenceI;
+import jalview.io.FileFormat;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.DoubleParameter;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws2.api.Credentials;
+import jalview.ws2.api.JobStatus;
+import jalview.ws2.api.WebServiceJobHandle;
+import jalview.ws2.client.api.WebServiceClientI;
+import uk.ac.dundee.compbio.hmmerclient.PhmmerClient;
+import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest;
+import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SequenceDatabase;
+import uk.ac.dundee.compbio.hmmerclient.PhmmerRequest.SubstitutionMatrix;
+
+public class PhmmerWSClient implements WebServiceClientI
+{
+
+  final PhmmerClient client;
+
+  PhmmerWSClient(PhmmerClient client)
+  {
+    this.client = client;
+  }
+
+  @Override
+  public String getUrl()
+  {
+    return client.getURL().toString();
+  }
+
+  @Override
+  public String getClientName()
+  {
+    return "ebi-job-dispatcher";
+  }
+
+  @Override
+  public WebServiceJobHandle submit(List<SequenceI> sequences,
+          List<ArgumentI> args, Credentials credentials) throws IOException
+  {
+    var request = PhmmerRequest.newBuilder();
+    String sequence = FileFormat.Fasta.getWriter(null)
+            .print(new SequenceI[]{ sequences.get(0) }, false);
+    request.sequence(new StringReader(sequence));
+    populateRequestArguments(request, args);
+    var email = credentials.getEmail() != null ? credentials.getEmail() :
+      "nouser@jalview.org";
+    var jobId = client.submit(request.build(), email);
+    return new WebServiceJobHandle(
+            getClientName(), "phmmer", getUrl(), jobId);
+  }
+  
+  private static void populateRequestArguments(PhmmerRequest.Builder request, List<ArgumentI> args)
+  {
+    boolean useBitScore = false;
+    boolean useEValue = false;
+    for (var arg : args)
+    {
+      if (arg.getName().equals("cut-offs"))
+        if (arg.getValue().equals("E"))
+          useEValue = true;
+        else if (arg.getValue().equals("T"))
+          useBitScore = true;
+        else
+          throw new IllegalArgumentException(
+                  "cut-offs argument contains value other than \"E\" or \"T\": "
+                          + arg.getValue());
+    }
+    assert (useBitScore || useEValue) && !(useBitScore && useEValue);
+    for (var arg : args)
+    {
+      switch (arg.getName())
+      {
+      case "incE":
+        request.incE(useEValue ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "incdomE":
+        request.incdomE(useEValue ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "E":
+        request.E(useEValue ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "domE":
+        request.domE(useEValue ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "incT":
+        request.incT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "incdomT":
+        request.incdomT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "T":
+        request.T(useBitScore ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "domT":
+        request.domT(useBitScore ? DoubleParameter.parseFloat(arg) : null);
+        break;
+      case "popen":
+        request.popen(DoubleParameter.parseFloat(arg));
+        break;
+      case "pextend":
+        request.pextend(DoubleParameter.parseFloat(arg));
+        break;
+      case "mx":
+        request.mx(parseSubstitutionMatrix(arg));
+        break;
+      case "nobias":
+        request.noBias(BooleanOption.parseBoolean(arg));
+        break;
+      case "compressedout":
+        request.compressedOut(BooleanOption.parseBoolean(arg));
+        break;
+      case "alignView":
+        request.compressedOut(BooleanOption.parseBoolean(arg));
+        break;
+      case "database":
+        request.database(parseSequenceDatabase(arg));
+        break;
+      case "evalue":
+        request.evalue(DoubleParameter.parseFloat(arg));
+        break;
+      case "nhits":
+        request.nhits(IntegerParameter.parseInt(arg));
+        break;
+      }
+    }
+  }
+
+  private static SubstitutionMatrix parseSubstitutionMatrix(ArgumentI arg)
+  {
+    if (arg.getValue() == null)
+      return null;
+    switch (arg.getValue())
+    {
+    case "BLOSUM45":
+      return SubstitutionMatrix.BLOSUM45;
+    case "BLOSUM62":
+      return SubstitutionMatrix.BLOSUM62;
+    case "BLOSUM90":
+      return SubstitutionMatrix.BLOSUM90;
+    case "PAM30":
+      return SubstitutionMatrix.PAM30;
+    case "PAM70":
+      return SubstitutionMatrix.PAM70;
+    default:
+      throw new IllegalArgumentException(
+              "invalid matrix " + arg.getValue());
+    }
+  }
+
+  private static SequenceDatabase parseSequenceDatabase(ArgumentI arg)
+  {
+    if (arg.getValue() == null)
+      return null;
+    switch (arg.getValue())
+    {
+    case "swissprot":
+      return SequenceDatabase.SWISS_PROT;
+    case "uniprotrefprot":
+      return SequenceDatabase.REFERENCE_PROTEOMES;
+    case "uniprotkb":
+      return SequenceDatabase.UNIPROTKB;
+    case "pdb":
+      return SequenceDatabase.PDB;
+    case "rp75":
+      return SequenceDatabase.RP75;
+    case "rp55":
+      return SequenceDatabase.RP55;
+    case "rp35":
+      return SequenceDatabase.RP35;
+    case "rp15":
+      return SequenceDatabase.RP15;
+    case "ensembl":
+      return SequenceDatabase.ENSEMBL;
+    case "merops":
+      return SequenceDatabase.MEROPS;
+    case "qfo":
+      return SequenceDatabase.QUEST_FOR_ORTHOLOGS;
+    case "chembl":
+      return SequenceDatabase.CHEMBL;
+    default:
+      throw new IllegalArgumentException(
+              "invalid database " + arg.getValue());
+    }
+  }
+
+  @Override
+  public JobStatus getStatus(WebServiceJobHandle job) throws IOException
+  {
+    var status = client.getStatus(job.getJobId());
+    switch (status)
+    {
+    case PENDING: return JobStatus.SUBMITTED;
+    case QUEUED: return JobStatus.QUEUED;
+    case RUNNING: return JobStatus.RUNNING;
+    case FINISHED: return JobStatus.COMPLETED;
+    case FAILURE: return JobStatus.FAILED;
+    case ERROR: return JobStatus.SERVER_ERROR;
+    case NOT_FOUND: return JobStatus.SERVER_ERROR;
+    case UNDEFINED: return JobStatus.UNKNOWN;
+    }
+    return JobStatus.UNKNOWN;
+  }
+
+  @Override
+  public String getLog(WebServiceJobHandle job) throws IOException
+  {
+    return "";
+  }
+
+  @Override
+  public String getErrorLog(WebServiceJobHandle job) throws IOException
+  {
+    return "";
+  }
+
+  @Override
+  public void cancel(WebServiceJobHandle job)
+          throws IOException, UnsupportedOperationException
+  {
+    throw new UnsupportedOperationException(
+            "ebi job dispather does not support job cancellation");
+  }
+
+}