From 129ad37552c4bd5b241e90e0caf8b7f32a32bfb7 Mon Sep 17 00:00:00 2001 From: jprocter Date: Mon, 14 Aug 2006 12:52:03 +0000 Subject: [PATCH] multiple subjobs can be cancelled and gui only allows results when a subjob actually completes. --- src/jalview/ws/MsaWSThread.java | 1203 +++++++++++++++++++++++++-------------- 1 file changed, 769 insertions(+), 434 deletions(-) diff --git a/src/jalview/ws/MsaWSThread.java b/src/jalview/ws/MsaWSThread.java index 090af4e..803bf44 100644 --- a/src/jalview/ws/MsaWSThread.java +++ b/src/jalview/ws/MsaWSThread.java @@ -1,95 +1,94 @@ package jalview.ws; -import jalview.datamodel.AlignmentView; -import jalview.datamodel.AlignmentOrder; -import jalview.datamodel.ColumnSelection; -import jalview.gui.WebserviceInfo; -import jalview.analysis.AlignSeq; -import jalview.bin.Cache; -import jalview.gui.AlignFrame; -import javax.swing.JOptionPane; +import java.util.*; -import vamsas.objects.simple.MsaResult; -import vamsas.objects.simple.Result; +import javax.swing.*; + +import jalview.analysis.*; +import jalview.bin.*; +import jalview.datamodel.*; import jalview.datamodel.Alignment; -import jalview.datamodel.SeqCigar; -import jalview.gui.Desktop; -import jalview.datamodel.SequenceI; -import java.util.Hashtable; -import java.util.Vector; +import jalview.gui.*; +import vamsas.objects.simple.MsaResult; /** *

* Title: *

- * + * *

* Description: *

- * + * *

* Copyright: Copyright (c) 2004 *

- * + * *

* Company: Dundee University *

- * + * * @author not attributable * @version 1.0 */ -class MsaWSThread extends Thread implements WSClientI { +class MsaWSThread + extends Thread implements WSClientI +{ jalview.gui.AlignFrame alignFrame; - + WebserviceInfo wsInfo = null; - + String WebServiceName = null; - + String OutputHeader; AlignmentView input; boolean submitGaps = false; // pass sequences including gaps to alignment - + // service - + boolean preserveOrder = true; // and always store and recover sequence - + // order - - class MsaWSJob { + + class MsaWSJob + { int jobnum = 0; // WebServiceInfo pane for this job - + String jobId; // ws job ticket - + vamsas.objects.simple.MsaResult result = null; - - vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet(); - + + vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple. + SequenceSet(); + /** * MsaWSJob - * + * * @param jobNum * int * @param jobId * String */ - public MsaWSJob(int jobNum, SequenceI[] inSeqs) { + public MsaWSJob(int jobNum, SequenceI[] inSeqs) + { this.jobnum = jobNum; - if (!prepareInput(inSeqs,2)) { - submitted=true; - subjobComplete=true; + if (!prepareInput(inSeqs, 2)) + { + submitted = true; + subjobComplete = true; result = new MsaResult(); result.setFinished(true); result.setStatus("Job never ran - input returned to user."); } - + } - + int allowedServerExceptions = 3; // thread dies if too many - + // exceptions. - boolean submitted=false; + boolean submitted = false; boolean subjobComplete = false; - + Hashtable SeqNames = new Hashtable(); Vector emptySeqs = new Vector(); /** @@ -98,154 +97,217 @@ class MsaWSThread extends Thread implements WSClientI { * @param minlen minimum number of residues required for this MsaWS service * @return true if seqs contains sequences to be submitted to service. */ - private boolean prepareInput(SequenceI[] seqs, int minlen) { + private boolean prepareInput(SequenceI[] seqs, int minlen) + { int nseqs = 0; - if (minlen<0) + if (minlen < 0) + { throw new Error("Implementation error: minlen must be zero or more."); - for (int i = 0; i < seqs.length; i++) { - if (seqs[i].getEnd()-seqs[i].getStart()>minlen-1) { + } + 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 - vamsas.objects.simple.Sequence[] seqarray = - (valid) - ? new vamsas.objects.simple.Sequence[nseqs] - :null; - 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) { - seqarray[n] = new vamsas.objects.simple.Sequence(); - seqarray[n].setId(newname); - seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequence() + boolean valid = nseqs > 1; // need at least two seqs + vamsas.objects.simple.Sequence[] seqarray = + (valid) + ? new vamsas.objects.simple.Sequence[nseqs] + : null; + 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) + { + seqarray[n] = new vamsas.objects.simple.Sequence(); + seqarray[n].setId(newname); + seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequence() + : AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, seqs[i] + .getSequence())); + } + else + { + String empty = null; + if (seqs[i].getEnd() >= seqs[i].getStart()) + { + empty = (submitGaps) ? seqs[i].getSequence() : AlignSeq.extractGaps( jalview.util.Comparison.GapChars, seqs[i] - .getSequence())); - } else { - String empty=null; - if (seqs[i].getEnd()>=seqs[i].getStart()) { - empty = (submitGaps) ? seqs[i].getSequence() - : AlignSeq.extractGaps( - jalview.util.Comparison.GapChars, seqs[i] - .getSequence()); - } - emptySeqs.add(new String[] { newname, empty}); + .getSequence()); } + emptySeqs.add(new String[] + {newname, empty}); } - this.seqs = new vamsas.objects.simple.SequenceSet(); - this.seqs.setSeqs(seqarray); - return valid; + } + this.seqs = new vamsas.objects.simple.SequenceSet(); + this.seqs.setSeqs(seqarray); + return valid; } + /** - * + * * @return true if getAlignment will return a valid alignment result. */ - public boolean hasResults() { - if (subjobComplete && result!=null && jobs[0].result.isFinished()) + public boolean hasResults() + { + if (subjobComplete && result != null && result.isFinished() + && result.getMsa() != null && result.getMsa().getSeqs() != null) + { return true; + } return false; } - public Object[] getAlignment() { - - if (result!=null && result.isFinished()) { - SequenceI[] alseqs=null; - char alseq_gapchar='-'; - int alseq_l=0; - if (result.getMsa() != null) { + + public Object[] getAlignment() + { + + if (result != null && result.isFinished()) + { + SequenceI[] alseqs = null; + char alseq_gapchar = '-'; + int alseq_l = 0; + if (result.getMsa() != null) + { alseqs = getVamsasAlignment(result.getMsa()); - alseq_gapchar=result.getMsa().getGapchar().charAt(0); + alseq_gapchar = result.getMsa().getGapchar().charAt(0); alseq_l = alseqs.length; } - if (emptySeqs.size()>0) { - SequenceI[] t_alseqs = new SequenceI[alseq_l+emptySeqs.size()]; + 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 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(); isw) { + } + 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].getSequence()+insbuff.substring(0,sw-nw)); + alseqs[i].setSequence(t_alseqs[i].getSequence() + + insbuff.substring(0, sw - nw)); } } } - for (i=0, w=emptySeqs.size(); i 0) { + int njobs = 1; + if (contigs != null && contigs.length > 0) + { int start = 0; - njobs=0; + njobs = 0; int width = _msa.getWidth(); - for (int contig = 0; contig < contigs.length; contig += 3) { - if ((contigs[contig+1] - start) > 0) { + for (int contig = 0; contig < contigs.length; contig += 3) + { + if ( (contigs[contig + 1] - start) > 0) + { njobs++; } - width+=contigs[contig+2];// end up with full region width (including hidden regions) - start = contigs[contig+1] + contigs[contig + 2]; + width += contigs[contig + 2]; // end up with full region width (including hidden regions) + start = contigs[contig + 1] + contigs[contig + 2]; } - if (start 0) { + start = 0; + int j = 0; + for (int contig = 0; contig < contigs.length; contig += 3) + { + if (contigs[contig + 1] - start > 0) + { SequenceI mseq[] = new SequenceI[msa.length]; - for (int s = 0; s < mseq.length; s++) { + for (int s = 0; s < mseq.length; s++) + { mseq[s] = msa[s].getSeq('-').getSubSequence(start, - contigs[contig+1]); + contigs[contig + 1]); } - if (j!=0) { + if (j != 0) + { jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq); - } else { + } + else + { jobs[j] = new MsaWSJob(0, mseq); } - wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum); + wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum); wsinfo.setProgressText(jobs[j].jobnum, OutputHeader); j++; } - start = contigs[contig+1] + contigs[contig + 2]; + start = contigs[contig + 1] + contigs[contig + 2]; } - if (start 0) { + + ") Server exception: " + ex.getMessage()); + + if (jobs[j].allowedServerExceptions > 0) + { jobs[j].allowedServerExceptions--; Cache.log.debug("Sleeping after a server exception."); - try { + try + { Thread.sleep(5000); } - catch (InterruptedException ex1) { + catch (InterruptedException ex1) + { } - } else { - Cache.log.warn("Dropping job "+j+" "+jobs[j].jobId); - jobs[j].subjobComplete=true; - wsInfo.setStatus(jobs[j].jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR); + } + else + { + Cache.log.warn("Dropping job " + j + " " + jobs[j].jobId); + jobs[j].subjobComplete = true; + wsInfo.setStatus(jobs[j].jobnum, + WebserviceInfo.STATE_STOPPED_SERVERERROR); } } - catch (OutOfMemoryError er) { + catch (OutOfMemoryError er) + { jobComplete = true; - jobs[j].subjobComplete=true; - jobs[j].result=null; // may contain out of date result object + jobs[j].subjobComplete = true; + jobs[j].result = null; // may contain out of date result object wsInfo.setStatus(jobs[j].jobnum, - WebserviceInfo.STATE_STOPPED_ERROR); + WebserviceInfo.STATE_STOPPED_ERROR); JOptionPane - .showInternalMessageDialog( - Desktop.desktop, - "Out of memory handling result for job !!" - + "\nSee help files for increasing Java Virtual Machine memory.", - "Out of memory", JOptionPane.WARNING_MESSAGE); - Cache.log.error("Out of memory when retrieving Job "+j+" id:" + WsUrl+"/"+jobs[j].jobId, er); + .showInternalMessageDialog( + Desktop.desktop, + "Out of memory handling result for job !!" + + + "\nSee help files for increasing Java Virtual Machine memory.", + "Out of memory", JOptionPane.WARNING_MESSAGE); + Cache.log.error("Out of memory when retrieving Job " + j + " id:" + + WsUrl + "/" + jobs[j].jobId, er); System.gc(); } } - if (jobs[j].result!=null) { - String progheader=""; - // Parse state of job[j] - if (jobs[j].result.isRunning()) { - running++; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_RUNNING); - } else if (jobs[j].result.isQueued()) { - queuing++; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_QUEUING); - } else if (jobs[j].result.isFinished()) { - finished++; - jobs[j].subjobComplete = true; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_OK); - } else if (jobs[j].result.isFailed()) { - progheader += "Job failed.\n"; - jobs[j].subjobComplete=true; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR); - error++; - } else if (jobs[j].result.isServerError()) { - serror++; - jobs[j].subjobComplete = true; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_SERVERERROR); - } else if (jobs[j].result.isBroken() || jobs[j].result.isFailed()) { - error++; - jobs[j].subjobComplete=true; - wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR); - } - // and pass on any sub-job messages to the user - wsInfo.setProgressText(jobs[j].jobnum, OutputHeader); - wsInfo.appendProgressText(jobs[j].jobnum, progheader); - if (jobs[j].result.getStatus() != null) { - wsInfo.appendProgressText(jobs[j].jobnum, jobs[j].result.getStatus()); - } - } else { - if (jobs[j].submitted && jobs[j].subjobComplete) { - if (jobs[j].allowedServerExceptions==0) { - serror++; - } else if (jobs[j].result==null) { - error++; - } - } - } + jstate.updateJobPanelState(wsInfo, jobs[j]); } // Decide on overall state based on collected jobs[] states - if (running>0) { + if (jstate.running > 0) + { wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); - } else if (queuing>0) { + } + else if (jstate.queuing > 0) + { wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); - } else { - jobComplete=true; - if (finished>0) { + } + else + { + jobComplete = true; + if (jstate.finished > 0) + { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); - } else if (error>0) { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - } else if (serror>0) { + } + else if (jstate.error > 0) + { + wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); + } + else if (jstate.serror > 0) + { wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); } } - if (!jobComplete) { - try { + if (!jobComplete) + { + try + { Thread.sleep(5000); } - catch (InterruptedException e) { - Cache.log.debug("Interrupted sleep waiting for next job poll.",e); + catch (InterruptedException e) + { + Cache.log.debug("Interrupted sleep waiting for next job poll.", e); } // System.out.println("I'm alive "+alTitle); } } - if (jobComplete) { + if (jobComplete) + { parseResult(); // tidy up and make results available to user } } - - void StartJob(MsaWSJob j) { - if (j.submitted) { - if (Cache.log.isDebugEnabled()) { - Cache.log.debug("Tried to submit an already submitted job "+j.jobId); + + void StartJob(MsaWSJob j) + { + if (j.submitted) + { + if (Cache.log.isDebugEnabled()) + { + Cache.log.debug("Tried to submit an already submitted job " + j.jobId); } return; } - if (j.seqs.getSeqs()==null) { + if (j.seqs.getSeqs() == null) + { // special case - selection consisted entirely of empty sequences... - j.submitted=true; - j.result=new MsaResult(); + j.submitted = true; + j.result = new MsaResult(); j.result.setFinished(true); j.result.setStatus("Empty Alignment Job"); j.result.setMsa(null); } - try { + try + { vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs); - - if ((jobsubmit != null) && (jobsubmit.getStatus() == 1)) { + + if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1)) + { j.jobId = jobsubmit.getJobId(); - j.submitted=true; + j.submitted = true; j.subjobComplete = false; // System.out.println(WsURL + " Job Id '" + jobId + "'"); - } else { - if (jobsubmit == null) { + } + else + { + if (jobsubmit == null) + { throw new Exception( "Server at " + WsUrl - + " returned null object, it probably cannot be contacted. Try again later ?"); + + + " returned null object, it probably cannot be contacted. Try again later ?"); } - + throw new Exception(jobsubmit.getJobId()); } - } catch (Exception e) { + } + catch (Exception e) + { // 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.toString() + "\n"); + .println(WebServiceName + + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n" + + "When contacting Server:" + WsUrl + "\n" + + e.toString() + "\n"); j.allowedServerExceptions = 0; wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR); wsInfo - .appendProgressText( - j.jobnum, - "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"); - + .appendProgressText( + j.jobnum, + "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 } } - + private jalview.datamodel.Sequence[] getVamsasAlignment( - vamsas.objects.simple.Alignment valign) { + vamsas.objects.simple.Alignment valign) + { vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs(); - jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length]; - - for (int i = 0, j = seqs.length; i < j; i++) { + jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs. + length]; + + for (int i = 0, j = seqs.length; i < j; i++) + { msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i] - .getSeq()); + .getSeq()); } - + return msa; } - - void parseResult() { - try { - for (int j=0; j