2 * Jalview - A Sequence Alignment Editor and Viewer
3 * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 import jalview.analysis.*;
25 import jalview.datamodel.*;
26 import jalview.datamodel.Alignment;
28 import vamsas.objects.simple.MsaResult;
40 * Copyright: Copyright (c) 2004
44 * Company: Dundee University
47 * @author not attributable
51 extends WSThread implements WSClientI
53 boolean submitGaps = false; // pass sequences including gaps to alignment
57 boolean preserveOrder = true; // and always store and recover sequence
62 extends WSThread.WSJob
64 // hold special input for this
65 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.
76 public MsaWSJob(int jobNum, SequenceI[] inSeqs)
79 if (!prepareInput(inSeqs, 2))
82 subjobComplete = true;
83 result = new MsaResult();
84 result.setFinished(true);
85 result.setStatus("Job never ran - input returned to user.");
90 Hashtable SeqNames = new Hashtable();
91 Vector emptySeqs = new Vector();
93 * prepare input sequences for MsaWS service
94 * @param seqs jalview sequences to be prepared
95 * @param minlen minimum number of residues required for this MsaWS service
96 * @return true if seqs contains sequences to be submitted to service.
98 private boolean prepareInput(SequenceI[] seqs, int minlen)
103 throw new Error("Implementation error: minlen must be zero or more.");
105 for (int i = 0; i < seqs.length; i++)
107 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
112 boolean valid = nseqs > 1; // need at least two seqs
113 vamsas.objects.simple.Sequence[] seqarray =
115 ? new vamsas.objects.simple.Sequence[nseqs]
117 for (int i = 0, n = 0; i < seqs.length; i++)
120 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
124 SeqNames.put(newname, jalview.analysis.SeqsetUtils
125 .SeqCharacterHash(seqs[i]));
126 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
128 seqarray[n] = new vamsas.objects.simple.Sequence();
129 seqarray[n].setId(newname);
130 seqarray[n++].setSeq( (submitGaps) ? seqs[i].getSequenceAsString()
131 : AlignSeq.extractGaps(
132 jalview.util.Comparison.GapChars, seqs[i]
133 .getSequenceAsString()));
138 if (seqs[i].getEnd() >= seqs[i].getStart())
140 empty = (submitGaps) ? seqs[i].getSequenceAsString()
141 : AlignSeq.extractGaps(
142 jalview.util.Comparison.GapChars, seqs[i]
143 .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().charAt(0);
181 alseq_l = alseqs.length;
183 if (emptySeqs.size() > 0)
185 SequenceI[] t_alseqs = new SequenceI[alseq_l + emptySeqs.size()];
190 for (i = 0, w = alseqs[0].getLength(); i < alseq_l; i++)
192 if (w < alseqs[i].getLength())
194 w = alseqs[i].getLength();
196 t_alseqs[i] = alseqs[i];
200 // check that aligned width is at least as wide as emptySeqs width.
202 for (i = 0, w = emptySeqs.size(); i < w; i++)
204 String[] es = (String[]) emptySeqs.get(i);
205 if (es != null && es[1] != null)
207 int sw = es[1].length();
214 // make a gapped string.
215 StringBuffer insbuff = new StringBuffer(w);
216 for (i = 0; i < nw; i++)
218 insbuff.append(alseq_gapchar);
222 for (i = 0; i < alseq_l; i++)
224 int sw = t_alseqs[i].getLength();
228 alseqs[i].setSequence(t_alseqs[i].getSequenceAsString() +
229 insbuff.substring(0, sw - nw));
233 for (i = 0, w = emptySeqs.size(); i < w; i++)
235 String[] es = (String[]) emptySeqs.get(i);
239 alseq_l] = new jalview.datamodel.Sequence(es[0],
240 insbuff.toString(), 1, 0);
244 if (es[1].length() < nw)
247 alseq_l] = new jalview.datamodel.Sequence(es[0],
248 es[1] + insbuff.substring(0, nw - es[1].length()), 1,
254 alseq_l] = new jalview.datamodel.Sequence(es[0], es[1]);
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);
273 * mark subjob as cancelled and set result object appropriatly
278 subjobComplete = true;
284 * @return boolean true if job can be submitted.
286 boolean hasValidInput()
288 if (seqs.getSeqs() != null)
296 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;
303 * set basic options for this (group) of Msa jobs
310 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
311 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
312 AlignmentView alview,
313 String wsname, boolean subgaps, boolean presorder)
315 this.server = server;
317 this.wsInfo = wsinfo;
318 this.WebServiceName = wsname;
320 this.submitGaps = subgaps;
321 this.preserveOrder = presorder;
322 this.alignFrame = alFrame;
326 * create one or more Msa jobs to align visible seuqences in _msa
339 MsaWSThread(ext.vamsas.MuscleWS server, String wsUrl,
340 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
341 String wsname, String title, AlignmentView _msa, boolean subgaps,
342 boolean presorder, Alignment seqset)
344 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, subgaps, presorder);
345 OutputHeader = wsInfo.getProgressText();
349 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
352 int njobs = conmsa.length;
353 jobs = new MsaWSJob[njobs];
354 for (int j = 0; j < njobs; j++)
358 jobs[j] = new MsaWSJob(wsinfo.addJobPane(), conmsa[j]);
362 jobs[j] = new MsaWSJob(0, conmsa[j]);
366 wsinfo.setProgressName("region " + jobs[j].jobnum, jobs[j].jobnum);
368 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
373 public boolean isCancellable()
378 public void cancelJob()
380 if (!jobComplete && jobs != null)
382 boolean cancelled = true;
383 for (int job = 0; job < jobs.length; job++)
385 if (jobs[job].submitted && !jobs[job].subjobComplete)
387 String cancelledMessage = "";
390 vamsas.objects.simple.WsJobId cancelledJob = server
391 .cancel(jobs[job].jobId);
392 if (cancelledJob.getStatus() == 2)
395 cancelledMessage = "Job cancelled.";
396 ( (MsaWSJob) jobs[job]).cancel();
397 wsInfo.setStatus(jobs[job].jobnum,
398 WebserviceInfo.STATE_CANCELLED_OK);
400 else if (cancelledJob.getStatus() == 3)
402 // VALID UNSTOPPABLE JOB
404 "Server cannot cancel this job. just close the window.\n";
406 // wsInfo.setStatus(jobs[job].jobnum,
407 // WebserviceInfo.STATE_RUNNING);
410 if (cancelledJob.getJobId() != null)
412 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
415 cancelledMessage += "\n";
417 catch (Exception exc)
420 ("\nProblems cancelling the job : Exception received...\n"
422 Cache.log.warn("Exception whilst cancelling " + jobs[job].jobId,
425 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
426 + cancelledMessage + "\n");
431 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
434 this.interrupt(); // kick thread to update job states.
441 .setProgressText(OutputHeader
442 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
447 void pollJob(WSJob job)
450 ( (MsaWSJob) job).result = server.getResult( ( (MsaWSJob) job).jobId);
453 void StartJob(WSJob job)
455 if (! (job instanceof MsaWSJob))
457 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance " +
460 MsaWSJob j = (MsaWSJob) job;
463 if (Cache.log.isDebugEnabled())
465 Cache.log.debug("Tried to submit an already submitted job " + j.jobId);
469 if (j.seqs.getSeqs() == null)
471 // special case - selection consisted entirely of empty sequences...
473 j.result = new MsaResult();
474 j.result.setFinished(true);
475 j.result.setStatus("Empty Alignment Job");
476 ( (MsaResult) j.result).setMsa(null);
480 vamsas.objects.simple.WsJobId jobsubmit = server.align(j.seqs);
482 if ( (jobsubmit != null) && (jobsubmit.getStatus() == 1))
484 j.jobId = jobsubmit.getJobId();
486 j.subjobComplete = false;
487 // System.out.println(WsURL + " Job Id '" + jobId + "'");
491 if (jobsubmit == null)
497 " returned null object, it probably cannot be contacted. Try again later ?");
500 throw new Exception(jobsubmit.getJobId());
505 // TODO: JBPNote catch timeout or other fault types explicitly
506 // For unexpected errors
508 .println(WebServiceName
509 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
510 + "When contacting Server:" + WsUrl + "\n"
511 + e.toString() + "\n");
512 j.allowedServerExceptions = 0;
513 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
514 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
518 "Failed to submit sequences for alignment.\n"
519 + "It is most likely that there is a problem with the server.\n"
520 + "Just close the window\n");
522 // e.printStackTrace(); // TODO: JBPNote DEBUG
526 private jalview.datamodel.Sequence[] getVamsasAlignment(
527 vamsas.objects.simple.Alignment valign)
529 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
530 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.
533 for (int i = 0, j = seqs.length; i < j; i++)
535 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
544 int results = 0; // number of result sets received
545 JobStateSummary finalState = new JobStateSummary();
548 for (int j = 0; j < jobs.length; j++)
550 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
551 if (jobs[j].submitted && jobs[j].subjobComplete && jobs[j].hasResults())
554 vamsas.objects.simple.Alignment valign = ( (MsaResult) jobs[j].result).
558 wsInfo.appendProgressText(jobs[j].jobnum,
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].jobnum, lines[line] + "\n");
565 // JBPNote The returned files from a webservice could be
566 // hidden behind icons in the monitor window that,
567 // when clicked, pop up their corresponding data
575 Cache.log.error("Unexpected exception when processing results for " +
577 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
581 wsInfo.showResultsNewFrame
582 .addActionListener(new java.awt.event.ActionListener()
584 public void actionPerformed(
585 java.awt.event.ActionEvent evt)
587 displayResults(true);
591 .addActionListener(new java.awt.event.ActionListener()
593 public void actionPerformed(
594 java.awt.event.ActionEvent evt)
596 displayResults(false);
599 wsInfo.setResultsReady();
603 wsInfo.setFinishedNoResults();
607 void displayResults(boolean newFrame)
609 // view input or result data for each block
610 Vector alorders = new Vector();
611 SequenceI[][] results = new SequenceI[jobs.length][];
612 AlignmentOrder[] orders = new AlignmentOrder[jobs.length];
614 for (int j = 0; j < jobs.length; j++)
616 if (jobs[j].hasResults())
618 Object[] res = ( (MsaWSJob) jobs[j]).getAlignment();
619 alorders.add(res[1]);
620 results[j] = (SequenceI[]) res[0];
621 orders[j] = (AlignmentOrder) res[1];
622 // SequenceI[] alignment = input.getUpdated
629 Object[] newview = input.getUpdatedView(results, orders, '-');
630 // trash references to original result data
631 for (int j = 0; j < jobs.length; j++)
636 SequenceI[] alignment = (SequenceI[]) newview[0];
637 ColumnSelection columnselection = (ColumnSelection) newview[1];
638 Alignment al = new Alignment(alignment);
641 al.setDataset(dataset);
644 // JBNote- TODO: warn user if a block is input rather than aligned data ?
648 AlignFrame af = new AlignFrame(al, columnselection,
649 AlignFrame.DEFAULT_WIDTH,
650 AlignFrame.DEFAULT_HEIGHT);
652 // >>>This is a fix for the moment, until a better solution is
654 af.getFeatureRenderer().transferSettings(
655 alignFrame.getFeatureRenderer());
657 if (alorders.size() > 0)
659 if (alorders.size() == 1)
661 af.addSortByOrderMenuItem(WebServiceName + " Ordering",
662 (AlignmentOrder) alorders.get(0));
666 // construct a non-redundant ordering set
667 Vector names = new Vector();
668 for (int i = 0, l = alorders.size(); i < l; i++)
670 String orderName = new String(" Region " + i);
675 if ( ( (AlignmentOrder) alorders.get(i)).equals( ( (
676 AlignmentOrder) alorders.get(j))))
680 orderName += "," + j;
688 if (i == 0 && j == 1)
690 names.add(new String(""));
694 names.add(orderName);
697 for (int i = 0, l = alorders.size(); i < l; i++)
699 af.addSortByOrderMenuItem(WebServiceName
700 + ( (String) names.get(i)) +
702 (AlignmentOrder) alorders.get(i));
707 Desktop.addInternalFrame(af, alTitle,
708 AlignFrame.DEFAULT_WIDTH,
709 AlignFrame.DEFAULT_HEIGHT);
714 System.out.println("MERGE WITH OLD FRAME");
719 public boolean canMergeResults()