X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fws%2FMsaWSThread.java;h=3be0c5622281da2d6374d8d4270a2c8d89e15a41;hb=300c01c1363c3d0d0f92df3750a07314479ed7ca;hp=090af4ee0ecc1d3701616c23112c2f8df978f070;hpb=b31d6ded1992d8d8ea16f4321672b432b425693c;p=jalview.git diff --git a/src/jalview/ws/MsaWSThread.java b/src/jalview/ws/MsaWSThread.java index 090af4e..3be0c56 100644 --- a/src/jalview/ws/MsaWSThread.java +++ b/src/jalview/ws/MsaWSThread.java @@ -1,95 +1,92 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer + * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ 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 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 { - jalview.gui.AlignFrame alignFrame; - - WebserviceInfo wsInfo = null; - - String WebServiceName = null; - - String OutputHeader; - AlignmentView input; +class MsaWSThread + extends WSThread implements WSClientI +{ boolean submitGaps = false; // pass sequences including gaps to alignment - + // service - + boolean preserveOrder = true; // and always store and recover sequence - + // order - - 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(); - + + class MsaWSJob + extends WSThread.WSJob + { + // hold special input for this + 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 subjobComplete = false; - + Hashtable SeqNames = new Hashtable(); Vector emptySeqs = new Vector(); /** @@ -98,167 +95,232 @@ 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].getSequenceAsString() + : AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, seqs[i] + .getSequenceAsString())); + } + else + { + String empty = null; + if (seqs[i].getEnd() >= seqs[i].getStart()) + { + empty = (submitGaps) ? seqs[i].getSequenceAsString() : 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}); + .getSequenceAsString()); } + 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() + && ( (MsaResult) result).getMsa() != null && + ( (MsaResult) 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) { - alseqs = getVamsasAlignment(result.getMsa()); - alseq_gapchar=result.getMsa().getGapchar().charAt(0); + + public Object[] getAlignment() + { + + if (result != null && result.isFinished()) + { + SequenceI[] alseqs = null; + char alseq_gapchar = '-'; + int alseq_l = 0; + if ( ( (MsaResult) result).getMsa() != null) + { + alseqs = getVamsasAlignment( ( (MsaResult) result).getMsa()); + alseq_gapchar = ( (MsaResult) 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].getSequenceAsString() + + insbuff.substring(0, sw - nw)); } } } - for (i=0, w=emptySeqs.size(); i 0) { - int start = 0; - njobs=0; - int width = _msa.getWidth(); - 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]; - } - if (start 0) { - SequenceI mseq[] = new SequenceI[msa.length]; - for (int s = 0; s < mseq.length; s++) { - mseq[s] = msa[s].getSeq('-').getSubSequence(start, - contigs[contig+1]); - } - if (j!=0) { - jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq); - } else { - jobs[j] = new MsaWSJob(0, mseq); - } - wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum); - wsinfo.setProgressText(jobs[j].jobnum, OutputHeader); - j++; + for (int j = 0; j < njobs; j++) + { + if (j != 0) + { + jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]); } - start = contigs[contig+1] + contigs[contig + 2]; - } - if (start 0) + { + 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++; } - } else { - SequenceI mseq[] = new SequenceI[msa.length]; - for (int s = 0; s < mseq.length; s++) { - mseq[s] = msa[s].getSeq('-'); - } - jobs = new MsaWSJob[1]; - wsinfo.setProgressText(OutputHeader); // ensures default text - jobs[0] = new MsaWSJob(0, mseq); } } - - public boolean isCancellable() { + + public boolean isCancellable() + { return true; } - - public void cancelJob() { - if (!jobComplete && jobs != null) { + + public void cancelJob() + { + if (!jobComplete && jobs != null) + { boolean cancelled = true; - for (int job = 0; job < jobs.length; job++) { + for (int job = 0; job < jobs.length; job++) + { if (jobs[job].submitted && !jobs[job].subjobComplete) - { + { String cancelledMessage = ""; - try { + try + { vamsas.objects.simple.WsJobId cancelledJob = server - .cancel(jobs[job].jobId); - if (cancelledJob.getStatus() == 2) { + .cancel(jobs[job].jobId); + if (cancelledJob.getStatus() == 2) + { // CANCELLED_JOB cancelledMessage = "Job cancelled."; - jobs[job].subjobComplete = true; - jobs[job].result = null; - wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK); - } else if (cancelledJob.getStatus() == 3) { + ( (MsaWSJob) jobs[job]).cancel(); + wsInfo.setStatus(jobs[job].jobnum, + WebserviceInfo.STATE_CANCELLED_OK); + } + else if (cancelledJob.getStatus() == 3) + { // VALID UNSTOPPABLE JOB - cancelledMessage += "Server cannot cancel this job. just close the window.\n"; + cancelledMessage += + "Server cannot cancel this job. just close the window.\n"; cancelled = false; - wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK); + // wsInfo.setStatus(jobs[job].jobnum, + // WebserviceInfo.STATE_RUNNING); } - - if (cancelledJob.getJobId() != null) { + + if (cancelledJob.getJobId() != null) + { cancelledMessage += ("[" + cancelledJob.getJobId() + "]"); } - + cancelledMessage += "\n"; - } catch (Exception exc) { - cancelledMessage += ("\nProblems cancelling the job : Exception received...\n" - + exc + "\n"); - exc.printStackTrace(); + } + catch (Exception exc) + { + cancelledMessage += + ("\nProblems cancelling the job : Exception received...\n" + + exc + "\n"); + Cache.log.warn("Exception whilst cancelling " + jobs[job].jobId, + exc); } wsInfo.setProgressText(jobs[job].jobnum, OutputHeader - + cancelledMessage + "\n"); + + cancelledMessage + "\n"); } } - if (cancelled) { + if (cancelled) + { wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK); jobComplete = true; } - } else { - if (!jobComplete) { + this.interrupt(); // kick thread to update job states. + } + else + { + if (!jobComplete) + { wsInfo - .setProgressText(OutputHeader - + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); + .setProgressText(OutputHeader + + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n"); } } } - - public void run() { - - while (!jobComplete) { - int running=0; - int queuing=0; - int finished=0; - int error=0; - int serror=0; - for (int j=0; j 0) { - jobs[j].allowedServerExceptions--; - Cache.log.debug("Sleeping after a server exception."); - try { - Thread.sleep(5000); - } - 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); - } - } - catch (OutOfMemoryError er) { - jobComplete = true; - jobs[j].subjobComplete=true; - jobs[j].result=null; // may contain out of date result object - wsInfo.setStatus(jobs[j].jobnum, - 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); - 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++; - } - } - } - } - // Decide on overall state based on collected jobs[] states - if (running>0) { - wsInfo.setStatus(WebserviceInfo.STATE_RUNNING); - } else if (queuing>0) { - wsInfo.setStatus(WebserviceInfo.STATE_QUEUING); - } else { - jobComplete=true; - if (finished>0) { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK); - } else if (error>0) { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR); - } else if (serror>0) { - wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR); - } - } - if (!jobComplete) { - try { - Thread.sleep(5000); - } - catch (InterruptedException e) { - Cache.log.debug("Interrupted sleep waiting for next job poll.",e); - } - // System.out.println("I'm alive "+alTitle); - } - } - if (jobComplete) { - parseResult(); // tidy up and make results available to user - } + + void pollJob(WSJob job) + throws Exception + { + ( (MsaWSJob) job).result = server.getResult( ( (MsaWSJob) job).jobId); } - - 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(WSJob job) + { + if (! (job instanceof MsaWSJob)) + { + throw new Error("StartJob(MsaWSJob) called on a WSJobInstance " + + job.getClass()); + } + MsaWSJob j = (MsaWSJob) job; + 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); + ( (MsaResult) 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