From: Mateusz Warowny Date: Wed, 28 Jul 2021 10:36:30 +0000 (+0200) Subject: Merge branch 'improvement/JAL-3848_slivka_0.8' into alpha/JAL-3066_Jalview_212_slivka... X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=871ad3a9474c5f4fbbe896a8a0551d0a6250cb77;hp=-c;p=jalview.git Merge branch 'improvement/JAL-3848_slivka_0.8' into alpha/JAL-3066_Jalview_212_slivka-integration --- 871ad3a9474c5f4fbbe896a8a0551d0a6250cb77 diff --combined j11lib/slivka-client.jar index 68cc932,9cb3a61..49ab4fc Binary files differ diff --combined src/jalview/ws/jws2/JPredThread.java index d10ca8a,0000000..67f44fa mode 100644,000000..100644 --- a/src/jalview/ws/jws2/JPredThread.java +++ b/src/jalview/ws/jws2/JPredThread.java @@@ -1,406 -1,0 +1,405 @@@ +package jalview.ws.jws2; + +import static java.lang.String.format; + +import java.util.Hashtable; +import java.util.List; + +import jalview.analysis.SeqsetUtils; +import jalview.bin.Cache; +import jalview.commands.RemoveGapsCommand; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +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.io.JPredFile; +import jalview.io.JnetAnnotationMaker; +import jalview.util.MessageManager; +import jalview.ws.AWSThread; +import jalview.ws.AWsJob; +import jalview.ws.JobStateSummary; +import jalview.ws.WSClientI; +import jalview.ws.api.CancellableI; +import jalview.ws.api.JPredServiceI; +import jalview.ws.gui.WsJob; +import jalview.ws.gui.WsJob.JobState; + + +public class JPredThread extends AWSThread implements WSClientI +{ + + private static class JPredJob extends WsJob + { + private final Hashtable sequenceInfo; + private final List msf; + private final int[] delMap; + private AlignmentI alignment = null; + private HiddenColumns hiddenCols = null; + + private JPredJob(Hashtable sequenceInfo, SequenceI[] msf, int[] delMap) + { + this.sequenceInfo = sequenceInfo; + this.msf = List.of(msf); + this.delMap = delMap; + } + + @Override + public boolean hasValidInput() + { + return true; + } + + @Override + public boolean hasResults() + { + return (isSubjobComplete() && alignment != null); + } + + public boolean isMSA() + { + return msf.size() > 1; + } + } + + + private JPredServiceI server; + private String title; + private Hashtable sequenceInfo; + private SequenceI[] msf; + private int[] delMap; + + public JPredThread(WebserviceInfo wsInfo, String title, + JPredServiceI 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.predict(job.msf, job.isMSA()); + 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 { + prepareJobResult(job); + } + 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.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.appendInfoText("No jobs ran."); + wsInfo.setFinishedNoResults(); + } + updateGlobalStatus(finalState); + wsInfo.removeProgressBar(progbar); + } + + static final int msaIndex = 0; + + private void prepareJobResult(JPredJob job) throws Exception + { + HiddenColumns hiddenCols = null; + int firstSeq = -1; + AlignmentI alignment; + var prediction = server.getPrediction(job.getJobHandle()); + var preds = prediction.getSeqsAsArray(); + + if (job.msf.size() > 1) + { + if (job.delMap != null) + { + Object[] alandcolsel = input + .getAlignmentAndHiddenColumns(getGapChar()); + alignment = new Alignment((SequenceI[]) alandcolsel[0]); + hiddenCols = (HiddenColumns) alandcolsel[1]; + } + else + { + alignment = server.getAlignment(job.getJobHandle()); + var seqs = new SequenceI[alignment.getHeight()]; + for (int i = 0; i < alignment.getHeight(); i++) + { + seqs[i] = alignment.getSequenceAt(i); + } + if (!SeqsetUtils.deuniquify(sequenceInfo, seqs)) + { + throw (new Exception(MessageManager.getString( + "exception.couldnt_recover_sequence_properties_for_alignment"))); + } + } + firstSeq = 0; + if (currentView.getDataset() != null) + { + alignment.setDataset(currentView.getDataset()); + } + else + { + alignment.setDataset(null); + } + JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, false, + job.delMap); + } + else + { + alignment = new Alignment(preds); + firstSeq = prediction.getQuerySeqPosition(); + if (job.delMap != null) + { + Object[] alanndcolsel = input.getAlignmentAndHiddenColumns(getGapChar()); + SequenceI[] seqs = (SequenceI[]) alanndcolsel[0]; + new RemoveGapsCommand(MessageManager.getString("label.remove_gaps"), + new SequenceI[] {seqs[msaIndex]}, currentView); + SequenceI profileSeq = alignment.getSequenceAt(firstSeq); + profileSeq.setSequence(seqs[msaIndex].getSequenceAsString()); + } + if (!SeqsetUtils.SeqCharacterUnhash( + alignment.getSequenceAt(firstSeq), sequenceInfo)) + { + throw new Exception(MessageManager.getString( + "exception.couldnt_recover_sequence_props_for_jnet_query")); + } + alignment.setDataset(currentView.getDataset()); + JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, true, + job.delMap); + SequenceI profileSeq = alignment.getSequenceAt(0); + alignToProfileSeq(alignment, profileSeq); + if (job.delMap != null) + { + hiddenCols = alignment.propagateInsertions(profileSeq, input); + } + } + + for (var annot : alignment.getAlignmentAnnotation()) + { + if (annot.sequenceRef != null) + { + replaceAnnotationOnAlignmentWith(annot, annot.label, + "jalview.ws.JPred", annot.sequenceRef); + } + } + job.alignment = alignment; + job.hiddenCols = hiddenCols; + } + + private static void replaceAnnotationOnAlignmentWith( + AlignmentAnnotation newAnnot, String typeName, String calcId, + SequenceI aSeq) + { + SequenceI dsseq = aSeq.getDatasetSequence(); + while (dsseq.getDatasetSequence() != null) + { + dsseq = dsseq.getDatasetSequence(); + } + // look for same annotation on dataset and lift this one over + List dsan = dsseq.getAlignmentAnnotations(calcId, + typeName); + if (dsan != null && dsan.size() > 0) + { + for (AlignmentAnnotation dssan : dsan) + { + dsseq.removeAlignmentAnnotation(dssan); + } + } + AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot); + dsseq.addAlignmentAnnotation(dssan); + dssan.adjustForAlignment(); + } + + private static void alignToProfileSeq(AlignmentI al, SequenceI profileseq) + { + char gc = al.getGapCharacter(); + int[] gapMap = profileseq.gapMap(); + // insert gaps into profile + for (int lp = 0, r = 0; r < gapMap.length; r++) + { + if (gapMap[r] - lp > 1) + { + StringBuffer sb = new StringBuffer(); + for (int s = 0, ns = gapMap[r] - lp; s < ns; s++) + { + sb.append(gc); + } + for (int s = 1, ns = al.getHeight(); s < ns; s++) + { + String sq = al.getSequenceAt(s).getSequenceAsString(); + int diff = gapMap[r] - sq.length(); + if (diff > 0) + { + // pad gaps + sq = sq + sb; + while ((diff = gapMap[r] - sq.length()) > 0) + { + sq = sq + ((diff >= sb.length()) ? sb.toString() + : sb.substring(0, diff)); + } + al.getSequenceAt(s).setSequence(sq); + } + else + { + al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r]) + + sb.toString() + sq.substring(gapMap[r])); + } + } + } + lp = gapMap[r]; + } + } + + private void displayResults(boolean newWindow) + { + if (jobs == null || jobs.length == 0) + { + return; + } + var job = (JPredJob) jobs[0]; + if (job.hasResults() && newWindow) + { + job.alignment.setSeqrep(job.alignment.getSequenceAt(0)); + AlignFrame frame = new AlignFrame(job.alignment, job.hiddenCols, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + Desktop.addInternalFrame(frame, title, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + } + } + +} diff --combined src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java index 462be28,0000000..3958198 mode 100644,000000..100644 --- a/src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java +++ b/src/jalview/ws/slivkaws/SlivkaJPredServiceInstance.java @@@ -1,96 -1,0 +1,98 @@@ +package jalview.ws.slivkaws; + +import java.io.IOError; +import java.io.IOException; ++import java.util.Collection; +import java.util.List; + +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.JPredFile; +import jalview.ws.api.JPredServiceI; +import jalview.ws.api.JobId; +import jalview.ws.params.ArgumentI; +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 JPredServiceI +{ + + private class InputFormatParameter implements ArgumentI + { + String value = ""; + + @Override + public String getName() + { + return "format"; + } + + @Override + public String getValue() + { + return value; + } + + @Override + public void setValue(String selectedItem) + { + value = selectedItem; + } + } + + + public SlivkaJPredServiceInstance(SlivkaClient client, + SlivkaService service, String action) + { + super(client, service, action); + style = ServiceClient.JPREDWSCLIENT; + } + + @Override + public JobId predict(List sequences, boolean msa) throws Throwable + { + // Hack allowing to send both single and msa jobs + // until msa and single sequence services are separated. + var arg = new InputFormatParameter(); + arg.setValue(msa ? "fasta" : "seq"); + return super.submit(sequences, null, List.of(arg)); + } + + @Override + public AlignmentI getAlignment(JobId jobId) throws Exception + { - List files; ++ Collection files; + try { - files = client.getJobResults(jobId.getJobId()); ++ var job = client.getJob(jobId.getJobId()); ++ files = job.getResults(); + for (RemoteFile f : files) { + var alignment = readAlignment(f); + if (alignment != null) + { + return alignment; + } + } + } + catch (IOException e) { + throw new IOError(e); + } + return null; + } + + @Override + public JPredFile getPrediction(JobId jobId) throws Exception + { - List files = client.getJobResults(jobId.getJobId()); ++ Collection files = client.getJob(jobId.getJobId()).getResults(); + for (RemoteFile f : files) + { + if (f.getLabel().equals("concise")) + { - return new JPredFile(f.getURL(), DataSourceType.URL); ++ return new JPredFile(f.getContentUrl(), DataSourceType.URL); + } + } + return null; + } +} diff --combined src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java index 8d6332c,03dda3f..b992fbe --- a/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java +++ b/src/jalview/ws/slivkaws/SlivkaMsaServiceInstance.java @@@ -1,7 -1,11 +1,11 @@@ package jalview.ws.slivkaws; + import jalview.bin.Cache; 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; @@@ -11,8 -15,10 +15,9 @@@ import jalview.ws.params.WsParamSetI import java.io.IOError; import java.io.IOException; import java.rmi.ServerError; + import java.util.Collection; 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; @@@ -33,15 -39,20 +38,20 @@@ public class SlivkaMsaServiceInstance e @Override public AlignmentI getAlignmentFor(JobId jobId) throws InvalidArgumentException, ServerError, IOError { + Collection files; try { - List files = client.getJobResults(jobId.getJobId()); + var slivkaJob = client.getJob(jobId.getJobId()); + files = slivkaJob.getResults(); for (RemoteFile f : files) { - var aln = readAlignment(f); - if (aln != null) + if (f.getMediaType().equals("application/clustal")) { - return aln; + return new FormatAdapter().readFile(f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Clustal); + } + else if (f.getMediaType().equals("application/fasta")) + { + return new FormatAdapter().readFile(f.getContentUrl().toString(), DataSourceType.URL, FileFormat.Fasta); } } } catch (IOException e) diff --combined src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java index d290024,accb40d..50fa2d6 --- a/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java +++ b/src/jalview/ws/slivkaws/SlivkaWSDiscoverer.java @@@ -4,6 -4,6 +4,8 @@@ import jalview.bin.Cache import jalview.ws.ServiceChangeListener; import jalview.ws.WSDiscovererI; import jalview.ws.api.ServiceWithParameters; ++import javajs.http.HttpClientFactory; ++ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@@ -122,7 -122,7 +124,7 @@@ public class SlivkaWSDiscoverer impleme 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": @@@ -215,7 -215,7 +217,7 @@@ { List services = new SlivkaClient(url).getServices(); return services.isEmpty() ? STATUS_NO_SERVICES : STATUS_OK; - } catch (IOException e) + } catch (IOException | org.json.JSONException e) { Cache.log.error("Slivka could not retrieve services list", e); return STATUS_INVALID; diff --combined src/jalview/ws/slivkaws/SlivkaWSInstance.java index fa54cf0,0c71c35..80e928a --- a/src/jalview/ws/slivkaws/SlivkaWSInstance.java +++ b/src/jalview/ws/slivkaws/SlivkaWSInstance.java @@@ -1,21 -1,7 +1,20 @@@ package jalview.ws.slivkaws; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashSet; +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; @@@ -27,16 -13,26 +26,15 @@@ 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.FileField; - import uk.ac.dundee.compbio.slivkaclient.FormField; - import uk.ac.dundee.compbio.slivkaclient.FormValidationException; - import uk.ac.dundee.compbio.slivkaclient.JobState; + import javajs.http.ClientProtocolException; + -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOError; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; + import java.util.Collection; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - + import uk.ac.dundee.compbio.slivkaclient.Job; + import uk.ac.dundee.compbio.slivkaclient.JobRequest; + import uk.ac.dundee.compbio.slivkaclient.Parameter; import uk.ac.dundee.compbio.slivkaclient.RemoteFile; import uk.ac.dundee.compbio.slivkaclient.SlivkaClient; - import uk.ac.dundee.compbio.slivkaclient.SlivkaForm; import uk.ac.dundee.compbio.slivkaclient.SlivkaService; - import uk.ac.dundee.compbio.slivkaclient.ValidationException; public abstract class SlivkaWSInstance extends ServiceWithParameters implements JalviewServiceEndpointProviderI, JalviewWebServiceI @@@ -47,19 -43,19 +45,19 @@@ protected SlivkaDatastore store = null; - protected static final EnumMap stateMap = new EnumMap<>(JobState.class); + protected static final EnumMap stateMap = new EnumMap<>(Job.Status.class); { - stateMap.put(JobState.PENDING, WsJob.JobState.QUEUED); - stateMap.put(JobState.REJECTED, WsJob.JobState.INVALID); - stateMap.put(JobState.ACCEPTED, WsJob.JobState.QUEUED); - stateMap.put(JobState.QUEUED, WsJob.JobState.QUEUED); - stateMap.put(JobState.RUNNING, WsJob.JobState.RUNNING); - stateMap.put(JobState.COMPLETED, WsJob.JobState.FINISHED); - stateMap.put(JobState.INTERRUPTED, WsJob.JobState.CANCELLED); - stateMap.put(JobState.DELETED, WsJob.JobState.CANCELLED); - stateMap.put(JobState.FAILED, WsJob.JobState.FAILED); - stateMap.put(JobState.ERROR, WsJob.JobState.SERVERERROR); - stateMap.put(JobState.UNKNOWN, WsJob.JobState.UNKNOWN); + stateMap.put(Job.Status.PENDING, WsJob.JobState.QUEUED); + stateMap.put(Job.Status.REJECTED, WsJob.JobState.INVALID); + stateMap.put(Job.Status.ACCEPTED, WsJob.JobState.QUEUED); + stateMap.put(Job.Status.QUEUED, WsJob.JobState.QUEUED); + stateMap.put(Job.Status.RUNNING, WsJob.JobState.RUNNING); + stateMap.put(Job.Status.COMPLETED, WsJob.JobState.FINISHED); + stateMap.put(Job.Status.INTERRUPTED, WsJob.JobState.CANCELLED); + stateMap.put(Job.Status.DELETED, WsJob.JobState.CANCELLED); + stateMap.put(Job.Status.FAILED, WsJob.JobState.FAILED); + stateMap.put(Job.Status.ERROR, WsJob.JobState.SERVERERROR); + stateMap.put(Job.Status.UNKNOWN, WsJob.JobState.UNKNOWN); } protected final Set failedStates = new HashSet<>(Arrays.asList( WsJob.JobState.INVALID, WsJob.JobState.BROKEN, WsJob.JobState.FAILED, @@@ -68,7 -64,7 +66,7 @@@ public SlivkaWSInstance(SlivkaClient client, SlivkaService service, String action) { - super(action, action, service.getLabel(), "Slivka", client.getUrl().toString()); + super(action, action, service.getName(), "Slivka", client.getUrl().toString()); this.client = client; this.service = service; } @@@ -76,16 -72,17 +74,17 @@@ protected final JobId submit(List sequences, WsParamSetI preset, List args) throws Throwable { - SlivkaForm form = service.getForm(); - for (FormField field : form.getFields()) + var parameters = service.getParameters(); + var request = new JobRequest(); + for (Parameter param : parameters) { - if (field.getType() == FieldType.FILE) + if (param instanceof Parameter.FileParameter) { FormatAdapter fa = new FormatAdapter(); fa.setNewlineString("\r\n"); - FileField fileField = (FileField) field; + Parameter.FileParameter fileParam = (Parameter.FileParameter) param; FileFormat format; - switch (fileField.getMediaType()) + switch (fileParam.getMediaType()) { case "application/pfam": format = FileFormat.Pfam; @@@ -98,12 -95,13 +97,13 @@@ format = FileFormat.Fasta; break; } - InputStream stream = new ByteArrayInputStream( - fa.formatSequences(format, sequences.toArray(new SequenceI[0])) + + // we avoid any use of Jalview's user facing export routines here + + InputStream stream = new ByteArrayInputStream(format.getWriter(null) + .print(sequences.toArray(new SequenceI[0]), false) .getBytes()); - RemoteFile rf = client.uploadFile(stream, "input", - fileField.getMediaType()); - form.insert(field.getName(), rf); + request.addFile(param.getId(), stream); } } if (args != null) @@@ -112,22 -110,22 +112,22 @@@ { // multiple choice field names are name$number to avoid duplications // the number is stripped here - String fieldName = arg.getName().split("\\$", 2)[0]; - FormField field = form.getField(fieldName); - if (field.getType() == FieldType.BOOLEAN) - { - form.insert(fieldName, - (arg.getValue() != null && !arg.getValue().isBlank()) - ? true - : false); + String paramId = arg.getName().split("\\$", 2)[0]; + Parameter param = service.getParameter(paramId); + if (param instanceof Parameter.FlagParameter) { + if (arg.getValue() != null && !arg.getValue().isBlank()) + request.addData(paramId, true); + else + request.addData(paramId, false); } else { - form.insert(fieldName, arg.getValue()); + request.addData(paramId, arg.getValue()); } } } - return new JobId(service.getName(), service.getName(), form.submit()); + var job = service.submitJob(request); + return new JobId(service.getName(), service.getName(), job.getId()); } @Override @@@ -135,7 -133,8 +135,8 @@@ { try { - job.setState(stateMap.get(client.getJobState(job.getJobId()))); + var slivkaJob = client.getJob(job.getJobId()); + job.setState(stateMap.get(slivkaJob.getStatus())); } catch (IOException e) { throw new IOError(e); @@@ -144,8 -143,9 +145,9 @@@ @Override public final boolean updateJobProgress(WsJob job) throws IOException - { - List files = client.getJobResults(job.getJobId()); + { + var slivkaJob = client.getJob(job.getJobId()); + Collection files = slivkaJob.getResults(); RemoteFile logFile=null; for (RemoteFile f : files) { @@@ -197,17 -197,10 +199,10 @@@ @Override public final boolean handleSubmitError(Throwable _lex, WsJob j, WebserviceInfo wsInfo) { - if (_lex instanceof FormValidationException) + if (_lex instanceof ClientProtocolException) { - FormValidationException formError = (FormValidationException) _lex; - String[] messages = new String[formError.getErrors().size()]; - int i = 0; - for (ValidationException e : formError.getErrors()) - { - messages[i++] = String.format("%s: %s,", e.getField().getName(), e.getMessage()); - } j.setState(WsJob.JobState.INVALID); - j.setStatus(String.join(", ", messages)); + j.setStatus(_lex.getMessage()); return true; } return false; @@@ -261,19 -254,5 +256,19 @@@ } return store; } + + public static AlignmentI readAlignment(RemoteFile f) throws IOException + { - final var mimetype = f.getMimeType(); ++ final var mimetype = f.getMediaType(); + FileFormat format; + if (mimetype.equals("application/clustal")) + format = FileFormat.Clustal; + else if (mimetype.equals("application/fasta")) + format = FileFormat.Fasta; + else + return null; - return new FormatAdapter().readFile(f.getURL().toString(), ++ return new FormatAdapter().readFile(f.getContentUrl().toString(), + DataSourceType.URL, format); + } }