3 import jalview.datamodel.AlignmentView;
4 import jalview.datamodel.AlignmentOrder;
5 import jalview.datamodel.ColumnSelection;
6 import jalview.gui.WebserviceInfo;
7 import jalview.analysis.AlignSeq;
8 import jalview.bin.Cache;
9 import jalview.gui.AlignFrame;
10 import javax.swing.JOptionPane;
12 import vamsas.objects.simple.MsaResult;
13 import vamsas.objects.simple.Result;
14 import jalview.datamodel.Alignment;
15 import jalview.datamodel.SeqCigar;
16 import jalview.gui.Desktop;
17 import jalview.datamodel.SequenceI;
18 import java.util.Hashtable;
19 import java.util.Vector;
31 * Copyright: Copyright (c) 2004
35 * Company: Dundee University
38 * @author not attributable
41 class MsaWSThread extends Thread implements WSClientI {
42 jalview.gui.AlignFrame alignFrame;
44 WebserviceInfo wsInfo = null;
46 String WebServiceName = null;
50 boolean submitGaps = false; // pass sequences including gaps to alignment
54 boolean preserveOrder = true; // and always store and recover sequence
59 int jobnum = 0; // WebServiceInfo pane for this job
61 String jobId; // ws job ticket
63 vamsas.objects.simple.MsaResult result = null;
65 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
75 public MsaWSJob(int jobNum, SequenceI[] inSeqs) {
80 int allowedServerExceptions = 3; // thread dies if too many
83 boolean submitted=false;
84 boolean subjobComplete = false;
86 Hashtable SeqNames = new Hashtable();
87 Vector emptySeqs = new Vector();
88 private void prepareInput(SequenceI[] seqs) {
90 for (int i = 0; i < seqs.length; i++) {
91 if (seqs[i].getStart() < seqs[i].getEnd()) {
95 vamsas.objects.simple.Sequence[] seqarray =
97 ? new vamsas.objects.simple.Sequence[nseqs]
99 for (int i = 0, n = 0; i < seqs.length; i++) {
101 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
105 SeqNames.put(newname, jalview.analysis.SeqsetUtils
106 .SeqCharacterHash(seqs[i]));
107 if (seqs[i].getStart() < seqs[i].getEnd()) {
108 seqarray[n] = new vamsas.objects.simple.Sequence();
109 seqarray[n].setId(newname);
110 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequence()
111 : AlignSeq.extractGaps(
112 jalview.util.Comparison.GapChars, seqs[i]
115 emptySeqs.add(newname);
118 this.seqs = new vamsas.objects.simple.SequenceSet();
119 this.seqs.setSeqs(seqarray);
121 public Object[] getAlignment() {
124 SequenceI[] alseqs=null;
125 char alseq_gapchar='-';
127 if (result.getMsa() != null) {
128 alseqs = getVamsasAlignment(result.getMsa());
129 alseq_gapchar=result.getMsa().getGapchar().charAt(0);
130 alseq_l = alseqs.length;
132 if (emptySeqs.size()>0) {
133 SequenceI[] t_alseqs = new SequenceI[alseq_l+emptySeqs.size()];
137 for (i=0,w=alseqs[0].getLength(); i<alseq_l; i++) {
138 if (w<alseqs[i].getLength())
139 w=alseqs[i].getLength();
140 t_alseqs[i] = alseqs[i];
144 // make a gapped string.
145 StringBuffer insbuff=new StringBuffer(w);
147 insbuff.append(alseq_gapchar);
148 for (i=0, w=emptySeqs.size(); i<w; i++) {
149 t_alseqs[i+alseqs.length] = new jalview.datamodel.Sequence((String)emptySeqs.get(i), insbuff.toString());
153 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
154 // always recover the order - makes parseResult()'s life easier.
155 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
156 // account for any missing sequences
157 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
158 return new Object[] { alseqs, msaorder};
163 MsaWSJob jobs[] = null;
165 String alTitle; // name which will be used to form new alignment window.
167 boolean jobComplete = false;
169 Alignment dataset; // dataset to which the new alignment will be
173 ext.vamsas.MuscleWS server = null;
178 * set basic options for this (group) of Msa jobs
185 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
186 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame, AlignmentView alview,
187 String wsname, boolean subgaps, boolean presorder) {
188 this.server = server;
190 this.wsInfo = wsinfo;
191 this.WebServiceName = wsname;
193 this.submitGaps = subgaps;
194 this.preserveOrder = presorder;
195 this.alignFrame = alFrame;
199 * create one or more Msa jobs to align visible seuqences in _msa
212 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
213 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
214 String wsname, String title, AlignmentView _msa, boolean subgaps,
215 boolean presorder, Alignment seqset) {
216 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
217 OutputHeader = wsInfo.getProgressText();
220 SeqCigar[] msa = _msa.getSequences();
221 int[] contigs = _msa.getContigs();
223 if (contigs != null && contigs.length > 0) {
226 int width = _msa.getWidth();
227 for (int contig = 0; contig < contigs.length; contig += 3) {
228 if ((contigs[contig+1] - start) > 0) {
231 width+=contigs[contig+2];// end up with full region width (including hidden regions)
232 start = contigs[contig+1] + contigs[contig + 2];
237 jobs = new MsaWSJob[njobs];
240 for (int contig = 0; contig < contigs.length; contig += 3) {
241 if (contigs[contig+1] - start > 0) {
242 SequenceI mseq[] = new SequenceI[msa.length];
243 for (int s = 0; s < mseq.length; s++) {
244 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
248 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
250 jobs[j] = new MsaWSJob(0, mseq);
252 wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum);
253 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
256 start = contigs[contig+1] + contigs[contig + 2];
259 SequenceI mseq[] = new SequenceI[msa.length];
260 for (int s = 0; s < mseq.length; s++) {
261 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
265 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
267 jobs[j] = new MsaWSJob(0, mseq);
269 wsinfo.setProgressName("region "+jobs[j].jobnum,jobs[j].jobnum);
270 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
274 SequenceI mseq[] = new SequenceI[msa.length];
275 for (int s = 0; s < mseq.length; s++) {
276 mseq[s] = msa[s].getSeq('-');
278 jobs = new MsaWSJob[1];
279 wsinfo.setProgressText(OutputHeader); // ensures default text
280 jobs[0] = new MsaWSJob(0, mseq);
284 public boolean isCancellable() {
288 public void cancelJob() {
289 if (!jobComplete && jobs != null) {
290 boolean cancelled = true;
291 for (int job = 0; job < jobs.length; job++) {
292 if (jobs[job].submitted && !jobs[job].subjobComplete)
294 String cancelledMessage = "";
296 vamsas.objects.simple.WsJobId cancelledJob = server
297 .cancel(jobs[job].jobId);
298 if (cancelledJob.getStatus() == 2) {
300 cancelledMessage = "Job cancelled.";
301 jobs[job].subjobComplete = true;
302 jobs[job].result = null;
303 wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK);
304 } else if (cancelledJob.getStatus() == 3) {
305 // VALID UNSTOPPABLE JOB
306 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
308 wsInfo.setStatus(jobs[job].jobnum, WebserviceInfo.STATE_CANCELLED_OK);
311 if (cancelledJob.getJobId() != null) {
312 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
315 cancelledMessage += "\n";
316 } catch (Exception exc) {
317 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
319 exc.printStackTrace();
321 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
322 + cancelledMessage + "\n");
326 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
332 .setProgressText(OutputHeader
333 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
340 while (!jobComplete) {
346 for (int j=0; j<jobs.length; j++) {
348 if (!jobs[j].submitted && jobs[j].seqs.getSeqs()!=null)
351 if (jobs[j].submitted && !jobs[j].subjobComplete) {
353 if ((jobs[j].result = server.getResult(jobs[j].jobId)) == null) {
354 throw (new Exception(
355 "Timed out when communicating with server\nTry again later.\n"));
357 jalview.bin.Cache.log.debug("Job "+j+" Result state " + jobs[j].result.getState()
358 + "(ServerError=" + jobs[j].result.isServerError() + ")");
359 } catch (Exception ex) {
360 // Deal with Transaction exceptions
361 wsInfo.appendProgressText(jobs[j].jobnum, "\n" + WebServiceName
362 + " Server exception!\n" + ex.getMessage());
363 Cache.log.warn(WebServiceName + " job(" + jobs[j].jobnum
364 + ") Server exception: " + ex.getMessage());
366 if (jobs[j].allowedServerExceptions > 0) {
367 jobs[j].allowedServerExceptions--;
368 Cache.log.debug("Sleeping after a server exception.");
372 catch (InterruptedException ex1) {
375 Cache.log.warn("Dropping job "+j+" "+jobs[j].jobId);
376 jobs[j].subjobComplete=true;
377 wsInfo.setStatus(jobs[j].jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
380 catch (OutOfMemoryError er) {
382 jobs[j].subjobComplete=true;
383 jobs[j].result=null; // may contain out of date result object
384 wsInfo.setStatus(jobs[j].jobnum,
385 WebserviceInfo.STATE_STOPPED_ERROR);
387 .showInternalMessageDialog(
389 "Out of memory handling result for job !!"
390 + "\nSee help files for increasing Java Virtual Machine memory.",
391 "Out of memory", JOptionPane.WARNING_MESSAGE);
392 Cache.log.error("Out of memory when retrieving Job "+j+" id:" + WsUrl+"/"+jobs[j].jobId, er);
396 if (jobs[j].result!=null) {
397 String progheader="";
398 // Parse state of job[j]
399 if (jobs[j].result.isRunning()) {
401 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_RUNNING);
402 } else if (jobs[j].result.isQueued()) {
404 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_QUEUING);
405 } else if (jobs[j].result.isFinished()) {
407 jobs[j].subjobComplete = true;
408 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_OK);
409 } else if (jobs[j].result.isFailed()) {
410 progheader += "Job failed.\n";
411 jobs[j].subjobComplete=true;
412 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
414 } else if (jobs[j].result.isServerError()) {
416 jobs[j].subjobComplete = true;
417 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_SERVERERROR);
418 } else if (jobs[j].result.isBroken() || jobs[j].result.isFailed()) {
420 jobs[j].subjobComplete=true;
421 wsInfo.setStatus(jobs[j].jobnum,WebserviceInfo.STATE_STOPPED_ERROR);
423 // and pass on any sub-job messages to the user
424 wsInfo.setProgressText(jobs[j].jobnum, OutputHeader);
425 wsInfo.appendProgressText(jobs[j].jobnum, progheader);
426 if (jobs[j].result.getStatus() != null) {
427 wsInfo.appendProgressText(jobs[j].jobnum, jobs[j].result.getStatus());
430 if (jobs[j].submitted && jobs[j].subjobComplete) {
431 if (jobs[j].allowedServerExceptions==0) {
433 } else if (jobs[j].result==null) {
439 // Decide on overall state based on collected jobs[] states
441 wsInfo.setStatus(WebserviceInfo.STATE_RUNNING);
442 } else if (queuing>0) {
443 wsInfo.setStatus(WebserviceInfo.STATE_QUEUING);
447 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_OK);
448 } else if (error>0) {
449 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
450 } else if (serror>0) {
451 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
458 catch (InterruptedException e) {
459 Cache.log.debug("Interrupted sleep waiting for next job poll.",e);
461 // System.out.println("I'm alive "+alTitle);
465 parseResult(); // tidy up and make results available to user
469 void StartJob(MsaWSJob j) {
471 if (Cache.log.isDebugEnabled()) {
472 Cache.log.debug("Tried to submit an already submitted job "+j.jobId);
476 if (j.seqs.getSeqs()==null) {
477 // special case - selection consisted entirely of empty sequences...
479 j.result=new MsaResult();
480 j.result.setFinished(true);
481 j.result.setStatus("Empty Alignment Job");
482 j.result.setMsa(null);
485 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
487 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1)) {
488 j.jobId = jobsubmit.getJobId();
490 j.subjobComplete = false;
491 // System.out.println(WsURL + " Job Id '" + jobId + "'");
493 if (jobsubmit == null) {
497 + " returned null object, it probably cannot be contacted. Try again later ?");
500 throw new Exception(jobsubmit.getJobId());
502 } catch (Exception e) {
503 // TODO: JBPNote catch timeout or other fault types explicitly
504 // For unexpected errors
506 .println(WebServiceName
507 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
508 + "When contacting Server:" + WsUrl + "\n"
509 + e.toString() + "\n");
510 j.allowedServerExceptions = 0;
511 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
512 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
516 "Failed to submit sequences for alignment.\n"
517 + "It is most likely that there is a problem with the server.\n"
518 + "Just close the window\n");
520 // e.printStackTrace(); // TODO: JBPNote DEBUG
524 private jalview.datamodel.Sequence[] getVamsasAlignment(
525 vamsas.objects.simple.Alignment valign) {
526 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
527 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
529 for (int i = 0, j = seqs.length; i < j; i++) {
530 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
539 for (int j=0; j<jobs.length; j++) {
540 if (jobs[j].submitted && jobs[j].subjobComplete) {
541 if (jobs[j].result!=null) {
542 vamsas.objects.simple.Alignment valign = jobs[j].result.getMsa();
544 wsInfo.appendProgressText(jobs[j].jobnum,"\nAlignment Object Method Notes\n");
545 String[] lines = valign.getMethod();
546 for (int line = 0; line < lines.length; line++) {
547 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
549 // JBPNote The returned files from a webservice could be
550 // hidden behind icons in the monitor window that,
551 // when clicked, pop up their corresponding data
557 catch (Exception ex) {
559 Cache.log.error("Unexpected exception when processing results for "+alTitle,ex);
560 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
563 wsInfo.showResultsNewFrame
564 .addActionListener(new java.awt.event.ActionListener() {
565 public void actionPerformed(
566 java.awt.event.ActionEvent evt) {
567 displayResults(true);
571 .addActionListener(new java.awt.event.ActionListener() {
572 public void actionPerformed(
573 java.awt.event.ActionEvent evt) {
574 displayResults(false);
577 wsInfo.setResultsReady();
579 void displayResults(boolean newFrame) {
580 int contigs[] = input.getContigs();
581 SeqCigar[] seqs = input.getSequences();
582 SequenceI[] alignment = new SequenceI[seqs.length];
583 ColumnSelection columnselection = new ColumnSelection();
584 Vector alorders=new Vector();
585 if (contigs != null && contigs.length > 0) {
590 for (int contig = 0; contig < contigs.length; contig += 3) {
591 if (cshift+contigs[contig] - start > 0) {
592 Object[] subalg = jobs[j++].getAlignment();
593 alorders.add(subalg[1]);
594 SequenceI mseq[] = (SequenceI[]) subalg[0];
595 int width = mseq[0].getLength();
596 for (int s = 0; s < mseq.length; s++) {
597 if (alignment[s]==null) {
598 alignment[s] = mseq[s];
600 alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
601 if (alignment[s].getEnd()<mseq[s].getEnd())
602 alignment[s].setEnd(mseq[s].getEnd());
603 ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
608 // advance to begining of visible region
609 start = cshift+contigs[contig] + contigs[contig + 2];
610 // add hidden segment to right of next region
611 for (int s=0; s<seqs.length; s++) {
612 SequenceI hseq = seqs[s].getSeq('-').getSubSequence(cshift+contigs[contig], start);
613 if (alignment[s]==null) {
616 alignment[s].setSequence(alignment[s].getSequence()+hseq.getSequence());
617 alignment[s].setEnd(hseq.getEnd());
620 // mark hidden segment as hidden in the new alignment
621 columnselection.hideColumns(nwidth, nwidth+contigs[contig+2]-1);
622 nwidth+=contigs[contig+2];
623 cshift+=contigs[contig+2];
625 // Do final job - if it exists
627 Object[] subalg = jobs[j].getAlignment();
628 alorders.add(subalg[1]);
629 SequenceI mseq[] = (SequenceI[]) subalg[0];
630 int width = mseq[0].getLength();
631 for (int s = 0; s < mseq.length; s++) {
632 if (alignment[s]==null) {
633 alignment[s] = mseq[s];
635 alignment[s].setSequence(alignment[s].getSequence()+mseq[s].getSequence());
636 alignment[s].setEnd(mseq[s].getEnd());
637 ((AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
643 if (jobs[0].subjobComplete && jobs[0].result!=null) {
644 Object[] alg = jobs[0].getAlignment();
645 alignment = (SequenceI[]) alg[0];
646 alorders.add(alg[1]);
648 alignment = SeqCigar.createAlignmentSequences(seqs, '-', columnselection,null);
651 Alignment al = new Alignment(alignment);
652 if (dataset != null) {
653 al.setDataset(dataset);
657 // TODO: JBPNote Should also rename the query sequence
659 AlignFrame af = new AlignFrame(al,columnselection);
661 // >>>This is a fix for the moment, until a better solution is
663 af.getFeatureRenderer().transferSettings(
664 alignFrame.getFeatureRenderer());
665 if (alorders.size()>0) {
666 if (alorders.size()==1) {
667 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
668 (AlignmentOrder) alorders.get(0));
670 for (int i=0,l=alorders.size(); i<l; i++) {
671 af.addSortByOrderMenuItem(WebServiceName + " Region "+i+" Ordering",
672 (AlignmentOrder) alorders.get(i));
677 Desktop.addInternalFrame(af, alTitle,
678 AlignFrame.NEW_WINDOW_WIDTH,
679 AlignFrame.NEW_WINDOW_HEIGHT);
682 System.out.println("MERGE WITH OLD FRAME");