JAL-3807 JPred can now successfully submit and track the job.
authorMateusz <mmzwarowny@dundee.ac.uk>
Wed, 27 Jan 2021 17:11:16 +0000 (18:11 +0100)
committerMateusz Warowny <mmzwarowny@dundee.ac.uk>
Mon, 22 Feb 2021 17:53:46 +0000 (18:53 +0100)
src/jalview/ws/JPredClient.java [new file with mode: 0644]
src/jalview/ws/JPredThread.java [new file with mode: 0644]
src/jalview/ws/api/JPredMutlipleAlignmentServiceI.java [new file with mode: 0644]
src/jalview/ws/api/ServiceWithParameters.java
src/jalview/ws/jws2/jabaws2/Jws2Instance.java
src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java [new file with mode: 0644]
src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java
src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java
src/jalview/ws/slivkaws/SlivkaWSInstance.java

diff --git a/src/jalview/ws/JPredClient.java b/src/jalview/ws/JPredClient.java
new file mode 100644 (file)
index 0000000..f431a0c
--- /dev/null
@@ -0,0 +1,67 @@
+package jalview.ws;
+
+import javax.swing.JMenuItem;
+
+import jalview.analysis.SeqsetUtils;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.ws.api.JPredMutlipleAlignmentServiceI;
+import jalview.ws.api.ServiceWithParameters;
+
+public class JPredClient extends WSClient
+{
+  JPredMutlipleAlignmentServiceI server;
+
+  public JPredClient(ServiceWithParameters sh, String title,
+      AlignmentView alView, AlignFrame alFrame, boolean viewOnly)
+  {
+    server = (JPredMutlipleAlignmentServiceI) sh.getEndpoint();
+    wsInfo = setWebService(sh, false);
+    startClient(title, alView, alFrame, viewOnly);
+  }
+
+  private void startClient(String title, AlignmentView view,
+      AlignFrame frame, boolean viewOnly)
+  {
+    var msf = view.getSequences();
+    var seq = msf[0].getSeq('-');
+    if (msf.length <= 1)
+      throw new RuntimeException("You need more than one sequence.");
+    var aln = new SequenceI[msf.length];
+    for (int i = 0; i < msf.length; i++)
+    {
+      aln[i] = msf[i].getSeq('-');
+    }
+    int[] delMap = viewOnly ?
+      view.getVisibleContigMapFor(seq.gapMap()) : null;
+    var sequenceInfo = SeqsetUtils.uniquify(aln, true);
+    var thread = new JPredThread(wsInfo, title, server, sequenceInfo, aln,
+        delMap, view, frame, WsURL);
+    wsInfo.setthisService(thread);
+    wsInfo.setVisible(true);
+    thread.start();
+  }
+
+  // sh parameter should be moved to the WSMenuEntryProvider interface
+  public static WSMenuEntryProviderI getMenuEntryProvider(ServiceWithParameters sh)
+  {
+    return (menu, frame) -> {
+      final JMenuItem mi = new JMenuItem(sh.getName());
+      mi.setToolTipText(sh.getHostURL());
+      mi.addActionListener((event) -> {
+        var view = frame.gatherSeqOrMsaForSecStrPrediction();
+        if (view.getSequences().length > 1)
+        {
+          new JPredClient(sh, frame.getTitle(), view, frame, true);
+        }
+        else
+        {
+          Cache.log.error("Single sequence not supported");
+        }
+      });
+      menu.add(mi);
+    };
+  }
+}
diff --git a/src/jalview/ws/JPredThread.java b/src/jalview/ws/JPredThread.java
new file mode 100644 (file)
index 0000000..ed6d4af
--- /dev/null
@@ -0,0 +1,222 @@
+package jalview.ws;
+
+import static java.lang.String.format;
+
+import java.util.Hashtable;
+import java.util.List;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.WebserviceInfo;
+import jalview.util.MessageManager;
+import jalview.ws.api.CancellableI;
+import jalview.ws.api.JPredMutlipleAlignmentServiceI;
+import jalview.ws.gui.WsJob;
+import jalview.ws.gui.WsJob.JobState;
+
+
+class JPredJob extends WsJob
+{
+  Hashtable<?, ?> sequenceInfo;
+  List<SequenceI> msf;
+  int[] delMap;
+  public AlignmentI alignment;
+  
+  public JPredJob(Hashtable<?, ?> sequenceInfo, SequenceI[] msf, int[] delMap)
+  {
+    this.sequenceInfo = sequenceInfo;
+    this.msf = List.of(msf);
+    this.delMap = delMap;
+  }
+  
+  @Override
+  public boolean hasValidInput()
+  {
+    return true;
+  }
+}
+
+
+public class JPredThread extends AWSThread implements WSClientI
+{
+  
+  private JPredMutlipleAlignmentServiceI server;
+  private String title;
+  private Hashtable<?, ?> sequenceInfo;
+  private SequenceI[] msf;
+  private int[] delMap;  
+  
+  public JPredThread(WebserviceInfo wsInfo, String title,
+      JPredMutlipleAlignmentServiceI server, Hashtable<?, ?> sequenceInfo,
+      SequenceI[] msf, int[] delMap, AlignmentView view, AlignFrame frame,
+      String wsURL)
+  {
+    super(frame, wsInfo, view, wsURL);
+    this.server = server;
+    this.title = title;
+    this.sequenceInfo = sequenceInfo;
+    this.msf = msf;
+    this.delMap = delMap;
+    JPredJob job = new JPredJob(sequenceInfo, msf, delMap);
+    this.jobs = new JPredJob[] { job };
+  }
+
+  @Override
+  public boolean isCancellable()
+  {
+    return server instanceof CancellableI;
+  }
+
+  @Override
+  public boolean canMergeResults()
+  {
+    return false;
+  }
+
+  @Override
+  public void cancelJob()
+  {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public void pollJob(AWsJob job_) throws Exception
+  {
+    var job = (JPredJob) job_;
+    server.updateStatus(job);
+    server.updateJobProgress(job);
+  }
+
+  @Override
+  public void StartJob(AWsJob job_)
+  {
+    if (!(job_ instanceof JPredJob))
+      throw new RuntimeException("Invalid job type");
+    var job = (JPredJob) job_;
+    if (job.isSubmitted())
+    {
+      return;
+    }
+    try {
+      try
+      {
+        var jobHandle = server.align(job.msf);
+        if (jobHandle != null)
+          job.setJobHandle(jobHandle);
+      } 
+      catch (Throwable th) {
+        if (!server.handleSubmitError(th, job, wsInfo)) {
+          throw th;
+        }
+      }
+      if (job.getJobId() != null) {
+        job.setSubmitted(true);
+        job.setSubjobComplete(false);
+        return;
+      }
+      else {
+        throw new Exception(MessageManager.formatMessage(
+                "exception.web_service_returned_null_try_later",
+                new String[]
+                { WsUrl }));
+      }
+    }
+    catch (Throwable th)
+    {
+      // For unexpected errors
+      System.err.println(WebServiceName
+              + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
+              + "When contacting Server:" + WsUrl + "\n");
+      th.printStackTrace(System.err);
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      wsInfo.setStatus(job.getJobnum(),
+              WebserviceInfo.STATE_STOPPED_SERVERERROR);
+      
+    }
+    finally
+    {
+      if (!job.isSubmitted())
+      {
+        job.setAllowedServerExceptions(0);
+        wsInfo.appendProgressText(job.getJobnum(), MessageManager.getString(
+                "info.failed_to_submit_sequences_for_alignment"));
+      }
+    }
+  }
+
+  @Override
+  public void parseResult()
+  {
+    long progbar = (long) (Math.random() * ~(1L << 63));
+    wsInfo.setProgressBar(
+        MessageManager.getString("status.collecting_job_results"), progbar);
+    int results = 0;
+    var finalState = new JobStateSummary();
+    try
+    {
+      for (int i = 0; i < jobs.length; i++) {
+        final var job = (JPredJob) jobs[i];
+        finalState.updateJobPanelState(wsInfo, OutputHeader, job);
+        if (job.isFinished()) {
+          try {
+            server.updateJobProgress(job);
+          }
+          catch (Exception e) {
+            Cache.log.warn(format(
+                "Exception when retrieving remaining Job progress data " +
+                "for job %s on server %s", job.getJobId(), WsUrl));
+            e.printStackTrace();
+          }
+          // removed the waiting loop
+          Cache.log.debug(format("Job Execution file for job: %s " +
+              "on server %s%n%s", job.getJobId(), WsUrl, job.getStatus()));
+          try {
+            job.alignment = server.getResult(job.getJobHandle());
+          }
+          catch (Exception e) {
+            if (!server.handleCollectionException(e, job, wsInfo)) {
+              Cache.log.error("Could not get alignment for job.", e);
+              job.setState(JobState.SERVERERROR);
+            }
+          }
+        }
+        finalState.updateJobPanelState(wsInfo, OutputHeader, job);
+        if (job.isSubmitted() && job.isSubjobComplete() && job.hasResults()) {
+          results++;
+        }
+      }
+    }
+    catch (Exception e) {
+      Cache.log.error(
+          "Unexpected exception when processing results for " + title, e);
+      wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
+    }
+    if (results > 0) {
+      wsInfo.showResultsNewFrame.addActionListener(
+          (evt) -> displayResults(true));
+      wsInfo.mergeResults.addActionListener(
+          (evt) -> displayResults(false));
+      wsInfo.setResultsReady();
+    }
+    else {
+      wsInfo.setFinishedNoResults();
+    }
+    updateGlobalStatus(finalState);
+    wsInfo.removeProgressBar(progbar);
+  }
+
+  
+
+  private void displayResults(boolean newWindow)
+  {
+    System.out.println("DISPLAYING THE RESULT");
+  }
+  
+}
diff --git a/src/jalview/ws/api/JPredMutlipleAlignmentServiceI.java b/src/jalview/ws/api/JPredMutlipleAlignmentServiceI.java
new file mode 100644 (file)
index 0000000..261f1f8
--- /dev/null
@@ -0,0 +1,13 @@
+package jalview.ws.api;
+
+import java.util.List;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+
+public interface JPredMutlipleAlignmentServiceI extends JalviewWebServiceI
+{
+  public JobId align(List<SequenceI> sequences) throws Throwable;
+  
+  public AlignmentI getResult(JobId jobId) throws Exception;
+}
index 645ef34..d875fd7 100644 (file)
@@ -2,6 +2,7 @@ package jalview.ws.api;
 
 import jalview.bin.Cache;
 import jalview.gui.AlignFrame;
+import jalview.ws.JPredClient;
 import jalview.ws.jws2.MsaWSClient;
 import jalview.ws.jws2.SequenceAnnotationWSClient;
 import jalview.ws.params.ParamManager;
@@ -9,6 +10,7 @@ import jalview.ws.params.ParamManager;
 import javax.swing.JMenu;
 
 public abstract class ServiceWithParameters extends UIinfo
+    implements JalviewServiceEndpointProviderI
 {
 
   protected jalview.ws.uimodel.AlignAnalysisUIText aaui;
@@ -87,7 +89,7 @@ public abstract class ServiceWithParameters extends UIinfo
 
   protected enum ServiceClient
   {
-    MSAWSCLIENT, SEQUENCEANNOTATIONWSCLIENT;
+    MSAWSCLIENT, SEQUENCEANNOTATIONWSCLIENT, JPREDWSCLIENT;
   };
 
   protected ServiceClient style = null;
@@ -99,6 +101,9 @@ public abstract class ServiceWithParameters extends UIinfo
     case MSAWSCLIENT:
         new MsaWSClient().attachWSMenuEntry(atpoint, this, alignFrame);
       break;
+    case JPREDWSCLIENT:
+        JPredClient.getMenuEntryProvider(this).attachWSMenuEntry(atpoint, alignFrame);
+        break;
     case SEQUENCEANNOTATIONWSCLIENT:
         new SequenceAnnotationWSClient().attachWSMenuEntry(atpoint, this,
                 alignFrame);
index 47fb9c6..36a42ab 100644 (file)
@@ -38,7 +38,7 @@ import compbio.metadata.PresetManager;
 import compbio.metadata.RunnerConfig;
 
 public class Jws2Instance extends ServiceWithParameters
-        implements JalviewServiceEndpointProviderI, AutoCloseable
+        implements AutoCloseable
 {
 
   public JABAService service;
diff --git a/src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java b/src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java
new file mode 100644 (file)
index 0000000..a614f02
--- /dev/null
@@ -0,0 +1,47 @@
+package jalview.ws.slivkaws;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.util.List;
+
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.ws.api.JPredMutlipleAlignmentServiceI;
+import jalview.ws.api.JobId;
+import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
+import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
+
+public class SlivkaJPredServiceInstance extends SlivkaWSInstance
+    implements JPredMutlipleAlignmentServiceI
+{
+
+  public SlivkaJPredServiceInstance(SlivkaClient client,
+      SlivkaService service, String action)
+  {
+    super(client, service, action);
+    style = ServiceClient.JPREDWSCLIENT;
+  }
+
+  @Override
+  public JobId align(List<SequenceI> sequences) throws Throwable
+  {
+    return super.submit(sequences, null, null);
+  }
+
+  @Override
+  public AlignmentI getResult(JobId jobId) throws Exception
+  {
+    List<RemoteFile> files;
+    try {
+      files = client.getJobResults(jobId.getJobId());
+      for (RemoteFile f : files) {
+        return readAlignment(f);
+      }
+    }
+    catch (IOException e) {
+      throw new IOError(e);
+    }
+    return null;  
+  }
+}
index 9a33b04..a04cff5 100644 (file)
@@ -1,22 +1,17 @@
 package jalview.ws.slivkaws;
 
+import java.io.IOError;
+import java.io.IOException;
+import java.rmi.ServerError;
+import java.util.List;
+
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
-import jalview.io.DataSourceType;
-import jalview.io.FileFormat;
-import jalview.io.FormatAdapter;
 import jalview.ws.api.JobId;
 import jalview.ws.api.MultipleSequenceAlignmentI;
 import jalview.ws.params.ArgumentI;
 import jalview.ws.params.InvalidArgumentException;
 import jalview.ws.params.WsParamSetI;
-
-import java.io.IOError;
-import java.io.IOException;
-import java.rmi.ServerError;
-import java.util.List;
-
-import compbio.data.msa.Category;
 import uk.ac.dundee.compbio.slivkaclient.RemoteFile;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaClient;
 import uk.ac.dundee.compbio.slivkaclient.SlivkaService;
@@ -43,14 +38,7 @@ public class SlivkaMsaServiceInstance extends SlivkaWSInstance implements Multip
       files = client.getJobResults(jobId.getJobId());
       for (RemoteFile f : files)
       {
-        if (f.getMimeType().equals("application/clustal"))
-        {
-          return new FormatAdapter().readFile(f.getURL().toString(), DataSourceType.URL, FileFormat.Clustal);
-        }
-        else if (f.getMimeType().equals("application/fasta"))
-        {
-          return new FormatAdapter().readFile(f.getURL().toString(), DataSourceType.URL, FileFormat.Fasta);
-        }
+        return readAlignment(f);
       }
     } catch (IOException e)
     {
index e849f97..d290024 100644 (file)
@@ -122,7 +122,7 @@ public class SlivkaWSDiscoverer implements WSDiscovererI
                       service, Category.CATEGORY_DISORDER);
               break;
             case "protein secondary structure prediction":
-              newInstance = new SlivkaAnnotationServiceInstance(client,
+              newInstance = new SlivkaJPredServiceInstance(client,
                       service, "Secondary Structure Prediction");
               break;
             case "multiple sequence alignment":
index 8456b55..8aa56fa 100644 (file)
@@ -1,17 +1,5 @@
 package jalview.ws.slivkaws;
 
-import jalview.datamodel.SequenceI;
-import jalview.gui.WebserviceInfo;
-import jalview.ws.api.JalviewServiceEndpointProviderI;
-import jalview.ws.api.JalviewWebServiceI;
-import jalview.ws.api.JobId;
-import jalview.ws.api.ServiceWithParameters;
-import jalview.ws.gui.WsJob;
-import jalview.ws.params.ArgumentI;
-import jalview.ws.params.ParamDatastoreI;
-import jalview.ws.params.ParamManager;
-import jalview.ws.params.WsParamSetI;
-
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOError;
@@ -24,6 +12,21 @@ import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.WebserviceInfo;
+import jalview.io.DataSourceType;
+import jalview.io.FileFormat;
+import jalview.io.FormatAdapter;
+import jalview.ws.api.JalviewServiceEndpointProviderI;
+import jalview.ws.api.JalviewWebServiceI;
+import jalview.ws.api.JobId;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.gui.WsJob;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.ParamManager;
+import jalview.ws.params.WsParamSetI;
 import uk.ac.dundee.compbio.slivkaclient.FieldType;
 import uk.ac.dundee.compbio.slivkaclient.FormField;
 import uk.ac.dundee.compbio.slivkaclient.FormValidationException;
@@ -244,5 +247,19 @@ public abstract class SlivkaWSInstance extends ServiceWithParameters
     }
     return store;
   }
+  
+  public static AlignmentI readAlignment(RemoteFile f) throws IOException
+  {
+    final var mimetype = f.getMimeType();
+    FileFormat format;
+    if (mimetype == "application/clustal")
+      format = FileFormat.Clustal;
+    else if (mimetype == "application/fasta")
+      format = FileFormat.Fasta;
+    else
+      return null;
+    return new FormatAdapter().readFile(f.getURL().toString(),
+        DataSourceType.URL, format);
+  }
 
 }