From 2640ef898b186abf1abffedcb7064103f2c919e4 Mon Sep 17 00:00:00 2001 From: jprocter Date: Fri, 10 Sep 2010 15:22:11 +0000 Subject: [PATCH] properly report invalid jobs (server doesn't support service, seuqence set too big/wide, invalid input parameters) in a pop up dialog --- src/jalview/gui/WebserviceInfo.java | 52 ++++-- src/jalview/ws/jws2/MsaWSThread.java | 287 +++++++++++++++++++++------------- 2 files changed, 217 insertions(+), 122 deletions(-) diff --git a/src/jalview/gui/WebserviceInfo.java b/src/jalview/gui/WebserviceInfo.java index e0090be..aafcedb 100755 --- a/src/jalview/gui/WebserviceInfo.java +++ b/src/jalview/gui/WebserviceInfo.java @@ -232,20 +232,19 @@ public class WebserviceInfo extends GWebserviceInfo Thread thread = new Thread(ap); thread.start(); final WebserviceInfo thisinfo = this; - frame - .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() - { - public void internalFrameClosed( - javax.swing.event.InternalFrameEvent evt) - { - // System.out.println("Shutting down webservice client"); - WSClientI service = thisinfo.getthisService(); - if (service != null && service.isCancellable()) - { - service.cancelJob(); - } - }; - }); + frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter() + { + public void internalFrameClosed( + javax.swing.event.InternalFrameEvent evt) + { + // System.out.println("Shutting down webservice client"); + WSClientI service = thisinfo.getthisService(); + if (service != null && service.isCancellable()) + { + service.cancelJob(); + } + }; + }); } @@ -460,9 +459,8 @@ public class WebserviceInfo extends GWebserviceInfo // anyhow - it has to stop threads and clean up // JBPNote : TODO: Instead of a warning, we should have an optional 'Are // you sure?' prompt - JOptionPane.showInternalMessageDialog(Desktop.desktop, - "This job cannot be cancelled.\nJust close the window.", - "Cancel job", JOptionPane.WARNING_MESSAGE); + warnUser("This job cannot be cancelled.\nJust close the window.", + "Cancel job"); } else { @@ -472,6 +470,26 @@ public class WebserviceInfo extends GWebserviceInfo } /** + * Spawns a thread that pops up a warning dialog box with the given message + * and title. + * + * @param message + * @param title + */ + public void warnUser(final String message, final String title) + { + javax.swing.SwingUtilities.invokeLater(new Runnable() + { + public void run() + { + JOptionPane.showInternalMessageDialog(Desktop.desktop, message, + title, JOptionPane.WARNING_MESSAGE); + + } + }); + } + + /** * Set up GUI for user to get at results - and possibly automatically display * them if viewResultsImmediatly is set. */ diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index dabe368..79ffa90 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -67,20 +67,26 @@ class MsaWSThread extends AWS2Thread implements WSClientI class MsaWSJob extends JWs2Job { - long lastChunk=0; - Preset preset=null; - List arguments = null; + long lastChunk = 0; + + Preset preset = null; + + List arguments = null; + /** - * input + * 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; - + + // set if the job didn't get run - then the input is simply returned to the + // user + private boolean returnInput = false; + /** * MsaWSJob * @@ -101,7 +107,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI } - Hashtable SeqNames = new Hashtable(); + Hashtable SeqNames = new Hashtable(); Vector emptySeqs = new Vector(); @@ -139,15 +145,16 @@ class MsaWSThread extends AWS2Thread implements WSClientI // for // any // subjob - SeqNames.put(newname, jalview.analysis.SeqsetUtils - .SeqCharacterHash(seqs[i])); + 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())); + : AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString())); this.seqs.add(seq); } else @@ -156,8 +163,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (seqs[i].getEnd() >= seqs[i].getStart()) { empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq - .extractGaps(jalview.util.Comparison.GapChars, seqs[i] - .getSequenceAsString()); + .extractGaps(jalview.util.Comparison.GapChars, + seqs[i].getSequenceAsString()); } emptySeqs.add(new String[] { newname, empty }); @@ -172,7 +179,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI */ public boolean hasResults() { - if (subjobComplete && isFinished() && (alignment!=null || (emptySeqs!=null && emptySeqs.size()>0))) + if (subjobComplete + && isFinished() + && (alignment != null || (emptySeqs != null && emptySeqs + .size() > 0))) { return true; } @@ -181,7 +191,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI /** * - * 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. + * 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() @@ -192,15 +205,16 @@ class MsaWSThread extends AWS2Thread implements WSClientI SequenceI[] alseqs = null; char alseq_gapchar = '-'; int alseq_l = 0; - if (alignment.getSequences().size()>0) + if (alignment.getSequences().size() > 0) { alseqs = new SequenceI[alignment.getSequences().size()]; - for (compbio.data.sequence.FastaSequence seq: alignment.getSequences()) + for (compbio.data.sequence.FastaSequence seq : alignment + .getSequences()) { - alseqs[alseq_l++] = new Sequence(seq.getId(),seq.getSequence()); + alseqs[alseq_l++] = new Sequence(seq.getId(), seq.getSequence()); } alseq_gapchar = alignment.getMetadata().getGapchar(); - + } // add in the empty seqs. if (emptySeqs.size() > 0) @@ -306,14 +320,17 @@ class MsaWSThread extends AWS2Thread implements WSClientI */ 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 ? + // 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(); + + StringBuffer jobProgress = new StringBuffer(); + public void setStatus(String string) { jobProgress.setLength(0); @@ -329,7 +346,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI @Override public boolean hasStatus() { - return jobProgress!=null; + return jobProgress != null; } /** @@ -341,19 +358,21 @@ class MsaWSThread extends AWS2Thread implements WSClientI } /** - * @param lastChunk the lastChunk to set + * @param lastChunk + * the lastChunk to set */ public void setLastChunk(long lastChunk) { this.lastChunk = lastChunk; } - String alignmentProgram=null; + String alignmentProgram = null; + public String getAlignmentProgram() { return alignmentProgram; } - + } String alTitle; // name which will be used to form new alignment window. @@ -373,10 +392,9 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param presorder * boolean */ - MsaWSThread(MsaWS server, String wsUrl, - WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, - AlignmentView alview, String wsname, boolean subgaps, - boolean presorder) + MsaWSThread(MsaWS server, String wsUrl, WebserviceInfo wsinfo, + jalview.gui.AlignFrame alFrame, AlignmentView alview, + String wsname, boolean subgaps, boolean presorder) { super(alFrame, wsinfo, alview, wsname, wsUrl); this.server = server; @@ -398,12 +416,13 @@ class MsaWSThread extends AWS2Thread implements WSClientI * @param seqset * Alignment */ - MsaWSThread(MsaWS server2, Preset preset, List paramset, String wsUrl, - WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, - String wsname, String title, AlignmentView _msa, boolean subgaps, - boolean presorder, Alignment seqset) + MsaWSThread(MsaWS server2, Preset preset, List paramset, + String wsUrl, WebserviceInfo wsinfo, + jalview.gui.AlignFrame alFrame, String wsname, String title, + AlignmentView _msa, boolean subgaps, boolean presorder, + Alignment seqset) { - this(server2,wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder); + this(server2, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder); OutputHeader = wsInfo.getProgressText(); alTitle = title; dataset = seqset; @@ -428,9 +447,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI ((MsaWSJob) jobs[j]).alignmentProgram = wsname; if (njobs > 0) { - wsinfo - .setProgressName("region " + jobs[j].getJobnum(), - jobs[j].getJobnum()); + wsinfo.setProgressName("region " + jobs[j].getJobnum(), + jobs[j].getJobnum()); } wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader); } @@ -454,19 +472,20 @@ class MsaWSThread extends AWS2Thread implements WSClientI String cancelledMessage = ""; try { - boolean cancelledJob = server - .cancelJob(jobs[job].getJobId()); + boolean cancelledJob = server.cancelJob(jobs[job].getJobId()); if (cancelledJob || true) { // CANCELLED_JOB - // if the Jaba server indicates the job can't be cancelled, its because its running on the server's local execution engine + // 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 - + ((MsaWSJob) jobs[job]).cancel(); // TODO: refactor to avoid this + // ugliness - wsInfo.setStatus(jobs[job].getJobnum(), WebserviceInfo.STATE_CANCELLED_OK); - } - else + } + else { // VALID UNSTOPPABLE JOB cancelledMessage += "Server cannot cancel this job. just close the window.\n"; @@ -479,7 +498,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI cancelledMessage += ("\nProblems cancelling the job : Exception received...\n" + exc + "\n"); Cache.log.warn( - "Exception whilst cancelling " + jobs[job].getJobId(), exc); + "Exception whilst cancelling " + jobs[job].getJobId(), + exc); } wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader + cancelledMessage + "\n"); @@ -496,9 +516,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI { if (!jobComplete) { - wsInfo - .setProgressText(OutputHeader - + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); + wsInfo.setProgressText(OutputHeader + + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); } } } @@ -506,26 +525,35 @@ class MsaWSThread extends AWS2Thread implements WSClientI public void pollJob(AWsJob job) throws Exception { // TODO: investigate if we still need to cast here in J1.6 - MsaWSJob j=((MsaWSJob) job); - // 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. + MsaWSJob j = ((MsaWSJob) job); + // 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); } - protected void updateJobProgress(MsaWSJob j) throws Exception { + + protected void updateJobProgress(MsaWSJob j) throws Exception + { StringBuffer response = j.jobProgress; long lastchunk = j.getLastChunk(); - do { + do + { j.setLastChunk(lastchunk); - ChunkHolder chunk = server.pullExecStatistics(j.getJobId(), lastchunk); - if (chunk!=null) { + ChunkHolder chunk = server + .pullExecStatistics(j.getJobId(), lastchunk); + if (chunk != null) + { response.append(chunk.getChunk()); lastchunk = chunk.getNextPosition(); - }; - } while (lastchunk>=0 && j.getLastChunk()!=lastchunk); + } + ; + } while (lastchunk >= 0 && j.getLastChunk() != lastchunk); } public void StartJob(AWsJob job) { + Exception lex = null; // boiler plate template if (!(job instanceof MsaWSJob)) { @@ -543,8 +571,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI return; } // end boilerplate - - if (j.seqs == null || j.seqs.size()==0) + + if (j.seqs == null || j.seqs.size() == 0) { // special case - selection consisted entirely of empty sequences... j.setjobStatus(JobStatus.FINISHED); @@ -553,23 +581,27 @@ class MsaWSThread extends AWS2Thread implements WSClientI try { // TODO: get the parameters (if any) for this job and submit the job - if (j.arguments!=null && j.arguments.size()>0) + if (j.arguments != null && j.arguments.size() > 0) { StringBuffer pset = new StringBuffer(); - for (Argument arg: j.arguments) { - pset.append(arg.getName()+" "+arg.getDefaultValue()+"\n"); - } - j.setStatus("Custom Parameters:\n"+pset.toString()+"\nJob Output:\n"); - j.setJobId(server.customAlign(j.seqs, j.arguments)); - } else - if (j.preset!=null) + for (Argument arg : j.arguments) { - j.setJobId(server.presetAlign(j.seqs, j.preset)); - } else { - j.setJobId(server.align(j.seqs)); + pset.append(arg.getName() + " " + arg.getDefaultValue() + "\n"); } + j.setStatus("Custom Parameters:\n" + pset.toString() + + "\nJob Output:\n"); + j.setJobId(server.customAlign(j.seqs, j.arguments)); + } + else if (j.preset != null) + { + j.setJobId(server.presetAlign(j.seqs, j.preset)); + } + else + { + j.setJobId(server.align(j.seqs)); + } - if (j.getJobId()!= null) + if (j.getJobId() != null) { j.setSubmitted(true); j.setSubjobComplete(false); @@ -578,34 +610,73 @@ class MsaWSThread extends AWS2Thread implements WSClientI else { throw new Exception( - "Server at " - + WsUrl - + " returned null string for job id, it probably cannot be contacted. Try again later ?"); - } - } catch (Exception e) + "Server at " + + WsUrl + + " returned null string for job id, it probably cannot be contacted. Try again later ?"); + } + } catch (compbio.metadata.UnsupportedRuntimeException _lex) + { + lex = _lex; + wsInfo.appendProgressText("Job could not be run because the server doesn't support this program.\n" + + _lex.getMessage()); + wsInfo.warnUser(_lex.getMessage(), "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("Job could not be run because it exceeded a hard limit on the server.\n" + + _lex.getMessage()); + wsInfo.warnUser(_lex.getMessage(), "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(), "Invalid job parameter set!"); + wsInfo.appendProgressText("Job could not be run because some of the parameter settings are not supported by the server.\n" + + _lex.getMessage() + + "\nPlease check to make sure you have used the correct parameter set for this service!\n"); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_ERROR); + } + catch (Error e) { - // Boilerplate code here - // TODO: JBPNote catch timeout or other fault types explicitly // 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"); e.printStackTrace(System.err); - j.setAllowedServerExceptions(0); wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo.setStatus(j.getJobnum(), WebserviceInfo.STATE_STOPPED_SERVERERROR); - wsInfo - .appendProgressText( - j.getJobnum(), - "Failed to submit sequences for alignment.\n" - + "It is most likely that there is a problem with the server.\n" - + "Just close the window\n"); - - // e.printStackTrace(); // TODO: JBPNote DEBUG + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); } - } + catch (Exception e) + { + // 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"); + e.printStackTrace(System.err); + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); + wsInfo.setStatus(j.getJobnum(), + WebserviceInfo.STATE_STOPPED_SERVERERROR); + } finally + { + // Boilerplate code here + // TODO: JBPNote catch timeout or other fault types explicitly + j.setAllowedServerExceptions(0); + wsInfo.appendProgressText(j.getJobnum(), + "Failed to submit sequences for alignment.\n" + + "Just close the window\n"); + } + } public void parseResult() { @@ -616,28 +687,32 @@ class MsaWSThread extends AWS2Thread implements WSClientI for (int j = 0; j < jobs.length; j++) { MsaWSJob msjob = ((MsaWSJob) jobs[j]); - if (jobs[j].isFinished() && msjob.alignment==null) + if (jobs[j].isFinished() && msjob.alignment == null) { - try { + try + { updateJobProgress(msjob); } catch (Exception e) { - Cache.log.warn("Exception when retrieving remaining Job progress data for job "+msjob.getJobId()+" on server "+WsUrl); + Cache.log + .warn("Exception when retrieving remaining Job progress data for job " + + msjob.getJobId() + " on server " + WsUrl); e.printStackTrace(); } if (Cache.log.isDebugEnabled()) { - System.out.println("Job Execution file for job: "+msjob.getJobId()+" on server "+WsUrl); + System.out.println("Job Execution file for job: " + + msjob.getJobId() + " on server " + WsUrl); System.out.println(msjob.getStatus()); System.out.println("*** End of status"); - + } - try { + try + { msjob.alignment = server.getResult(msjob.getJobId()); - } - catch (Exception e) + } catch (Exception e) { - Cache.log.error("Couldn't get Alignment for job.",e); + Cache.log.error("Couldn't get Alignment for job.", e); } } finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]); @@ -649,9 +724,10 @@ class MsaWSThread extends AWS2Thread implements WSClientI 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()); + // 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 @@ -703,7 +779,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI { if (jobs[j].hasResults()) { - msjob = (MsaWSJob)jobs[j]; + msjob = (MsaWSJob) jobs[j]; Object[] res = msjob.getAlignment(); lastProgram = msjob.getAlignmentProgram(); alorders.add(res[1]); @@ -728,7 +804,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI ColumnSelection columnselection = (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment); // TODO: add 'provenance' property to alignment from the method notes - if (lastProgram!=null) { + if (lastProgram != null) + { al.setProperty("Alignment Program", lastProgram); } // accompanying each subjob @@ -790,8 +867,8 @@ class MsaWSThread extends AWS2Thread implements WSClientI } for (int i = 0, l = alorders.size(); i < l; i++) { - af.addSortByOrderMenuItem(WebServiceName - + ((String) names.get(i)) + " Ordering", + af.addSortByOrderMenuItem( + WebServiceName + ((String) names.get(i)) + " Ordering", (AlignmentOrder) alorders.get(i)); } } -- 1.7.10.2