2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.ws.jws1;
22 import jalview.analysis.*;
24 import jalview.datamodel.*;
26 import jalview.ws.AWsJob;
27 import jalview.ws.JobStateSummary;
28 import jalview.ws.WSClientI;
29 import vamsas.objects.simple.MsaResult;
41 * Copyright: Copyright (c) 2004
45 * Company: Dundee University
48 * @author not attributable
51 class MsaWSThread extends JWS1Thread implements WSClientI
53 boolean submitGaps = false; // pass sequences including gaps to alignment
57 boolean preserveOrder = true; // and always store and recover sequence
61 class MsaWSJob extends WSJob
63 // hold special input for this
64 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
74 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
77 if (!prepareInput(inSeqs, 2))
80 subjobComplete = true;
81 result = new MsaResult();
82 result.setFinished(true);
83 result.setStatus("Job never ran - input returned to user.");
88 Hashtable SeqNames = new Hashtable();
90 Vector emptySeqs = new Vector();
93 * prepare input sequences for MsaWS service
96 * jalview sequences to be prepared
98 * minimum number of residues required for this MsaWS service
99 * @return true if seqs contains sequences to be submitted to service.
101 private boolean prepareInput(SequenceI[] seqs, int minlen)
107 "Implementation error: minlen must be zero or more.");
109 for (int i = 0; i < seqs.length; i++)
111 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
116 boolean valid = nseqs > 1; // need at least two seqs
117 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
119 for (int i = 0, n = 0; i < seqs.length; i++)
122 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
126 SeqNames.put(newname,
127 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
128 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
130 seqarray[n] = new vamsas.objects.simple.Sequence();
131 seqarray[n].setId(newname);
132 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
133 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
134 seqs[i].getSequenceAsString()));
139 if (seqs[i].getEnd() >= seqs[i].getStart())
141 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
142 .extractGaps(jalview.util.Comparison.GapChars,
143 seqs[i].getSequenceAsString());
145 emptySeqs.add(new String[]
149 this.seqs = new vamsas.objects.simple.SequenceSet();
150 this.seqs.setSeqs(seqarray);
156 * @return true if getAlignment will return a valid alignment result.
158 public boolean hasResults()
160 if (subjobComplete && result != null && result.isFinished()
161 && ((MsaResult) result).getMsa() != null
162 && ((MsaResult) result).getMsa().getSeqs() != null)
169 public Object[] getAlignment()
172 if (result != null && result.isFinished())
174 SequenceI[] alseqs = null;
175 char alseq_gapchar = '-';
177 if (((MsaResult) result).getMsa() != null)
179 alseqs = getVamsasAlignment(((MsaResult) result).getMsa());
180 alseq_gapchar = ((MsaResult) result).getMsa().getGapchar()
182 alseq_l = alseqs.length;
184 if (emptySeqs.size() > 0)
186 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
191 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
193 if (w < alseqs[i].getLength())
195 w = alseqs[i].getLength();
197 t_alseqs[i] = alseqs[i];
201 // check that aligned width is at least as wide as emptySeqs width.
203 for (i = 0, w = emptySeqs.size(); i < w; i++)
205 String[] es = (String[]) emptySeqs.get(i);
206 if (es != null && es[1] != null)
208 int sw = es[1].length();
215 // make a gapped string.
216 StringBuffer insbuff = new StringBuffer(w);
217 for (i = 0; i < nw; i++)
219 insbuff.append(alseq_gapchar);
223 for (i = 0; i < alseq_l; i++)
225 int sw = t_alseqs[i].getLength();
229 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString()
230 + insbuff.substring(0, sw - nw));
234 for (i = 0, w = emptySeqs.size(); i < w; i++)
236 String[] es = (String[]) emptySeqs.get(i);
239 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(es[0],
240 insbuff.toString(), 1, 0);
244 if (es[1].length() < nw)
246 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
248 es[1] + insbuff.substring(0, nw - es[1].length()),
249 1, 1 + es[1].length());
253 t_alseqs[i + alseq_l] = new jalview.datamodel.Sequence(
260 AlignmentOrder msaorder = new AlignmentOrder(alseqs);
261 // always recover the order - makes parseResult()'s life easier.
262 jalview.analysis.AlignmentSorter.recoverOrder(alseqs);
263 // account for any missing sequences
264 jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs);
266 { alseqs, msaorder };
272 * mark subjob as cancelled and set result object appropriatly
277 subjobComplete = true;
283 * @return boolean true if job can be submitted.
285 public boolean hasValidInput()
287 if (seqs.getSeqs() != null)
295 String alTitle; // name which will be used to form new alignment window.
297 Alignment dataset; // dataset to which the new alignment will be
301 ext.vamsas.MuscleWS server = null;
304 * set basic options for this (group) of Msa jobs
311 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
312 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
313 AlignmentView alview, String wsname, boolean subgaps,
316 super(alFrame, wsinfo, alview, wsname, wsUrl);
317 this.server = server;
318 this.submitGaps = subgaps;
319 this.preserveOrder = presorder;
323 * create one or more Msa jobs to align visible seuqences in _msa
336 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
337 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
338 String wsname, String title, AlignmentView _msa, boolean subgaps,
339 boolean presorder, Alignment seqset)
341 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
342 OutputHeader = wsInfo.getProgressText();
346 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
349 int njobs = conmsa.length;
350 jobs = new MsaWSJob[njobs];
351 for (int j = 0; j < njobs; j++)
355 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
359 jobs[j] = new MsaWSJob(0, conmsa[j]);
363 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
364 jobs[j].getJobnum());
366 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
371 public boolean isCancellable()
376 public void cancelJob()
378 if (!jobComplete && jobs != null)
380 boolean cancelled = true;
381 for (int job = 0; job < jobs.length; job++)
383 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
385 String cancelledMessage = "";
388 vamsas.objects.simple.WsJobId cancelledJob = server
389 .cancel(jobs[job].getJobId());
390 if (cancelledJob.getStatus() == 2)
393 cancelledMessage = "Job cancelled.";
394 ((MsaWSJob) jobs[job]).cancel();
395 wsInfo.setStatus(jobs[job].getJobnum(),
396 WebserviceInfo.STATE_CANCELLED_OK);
398 else if (cancelledJob.getStatus() == 3)
400 // VALID UNSTOPPABLE JOB
401 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
403 // wsInfo.setStatus(jobs[job].jobnum,
404 // WebserviceInfo.STATE_RUNNING);
407 if (cancelledJob.getJobId() != null)
409 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
412 cancelledMessage += "\n";
413 } catch (Exception exc)
415 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
418 "Exception whilst cancelling " + jobs[job].getJobId(),
421 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
422 + cancelledMessage + "\n");
427 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
430 this.interrupt(); // kick thread to update job states.
436 wsInfo.setProgressText(OutputHeader
437 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
442 public void pollJob(AWsJob job) throws Exception
444 ((MsaWSJob) job).result = server.getResult(((MsaWSJob) job).getJobId());
447 public void StartJob(AWsJob job)
449 if (!(job instanceof MsaWSJob))
451 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "
454 MsaWSJob j = (MsaWSJob) job;
457 if (Cache.log.isDebugEnabled())
459 Cache.log.debug("Tried to submit an already submitted job "
464 if (j.seqs.getSeqs() == null)
466 // special case - selection consisted entirely of empty sequences...
467 j.setSubmitted(true);
468 j.result = new MsaResult();
469 j.result.setFinished(true);
470 j.result.setStatus("Empty Alignment Job");
471 ((MsaResult) j.result).setMsa(null);
475 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
477 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
479 j.setJobId(jobsubmit.getJobId());
480 j.setSubmitted(true);
481 j.setSubjobComplete(false);
482 // System.out.println(WsURL + " Job Id '" + jobId + "'");
486 if (jobsubmit == null)
491 + " returned null object, it probably cannot be contacted. Try again later ?");
494 throw new Exception(jobsubmit.getJobId());
496 } catch (Exception e)
498 // TODO: JBPNote catch timeout or other fault types explicitly
499 // For unexpected errors
501 .println(WebServiceName
502 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
503 + "When contacting Server:" + WsUrl + "\n"
504 + e.toString() + "\n");
505 j.setAllowedServerExceptions(0);
506 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
507 wsInfo.setStatus(j.getJobnum(),
508 WebserviceInfo.STATE_STOPPED_SERVERERROR);
509 wsInfo.appendProgressText(
511 "Failed to submit sequences for alignment.\n"
512 + "It is most likely that there is a problem with the server.\n"
513 + "Just close the window\n");
515 // e.printStackTrace(); // TODO: JBPNote DEBUG
519 private jalview.datamodel.Sequence[] getVamsasAlignment(
520 vamsas.objects.simple.Alignment valign)
522 // TODO: refactor to helper class for vamsas.objects.simple objects
523 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
524 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
526 for (int i = 0, j = seqs.length; i < j; i++)
528 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
535 public void parseResult()
537 int results = 0; // number of result sets received
538 JobStateSummary finalState = new JobStateSummary();
541 for (int j = 0; j < jobs.length; j++)
543 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
544 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
545 && jobs[j].hasResults())
548 // if (Cache.log.isDebugEnabled())
550 // System.out.println("Job lob for job "+jobs[j].getJobId()+":"+jobs[j].getJobnum());
551 // System.out.println(jobs[j].getStatus());
554 vamsas.objects.simple.Alignment valign = ((MsaResult) ((MsaWSJob) jobs[j]).result)
558 wsInfo.appendProgressText(jobs[j].getJobnum(),
559 "\nAlignment Object Method Notes\n");
560 String[] lines = valign.getMethod();
561 for (int line = 0; line < lines.length; line++)
563 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
566 // JBPNote The returned files from a webservice could be
567 // hidden behind icons in the monitor window that,
568 // when clicked, pop up their corresponding data
573 } catch (Exception ex)
576 Cache.log.error("Unexpected exception when processing results for "
578 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
582 wsInfo.showResultsNewFrame
583 .addActionListener(new java.awt.event.ActionListener()
585 public void actionPerformed(java.awt.event.ActionEvent evt)
587 displayResults(true);
591 .addActionListener(new java.awt.event.ActionListener()
593 public void actionPerformed(java.awt.event.ActionEvent evt)
595 displayResults(false);
598 wsInfo.setResultsReady();
602 wsInfo.setFinishedNoResults();
606 void displayResults(boolean newFrame)
608 // view input or result data for each block
609 Vector alorders = new Vector();
610 SequenceI[][] results = new SequenceI[jobs.length][];
611 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
612 for (int j = 0; j < jobs.length; j++)
614 if (jobs[j].hasResults())
616 Object[] res = ((MsaWSJob) jobs[j]).getAlignment();
617 alorders.add(res[1]);
618 results[j] = (SequenceI[]) res[0];
619 orders[j] = (AlignmentOrder) res[1];
621 // SequenceI[] alignment = input.getUpdated
628 Object[] newview = input.getUpdatedView(results, orders, getGapChar());
629 // trash references to original result data
630 for (int j = 0; j < jobs.length; j++)
635 SequenceI[] alignment = (SequenceI[]) newview[0];
636 ColumnSelection columnselection = (ColumnSelection) newview[1];
637 Alignment al = new Alignment(alignment);
638 // TODO: add 'provenance' property to alignment from the method notes
639 // accompanying each subjob
642 al.setDataset(dataset);
645 propagateDatasetMappings(al);
646 // JBNote- TODO: warn user if a block is input rather than aligned data ?
650 AlignFrame af = new AlignFrame(al, columnselection,
651 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
653 // initialise with same renderer settings as in parent alignframe.
654 af.getFeatureRenderer().transferSettings(this.featureSettings);
656 if (alorders.size() > 0)
658 if (alorders.size() == 1)
660 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
661 (AlignmentOrder) alorders.get(0));
665 // construct a non-redundant ordering set
666 Vector names = new Vector();
667 for (int i = 0, l = alorders.size(); i < l; i++)
669 String orderName = new String(" Region " + i);
674 if (((AlignmentOrder) alorders.get(i))
675 .equals(((AlignmentOrder) alorders.get(j))))
679 orderName += "," + j;
687 if (i == 0 && j == 1)
689 names.add(new String(""));
693 names.add(orderName);
696 for (int i = 0, l = alorders.size(); i < l; i++)
698 af.addSortByOrderMenuItem(
699 WebServiceName + ((String) names.get(i)) + " Ordering",
700 (AlignmentOrder) alorders.get(i));
705 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
706 AlignFrame.DEFAULT_HEIGHT);
711 System.out.println("MERGE WITH OLD FRAME");
712 // TODO: modify alignment in original frame, replacing old for new
713 // alignment using the commands.EditCommand model to ensure the update can
718 public boolean canMergeResults()