2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
\r
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
\r
5 * This file is part of Jalview.
\r
7 * Jalview is free software: you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
\r
11 * Jalview is distributed in the hope that it will be useful, but
\r
12 * WITHOUT ANY WARRANTY; without even the implied warranty
\r
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
14 * PURPOSE. See the GNU General Public License for more details.
\r
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
\r
22 import jalview.analysis.*;
\r
23 import jalview.bin.*;
\r
24 import jalview.datamodel.*;
\r
25 import jalview.gui.*;
\r
26 import jalview.io.NewickFile;
\r
27 import vamsas.objects.simple.MsaResult;
\r
28 import vamsas.objects.simple.SeqSearchResult;
\r
40 * Copyright: Copyright (c) 2004
\r
44 * Company: Dundee University
\r
47 * @author not attributable
\r
50 class SeqSearchWSThread extends JWS1Thread implements WSClientI
\r
54 boolean profile = false;
\r
56 class SeqSearchWSJob extends WSJob
\r
58 // hold special input for this
\r
59 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
\r
69 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
\r
71 this.jobnum = jobNum;
\r
72 if (!prepareInput(inSeqs, 2))
\r
75 subjobComplete = true;
\r
76 result = new MsaResult();
\r
77 result.setFinished(true);
\r
78 result.setStatus("Job never ran - input returned to user.");
\r
83 Hashtable SeqNames = new Hashtable();
\r
85 Vector emptySeqs = new Vector();
\r
88 * prepare input sequences for service
\r
91 * jalview sequences to be prepared
\r
93 * minimum number of residues required for this MsaWS service
\r
94 * @return true if seqs contains sequences to be submitted to service.
\r
96 private boolean prepareInput(SequenceI[] seqs, int minlen)
\r
102 "Implementation error: minlen must be zero or more.");
\r
104 for (int i = 0; i < seqs.length; i++)
\r
106 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
\r
111 boolean valid = nseqs >= 1; // need at least one sequence for valid input
\r
112 // TODO: generalise
\r
113 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
\r
115 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
\r
117 for (int i = 0, n = 0; i < seqs.length; i++)
\r
120 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
\r
124 SeqNames.put(newname, jalview.analysis.SeqsetUtils
\r
125 .SeqCharacterHash(seqs[i]));
\r
126 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
\r
128 seqarray[n] = new vamsas.objects.simple.Sequence();
\r
129 seqarray[n].setId(newname);
\r
130 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
\r
131 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
\r
132 seqs[i].getSequenceAsString()));
\r
136 String empty = null;
\r
137 if (seqs[i].getEnd() >= seqs[i].getStart())
\r
139 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
\r
140 .extractGaps(jalview.util.Comparison.GapChars, seqs[i]
\r
141 .getSequenceAsString());
\r
143 emptySeqs.add(new String[]
\r
144 { newname, empty });
\r
149 // almost certainly have to remove gapped columns here
\r
151 this.seqs = new vamsas.objects.simple.SequenceSet();
\r
152 this.seqs.setSeqs(seqarray);
\r
158 * @return true if getAlignment will return a valid alignment result.
\r
160 public boolean hasResults()
\r
164 && result.isFinished()
\r
165 && ((SeqSearchResult) result).getAlignment() != null
\r
166 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
\r
174 * return sequence search results for display
\r
176 * @return null or { Alignment(+features and annotation), NewickFile)}
\r
178 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
\r
181 if (result != null && result.isFinished())
\r
183 SequenceI[] alseqs = null;
\r
184 // char alseq_gapchar = '-';
\r
185 // int alseq_l = 0;
\r
186 if (((SeqSearchResult) result).getAlignment() != null)
\r
188 alseqs = getVamsasAlignment(((SeqSearchResult) result)
\r
190 // alseq_gapchar = ( (SeqSearchResult)
\r
191 // result).getAlignment().getGapchar().charAt(0);
\r
192 // alseq_l = alseqs.length;
\r
195 * what has to be done. 1 - annotate returned alignment with annotation
\r
196 * file and sequence features file, and associate any tree-nodes. 2.
\r
197 * connect alignment back to any associated dataset: 2.a. deuniquify
\r
198 * recovers sequence information - but additionally, relocations must be
\r
199 * made from the returned aligned sequence back to the dataset.
\r
201 // construct annotated alignment as it would be done by the jalview
\r
203 jalview.datamodel.Alignment al = new Alignment(alseqs);
\r
204 // al.setDataset(dataset);
\r
206 String inFile = null;
\r
209 inFile = ((SeqSearchResult) result).getAnnotation();
\r
210 if (inFile != null && inFile.length() > 0)
\r
212 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
\r
213 jalview.io.AppletFormatAdapter.PASTE);
\r
215 } catch (Exception e)
\r
218 .println("Failed to parse the annotation file associated with the alignment.");
\r
219 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
220 e.printStackTrace(System.err);
\r
225 inFile = ((SeqSearchResult) result).getFeatures();
\r
226 if (inFile != null && inFile.length() > 0)
\r
228 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
\r
229 inFile, jalview.io.AppletFormatAdapter.PASTE);
\r
230 ff.parse(al, featureColours, false);
\r
232 } catch (Exception e)
\r
235 .println("Failed to parse the Features file associated with the alignment.");
\r
236 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
237 e.printStackTrace(System.err);
\r
239 jalview.io.NewickFile nf = null;
\r
242 inFile = ((SeqSearchResult) result).getNewickTree();
\r
243 if (inFile != null && inFile.length() > 0)
\r
245 nf = new jalview.io.NewickFile(inFile,
\r
246 jalview.io.AppletFormatAdapter.PASTE);
\r
253 } catch (Exception e)
\r
256 .println("Failed to parse the treeFile associated with the alignment.");
\r
257 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
258 e.printStackTrace(System.err);
\r
262 * TODO: housekeeping w.r.t. recovery of dataset and annotation
\r
263 * references for input sequences, and then dataset sequence creation
\r
264 * for new sequences retrieved from service // finally, attempt to
\r
265 * de-uniquify to recover input sequence identity, and try to map back
\r
266 * onto dataset Note: this
\r
267 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
\r
268 * NOT WORK - the returned alignment may contain multiple versions of
\r
269 * the input sequence, each being a subsequence of the original.
\r
270 * deuniquify also removes existing annotation and features added in the
\r
271 * previous step... al.setDataset(dataset); // add in new sequences
\r
272 * retrieved from sequence search which are not already in dataset. //
\r
273 * trigger a 'fetchDBids' to annotate sequences with database ids...
\r
276 return new Object[]
\r
283 * mark subjob as cancelled and set result object appropriatly
\r
288 subjobComplete = true;
\r
294 * @return boolean true if job can be submitted.
\r
296 public boolean hasValidInput()
\r
298 if (seqs.getSeqs() != null)
\r
306 String alTitle; // name which will be used to form new alignment window.
\r
308 Alignment dataset; // dataset to which the new alignment will be
\r
312 ext.vamsas.SeqSearchI server = null;
\r
314 private String dbArg;
\r
317 * set basic options for this (group) of Msa jobs
\r
324 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
\r
325 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
\r
326 AlignmentView alview, String wsname, String db)
\r
328 super(alFrame, wsinfo, alview, wsname, wsUrl);
\r
329 this.server = server;
\r
334 * create one or more Msa jobs to align visible seuqences in _msa
\r
347 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
\r
348 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
\r
349 String wsname, String title, AlignmentView _msa, String db,
\r
352 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
\r
353 OutputHeader = wsInfo.getProgressText();
\r
357 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
\r
358 if (conmsa != null)
\r
360 int njobs = conmsa.length;
\r
361 jobs = new SeqSearchWSJob[njobs];
\r
362 for (int j = 0; j < njobs; j++)
\r
366 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
\r
370 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
\r
375 .setProgressName("region " + jobs[j].jobnum,
\r
378 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
\r
383 public boolean isCancellable()
\r
388 public void cancelJob()
\r
390 if (!jobComplete && jobs != null)
\r
392 boolean cancelled = true;
\r
393 for (int job = 0; job < jobs.length; job++)
\r
395 if (jobs[job].submitted && !jobs[job].subjobComplete)
\r
397 String cancelledMessage = "";
\r
400 vamsas.objects.simple.WsJobId cancelledJob = server
\r
401 .cancel(jobs[job].jobId);
\r
402 if (cancelledJob.getStatus() == 2)
\r
405 cancelledMessage = "Job cancelled.";
\r
406 ((SeqSearchWSJob) jobs[job]).cancel();
\r
407 wsInfo.setStatus(jobs[job].jobnum,
\r
408 WebserviceInfo.STATE_CANCELLED_OK);
\r
410 else if (cancelledJob.getStatus() == 3)
\r
412 // VALID UNSTOPPABLE JOB
\r
413 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
\r
415 // wsInfo.setStatus(jobs[job].jobnum,
\r
416 // WebserviceInfo.STATE_RUNNING);
\r
419 if (cancelledJob.getJobId() != null)
\r
421 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
\r
424 cancelledMessage += "\n";
\r
425 } catch (Exception exc)
\r
427 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
\r
430 "Exception whilst cancelling " + jobs[job].jobId, exc);
\r
432 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
\r
433 + cancelledMessage + "\n");
\r
438 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
\r
439 jobComplete = true;
\r
441 this.interrupt(); // kick thread to update job states.
\r
448 .setProgressText(OutputHeader
\r
449 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
\r
454 public void pollJob(AWsJob job) throws Exception
\r
456 ((SeqSearchWSJob) job).result = server
\r
457 .getResult(((SeqSearchWSJob) job).jobId);
\r
460 public void StartJob(AWsJob job)
\r
462 if (!(job instanceof SeqSearchWSJob))
\r
464 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "
\r
467 SeqSearchWSJob j = (SeqSearchWSJob) job;
\r
470 if (Cache.log.isDebugEnabled())
\r
472 Cache.log.debug("Tried to submit an already submitted job "
\r
477 if (j.seqs.getSeqs() == null)
\r
479 // special case - selection consisted entirely of empty sequences...
\r
480 j.submitted = true;
\r
481 j.result = new MsaResult();
\r
482 j.result.setFinished(true);
\r
483 j.result.setStatus("Empty Alignment Job");
\r
484 ((MsaResult) j.result).setMsa(null);
\r
488 vamsas.objects.simple.WsJobId jobsubmit = server.search(j.seqs
\r
489 .getSeqs()[0], dbArg);
\r
491 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
\r
493 j.jobId = jobsubmit.getJobId();
\r
494 j.submitted = true;
\r
495 j.subjobComplete = false;
\r
496 // System.out.println(WsURL + " Job Id '" + jobId + "'");
\r
500 if (jobsubmit == null)
\r
502 throw new Exception(
\r
505 + " returned null object, it probably cannot be contacted. Try again later ?");
\r
508 throw new Exception(jobsubmit.getJobId());
\r
510 } catch (Exception e)
\r
512 // TODO: JBPNote catch timeout or other fault types explicitly
\r
513 // For unexpected errors
\r
515 .println(WebServiceName
\r
516 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
\r
517 + "When contacting Server:" + WsUrl + "\n"
\r
518 + e.toString() + "\n");
\r
519 j.allowedServerExceptions = 0;
\r
520 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
521 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
523 .appendProgressText(
\r
525 "Failed to submit sequences for alignment.\n"
\r
526 + "It is most likely that there is a problem with the server.\n"
\r
527 + "Just close the window\n");
\r
529 // e.printStackTrace(); // TODO: JBPNote DEBUG
\r
533 private jalview.datamodel.Sequence[] getVamsasAlignment(
\r
534 vamsas.objects.simple.Alignment valign)
\r
536 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
\r
537 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
\r
539 for (int i = 0, j = seqs.length; i < j; i++)
\r
541 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
\r
548 public void parseResult()
\r
550 int results = 0; // number of result sets received
\r
551 JobStateSummary finalState = new JobStateSummary();
\r
554 for (int j = 0; j < jobs.length; j++)
\r
556 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
\r
557 if (jobs[j].submitted && jobs[j].subjobComplete
\r
558 && jobs[j].hasResults())
\r
561 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob)jobs[j]).result)
\r
563 if (valign != null)
\r
565 wsInfo.appendProgressText(jobs[j].jobnum,
\r
566 "\nAlignment Object Method Notes\n");
\r
567 String[] lines = valign.getMethod();
\r
568 for (int line = 0; line < lines.length; line++)
\r
570 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
\r
572 // JBPNote The returned files from a webservice could be
\r
573 // hidden behind icons in the monitor window that,
\r
574 // when clicked, pop up their corresponding data
\r
578 } catch (Exception ex)
\r
581 Cache.log.error("Unexpected exception when processing results for "
\r
583 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
\r
587 wsInfo.showResultsNewFrame
\r
588 .addActionListener(new java.awt.event.ActionListener()
\r
590 public void actionPerformed(java.awt.event.ActionEvent evt)
\r
592 displayResults(true);
\r
595 wsInfo.mergeResults
\r
596 .addActionListener(new java.awt.event.ActionListener()
\r
598 public void actionPerformed(java.awt.event.ActionEvent evt)
\r
600 displayResults(false);
\r
603 wsInfo.setResultsReady();
\r
607 wsInfo.setFinishedNoResults();
\r
611 void displayResults(boolean newFrame)
\r
615 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
\r
618 // each subjob is an independent alignment for the moment
\r
619 // Alignment al[] = new Alignment[jobs.length];
\r
620 // NewickFile nf[] = new NewickFile[jobs.length];
\r
621 for (int j = 0; j < jobs.length; j++)
\r
623 Hashtable featureColours = new Hashtable();
\r
624 Alignment al = null;
\r
625 NewickFile nf = null;
\r
626 if (jobs[j].hasResults())
\r
628 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
\r
635 al = (Alignment) res[0];
\r
636 nf = (NewickFile) res[1];
\r
645 * We can't map new alignment back with insertions from input's hidden
\r
646 * regions until dataset mapping is sorted out... but basically it goes
\r
647 * like this: 1. Merge each domain hit back onto the visible segments in
\r
648 * the same way as a Jnet prediction is mapped back
\r
650 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
\r
651 * // trash references to original result data for (int j = 0; j <
\r
652 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
\r
653 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
\r
654 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
\r
656 * if (dataset != null) { al.setDataset(dataset); }
\r
658 * propagateDatasetMappings(al); }
\r
661 AlignFrame af = new AlignFrame(al,// columnselection,
\r
662 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
\r
665 af.ShowNewickTree(nf, "Tree from " + this.alTitle);
\r
667 // initialise with same renderer settings as in parent alignframe.
\r
668 af.getFeatureRenderer().transferSettings(this.featureSettings);
\r
669 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
\r
670 AlignFrame.DEFAULT_HEIGHT);
\r
674 public boolean canMergeResults()
\r