5 import jalview.analysis.*;
7 import jalview.datamodel.*;
8 import jalview.datamodel.Alignment;
9 import jalview.datamodel.Sequence;
11 import vamsas.objects.simple.MsaResult;
23 * Copyright: Copyright (c) 2004
27 * Company: Dundee University
30 * @author not attributable
34 extends WSThread implements WSClientI
36 boolean submitGaps = false; // pass sequences including gaps to alignment
40 boolean preserveOrder = true; // and always store and recover sequence
44 class MsaWSJob extends WSThread.WSJob
46 // hold special input for this
47 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.
58 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
61 if (!prepareInput(inSeqs, 2))
64 subjobComplete = true;
65 result = new MsaResult();
66 result.setFinished(true);
67 result.setStatus("Job never ran - input returned to user.");
72 Hashtable SeqNames = new Hashtable();
73 Vector emptySeqs = new Vector();
75 * prepare input sequences for MsaWS service
76 * @param seqs jalview sequences to be prepared
77 * @param minlen minimum number of residues required for this MsaWS service
78 * @return true if seqs contains sequences to be submitted to service.
80 private boolean prepareInput(SequenceI[] seqs, int minlen)
85 throw new Error("Implementation error: minlen must be zero or more.");
87 for (int i = 0; i < seqs.length; i++)
89 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
94 boolean valid = nseqs > 1; // need at least two seqs
95 vamsas.objects.simple.Sequence[] seqarray =
97 ? new vamsas.objects.simple.Sequence[nseqs]
99 for (int i = 0, n = 0; i < seqs.length; i++)
102 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
106 SeqNames.put(newname, jalview.analysis.SeqsetUtils
107 .SeqCharacterHash(seqs[i]));
108 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
110 seqarray[n] = new vamsas.objects.simple.Sequence();
111 seqarray[n].setId(newname);
112 seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequence()
113 : AlignSeq.extractGaps(
114 jalview.util.Comparison.GapChars, seqs[i]
120 if (seqs[i].getEnd() >= seqs[i].getStart())
122 empty = (submitGaps) ? seqs[i].getSequence()
123 : AlignSeq.extractGaps(
124 jalview.util.Comparison.GapChars, seqs[i]
127 emptySeqs.add(new String[]
131 this.seqs = new vamsas.objects.simple.SequenceSet();
132 this.seqs.setSeqs(seqarray);
138 * @return true if getAlignment will return a valid alignment result.
140 public boolean hasResults()
142 if (subjobComplete && result != null && result.isFinished()
143 && ((MsaResult) result).getMsa() != null && ((MsaResult) result).getMsa().getSeqs() != null)
150 public Object[] getAlignment()
153 if (result != null && result.isFinished())
155 SequenceI[] alseqs = null;
156 char alseq_gapchar = '-';
158 if (((MsaResult) result).getMsa() != null)
160 alseqs = getVamsasAlignment(((MsaResult) result).getMsa());
161 alseq_gapchar = ((MsaResult) result).getMsa().getGapchar().charAt(0);
162 alseq_l = alseqs.length;
164 if (emptySeqs.size() > 0)
166 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
171 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
173 if (w < alseqs[i].getLength())
175 w = alseqs[i].getLength();
177 t_alseqs[i] = alseqs[i];
181 // check that aligned width is at least as wide as emptySeqs width.
183 for (i = 0, w = emptySeqs.size(); i < w; i++)
185 String[] es = (String[]) emptySeqs.get(i);
186 if (es != null && es[1] != null)
188 int sw = es[1].length();
195 // make a gapped string.
196 StringBuffer insbuff = new StringBuffer(w);
197 for (i = 0; i < nw; i++)
199 insbuff.append(alseq_gapchar);
203 for (i = 0; i < alseq_l; i++)
205 int sw = t_alseqs[i].getLength();
209 alseqs[i].setSequence(t_alseqs[i].getSequence() +
210 insbuff.substring(0, sw - nw));
214 for (i = 0, w = emptySeqs.size(); i < w; i++)
216 String[] es = (String[]) emptySeqs.get(i);
220 alseq_l] = new jalview.datamodel.Sequence(es[0],
221 insbuff.toString(), 1, 0);
225 if (es[1].length() < nw)
228 alseq_l] = new jalview.datamodel.Sequence(es[0],
229 es[1] + insbuff.substring(0, nw - es[1].length()), 1,
235 alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
241 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
242 // always recover the order - makes parseResult()'s life easier.
243 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
244 // account for any missing sequences
245 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
253 * mark subjob as cancelled and set result object appropriatly
257 subjobComplete = true;
262 * @return boolean true if job can be submitted.
264 boolean hasValidInput() {
265 if (seqs.getSeqs()!=null)
272 String alTitle; // name which will be used to form new alignment window.
273 Alignment dataset; // dataset to which the new alignment will be
277 ext.vamsas.MuscleWS server = null;
279 * set basic options for this (group) of Msa jobs
286 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
287 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
288 AlignmentView alview,
289 String wsname, boolean subgaps, boolean presorder)
291 this.server = server;
293 this.wsInfo = wsinfo;
294 this.WebServiceName = wsname;
296 this.submitGaps = subgaps;
297 this.preserveOrder = presorder;
298 this.alignFrame = alFrame;
302 * create one or more Msa jobs to align visible seuqences in _msa
315 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
316 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
317 String wsname, String title, AlignmentView _msa, boolean subgaps,
318 boolean presorder, Alignment seqset)
320 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
321 OutputHeader = wsInfo.getProgressText();
324 SeqCigar[] msa = _msa.getSequences();
325 int[] contigs = _msa.getContigs();
327 if (contigs != null && contigs.length > 0)
331 int width = _msa.getWidth();
332 for (int contig = 0; contig < contigs.length; contig += 3)
334 if ( (contigs[contig + 1] - start) > 0)
338 width += contigs[contig + 2]; // end up with full region width (including hidden regions)
339 start = contigs[contig + 1] + contigs[contig + 2];
345 jobs = new MsaWSJob[njobs];
348 for (int contig = 0; contig < contigs.length; contig += 3)
350 if (contigs[contig + 1] - start > 0)
352 SequenceI mseq[] = new SequenceI[msa.length];
353 for (int s = 0; s < mseq.length; s++)
355 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
356 contigs[contig + 1]);
360 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
364 jobs[j] = new MsaWSJob(0, mseq);
366 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
367 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
370 start = contigs[contig + 1] + contigs[contig + 2];
374 SequenceI mseq[] = new SequenceI[msa.length];
375 for (int s = 0; s < mseq.length; s++)
377 mseq[s] = msa[s].getSeq('-').getSubSequence(start,
382 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), mseq);
386 jobs[j] = new MsaWSJob(0, mseq);
388 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
389 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
395 SequenceI mseq[] = new SequenceI[msa.length];
396 for (int s = 0; s < mseq.length; s++)
398 mseq[s] = msa[s].getSeq('-');
400 jobs = new MsaWSJob[1];
401 wsinfo.setProgressText(OutputHeader); // ensures default text
402 jobs[0] = new MsaWSJob(0, mseq);
406 public boolean isCancellable()
411 public void cancelJob()
413 if (!jobComplete && jobs != null)
415 boolean cancelled = true;
416 for (int job = 0; job < jobs.length; job++)
418 if (jobs[job].submitted && !jobs[job].subjobComplete)
420 String cancelledMessage = "";
423 vamsas.objects.simple.WsJobId cancelledJob = server
424 .cancel(jobs[job].jobId);
425 if (cancelledJob.getStatus() == 2)
428 cancelledMessage = "Job cancelled.";
429 ((MsaWSJob) jobs[job]).cancel();
430 wsInfo.setStatus(jobs[job].jobnum,
431 WebserviceInfo.STATE_CANCELLED_OK);
433 else if (cancelledJob.getStatus() == 3)
435 // VALID UNSTOPPABLE JOB
437 "Server cannot cancel this job. just close the window.\n";
439 // wsInfo.setStatus(jobs[job].jobnum,
440 // WebserviceInfo.STATE_RUNNING);
443 if (cancelledJob.getJobId() != null)
445 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
448 cancelledMessage += "\n";
450 catch (Exception exc)
453 ("\nProblems cancelling the job : Exception received...\n"
455 Cache.log.warn("Exception whilst cancelling "+jobs[job].jobId,exc);
457 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
458 + cancelledMessage + "\n");
463 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
466 this.interrupt(); // kick thread to update job states.
473 .setProgressText(OutputHeader
474 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
478 void pollJob(WSJob job) throws Exception {
479 ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);
481 void StartJob(WSJob job)
483 if (!(job instanceof MsaWSJob)) {
484 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "+job.getClass());
486 MsaWSJob j = (MsaWSJob) job;
489 if (Cache.log.isDebugEnabled())
491 Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
495 if (j.seqs.getSeqs() == null)
497 // special case - selection consisted entirely of empty sequences...
499 j.result = new MsaResult();
500 j.result.setFinished(true);
501 j.result.setStatus("Empty Alignment Job");
502 ((MsaResult) j.result).setMsa(null);
506 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
508 if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
510 j.jobId = jobsubmit.getJobId();
512 j.subjobComplete = false;
513 // System.out.println(WsURL + " Job Id '" + jobId + "'");
517 if (jobsubmit == null)
523 " returned null object, it probably cannot be contacted. Try again later ?");
526 throw new Exception(jobsubmit.getJobId());
531 // TODO: JBPNote catch timeout or other fault types explicitly
532 // For unexpected errors
534 .println(WebServiceName
535 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
536 + "When contacting Server:" + WsUrl + "\n"
537 + e.toString() + "\n");
538 j.allowedServerExceptions = 0;
539 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
540 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
544 "Failed to submit sequences for alignment.\n"
545 + "It is most likely that there is a problem with the server.\n"
546 + "Just close the window\n");
548 // e.printStackTrace(); // TODO: JBPNote DEBUG
552 private jalview.datamodel.Sequence[] getVamsasAlignment(
553 vamsas.objects.simple.Alignment valign)
555 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
556 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
559 for (int i = 0, j = seqs.length; i < j; i++)
561 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
570 int results = 0; // number of result sets received
571 JobStateSummary finalState = new JobStateSummary();
574 for (int j = 0; j < jobs.length; j++)
576 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
577 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
580 vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result).getMsa();
583 wsInfo.appendProgressText(jobs[j].jobnum,
584 "\nAlignment Object Method Notes\n");
585 String[] lines = valign.getMethod();
586 for (int line = 0; line < lines.length; line++)
588 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
590 // JBPNote The returned files from a webservice could be
591 // hidden behind icons in the monitor window that,
592 // when clicked, pop up their corresponding data
600 Cache.log.error("Unexpected exception when processing results for " +
602 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
606 wsInfo.showResultsNewFrame
607 .addActionListener(new java.awt.event.ActionListener()
609 public void actionPerformed(
610 java.awt.event.ActionEvent evt)
612 displayResults(true);
616 .addActionListener(new java.awt.event.ActionListener()
618 public void actionPerformed(
619 java.awt.event.ActionEvent evt)
621 displayResults(false);
624 wsInfo.setResultsReady();
626 wsInfo.setFinishedNoResults();
629 void displayResults(boolean newFrame)
631 // view input or result data for each block
632 // warn user if a block is input rather than aligned data ?
634 int contigs[] = input.getContigs();
635 SeqCigar[] seqs = input.getSequences();
636 SequenceI[] alignment = new SequenceI[seqs.length];
637 ColumnSelection columnselection = new ColumnSelection();
638 Vector alorders = new Vector();
639 if (contigs != null && contigs.length > 0)
643 int owidth = input.getWidth();
645 for (int contig = 0; contig < contigs.length; contig += 3)
647 owidth += contigs[contig + 2]; // recover final column width
648 if (contigs[contig + 1] - start > 0)
650 int width = 0; // subalignment width
651 if (jobs[j].hasResults())
653 Object[] subalg = ((MsaWSJob) jobs[j++]).getAlignment();
654 alorders.add(subalg[1]);
655 SequenceI mseq[] = (SequenceI[]) subalg[0];
656 width = mseq[0].getLength();
657 for (int s = 0; s < mseq.length; s++)
659 if (alignment[s] == null)
661 alignment[s] = mseq[s];
665 alignment[s].setSequence(alignment[s].getSequence() +
666 mseq[s].getSequence());
667 if (mseq[s].getStart() <= mseq[s].getEnd())
669 alignment[s].setEnd(mseq[s].getEnd());
671 ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s],
678 // recover input data or place gaps
681 // recover input data
682 for (int s = 0; s < seqs.length; s++)
684 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
685 contigs[contig + 1]);
686 if (width < oseq.getLength())
688 width = oseq.getLength();
690 if (alignment[s] == null)
696 alignment[s].setSequence(alignment[s].getSequence() +
698 if (oseq.getEnd() >= oseq.getStart())
700 alignment[s].setEnd(oseq.getEnd());
710 // advance to begining of visible region
711 start = contigs[contig + 1] + contigs[contig + 2];
712 // add hidden segment to right of next region
713 for (int s = 0; s < seqs.length; s++)
715 SequenceI hseq = seqs[s].getSeq('-').getSubSequence(contigs[contig +
717 if (alignment[s] == null)
723 alignment[s].setSequence(alignment[s].getSequence() +
725 if (hseq.getEnd() >= hseq.getStart())
727 alignment[s].setEnd(hseq.getEnd());
731 // mark hidden segment as hidden in the new alignment
732 columnselection.hideColumns(nwidth, nwidth + contigs[contig + 2] - 1);
733 nwidth += contigs[contig + 2];
735 // Do final job - if it exists
739 if (jobs[j].hasResults())
741 Object[] subalg = ((MsaWSJob) jobs[j]).getAlignment();
742 alorders.add(subalg[1]);
743 SequenceI mseq[] = (SequenceI[]) subalg[0];
744 width = mseq[0].getLength();
745 for (int s = 0; s < mseq.length; s++)
747 if (alignment[s] == null)
749 alignment[s] = mseq[s];
753 alignment[s].setSequence(alignment[s].getSequence() +
754 mseq[s].getSequence());
755 if (mseq[s].getEnd() >= mseq[s].getStart())
757 alignment[s].setEnd(mseq[s].getEnd());
759 ( (AlignmentOrder) subalg[1]).updateSequence(mseq[s], alignment[s]);
767 // recover input data or place gaps
770 // recover input data
771 for (int s = 0; s < seqs.length; s++)
773 SequenceI oseq = seqs[s].getSeq('-').getSubSequence(start,
775 if (width < oseq.getLength())
777 width = oseq.getLength();
779 if (alignment[s] == null)
785 alignment[s].setSequence(alignment[s].getSequence() +
787 if (oseq.getEnd() >= oseq.getStart())
789 alignment[s].setEnd(oseq.getEnd());
798 throw new Error("Padding not yet implemented.");
806 if (jobs[0].hasResults())
808 Object[] alg = ((MsaWSJob) jobs[0]).getAlignment();
809 alignment = (SequenceI[]) alg[0];
810 alorders.add(alg[1]);
814 alignment = SeqCigar.createAlignmentSequences(seqs, '-',
815 columnselection, null);
818 Alignment al = new Alignment(alignment);
821 al.setDataset(dataset);
826 AlignFrame af = new AlignFrame(al, columnselection);
828 // >>>This is a fix for the moment, until a better solution is
830 af.getFeatureRenderer().transferSettings(
831 alignFrame.getFeatureRenderer());
832 if (alorders.size() > 0)
834 if (alorders.size() == 1)
836 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
837 (AlignmentOrder) alorders.get(0));
841 // construct a non-redundant ordering set
842 Vector names = new Vector();
843 for (int i = 0, l = alorders.size(); i < l; i++)
845 String orderName = new String(" Region " + i);
850 if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
851 AlignmentOrder) alorders.get(j))))
855 orderName += "," + j;
863 if (i == 0 && j == 1)
865 names.add(new String(""));
869 names.add(orderName);
872 for (int i = 0, l = alorders.size(); i < l; i++)
874 af.addSortByOrderMenuItem(WebServiceName
875 +( (String) names.get(i)) +
877 (AlignmentOrder) alorders.get(i));
882 Desktop.addInternalFrame(af, alTitle,
883 AlignFrame.NEW_WINDOW_WIDTH,
884 AlignFrame.NEW_WINDOW_HEIGHT);
889 System.out.println("MERGE WITH OLD FRAME");