From 992a0adb0deed8313fde7cad88837355336e58a5 Mon Sep 17 00:00:00 2001 From: Mateusz Date: Wed, 27 Jan 2021 18:11:16 +0100 Subject: [PATCH] JAL-3807 JPred can now successfully submit and track the job. --- src/jalview/ws/JPredClient.java | 67 ++++++ src/jalview/ws/JPredThread.java | 222 ++++++++++++++++++++ .../ws/api/JPredMutlipleAlignmentServiceI.java | 13 ++ src/jalview/ws/api/ServiceWithParameters.java | 7 +- src/jalview/ws/jws2/jabaws2/Jws2Instance.java | 2 +- .../ws/slivkaws/SlivkaJPredServiceInstance.java | 47 +++++ .../ws/slivkaws/SlivkaMsaServiceInstance.java | 24 +-- src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java | 2 +- src/jalview/ws/slivkaws/SlivkaWSInstance.java | 41 ++-- 9 files changed, 392 insertions(+), 33 deletions(-) create mode 100644 src/jalview/ws/JPredClient.java create mode 100644 src/jalview/ws/JPredThread.java create mode 100644 src/jalview/ws/api/JPredMutlipleAlignmentServiceI.java create mode 100644 src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java diff --git a/src/jalview/ws/JPredClient.java b/src/jalview/ws/JPredClient.java new file mode 100644 index 0000000..f431a0c --- /dev/null +++ b/src/jalview/ws/JPredClient.java @@ -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 index 0000000..ed6d4af --- /dev/null +++ b/src/jalview/ws/JPredThread.java @@ -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 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 index 0000000..261f1f8 --- /dev/null +++ b/src/jalview/ws/api/JPredMutlipleAlignmentServiceI.java @@ -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 sequences) throws Throwable; + + public AlignmentI getResult(JobId jobId) throws Exception; +} diff --git a/src/jalview/ws/api/ServiceWithParameters.java b/src/jalview/ws/api/ServiceWithParameters.java index 645ef34..d875fd7 100644 --- a/src/jalview/ws/api/ServiceWithParameters.java +++ b/src/jalview/ws/api/ServiceWithParameters.java @@ -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); diff --git a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java index 47fb9c6..36a42ab 100644 --- a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java +++ b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java @@ -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 index 0000000..a614f02 --- /dev/null +++ b/src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java @@ -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 sequences) throws Throwable + { + return super.submit(sequences, null, null); + } + + @Override + public AlignmentI getResult(JobId jobId) throws Exception + { + List files; + try { + files = client.getJobResults(jobId.getJobId()); + for (RemoteFile f : files) { + return readAlignment(f); + } + } + catch (IOException e) { + throw new IOError(e); + } + return null; + } +} diff --git a/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java b/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java index 9a33b04..a04cff5 100644 --- a/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java +++ b/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java @@ -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) { diff --git a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java index e849f97..d290024 100644 --- a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java +++ b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java @@ -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": diff --git a/src/jalview/ws/slivkaws/SlivkaWSInstance.java b/src/jalview/ws/slivkaws/SlivkaWSInstance.java index 8456b55..8aa56fa 100644 --- a/src/jalview/ws/slivkaws/SlivkaWSInstance.java +++ b/src/jalview/ws/slivkaws/SlivkaWSInstance.java @@ -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); + } } -- 1.7.10.2