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.io.NewickFile;
27 import jalview.ws.AWsJob;
28 import jalview.ws.JobStateSummary;
29 import jalview.ws.WSClientI;
30 import vamsas.objects.simple.MsaResult;
31 import vamsas.objects.simple.SeqSearchResult;
43 * Copyright: Copyright (c) 2004
47 * Company: Dundee University
50 * @author not attributable
53 class SeqSearchWSThread extends JWS1Thread implements WSClientI
57 boolean profile = false;
59 class SeqSearchWSJob extends WSJob
61 // hold special input for this
62 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
72 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
75 if (!prepareInput(inSeqs, 2))
78 subjobComplete = true;
79 result = new MsaResult();
80 result.setFinished(true);
81 result.setStatus("Job never ran - input returned to user.");
86 Hashtable SeqNames = new Hashtable();
88 Vector emptySeqs = new Vector();
91 * prepare input sequences for service
94 * jalview sequences to be prepared
96 * minimum number of residues required for this MsaWS service
97 * @return true if seqs contains sequences to be submitted to service.
99 private boolean prepareInput(SequenceI[] seqs, int minlen)
105 "Implementation error: minlen must be zero or more.");
107 for (int i = 0; i < seqs.length; i++)
109 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
114 boolean valid = nseqs >= 1; // need at least one sequence for valid input
116 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
118 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
120 for (int i = 0, n = 0; i < seqs.length; i++)
123 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
127 SeqNames.put(newname,
128 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
129 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
131 seqarray[n] = new vamsas.objects.simple.Sequence();
132 seqarray[n].setId(newname);
133 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
134 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
135 seqs[i].getSequenceAsString()));
140 if (seqs[i].getEnd() >= seqs[i].getStart())
142 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
143 .extractGaps(jalview.util.Comparison.GapChars,
144 seqs[i].getSequenceAsString());
146 emptySeqs.add(new String[]
152 // almost certainly have to remove gapped columns here
154 this.seqs = new vamsas.objects.simple.SequenceSet();
155 this.seqs.setSeqs(seqarray);
161 * @return true if getAlignment will return a valid alignment result.
163 public boolean hasResults()
167 && result.isFinished()
168 && ((SeqSearchResult) result).getAlignment() != null
169 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
177 * return sequence search results for display
179 * @return null or { Alignment(+features and annotation), NewickFile)}
181 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
184 if (result != null && result.isFinished())
186 SequenceI[] alseqs = null;
187 // char alseq_gapchar = '-';
189 if (((SeqSearchResult) result).getAlignment() != null)
191 alseqs = getVamsasAlignment(((SeqSearchResult) result)
193 // alseq_gapchar = ( (SeqSearchResult)
194 // result).getAlignment().getGapchar().charAt(0);
195 // alseq_l = alseqs.length;
198 * what has to be done. 1 - annotate returned alignment with annotation
199 * file and sequence features file, and associate any tree-nodes. 2.
200 * connect alignment back to any associated dataset: 2.a. deuniquify
201 * recovers sequence information - but additionally, relocations must be
202 * made from the returned aligned sequence back to the dataset.
204 // construct annotated alignment as it would be done by the jalview
206 jalview.datamodel.Alignment al = new Alignment(alseqs);
207 // al.setDataset(dataset);
209 String inFile = null;
212 inFile = ((SeqSearchResult) result).getAnnotation();
213 if (inFile != null && inFile.length() > 0)
215 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
216 jalview.io.AppletFormatAdapter.PASTE);
218 } catch (Exception e)
221 .println("Failed to parse the annotation file associated with the alignment.");
222 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
223 e.printStackTrace(System.err);
228 inFile = ((SeqSearchResult) result).getFeatures();
229 if (inFile != null && inFile.length() > 0)
231 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
232 inFile, jalview.io.AppletFormatAdapter.PASTE);
233 ff.parse(al, featureColours, false);
235 } catch (Exception e)
238 .println("Failed to parse the Features file associated with the alignment.");
239 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
240 e.printStackTrace(System.err);
242 jalview.io.NewickFile nf = null;
245 inFile = ((SeqSearchResult) result).getNewickTree();
246 if (inFile != null && inFile.length() > 0)
248 nf = new jalview.io.NewickFile(inFile,
249 jalview.io.AppletFormatAdapter.PASTE);
256 } catch (Exception e)
259 .println("Failed to parse the treeFile associated with the alignment.");
260 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
261 e.printStackTrace(System.err);
265 * TODO: housekeeping w.r.t. recovery of dataset and annotation
266 * references for input sequences, and then dataset sequence creation
267 * for new sequences retrieved from service // finally, attempt to
268 * de-uniquify to recover input sequence identity, and try to map back
269 * onto dataset Note: this
270 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
271 * NOT WORK - the returned alignment may contain multiple versions of
272 * the input sequence, each being a subsequence of the original.
273 * deuniquify also removes existing annotation and features added in the
274 * previous step... al.setDataset(dataset); // add in new sequences
275 * retrieved from sequence search which are not already in dataset. //
276 * trigger a 'fetchDBids' to annotate sequences with database ids...
286 * mark subjob as cancelled and set result object appropriatly
291 subjobComplete = true;
297 * @return boolean true if job can be submitted.
299 public boolean hasValidInput()
301 if (seqs.getSeqs() != null)
309 String alTitle; // name which will be used to form new alignment window.
311 Alignment dataset; // dataset to which the new alignment will be
315 ext.vamsas.SeqSearchI server = null;
317 private String dbArg;
320 * set basic options for this (group) of Msa jobs
327 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
328 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
329 AlignmentView alview, String wsname, String db)
331 super(alFrame, wsinfo, alview, wsname, wsUrl);
332 this.server = server;
337 * create one or more Msa jobs to align visible seuqences in _msa
350 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
351 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
352 String wsname, String title, AlignmentView _msa, String db,
355 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
356 OutputHeader = wsInfo.getProgressText();
360 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
363 int njobs = conmsa.length;
364 jobs = new SeqSearchWSJob[njobs];
365 for (int j = 0; j < njobs; j++)
369 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
373 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
377 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
378 jobs[j].getJobnum());
380 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
385 public boolean isCancellable()
390 public void cancelJob()
392 if (!jobComplete && jobs != null)
394 boolean cancelled = true;
395 for (int job = 0; job < jobs.length; job++)
397 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
399 String cancelledMessage = "";
402 vamsas.objects.simple.WsJobId cancelledJob = server
403 .cancel(jobs[job].getJobId());
404 if (cancelledJob.getStatus() == 2)
407 cancelledMessage = "Job cancelled.";
408 ((SeqSearchWSJob) jobs[job]).cancel();
409 wsInfo.setStatus(jobs[job].getJobnum(),
410 WebserviceInfo.STATE_CANCELLED_OK);
412 else if (cancelledJob.getStatus() == 3)
414 // VALID UNSTOPPABLE JOB
415 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
417 // wsInfo.setStatus(jobs[job].jobnum,
418 // WebserviceInfo.STATE_RUNNING);
421 if (cancelledJob.getJobId() != null)
423 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
426 cancelledMessage += "\n";
427 } catch (Exception exc)
429 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
432 "Exception whilst cancelling " + jobs[job].getJobId(),
435 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
436 + cancelledMessage + "\n");
441 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
444 this.interrupt(); // kick thread to update job states.
450 wsInfo.setProgressText(OutputHeader
451 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
456 public void pollJob(AWsJob job) throws Exception
458 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
462 public void StartJob(AWsJob job)
464 if (!(job instanceof SeqSearchWSJob))
466 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "
469 SeqSearchWSJob j = (SeqSearchWSJob) job;
472 if (Cache.log.isDebugEnabled())
474 Cache.log.debug("Tried to submit an already submitted job "
479 if (j.seqs.getSeqs() == null)
481 // special case - selection consisted entirely of empty sequences...
482 j.setSubmitted(true);
483 j.result = new MsaResult();
484 j.result.setFinished(true);
485 j.result.setStatus("Empty Alignment Job");
486 ((MsaResult) j.result).setMsa(null);
490 vamsas.objects.simple.WsJobId jobsubmit = server.search(
491 j.seqs.getSeqs()[0], dbArg);
493 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
495 j.setJobId(jobsubmit.getJobId());
496 j.setSubmitted(true);
497 j.setSubjobComplete(false);
498 // System.out.println(WsURL + " Job Id '" + jobId + "'");
502 if (jobsubmit == null)
507 + " returned null object, it probably cannot be contacted. Try again later ?");
510 throw new Exception(jobsubmit.getJobId());
512 } catch (Exception e)
514 // TODO: JBPNote catch timeout or other fault types explicitly
515 // For unexpected errors
517 .println(WebServiceName
518 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
519 + "When contacting Server:" + WsUrl + "\n"
520 + e.toString() + "\n");
521 j.setAllowedServerExceptions(0);
522 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
523 wsInfo.setStatus(j.getJobnum(),
524 WebserviceInfo.STATE_STOPPED_SERVERERROR);
525 wsInfo.appendProgressText(
527 "Failed to submit sequences for alignment.\n"
528 + "It is most likely that there is a problem with the server.\n"
529 + "Just close the window\n");
531 // e.printStackTrace(); // TODO: JBPNote DEBUG
535 private jalview.datamodel.Sequence[] getVamsasAlignment(
536 vamsas.objects.simple.Alignment valign)
538 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
539 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
541 for (int i = 0, j = seqs.length; i < j; i++)
543 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
550 public void parseResult()
552 int results = 0; // number of result sets received
553 JobStateSummary finalState = new JobStateSummary();
556 for (int j = 0; j < jobs.length; j++)
558 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
559 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
560 && jobs[j].hasResults())
563 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
567 wsInfo.appendProgressText(jobs[j].getJobnum(),
568 "\nAlignment Object Method Notes\n");
569 String[] lines = valign.getMethod();
570 for (int line = 0; line < lines.length; line++)
572 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
575 // JBPNote The returned files from a webservice could be
576 // hidden behind icons in the monitor window that,
577 // when clicked, pop up their corresponding data
581 } catch (Exception ex)
584 Cache.log.error("Unexpected exception when processing results for "
586 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
590 wsInfo.showResultsNewFrame
591 .addActionListener(new java.awt.event.ActionListener()
593 public void actionPerformed(java.awt.event.ActionEvent evt)
595 displayResults(true);
599 .addActionListener(new java.awt.event.ActionListener()
601 public void actionPerformed(java.awt.event.ActionEvent evt)
603 displayResults(false);
606 wsInfo.setResultsReady();
610 wsInfo.setFinishedNoResults();
614 void displayResults(boolean newFrame)
618 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
621 // each subjob is an independent alignment for the moment
622 // Alignment al[] = new Alignment[jobs.length];
623 // NewickFile nf[] = new NewickFile[jobs.length];
624 for (int j = 0; j < jobs.length; j++)
626 Hashtable featureColours = new Hashtable();
628 NewickFile nf = null;
629 if (jobs[j].hasResults())
631 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
638 al = (Alignment) res[0];
639 nf = (NewickFile) res[1];
648 * We can't map new alignment back with insertions from input's hidden
649 * regions until dataset mapping is sorted out... but basically it goes
650 * like this: 1. Merge each domain hit back onto the visible segments in
651 * the same way as a Jnet prediction is mapped back
653 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
654 * // trash references to original result data for (int j = 0; j <
655 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
656 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
657 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
659 * if (dataset != null) { al.setDataset(dataset); }
661 * propagateDatasetMappings(al); }
664 AlignFrame af = new AlignFrame(al,// columnselection,
665 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
668 af.ShowNewickTree(nf, "Tree from " + this.alTitle);
670 // initialise with same renderer settings as in parent alignframe.
671 af.getFeatureRenderer().transferSettings(this.featureSettings);
672 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
673 AlignFrame.DEFAULT_HEIGHT);
677 public boolean canMergeResults()