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 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
327 int njobs = conmsa.length;
328 jobs = new MsaWSJob[njobs];
329 for (int j = 0; j < njobs; j++)
333 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
337 jobs[j] = new MsaWSJob(0, conmsa[j]);
340 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
341 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
345 public boolean isCancellable()
350 public void cancelJob()
352 if (!jobComplete && jobs != null)
354 boolean cancelled = true;
355 for (int job = 0; job < jobs.length; job++)
357 if (jobs[job].submitted && !jobs[job].subjobComplete)
359 String cancelledMessage = "";
362 vamsas.objects.simple.WsJobId cancelledJob = server
363 .cancel(jobs[job].jobId);
364 if (cancelledJob.getStatus() == 2)
367 cancelledMessage = "Job cancelled.";
368 ((MsaWSJob) jobs[job]).cancel();
369 wsInfo.setStatus(jobs[job].jobnum,
370 WebserviceInfo.STATE_CANCELLED_OK);
372 else if (cancelledJob.getStatus() == 3)
374 // VALID UNSTOPPABLE JOB
376 "Server cannot cancel this job. just close the window.\n";
378 // wsInfo.setStatus(jobs[job].jobnum,
379 // WebserviceInfo.STATE_RUNNING);
382 if (cancelledJob.getJobId() != null)
384 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
387 cancelledMessage += "\n";
389 catch (Exception exc)
392 ("\nProblems cancelling the job : Exception received...\n"
394 Cache.log.warn("Exception whilst cancelling "+jobs[job].jobId,exc);
396 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
397 + cancelledMessage + "\n");
402 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
405 this.interrupt(); // kick thread to update job states.
412 .setProgressText(OutputHeader
413 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
417 void pollJob(WSJob job) throws Exception {
418 ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).jobId);
420 void StartJob(WSJob job)
422 if (!(job instanceof MsaWSJob)) {
423 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "+job.getClass());
425 MsaWSJob j = (MsaWSJob) job;
428 if (Cache.log.isDebugEnabled())
430 Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
434 if (j.seqs.getSeqs() == null)
436 // special case - selection consisted entirely of empty sequences...
438 j.result = new MsaResult();
439 j.result.setFinished(true);
440 j.result.setStatus("Empty Alignment Job");
441 ((MsaResult) j.result).setMsa(null);
445 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
447 if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
449 j.jobId = jobsubmit.getJobId();
451 j.subjobComplete = false;
452 // System.out.println(WsURL + " Job Id '" + jobId + "'");
456 if (jobsubmit == null)
462 " returned null object, it probably cannot be contacted. Try again later ?");
465 throw new Exception(jobsubmit.getJobId());
470 // TODO: JBPNote catch timeout or other fault types explicitly
471 // For unexpected errors
473 .println(WebServiceName
474 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
475 + "When contacting Server:" + WsUrl + "\n"
476 + e.toString() + "\n");
477 j.allowedServerExceptions = 0;
478 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
479 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
483 "Failed to submit sequences for alignment.\n"
484 + "It is most likely that there is a problem with the server.\n"
485 + "Just close the window\n");
487 // e.printStackTrace(); // TODO: JBPNote DEBUG
491 private jalview.datamodel.Sequence[] getVamsasAlignment(
492 vamsas.objects.simple.Alignment valign)
494 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
495 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
498 for (int i = 0, j = seqs.length; i < j; i++)
500 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
509 int results = 0; // number of result sets received
510 JobStateSummary finalState = new JobStateSummary();
513 for (int j = 0; j < jobs.length; j++)
515 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
516 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
519 vamsas.objects.simple.Alignment valign = ((MsaResult) jobs[j].result).getMsa();
522 wsInfo.appendProgressText(jobs[j].jobnum,
523 "\nAlignment Object Method Notes\n");
524 String[] lines = valign.getMethod();
525 for (int line = 0; line < lines.length; line++)
527 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
529 // JBPNote The returned files from a webservice could be
530 // hidden behind icons in the monitor window that,
531 // when clicked, pop up their corresponding data
539 Cache.log.error("Unexpected exception when processing results for " +
541 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
545 wsInfo.showResultsNewFrame
546 .addActionListener(new java.awt.event.ActionListener()
548 public void actionPerformed(
549 java.awt.event.ActionEvent evt)
551 displayResults(true);
555 .addActionListener(new java.awt.event.ActionListener()
557 public void actionPerformed(
558 java.awt.event.ActionEvent evt)
560 displayResults(false);
563 wsInfo.setResultsReady();
565 wsInfo.setFinishedNoResults();
568 void displayResults(boolean newFrame)
570 // view input or result data for each block
571 Vector alorders = new Vector();
572 SequenceI[][] results=new SequenceI[jobs.length][];
573 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
574 SequenceI[] first=null;
575 for (int j=0; j<jobs.length; j++) {
576 if (jobs[j].hasResults()) {
577 Object[] res = ( (MsaWSJob) jobs[j]).getAlignment();
578 alorders.add(res[1]);
579 results[j] = (SequenceI[]) res[0];
580 orders[j] = (AlignmentOrder) res[1];
581 // SequenceI[] alignment = input.getUpdated
586 Object[] newview = input.getUpdatedView(results, orders, '-');
587 // trash references to original result data
588 for (int j=0; j<jobs.length; j++) {
592 SequenceI[] alignment = (SequenceI[]) newview[0];
593 ColumnSelection columnselection = (ColumnSelection) newview[1];
594 Alignment al = new Alignment(alignment);
597 al.setDataset(dataset);
600 // JBNote- TODO: warn user if a block is input rather than aligned data ?
604 AlignFrame af = new AlignFrame(al, columnselection);
606 // >>>This is a fix for the moment, until a better solution is
608 af.getFeatureRenderer().transferSettings(
609 alignFrame.getFeatureRenderer());
611 if (alorders.size() > 0)
613 if (alorders.size() == 1)
615 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
616 (AlignmentOrder) alorders.get(0));
620 // construct a non-redundant ordering set
621 Vector names = new Vector();
622 for (int i = 0, l = alorders.size(); i < l; i++)
624 String orderName = new String(" Region " + i);
629 if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
630 AlignmentOrder) alorders.get(j))))
634 orderName += "," + j;
642 if (i == 0 && j == 1)
644 names.add(new String(""));
648 names.add(orderName);
651 for (int i = 0, l = alorders.size(); i < l; i++)
653 af.addSortByOrderMenuItem(WebServiceName
654 +( (String) names.get(i)) +
656 (AlignmentOrder) alorders.get(i));
661 Desktop.addInternalFrame(af, alTitle,
662 AlignFrame.NEW_WINDOW_WIDTH,
663 AlignFrame.NEW_WINDOW_HEIGHT);
668 System.out.println("MERGE WITH OLD FRAME");
673 public boolean canMergeResults()