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 vamsas.objects.simple.MsaResult; import vamsas.objects.simple.Result; import jalview.datamodel.Alignment; import jalview.datamodel.SeqCigar; import jalview.gui.Desktop; import jalview.datamodel.SequenceI; import java.util.Hashtable; import java.util.Vector; /** *

* 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; 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(); /** * MsaWSJob * * @param jobNum * int * @param jobId * String */ public MsaWSJob(int jobNum, SequenceI[] inSeqs) { this.jobnum = jobNum; 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(); /** * 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. */ private boolean prepareInput(SequenceI[] seqs, int minlen) { int nseqs = 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) { 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() : 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}); } } 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()) 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); alseq_l = alseqs.length; } 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(); isw) { // pad at end alseqs[i].setSequence(t_alseqs[i].getSequence()+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++; } start = contigs[contig+1] + contigs[contig + 2]; } if (start 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 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) { // special case - selection consisted entirely of empty sequences... j.submitted=true; j.result=new MsaResult(); j.result.setFinished(true); j.result.setStatus("Empty Alignment Job"); j.result.setMsa(null); } try { vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs); if ((jobsubmit != null) && (jobsubmit.getStatus() == 1)) { j.jobId = jobsubmit.getJobId(); j.submitted=true; j.subjobComplete = false; // System.out.println(WsURL + " Job Id '" + jobId + "'"); } else { if (jobsubmit == null) { throw new Exception( "Server at " + WsUrl + " returned null object, it probably cannot be contacted. Try again later ?"); } throw new Exception(jobsubmit.getJobId()); } } 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"); 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"); // e.printStackTrace(); // TODO: JBPNote DEBUG } } private jalview.datamodel.Sequence[] getVamsasAlignment( 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++) { msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i] .getSeq()); } return msa; } void parseResult() { try { for (int j=0; j