7 import jalview.analysis.*;
9 import jalview.datamodel.*;
10 import jalview.datamodel.Alignment;
12 import vamsas.objects.simple.MsaResult;
24 * Copyright: Copyright (c) 2004
28 * Company: Dundee University
31 * @author not attributable
35 extends WSThread implements WSClientI
37 boolean submitGaps = false; // pass sequences including gaps to alignment
41 boolean preserveOrder = true; // and always store and recover sequence
45 class MsaWSJob extends WSThread.WSJob
47 // hold special input for this
48 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.
59 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
62 if (!prepareInput(inSeqs, 2))
65 subjobComplete = true;
66 result = new MsaResult();
67 result.setFinished(true);
68 result.setStatus("Job never ran - input returned to user.");
73 Hashtable SeqNames = new Hashtable();
74 Vector emptySeqs = new Vector();
76 * prepare input sequences for MsaWS service
77 * @param seqs jalview sequences to be prepared
78 * @param minlen minimum number of residues required for this MsaWS service
79 * @return true if seqs contains sequences to be submitted to service.
81 private boolean prepareInput(SequenceI[] seqs, int minlen)
86 throw new Error("Implementation error: minlen must be zero or more.");
88 for (int i = 0; i < seqs.length; i++)
90 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
95 boolean valid = nseqs > 1; // need at least two seqs
96 vamsas.objects.simple.Sequence[] seqarray =
98 ? new vamsas.objects.simple.Sequence[nseqs]
100 for (int i = 0, n = 0; i < seqs.length; i++)
103 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
107 SeqNames.put(newname, jalview.analysis.SeqsetUtils
108 .SeqCharacterHash(seqs[i]));
109 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
111 seqarray[n] = new vamsas.objects.simple.Sequence();
112 seqarray[n].setId(newname);
113 seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequence()
114 : AlignSeq.extractGaps(
115 jalview.util.Comparison.GapChars, seqs[i]
121 if (seqs[i].getEnd() >= seqs[i].getStart())
123 empty = (submitGaps) ? seqs[i].getSequence()
124 : AlignSeq.extractGaps(
125 jalview.util.Comparison.GapChars, seqs[i]
128 emptySeqs.add(new String[]
132 this.seqs = new vamsas.objects.simple.SequenceSet();
133 this.seqs.setSeqs(seqarray);
139 * @return true if getAlignment will return a valid alignment result.
141 public boolean hasResults()
143 if (subjobComplete && result != null && result.isFinished()
144 && ((MsaResult) result).getMsa() != null && ((MsaResult) result).getMsa().getSeqs() != null)
151 public Object[] getAlignment()
154 if (result != null && result.isFinished())
156 SequenceI[] alseqs = null;
157 char alseq_gapchar = '-';
159 if (((MsaResult) result).getMsa() != null)
161 alseqs = getVamsasAlignment(((MsaResult) result).getMsa());
162 alseq_gapchar = ((MsaResult) result).getMsa().getGapchar().charAt(0);
163 alseq_l = alseqs.length;
165 if (emptySeqs.size() > 0)
167 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
172 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
174 if (w < alseqs[i].getLength())
176 w = alseqs[i].getLength();
178 t_alseqs[i] = alseqs[i];
182 // check that aligned width is at least as wide as emptySeqs width.
184 for (i = 0, w = emptySeqs.size(); i < w; i++)
186 String[] es = (String[]) emptySeqs.get(i);
187 if (es != null && es[1] != null)
189 int sw = es[1].length();
196 // make a gapped string.
197 StringBuffer insbuff = new StringBuffer(w);
198 for (i = 0; i < nw; i++)
200 insbuff.append(alseq_gapchar);
204 for (i = 0; i < alseq_l; i++)
206 int sw = t_alseqs[i].getLength();
210 alseqs[i].setSequence(t_alseqs[i].getSequence() +
211 insbuff.substring(0, sw - nw));
215 for (i = 0, w = emptySeqs.size(); i < w; i++)
217 String[] es = (String[]) emptySeqs.get(i);
221 alseq_l] = new jalview.datamodel.Sequence(es[0],
222 insbuff.toString(), 1, 0);
226 if (es[1].length() < nw)
229 alseq_l] = new jalview.datamodel.Sequence(es[0],
230 es[1] + insbuff.substring(0, nw - es[1].length()), 1,
236 alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
242 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
243 // always recover the order - makes parseResult()'s life easier.
244 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
245 // account for any missing sequences
246 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
254 * mark subjob as cancelled and set result object appropriatly
258 subjobComplete = true;
263 * @return boolean true if job can be submitted.
265 boolean hasValidInput() {
266 if (seqs.getSeqs()!=null)
273 String alTitle; // name which will be used to form new alignment window.
274 Alignment dataset; // dataset to which the new alignment will be
278 ext.vamsas.MuscleWS server = null;
280 * set basic options for this (group) of Msa jobs
287 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
288 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
289 AlignmentView alview,
290 String wsname, boolean subgaps, boolean presorder)
292 this.server = server;
294 this.wsInfo = wsinfo;
295 this.WebServiceName = wsname;
297 this.submitGaps = subgaps;
298 this.preserveOrder = presorder;
299 this.alignFrame = alFrame;
303 * create one or more Msa jobs to align visible seuqences in _msa
316 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
317 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
318 String wsname, String title, AlignmentView _msa, boolean subgaps,
319 boolean presorder, Alignment seqset)
321 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
322 OutputHeader = wsInfo.getProgressText();
325 SeqCigar[] msa = _msa.getSequences();
326 int[] contigs = _msa.getContigs();
328 if (contigs != null && contigs.length > 0)
332 int width = _msa.getWidth();
333 for (int contig = 0; contig < contigs.length; contig += 3)
335 if ( (contigs[contig + 1] - start) > 0)
339 width += contigs[contig + 2]; // end up with full region width (including hidden regions)
340 start = contigs[contig + 1] + contigs[contig + 2];
346 jobs = new MsaWSJob[njobs];
349 for (int contig = 0; contig < contigs.length; contig += 3)
351 if (contigs[contig + 1] - start > 0)
353 SequenceI mseq[] = new SequenceI[msa.length];
354 for (int s = 0; s < mseq.length; s++)
356 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
357 contigs[contig + 1]);
361 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
365 jobs[j] = new MsaWSJob(0, mseq);
367 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
368 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
371 start = contigs[contig + 1] + contigs[contig + 2];
375 SequenceI mseq[] = new SequenceI[msa.length];
376 for (int s = 0; s < mseq.length; s++)
378 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
383 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
387 jobs[j] = new MsaWSJob(0, mseq);
389 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
390 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
396 SequenceI mseq[] = new SequenceI[msa.length];
397 for (int s = 0; s < mseq.length; s++)
399 mseq[s] = msa[s].getSeq('-');
401 jobs = new MsaWSJob[1];
402 wsinfo.setProgressText(OutputHeader); // ensures default text
403 jobs[0] = new MsaWSJob(0, mseq);
407 public boolean isCancellable()
412 public void cancelJob()
414 if (!jobComplete && jobs != null)
416 boolean cancelled = true;
417 for (int job = 0; job < jobs.length; job++)
419 if (jobs[job].submitted && !jobs[job].subjobComplete)
421 String cancelledMessage = "";
424 vamsas.objects.simple.WsJobId cancelledJob = server
425 .cancel(jobs[job].jobId);
426 if (cancelledJob.getStatus() == 2)
429 cancelledMessage = "Job cancelled.";
430 ((MsaWSJob) jobs[job]).cancel();
431 wsInfo.setStatus(jobs[job].jobnum,
432 WebserviceInfo.STATE_CANCELLED_OK);
434 else if (cancelledJob.getStatus() == 3)
436 // VALID UNSTOPPABLE JOB
438 "Server cannot cancel this job. just close the window.\n";
440 // wsInfo.setStatus(jobs[job].jobnum,
441 // WebserviceInfo.STATE_RUNNING);
444 if (cancelledJob.getJobId() != null)
446 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
449 cancelledMessage += "\n";
451 catch (Exception exc)
454 ("\nProblems cancelling the job : Exception received...\n"
456 Cache.log.warn("Exception whilst cancelling "+jobs[job].jobId,exc);
458 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
459 + cancelledMessage + "\n");
464 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
467 this.interrupt(); // kick thread to update job states.
474 .setProgressText(OutputHeader
475 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
479 void pollJob(WSJob job) throws Exception {
480 ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);
482 void StartJob(WSJob job)
484 if (!(job instanceof MsaWSJob)) {
485 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "+job.getClass());
487 MsaWSJob j = (MsaWSJob) job;
490 if (Cache.log.isDebugEnabled())
492 Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
496 if (j.seqs.getSeqs() == null)
498 // special case - selection consisted entirely of empty sequences...
500 j.result = new MsaResult();
501 j.result.setFinished(true);
502 j.result.setStatus("Empty Alignment Job");
503 ((MsaResult) j.result).setMsa(null);
507 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
509 if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
511 j.jobId = jobsubmit.getJobId();
513 j.subjobComplete = false;
514 // System.out.println(WsURL + " Job Id '" + jobId + "'");
518 if (jobsubmit == null)
524 " returned null object, it probably cannot be contacted. Try again later ?");
527 throw new Exception(jobsubmit.getJobId());
532 // TODO: JBPNote catch timeout or other fault types explicitly
533 // For unexpected errors
535 .println(WebServiceName
536 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
537 + "When contacting Server:" + WsUrl + "\n"
538 + e.toString() + "\n");
539 j.allowedServerExceptions = 0;
540 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
541 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
545 "Failed to submit sequences for alignment.\n"
546 + "It is most likely that there is a problem with the server.\n"
547 + "Just close the window\n");
549 // e.printStackTrace(); // TODO: JBPNote DEBUG
553 private jalview.datamodel.Sequence[] getVamsasAlignment(
554 vamsas.objects.simple.Alignment valign)
556 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
557 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
560 for (int i = 0, j = seqs.length; i < j; i++)
562 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
571 int results = 0; // number of result sets received
572 JobStateSummary finalState = new JobStateSummary();
575 for (int j = 0; j < jobs.length; j++)
577 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
578 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
581 vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result).getMsa();
584 wsInfo.appendProgressText(jobs[j].jobnum,
585 "\nAlignment Object Method Notes\n");
586 String[] lines = valign.getMethod();
587 for (int line = 0; line < lines.length; line++)
589 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
591 // JBPNote The returned files from a webservice could be
592 // hidden behind icons in the monitor window that,
593 // when clicked, pop up their corresponding data
601 Cache.log.error("Unexpected exception when processing results for " +
603 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
607 wsInfo.showResultsNewFrame
608 .addActionListener(new java.awt.event.ActionListener()
610 public void actionPerformed(
611 java.awt.event.ActionEvent evt)
613 displayResults(true);
617 .addActionListener(new java.awt.event.ActionListener()
619 public void actionPerformed(
620 java.awt.event.ActionEvent evt)
622 displayResults(false);
625 wsInfo.setResultsReady();
627 wsInfo.setFinishedNoResults();
630 void displayResults(boolean newFrame)
632 // view input or result data for each block
633 // warn user if a block is input rather than aligned data ?
635 int contigs[] = input.getContigs();
636 SeqCigar[] seqs = input.getSequences();
637 SequenceI[] alignment = new SequenceI[seqs.length];
638 ColumnSelection columnselection = new ColumnSelection();
639 Vector alorders = new Vector();
640 if (contigs != null && contigs.length > 0)
644 int owidth = input.getWidth();
646 for (int contig = 0; contig < contigs.length; contig += 3)
648 owidth += contigs[contig + 2]; // recover final column width
649 if (contigs[contig + 1] - start > 0)
651 int width = 0; // subalignment width
652 if (jobs[j].hasResults())
654 Object[] subalg = ((MsaWSJob) jobs[j++]).getAlignment();
655 alorders.add(subalg[1]);
656 SequenceI mseq[] = (SequenceI[]) subalg[0];
657 width = mseq[0].getLength();
658 for (int s = 0; s < mseq.length; s++)
660 if (alignment[s] == null)
662 alignment[s] = mseq[s];
666 alignment[s].setSequence(alignment[s].getSequence() +
667 mseq[s].getSequence());
668 if (mseq[s].getStart() <= mseq[s].getEnd())
670 alignment[s].setEnd(mseq[s].getEnd());
672 ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s],
679 // recover input data or place gaps
682 // recover input data
683 for (int s = 0; s < seqs.length; s++)
685 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
686 contigs[contig + 1]);
687 if (width < oseq.getLength())
689 width = oseq.getLength();
691 if (alignment[s] == null)
697 alignment[s].setSequence(alignment[s].getSequence() +
699 if (oseq.getEnd() >= oseq.getStart())
701 alignment[s].setEnd(oseq.getEnd());
711 // advance to begining of visible region
712 start = contigs[contig + 1] + contigs[contig + 2];
713 // add hidden segment to right of next region
714 for (int s = 0; s < seqs.length; s++)
716 SequenceI hseq = seqs[s].getSeq('-').getSubSequence(contigs[contig +
718 if (alignment[s] == null)
724 alignment[s].setSequence(alignment[s].getSequence() +
726 if (hseq.getEnd() >= hseq.getStart())
728 alignment[s].setEnd(hseq.getEnd());
732 // mark hidden segment as hidden in the new alignment
733 columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
734 nwidth += contigs[contig + 2];
736 // Do final job - if it exists
740 if (jobs[j].hasResults())
742 Object[] subalg = ((MsaWSJob) jobs[j]).getAlignment();
743 alorders.add(subalg[1]);
744 SequenceI mseq[] = (SequenceI[]) subalg[0];
745 width = mseq[0].getLength();
746 for (int s = 0; s < mseq.length; s++)
748 if (alignment[s] == null)
750 alignment[s] = mseq[s];
754 alignment[s].setSequence(alignment[s].getSequence() +
755 mseq[s].getSequence());
756 if (mseq[s].getEnd() >= mseq[s].getStart())
758 alignment[s].setEnd(mseq[s].getEnd());
760 ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
768 // recover input data or place gaps
771 // recover input data
772 for (int s = 0; s < seqs.length; s++)
774 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
776 if (width < oseq.getLength())
778 width = oseq.getLength();
780 if (alignment[s] == null)
786 alignment[s].setSequence(alignment[s].getSequence() +
788 if (oseq.getEnd() >= oseq.getStart())
790 alignment[s].setEnd(oseq.getEnd());
799 throw new Error("Padding not yet implemented.");
807 if (jobs[0].hasResults())
809 Object[] alg = ((MsaWSJob) jobs[0]).getAlignment();
810 alignment = (SequenceI[]) alg[0];
811 alorders.add(alg[1]);
815 alignment = SeqCigar.createAlignmentSequences(seqs, '-',
816 columnselection, null);
819 Alignment al = new Alignment(alignment);
822 al.setDataset(dataset);
827 // TODO: JBPNote Should also rename the query sequence
829 AlignFrame af = new AlignFrame(al, columnselection);
831 // >>>This is a fix for the moment, until a better solution is
833 af.getFeatureRenderer().transferSettings(
834 alignFrame.getFeatureRenderer());
835 if (alorders.size() > 0)
837 if (alorders.size() == 1)
839 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
840 (AlignmentOrder) alorders.get(0));
844 // construct a non-redundant ordering set
845 Vector names = new Vector();
846 for (int i = 0, l = alorders.size(); i < l; i++)
848 String orderName = new String("Region " + i);
853 if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
854 AlignmentOrder) alorders.get(j))))
858 orderName += "," + j;
866 if (i == 0 && j == 1)
868 names.add(new String(""));
872 names.add(orderName);
875 for (int i = 0, l = alorders.size(); i < l; i++)
877 af.addSortByOrderMenuItem(WebServiceName + ( (String) names.get(i)) +
879 (AlignmentOrder) alorders.get(i));
884 Desktop.addInternalFrame(af, alTitle,
885 AlignFrame.NEW_WINDOW_WIDTH,
886 AlignFrame.NEW_WINDOW_HEIGHT);
891 System.out.println("MERGE WITH OLD FRAME");