From: Jim Procter Date: Wed, 1 Aug 2018 20:17:29 +0000 (+0100) Subject: JAL-3070 refactored Client specific code from jalview.ws.jws2.MSA* as implementors... X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=02c1474aa3b80a034a475edd9dc77fe8928ad1f1 JAL-3070 refactored Client specific code from jalview.ws.jws2.MSA* as implementors of jalview.ws.api.* interfaces --- diff --git a/src/jalview/ws/AWsJob.java b/src/jalview/ws/AWsJob.java index bb203fc..4a9cb74 100644 --- a/src/jalview/ws/AWsJob.java +++ b/src/jalview/ws/AWsJob.java @@ -251,4 +251,36 @@ public abstract class AWsJob arguments = paramset; } + + public boolean isPresetJob() + { + return preset!=null && arguments==null; + } + + public List getArguments() + { + return arguments; + } + + public WsParamSetI getPreset() + { + return preset; + } + + long nextChunk = 0; + + /** + * update the record of the last position in the log file read for this job + * + * @param nextChunk + */ + public void setnextChunk(long nextChunk) + { + this.nextChunk = nextChunk; + } + + public long getNextChunk() + { + return nextChunk; + } } diff --git a/src/jalview/ws/WSClient.java b/src/jalview/ws/WSClient.java index d031142..33aea90 100755 --- a/src/jalview/ws/WSClient.java +++ b/src/jalview/ws/WSClient.java @@ -67,6 +67,11 @@ public abstract class WSClient // implements WSMenuEntryProviderI protected WebserviceInfo wsInfo; /** + * the root object for the service client + */ + protected UIinfo serviceHandle; + + /** * total number of jobs managed by this web service client instance. */ int jobsRunning = 0; diff --git a/src/jalview/ws/api/CancellableI.java b/src/jalview/ws/api/CancellableI.java new file mode 100644 index 0000000..adef2b9 --- /dev/null +++ b/src/jalview/ws/api/CancellableI.java @@ -0,0 +1,8 @@ +package jalview.ws.api; + +import jalview.ws.gui.WsJob; + +public interface CancellableI +{ + public boolean cancel(WsJob job); +} diff --git a/src/jalview/ws/api/JalviewWebServiceI.java b/src/jalview/ws/api/JalviewWebServiceI.java new file mode 100644 index 0000000..ecc8bab --- /dev/null +++ b/src/jalview/ws/api/JalviewWebServiceI.java @@ -0,0 +1,19 @@ +package jalview.ws.api; + +import jalview.gui.WebserviceInfo; +import jalview.ws.gui.WsJob; + +public interface JalviewWebServiceI +{ + + void updateStatus(WsJob job); + + boolean updateJobProgress(WsJob job) throws Exception; + + boolean handleSubmitError(Throwable _lex, WsJob j, WebserviceInfo wsInfo) + throws Exception, Error; + + boolean handleCollectionException(Exception e, WsJob msjob, + WebserviceInfo wsInfo); + +} diff --git a/src/jalview/ws/api/JobId.java b/src/jalview/ws/api/JobId.java new file mode 100644 index 0000000..2a092bd --- /dev/null +++ b/src/jalview/ws/api/JobId.java @@ -0,0 +1,59 @@ +package jalview.ws.api; + +import java.time.Instant; +import java.util.Date; + +public class JobId +{ + // TODO: JobId could include sequenceI anonymisation stuff + // TODO: getProgress() -> input stream to log file for job. + private String serviceType; + + private String serviceImpl; + + private String jobId; + + private Instant creationTime; + + public JobId(String serviceType, String serviceImpl, String id) + { + this.serviceType = serviceType; + this.serviceImpl = serviceImpl; + jobId = id; + creationTime = Instant.now(); + } + + @Override + public String toString() + { + return "" + serviceType + ":" + serviceImpl + ":" + jobId + "\nCreated " + + Date.from(creationTime); + } + /** + * a stringified version of the Job Id that can be saved in project. + */ + public String getURI() + { + return jobId; + } + + public String getServiceType() + { + return serviceType; + } + + public String getServiceImpl() + { + return serviceImpl; + } + + public String getJobId() + { + return jobId; + } + + public Instant getCreationTime() + { + return creationTime; + } +} diff --git a/src/jalview/ws/api/MsaI.java b/src/jalview/ws/api/MsaI.java new file mode 100644 index 0000000..3c426c0 --- /dev/null +++ b/src/jalview/ws/api/MsaI.java @@ -0,0 +1,36 @@ +package jalview.ws.api; + +import jalview.datamodel.SequenceI; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.WsParamSetI; + +import java.util.List; + +/** + * MSA analysis interface + * + * @author jprocter + * + * Generic job submission/management model: - A service instance + * implements one or more analysis interfaces, a status interface, a + * progress interface, and one or more results interface, plus any + * informational/descriptional interfaces - analysis interfaces return + * JobId or throw exceptions/errors. + * + * + */ +public interface MsaI +{ + /** + * Given a set of sequences + * + * @param toalign + * @param parameters + * @param list + * @return JobId or exceptions are thrown. + * @throws Throwable + */ + public JobId align(List toalign, WsParamSetI parameters, + List list) + throws Throwable; +} diff --git a/src/jalview/ws/api/MsaResultI.java b/src/jalview/ws/api/MsaResultI.java new file mode 100644 index 0000000..38c0a0a --- /dev/null +++ b/src/jalview/ws/api/MsaResultI.java @@ -0,0 +1,13 @@ +package jalview.ws.api; + +import jalview.datamodel.AlignmentI; +import jalview.ws.params.InvalidArgumentException; + +import java.io.IOError; +import java.rmi.ServerError; + +public interface MsaResultI +{ + public AlignmentI getAlignmentFor(JobId jobId) + throws InvalidArgumentException, ServerError, IOError; +} \ No newline at end of file diff --git a/src/jalview/ws/api/MultipleSequenceAlignmentI.java b/src/jalview/ws/api/MultipleSequenceAlignmentI.java new file mode 100644 index 0000000..10b8383 --- /dev/null +++ b/src/jalview/ws/api/MultipleSequenceAlignmentI.java @@ -0,0 +1,13 @@ +package jalview.ws.api; + +/** + * A simple parameterisable multiple sequence alignment service + * + * @author jprocter + * + */ +public interface MultipleSequenceAlignmentI + extends JalviewWebServiceI, MsaI, MsaResultI +{ + +} diff --git a/src/jalview/ws/gui/MsaWSJob.java b/src/jalview/ws/gui/MsaWSJob.java new file mode 100644 index 0000000..86d299a --- /dev/null +++ b/src/jalview/ws/gui/MsaWSJob.java @@ -0,0 +1,381 @@ +package jalview.ws.gui; + +import jalview.analysis.AlignSeq; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.util.MessageManager; +import jalview.ws.api.JobId; +import jalview.ws.jws2.dm.JabaWsParamSet; +import jalview.ws.params.ArgumentI; + +import java.util.ArrayList; +import java.util.Vector; + +class MsaWSJob extends WsJob +{ + /** + * holds basic MSA analysis configuration - todo - encapsulate + */ + private final MsaWSThread msaWSThread; + + long lastChunk = 0; + + /** + * input + */ + ArrayList seqs = new ArrayList<>(); + + /** + * output + */ + AlignmentI alignment; + + // set if the job didn't get run - then the input is simply returned to the + // user + private boolean returnInput = false; + + /** + * MsaWSJob + * + * @param jobNum + * int + * @param msaWSThread + * TODO - abstract the properties provided by the thread + * @param jobId + * String + */ + public MsaWSJob(MsaWSThread msaWSThread, int jobNum, SequenceI[] inSeqs) + { + this.msaWSThread = msaWSThread; + this.jobnum = jobNum; + if (!prepareInput(inSeqs, 2)) + { + submitted = true; + subjobComplete = true; + returnInput = true; + } + + } + + Vector emptySeqs = new Vector(); + + /** + * prepare input sequences for MsaWS service + * + * @param seqs + * jalview sequences to be prepared + * @param minlen + * minimum number of residues required for this MsaWS service + * @return true if seqs contains sequences to be submitted to service. + */ + // TODO: return compbio.seqs list or nothing to indicate validity. + private boolean prepareInput(SequenceI[] seqs, int minlen) + { + // TODO: service specific input data is generated in this method - for + // JABAWS it is client-side + // prepared, but for Slivka it could be uploaded at this stage. + + int nseqs = 0; + if (minlen < 0) + { + throw new Error(MessageManager.getString( + "error.implementation_error_minlen_must_be_greater_zero")); + } + for (int i = 0; i < seqs.length; i++) + { + if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1) + { + nseqs++; + } + } + boolean valid = nseqs > 1; // need at least two seqs + Sequence seq; + for (int i = 0, n = 0; i < seqs.length; i++) + { + String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same + // for + // any + // subjob + SeqNames.put(newname, + jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i])); + if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1) + { + // make new input sequence with or without gaps + seq = new Sequence(newname, + (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString() + : AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString())); + this.seqs.add(seq); + } + else + { + String empty = null; + if (seqs[i].getEnd() >= seqs[i].getStart()) + { + empty = (this.msaWSThread.submitGaps) ? seqs[i].getSequenceAsString() + : AlignSeq.extractGaps(jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString()); + } + emptySeqs.add(new String[] { newname, empty }); + } + } + return valid; + } + + /** + * + * @return true if getAlignment will return a valid alignment result. + */ + @Override + public boolean hasResults() + { + if (subjobComplete && isFinished() && (alignment != null + || (emptySeqs != null && emptySeqs.size() > 0))) + { + return true; + } + return false; + } + + /** + * + * get the alignment including any empty sequences in the original order + * with original ids. Caller must access the alignment.getMetadata() object + * to annotate the final result passsed to the user. + * + * @return { SequenceI[], AlignmentOrder } + */ + public Object[] getAlignment() + { + // TODO: make this generic based on MsaResultI + // TODO: decide if the data loss for this return signature is avoidable + // (ie should we just return AlignmentI instead ?) + if (hasResults()) + { + SequenceI[] alseqs = null; + char alseq_gapchar = '-'; + int alseq_l = 0; + alseqs = new SequenceI[alignment.getSequences().size()]; + if (alignment.getSequences().size() > 0) + { + for (SequenceI seq : alignment + .getSequences()) + { + alseqs[alseq_l++] = new Sequence(seq); + } + alseq_gapchar = alignment.getGapCharacter(); + + } + // add in the empty seqs. + if (emptySeqs.size() > 0) + { + SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()]; + // get width + int i, w = 0; + if (alseq_l > 0) + { + for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++) + { + if (w < alseqs[i].getLength()) + { + w = alseqs[i].getLength(); + } + t_alseqs[i] = alseqs[i]; + alseqs[i] = null; + } + } + // check that aligned width is at least as wide as emptySeqs width. + int ow = w, nw = w; + for (i = 0, w = emptySeqs.size(); i < w; i++) + { + String[] es = emptySeqs.get(i); + if (es != null && es[1] != null) + { + int sw = es[1].length(); + if (nw < sw) + { + nw = sw; + } + } + } + // make a gapped string. + StringBuffer insbuff = new StringBuffer(w); + for (i = 0; i < nw; i++) + { + insbuff.append(alseq_gapchar); + } + if (ow < nw) + { + for (i = 0; i < alseq_l; i++) + { + int sw = t_alseqs[i].getLength(); + if (nw > sw) + { + // pad at end + alseqs[i].setSequence(t_alseqs[i].getSequenceAsString() + + insbuff.substring(0, sw - nw)); + } + } + } + for (i = 0, w = emptySeqs.size(); i < w; i++) + { + String[] es = emptySeqs.get(i); + if (es[1] == null) + { + t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0], + insbuff.toString(), 1, 0); + } + else + { + if (es[1].length() < nw) + { + t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence( + es[0], + es[1] + insbuff.substring(0, nw - es[1].length()), + 1, 1 + es[1].length()); + } + else + { + t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence( + es[0], es[1]); + } + } + } + alseqs = t_alseqs; + } + AlignmentOrder msaorder = new AlignmentOrder(alseqs); + // always recover the order - makes parseResult()'s life easier. + jalview.analysis.AlignmentSorter.recoverOrder(alseqs); + // account for any missing sequences + jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs); + return new Object[] { alseqs, msaorder }; + } + return null; + } + + /** + * mark subjob as cancelled and set result object appropriatly + */ + void cancel() + { + cancelled = true; + subjobComplete = true; + alignment = null; + } + + /** + * + * @return boolean true if job can be submitted. + */ + @Override + public boolean hasValidInput() + { + // TODO: get attributes for this MsaWS instance to check if it can do two + // sequence alignment. + if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ? + { + return true; + } + return false; + } + + StringBuffer jobProgress = new StringBuffer(); + + @Override + public void setStatus(String string) + { + jobProgress.setLength(0); + jobProgress.append(string); + } + + @Override + public String getStatus() + { + return jobProgress.toString(); + } + + @Override + public boolean hasStatus() + { + return jobProgress != null; + } + + /** + * @return the lastChunk + */ + public long getLastChunk() + { + return lastChunk; + } + + /** + * @param lastChunk + * the lastChunk to set + */ + public void setLastChunk(long lastChunk) + { + this.lastChunk = lastChunk; + } + + String alignmentProgram = null; + + public String getAlignmentProgram() + { + return alignmentProgram; + } + + public boolean hasArguments() + { + return (arguments != null && arguments.size() > 0) + || (preset != null && preset instanceof JabaWsParamSet); + } + + /** + * add a progess header to status string containing presets/args used + */ + public void addInitialStatus() + { + // TODO: decide if it is useful to report 'JABAWS format' argument lists + // rather than generic Jalview service arguments + if (preset != null) + { + jobProgress.append( + "Using " + (preset.isModifiable() ? "Server" : "User") + + "Preset: " + preset.getName()); + for (ArgumentI opt : preset.getArguments()) + { + jobProgress.append(opt.getName() + " " + opt.getValue() + "\n"); + } + } + else + { + if (arguments != null && arguments.size() > 0) + { + jobProgress.append("With custom parameters : \n"); + // merge arguments with preset's own arguments. + for (ArgumentI opt : arguments) + { + jobProgress.append(opt.getName() + " " + opt.getValue() + "\n"); + } + } + jobProgress.append("\nJob Output:\n"); + } + } + + JobId jobHandle = null; + public void setJobHandle(JobId align) + { + jobHandle = align; + setJobId(jobHandle.getJobId()); + + } + + public JobId getJobHandle() + { + return jobHandle; + } + +} \ No newline at end of file diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/gui/MsaWSThread.java similarity index 54% rename from src/jalview/ws/jws2/MsaWSThread.java rename to src/jalview/ws/gui/MsaWSThread.java index b1d6452..7141e73 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/gui/MsaWSThread.java @@ -18,42 +18,37 @@ * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ -package jalview.ws.jws2; +package jalview.ws.gui; -import jalview.analysis.AlignSeq; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.HiddenColumns; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.SplitFrame; import jalview.gui.WebserviceInfo; import jalview.util.MessageManager; +import jalview.ws.AWSThread; import jalview.ws.AWsJob; import jalview.ws.JobStateSummary; import jalview.ws.WSClientI; -import jalview.ws.jws2.dm.JabaWsParamSet; +import jalview.ws.api.CancellableI; +import jalview.ws.api.JobId; +import jalview.ws.api.MultipleSequenceAlignmentI; +import jalview.ws.gui.WsJob.JobState; import jalview.ws.params.ArgumentI; import jalview.ws.params.WsParamSetI; import java.util.ArrayList; import java.util.List; -import java.util.Vector; import javax.swing.JInternalFrame; -import compbio.data.msa.MsaWS; -import compbio.metadata.Argument; -import compbio.metadata.ChunkHolder; -import compbio.metadata.JobStatus; -import compbio.metadata.Preset; - -class MsaWSThread extends AWS2Thread implements WSClientI +public class MsaWSThread extends AWSThread implements WSClientI { boolean submitGaps = false; // pass sequences including gaps to alignment @@ -63,377 +58,13 @@ class MsaWSThread extends AWS2Thread implements WSClientI // order - class MsaWSJob extends JWs2Job - { - long lastChunk = 0; - - /** - * input - */ - ArrayList seqs = new ArrayList<>(); - - /** - * output - */ - compbio.data.sequence.Alignment alignment; - - // set if the job didn't get run - then the input is simply returned to the - // user - private boolean returnInput = false; - - /** - * MsaWSJob - * - * @param jobNum - * int - * @param jobId - * String - */ - public MsaWSJob(int jobNum, SequenceI[] inSeqs) - { - this.jobnum = jobNum; - if (!prepareInput(inSeqs, 2)) - { - submitted = true; - subjobComplete = true; - returnInput = true; - } - - } - - Vector emptySeqs = new Vector(); - - /** - * prepare input sequences for MsaWS service - * - * @param seqs - * jalview sequences to be prepared - * @param minlen - * minimum number of residues required for this MsaWS service - * @return true if seqs contains sequences to be submitted to service. - */ - // TODO: return compbio.seqs list or nothing to indicate validity. - private boolean prepareInput(SequenceI[] seqs, int minlen) - { - int nseqs = 0; - if (minlen < 0) - { - throw new Error(MessageManager.getString( - "error.implementation_error_minlen_must_be_greater_zero")); - } - for (int i = 0; i < seqs.length; i++) - { - if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1) - { - nseqs++; - } - } - boolean valid = nseqs > 1; // need at least two seqs - compbio.data.sequence.FastaSequence seq; - for (int i = 0, n = 0; i < seqs.length; i++) - { - String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same - // for - // any - // subjob - SeqNames.put(newname, - jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i])); - if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1) - { - // make new input sequence with or without gaps - seq = new compbio.data.sequence.FastaSequence(newname, - (submitGaps) ? seqs[i].getSequenceAsString() - : AlignSeq.extractGaps( - jalview.util.Comparison.GapChars, - seqs[i].getSequenceAsString())); - this.seqs.add(seq); - } - else - { - String empty = null; - if (seqs[i].getEnd() >= seqs[i].getStart()) - { - empty = (submitGaps) ? seqs[i].getSequenceAsString() - : AlignSeq.extractGaps(jalview.util.Comparison.GapChars, - seqs[i].getSequenceAsString()); - } - emptySeqs.add(new String[] { newname, empty }); - } - } - return valid; - } - - /** - * - * @return true if getAlignment will return a valid alignment result. - */ - @Override - public boolean hasResults() - { - if (subjobComplete && isFinished() && (alignment != null - || (emptySeqs != null && emptySeqs.size() > 0))) - { - return true; - } - return false; - } - - /** - * - * get the alignment including any empty sequences in the original order - * with original ids. Caller must access the alignment.getMetadata() object - * to annotate the final result passsed to the user. - * - * @return { SequenceI[], AlignmentOrder } - */ - public Object[] getAlignment() - { - // is this a generic subjob or a Jws2 specific Object[] return signature - if (hasResults()) - { - SequenceI[] alseqs = null; - char alseq_gapchar = '-'; - int alseq_l = 0; - if (alignment.getSequences().size() > 0) - { - alseqs = new SequenceI[alignment.getSequences().size()]; - for (compbio.data.sequence.FastaSequence seq : alignment - .getSequences()) - { - alseqs[alseq_l++] = new Sequence(seq.getId(), - seq.getSequence()); - } - alseq_gapchar = alignment.getMetadata().getGapchar(); - - } - // add in the empty seqs. - if (emptySeqs.size() > 0) - { - SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()]; - // get width - int i, w = 0; - if (alseq_l > 0) - { - for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++) - { - if (w < alseqs[i].getLength()) - { - w = alseqs[i].getLength(); - } - t_alseqs[i] = alseqs[i]; - alseqs[i] = null; - } - } - // check that aligned width is at least as wide as emptySeqs width. - int ow = w, nw = w; - for (i = 0, w = emptySeqs.size(); i < w; i++) - { - String[] es = emptySeqs.get(i); - if (es != null && es[1] != null) - { - int sw = es[1].length(); - if (nw < sw) - { - nw = sw; - } - } - } - // make a gapped string. - StringBuffer insbuff = new StringBuffer(w); - for (i = 0; i < nw; i++) - { - insbuff.append(alseq_gapchar); - } - if (ow < nw) - { - for (i = 0; i < alseq_l; i++) - { - int sw = t_alseqs[i].getLength(); - if (nw > sw) - { - // pad at end - alseqs[i].setSequence(t_alseqs[i].getSequenceAsString() - + insbuff.substring(0, sw - nw)); - } - } - } - for (i = 0, w = emptySeqs.size(); i < w; i++) - { - String[] es = emptySeqs.get(i); - if (es[1] == null) - { - t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0], - insbuff.toString(), 1, 0); - } - else - { - if (es[1].length() < nw) - { - t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence( - es[0], - es[1] + insbuff.substring(0, nw - es[1].length()), - 1, 1 + es[1].length()); - } - else - { - t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence( - es[0], es[1]); - } - } - } - alseqs = t_alseqs; - } - AlignmentOrder msaorder = new AlignmentOrder(alseqs); - // always recover the order - makes parseResult()'s life easier. - jalview.analysis.AlignmentSorter.recoverOrder(alseqs); - // account for any missing sequences - jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs); - return new Object[] { alseqs, msaorder }; - } - return null; - } - - /** - * mark subjob as cancelled and set result object appropriatly - */ - void cancel() - { - cancelled = true; - subjobComplete = true; - alignment = null; - } - - /** - * - * @return boolean true if job can be submitted. - */ - @Override - public boolean hasValidInput() - { - // TODO: get attributes for this MsaWS instance to check if it can do two - // sequence alignment. - if (seqs != null && seqs.size() >= 2) // two or more sequences is valid ? - { - return true; - } - return false; - } - - StringBuffer jobProgress = new StringBuffer(); - - public void setStatus(String string) - { - jobProgress.setLength(0); - jobProgress.append(string); - } - - @Override - public String getStatus() - { - return jobProgress.toString(); - } - - @Override - public boolean hasStatus() - { - return jobProgress != null; - } - - /** - * @return the lastChunk - */ - public long getLastChunk() - { - return lastChunk; - } - - /** - * @param lastChunk - * the lastChunk to set - */ - public void setLastChunk(long lastChunk) - { - this.lastChunk = lastChunk; - } - - String alignmentProgram = null; - - public String getAlignmentProgram() - { - return alignmentProgram; - } - - public boolean hasArguments() - { - return (arguments != null && arguments.size() > 0) - || (preset != null && preset instanceof JabaWsParamSet); - } - - public List getJabaArguments() - { - List newargs = new ArrayList<>(); - if (preset != null && preset instanceof JabaWsParamSet) - { - newargs.addAll(((JabaWsParamSet) preset).getjabaArguments()); - } - if (arguments != null && arguments.size() > 0) - { - newargs.addAll(JabaParamStore.getJabafromJwsArgs(arguments)); - } - return newargs; - } - - /** - * add a progess header to status string containing presets/args used - */ - public void addInitialStatus() - { - if (preset != null) - { - jobProgress.append("Using " - + (preset instanceof JabaPreset ? "Server" : "User") - + "Preset: " + preset.getName()); - if (preset instanceof JabaWsParamSet) - { - for (Argument opt : getJabaArguments()) - { - jobProgress.append( - opt.getName() + " " + opt.getDefaultValue() + "\n"); - } - } - } - if (arguments != null && arguments.size() > 0) - { - jobProgress.append("With custom parameters : \n"); - // merge arguments with preset's own arguments. - for (Argument opt : getJabaArguments()) - { - jobProgress.append( - opt.getName() + " " + opt.getDefaultValue() + "\n"); - } - } - jobProgress.append("\nJob Output:\n"); - } - - public boolean isPresetJob() - { - return preset != null && preset instanceof JabaPreset; - } - - public Preset getServerPreset() - { - return (isPresetJob()) ? ((JabaPreset) preset).p : null; - } - } - String alTitle; // name which will be used to form new alignment window. AlignmentI dataset; // dataset to which the new alignment will be // associated. - @SuppressWarnings("unchecked") - MsaWS server = null; + MultipleSequenceAlignmentI server = null; /** * set basic options for this (group) of Msa jobs @@ -443,7 +74,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param presorder * boolean */ - private MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo, + private MsaWSThread(MultipleSequenceAlignmentI server, String wsUrl, + WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, AlignmentView alview, String wsname, boolean subgaps, boolean presorder) { @@ -454,7 +86,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI } /** - * create one or more Msa jobs to align visible seuqences in _msa + * create one or more Msa jobs to align visible sequences in _msa * * @param title * String @@ -467,7 +99,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param seqset * Alignment */ - MsaWSThread(MsaWS server2, WsParamSetI preset, List paramset, + public MsaWSThread(MultipleSequenceAlignmentI server2, WsParamSetI preset, + List paramset, String wsUrl, WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, String wsname, String title, AlignmentView _msa, boolean subgaps, boolean presorder, @@ -487,11 +120,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI { if (j != 0) { - jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]); + jobs[j] = new MsaWSJob(this, wsinfo.addJobPane(), conmsa[j]); } else { - jobs[j] = new MsaWSJob(0, conmsa[j]); + jobs[j] = new MsaWSJob(this, 0, conmsa[j]); } if (jobs[j].hasValidInput()) { @@ -525,12 +158,14 @@ class MsaWSThread extends AWS2Thread implements WSClientI @Override public boolean isCancellable() { - return true; + return server instanceof CancellableI; } @Override public void cancelJob() { + // TODO decide if when some jobs are not cancellable to shut down the thread + // anyhow ? if (!jobComplete && jobs != null) { boolean cancelled = true; @@ -541,13 +176,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI String cancelledMessage = ""; try { - boolean cancelledJob = server.cancelJob(jobs[job].getJobId()); - if (true) // cancelledJob || true) + CancellableI service = (CancellableI) server; + boolean cancelledJob = service.cancel((WsJob) jobs[job]); + if (cancelledJob) { // CANCELLED_JOB - // if the Jaba server indicates the job can't be cancelled, its - // because its running on the server's local execution engine - // so we just close the window anyway. cancelledMessage = "Job cancelled."; ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this // ugliness - @@ -607,42 +240,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI // this is standard code, but since the interface doesn't comprise of a // basic one that implements (getJobStatus, pullExecStatistics) we have to // repeat the code for all jw2s services. - j.setjobStatus(server.getJobStatus(job.getJobId())); - updateJobProgress(j); - } - - /** - * - * @param j - * @return true if more job progress data was available - * @throws Exception - */ - protected boolean updateJobProgress(MsaWSJob j) throws Exception - { - StringBuffer response = j.jobProgress; - long lastchunk = j.getLastChunk(); - boolean changed = false; - do - { - j.setLastChunk(lastchunk); - ChunkHolder chunk = server.pullExecStatistics(j.getJobId(), - lastchunk); - if (chunk != null) - { - changed |= chunk.getChunk().length() > 0; - response.append(chunk.getChunk()); - lastchunk = chunk.getNextPosition(); - try - { - Thread.sleep(50); - } catch (InterruptedException x) - { - } - ; - } - ; - } while (lastchunk >= 0 && j.getLastChunk() != lastchunk); - return changed; + server.updateStatus(j); + server.updateJobProgress(j); } @Override @@ -671,26 +270,37 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (j.seqs == null || j.seqs.size() == 0) { // special case - selection consisted entirely of empty sequences... - j.setjobStatus(JobStatus.FINISHED); + j.setState(JobState.FINISHED); j.setStatus(MessageManager.getString("label.empty_alignment_job")); } try { j.addInitialStatus(); // list the presets/parameters used for the job in // status - if (j.isPresetJob()) + try { - j.setJobId(server.presetAlign(j.seqs, j.getServerPreset())); - } - else if (j.hasArguments()) - { - j.setJobId(server.customAlign(j.seqs, j.getJabaArguments())); - } - else + JobId jobHandle = server.align(j.seqs, j.getPreset(), + j.getArguments()); + if (jobHandle != null) + { + j.setJobHandle(jobHandle); + } + + } catch (Throwable throwable) { - j.setJobId(server.align(j.seqs)); + if (!server.handleSubmitError(throwable, j, wsInfo)) + { + if (throwable instanceof Exception) + { + throw ((Exception) throwable); + } + if (throwable instanceof Error) + { + throw ((Error) throwable); + } + } } - + ///// generic if (j.getJobId() != null) { j.setSubmitted(true); @@ -705,40 +315,11 @@ class MsaWSThread extends AWS2Thread implements WSClientI new String[] { WsUrl })); } - } catch (compbio.metadata.UnsupportedRuntimeException _lex) - { - lex = _lex; - wsInfo.appendProgressText(MessageManager.formatMessage( - "info.job_couldnt_be_run_server_doesnt_support_program", - new String[] - { _lex.getMessage() })); - wsInfo.warnUser(_lex.getMessage(), - MessageManager.getString("warn.service_not_supported")); - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo.setStatus(j.getJobnum(), - WebserviceInfo.STATE_STOPPED_SERVERERROR); - } catch (compbio.metadata.LimitExceededException _lex) - { - lex = _lex; - wsInfo.appendProgressText(MessageManager.formatMessage( - "info.job_couldnt_be_run_exceeded_hard_limit", new String[] - { _lex.getMessage() })); - wsInfo.warnUser(_lex.getMessage(), - MessageManager.getString("warn.input_is_too_big")); - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); - } catch (compbio.metadata.WrongParameterException _lex) - { - lex = _lex; - wsInfo.warnUser(_lex.getMessage(), - MessageManager.getString("warn.invalid_job_param_set")); - wsInfo.appendProgressText(MessageManager.formatMessage( - "info.job_couldnt_be_run_incorrect_param_setting", - new String[] - { _lex.getMessage() })); - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); - } catch (Error e) + } + //// jabaws specific + + //// generic + catch (Error e) { // For unexpected errors System.err.println(WebServiceName @@ -794,7 +375,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI { try { - jpchanged = updateJobProgress(msjob); + jpchanged = server.updateJobProgress(msjob); jpex = false; if (jpchanged) { @@ -835,25 +416,18 @@ class MsaWSThread extends AWS2Thread implements WSClientI System.out.println("*** End of status"); } + ///// jabaws specific(ish) Get Result from Server when available try { - msjob.alignment = server.getResult(msjob.getJobId()); - } catch (compbio.metadata.ResultNotAvailableException e) - { - // job has failed for some reason - probably due to invalid - // parameters - Cache.log.debug( - "Results not available for finished job - marking as broken job.", - e); - msjob.jobProgress.append( - "\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n" - + e.getLocalizedMessage()); - msjob.setjobStatus(JobStatus.FAILED); + msjob.alignment = server.getAlignmentFor(msjob.getJobHandle()); } catch (Exception e) { - Cache.log.error("Couldn't get Alignment for job.", e); - // TODO: Increment count and retry ? - msjob.setjobStatus(JobStatus.UNDEFINED); + if (!server.handleCollectionException(e, msjob, wsInfo)) + { + Cache.log.error("Couldn't get Alignment for job.", e); + // TODO: Increment count and retry ? + msjob.setState(JobState.SERVERERROR); + } } } finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); @@ -861,19 +435,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI && jobs[j].hasResults()) { results++; - compbio.data.sequence.Alignment alignment = ((MsaWSJob) jobs[j]).alignment; - if (alignment != null) - { - // server.close(jobs[j].getJobnum()); - // wsInfo.appendProgressText(jobs[j].getJobnum(), - // "\nAlignment Object Method Notes\n"); - // wsInfo.appendProgressText(jobs[j].getJobnum(), - // "Calculated with - // "+alignment.getMetadata().getProgram().toString()); - // JBPNote The returned files from a webservice could be - // hidden behind icons in the monitor window that, - // when clicked, pop up their corresponding data - } } } } catch (Exception ex) diff --git a/src/jalview/ws/gui/WsJob.java b/src/jalview/ws/gui/WsJob.java new file mode 100644 index 0000000..05379d7 --- /dev/null +++ b/src/jalview/ws/gui/WsJob.java @@ -0,0 +1,176 @@ +/** + * + */ +package jalview.ws.gui; + +import jalview.ws.AWsJob; + +/** + * Bean that holds state for a job + * + * @author jprocter + * + */ +public class WsJob extends AWsJob +{ + + public enum JobState + { + INVALID, READY, SUBMITTED, QUEUED, RUNNING, FINISHED, BROKEN, FAILED, + UNKNOWN, SERVERERROR, CANCELLED; + }; + + JobState state = JobState.UNKNOWN; + + boolean hasResults = false, validInput = false; + /* (non-Javadoc) + * @see jalview.ws.AWsJob#hasResults() + */ + @Override + public boolean hasResults() + { + return hasResults; + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#hasValidInput() + */ + @Override + public boolean hasValidInput() + { + return validInput; + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isRunning() + */ + @Override + public boolean isRunning() + { + return JobState.RUNNING.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isQueued() + */ + @Override + public boolean isQueued() + { + return JobState.QUEUED.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isFinished() + */ + @Override + public boolean isFinished() + { + // TODO isSubjobComplete and finished flags mean same thing ? + return JobState.FINISHED.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isFailed() + */ + @Override + public boolean isFailed() + { + return JobState.FAILED.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isBroken() + */ + @Override + public boolean isBroken() + { + return JobState.BROKEN.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#isServerError() + */ + @Override + public boolean isServerError() + { + return JobState.SERVERERROR.equals(state); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#hasStatus() + */ + @Override + public boolean hasStatus() + { + return status != null && status.length() > 0; + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#getStatus() + */ + @Override + public String getStatus() + { + return status; + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#hasResponse() + */ + @Override + public boolean hasResponse() + { + // TODO Auto-generated method stub + return hasStatus(); + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#clearResponse() + */ + @Override + public void clearResponse() + { + status = ""; + } + + /* (non-Javadoc) + * @see jalview.ws.AWsJob#getState() + */ + @Override + public String getState() + { + return state.toString(); + } + + /** + * @return the current JobState + */ + public JobState getJobState() + { + return state; + } + + /** + * set the job state + * + * @param state + */ + public void setState(JobState state) + { + this.state = state; + } + + String status = ""; + + /** + * Set the log for this job + * + * @parag log + */ + public void setStatus(String log) + { + status = log; + + } + +} diff --git a/src/jalview/ws/jws2/JabaPreset.java b/src/jalview/ws/jws2/JabaPreset.java index 981b288..b6a18dd 100644 --- a/src/jalview/ws/jws2/JabaPreset.java +++ b/src/jalview/ws/jws2/JabaPreset.java @@ -100,4 +100,9 @@ public class JabaPreset implements WsParamSetI throw new Error(MessageManager .getString("error.cannot_set_params_for_ws_preset")); } + + public Preset getJabaPreset() + { + return p; + } } diff --git a/src/jalview/ws/jws2/MsaWSClient.java b/src/jalview/ws/jws2/MsaWSClient.java index dccdcea..a545d5d 100644 --- a/src/jalview/ws/jws2/MsaWSClient.java +++ b/src/jalview/ws/jws2/MsaWSClient.java @@ -27,6 +27,8 @@ import jalview.gui.Desktop; import jalview.gui.JvOptionPane; import jalview.gui.JvSwingUtils; import jalview.util.MessageManager; +import jalview.ws.api.MultipleSequenceAlignmentI; +import jalview.ws.gui.MsaWSThread; import jalview.ws.jws2.jabaws2.Jws2Instance; import jalview.ws.params.ArgumentI; import jalview.ws.params.WsParamSetI; @@ -41,8 +43,6 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.ToolTipManager; -import compbio.data.msa.MsaWS; - /** * DOCUMENT ME! * @@ -52,9 +52,11 @@ import compbio.data.msa.MsaWS; public class MsaWSClient extends Jws2Client { /** - * server is a WSDL2Java generated stub for an archetypal MsaWSI service. + * server is a proxy class implementing the core methods for submitting, + * monitoring and retrieving results from a multiple sequence alignment + * service */ - MsaWS server; + MultipleSequenceAlignmentI server; public MsaWSClient(Jws2Instance sh, String altitle, jalview.datamodel.AlignmentView msa, boolean submitGaps, @@ -104,7 +106,7 @@ public class MsaWSClient extends Jws2Client return; } - if (!(sh.service instanceof MsaWS)) + if (!(sh.getEndpoint() instanceof MultipleSequenceAlignmentI)) { // redundant at mo - but may change JvOptionPane.showMessageDialog(Desktop.desktop, @@ -117,7 +119,8 @@ public class MsaWSClient extends Jws2Client return; } - server = (MsaWS) sh.service; + serviceHandle = sh; + server = (MultipleSequenceAlignmentI) sh.getEndpoint(); if ((wsInfo = setWebService(sh, false)) == null) { JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager diff --git a/src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java b/src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java new file mode 100644 index 0000000..80de5b2 --- /dev/null +++ b/src/jalview/ws/jws2/jabaws2/JabawsMsaInstance.java @@ -0,0 +1,285 @@ +package jalview.ws.jws2.jabaws2; + +import jalview.bin.Cache; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.gui.WebserviceInfo; +import jalview.util.MessageManager; +import jalview.ws.api.CancellableI; +import jalview.ws.api.JobId; +import jalview.ws.api.MultipleSequenceAlignmentI; +import jalview.ws.gui.WsJob; +import jalview.ws.gui.WsJob.JobState; +import jalview.ws.jws2.JabaParamStore; +import jalview.ws.jws2.JabaPreset; +import jalview.ws.jws2.dm.JabaWsParamSet; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.InvalidArgumentException; +import jalview.ws.params.WsParamSetI; + +import java.io.IOError; +import java.rmi.ServerError; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import compbio.data.msa.MsaWS; +import compbio.data.sequence.Alignment; +import compbio.data.sequence.FastaSequence; +import compbio.metadata.Argument; +import compbio.metadata.ChunkHolder; +import compbio.metadata.JobStatus; +import compbio.metadata.Preset; +import compbio.metadata.ResultNotAvailableException; + +public class JabawsMsaInstance + implements MultipleSequenceAlignmentI, CancellableI +{ + /** + * our service instance handler generated by the discoverer + */ + Jws2Instance our; + + MsaWS service; + + @Override + public JobId align(List toalign, WsParamSetI parameters, + List arguments) throws Throwable + { + List seqs = new ArrayList<>(); + for (SequenceI seq : toalign) + { + seqs.add(new FastaSequence(seq.getName(), seq.getSequenceAsString())); + } + String jobid = null; + if (parameters != null) + { + if (parameters instanceof JabaPreset) + { + jobid = service.presetAlign(seqs, + ((JabaPreset) parameters).getJabaPreset()); + } + else + { + jobid = service.customAlign(seqs, JabaParamStore + .getJabafromJwsArgs(parameters.getArguments())); + } + } + else if (arguments != null && arguments.size() > 0) + { + jobid = service.customAlign(seqs, + JabaParamStore.getJabafromJwsArgs(arguments)); + } + else + { + jobid = service.align(seqs); + } + + if (jobid == null) + { + return null; + } + return new JobId(our.getServiceType(), our.getName(), jobid); + } + + @Override + public AlignmentI getAlignmentFor(JobId jobId) + throws InvalidArgumentException, ServerError, IOError + { + Alignment alignment = null; + try + { + alignment = service.getResult(jobId.getJobId()); + } catch (ResultNotAvailableException rnotav) + { + + // TODO - migrate JABA exception + // throw new ServerError("Couldn't get result for job",rnotav); + } + SequenceI[] alseqs; + int alseq_l = 0; + if (alignment.getSequences().size() == 0) + { + return null; + } + + alseqs = new SequenceI[alignment.getSequences().size()]; + for (compbio.data.sequence.FastaSequence seq : alignment.getSequences()) + { + alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence()); + } + AlignmentI jv_al = new jalview.datamodel.Alignment(alseqs); + jv_al.setGapCharacter(alignment.getMetadata().getGapchar()); + return jv_al; + + } + + public JabawsMsaInstance(Jws2Instance handle) + { + our = handle; + service = (MsaWS) our.service; + } + + @Override + public boolean cancel(WsJob job) + { + service.cancelJob(job.getJobId()); + // if the Jaba server indicates the job can't be cancelled, its + // because its running on the server's local execution engine + // so we just close the window anyway. + + return true; + } + + Map jwsState = new HashMap<>(); + { + jwsState.put(JobStatus.CANCELLED, JobState.CANCELLED); + jwsState.put(JobStatus.COLLECTED, JobState.FINISHED); + jwsState.put(JobStatus.FAILED, JobState.FAILED); + jwsState.put(JobStatus.FINISHED, JobState.FINISHED); + jwsState.put(JobStatus.PENDING, JobState.QUEUED); + jwsState.put(JobStatus.RUNNING, JobState.RUNNING); + jwsState.put(JobStatus.STARTED, JobState.RUNNING); + jwsState.put(JobStatus.SUBMITTED, JobState.SUBMITTED); + jwsState.put(JobStatus.UNDEFINED, JobState.UNKNOWN); + } + @Override + public void updateStatus(WsJob job) + { + JobStatus jwsstatus = service.getJobStatus(job.getJobId()); + job.setState(jwsState.get(jwsstatus)); + } + + @Override + public boolean updateJobProgress(WsJob job) throws Exception + { + StringBuilder response = new StringBuilder(job.getStatus()); + long lastchunk = job.getNextChunk(); + boolean changed = false; + do + { + ChunkHolder chunk = service.pullExecStatistics(job.getJobId(), + lastchunk); + if (chunk != null) + { + changed |= chunk.getChunk().length() > 0; + response.append(chunk.getChunk()); + lastchunk = chunk.getNextPosition(); + try + { + Thread.sleep(50); + } catch (InterruptedException x) + { + } + ; + } + ; + job.setnextChunk(lastchunk); + } while (lastchunk >= 0 && job.getNextChunk() != lastchunk); + if (job instanceof WsJob) + { + // TODO decide if WsJob will be the bean for all ng-webservices + job.setStatus(response.toString()); + } + return changed; + } + + public boolean isPresetJob(WsJob job) + { + return job.getPreset() != null && job.getPreset() instanceof JabaPreset; + } + + public Preset getServerPreset(WsJob job) + { + return (isPresetJob(job)) + ? ((JabaPreset) job.getPreset()).getJabaPreset() + : null; + } + + public List getJabaArguments(WsParamSetI preset) + { + List newargs = new ArrayList<>(); + if (preset != null) + { + if (preset instanceof JabaWsParamSet) + { + newargs.addAll(((JabaWsParamSet) preset).getjabaArguments()); + } + else + { + newargs.addAll( + JabaParamStore.getJabafromJwsArgs(preset.getArguments())); + } + } + return newargs; + } + + @Override + public boolean handleSubmitError(Throwable _lex, WsJob j, + WebserviceInfo wsInfo) throws Exception, Error + { + if (_lex instanceof compbio.metadata.UnsupportedRuntimeException) + { + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_server_doesnt_support_program", + new String[] + { _lex.getMessage() })); + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.service_not_supported")); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); + return true; + } + if (_lex instanceof compbio.metadata.LimitExceededException) + { + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_exceeded_hard_limit", new String[] + { _lex.getMessage() })); + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.input_is_too_big")); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); + return true; + } + if (_lex instanceof compbio.metadata.WrongParameterException) + { + wsInfo.warnUser(_lex.getMessage(), + MessageManager.getString("warn.invalid_job_param_set")); + wsInfo.appendProgressText(MessageManager.formatMessage( + "info.job_couldnt_be_run_incorrect_param_setting", + new String[] + { _lex.getMessage() })); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_ERROR); + return true; + } + // pass on to generic error handler + return false; + } + + @Override + public boolean handleCollectionException(Exception ex, WsJob msjob, + WebserviceInfo wsInfo) + { + if (ex instanceof compbio.metadata.ResultNotAvailableException) + { + // job has failed for some reason - probably due to invalid + // parameters + Cache.log.debug( + "Results not available for finished job - marking as broken job.", + ex); + String status = msjob.getStatus(); + + msjob.setStatus(status + + + "\nResult not available. Probably due to invalid input or parameter settings. Server error message below:\n\n" + + ex.getLocalizedMessage()); + msjob.setState(WsJob.JobState.BROKEN); + return true; + } + return false; + } +} diff --git a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java index 3bff20b..01c13a8 100644 --- a/src/jalview/ws/jws2/jabaws2/Jws2Instance.java +++ b/src/jalview/ws/jws2/jabaws2/Jws2Instance.java @@ -239,4 +239,26 @@ public class Jws2Instance extends ServiceWithParameters paramStore = new JabaParamStore(this, userParameterStore); } } + + /** + * an object that implements one or more interfaces in jalview.ws.api + * + * @return + */ + public Object getEndpoint() + { + if (aaui!=null) { + // TODO complete + return null; + } else { + if (service instanceof MsaWS) + { + return new JabawsMsaInstance(this); + } else { + // TODO complete + // service is for sequence analysis + return null; + } + } +} }