2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
\r
3 * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
23 import jalview.analysis.*;
\r
24 import jalview.bin.*;
\r
25 import jalview.datamodel.*;
\r
26 import jalview.gui.*;
\r
27 import jalview.io.NewickFile;
\r
28 import vamsas.objects.simple.MsaResult;
\r
29 import vamsas.objects.simple.SeqSearchResult;
\r
41 * Copyright: Copyright (c) 2004
\r
45 * Company: Dundee University
\r
48 * @author not attributable
\r
51 class SeqSearchWSThread extends WSThread implements WSClientI
\r
55 boolean profile = false;
\r
57 class SeqSearchWSJob extends WSThread.WSJob
\r
59 // hold special input for this
\r
60 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
\r
70 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
\r
72 this.jobnum = jobNum;
\r
73 if (!prepareInput(inSeqs, 2))
\r
76 subjobComplete = true;
\r
77 result = new MsaResult();
\r
78 result.setFinished(true);
\r
79 result.setStatus("Job never ran - input returned to user.");
\r
84 Hashtable SeqNames = new Hashtable();
\r
86 Vector emptySeqs = new Vector();
\r
89 * prepare input sequences for service
\r
92 * jalview sequences to be prepared
\r
94 * minimum number of residues required for this MsaWS service
\r
95 * @return true if seqs contains sequences to be submitted to service.
\r
97 private boolean prepareInput(SequenceI[] seqs, int minlen)
\r
103 "Implementation error: minlen must be zero or more.");
\r
105 for (int i = 0; i < seqs.length; i++)
\r
107 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
\r
112 boolean valid = nseqs >= 1; // need at least one sequence for valid input
\r
113 // TODO: generalise
\r
114 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
\r
116 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
\r
118 for (int i = 0, n = 0; i < seqs.length; i++)
\r
121 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
\r
125 SeqNames.put(newname, jalview.analysis.SeqsetUtils
\r
126 .SeqCharacterHash(seqs[i]));
\r
127 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
\r
129 seqarray[n] = new vamsas.objects.simple.Sequence();
\r
130 seqarray[n].setId(newname);
\r
131 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
\r
132 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
\r
133 seqs[i].getSequenceAsString()));
\r
137 String empty = null;
\r
138 if (seqs[i].getEnd() >= seqs[i].getStart())
\r
140 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
\r
141 .extractGaps(jalview.util.Comparison.GapChars, seqs[i]
\r
142 .getSequenceAsString());
\r
144 emptySeqs.add(new String[]
\r
145 { newname, empty });
\r
150 // almost certainly have to remove gapped columns here
\r
152 this.seqs = new vamsas.objects.simple.SequenceSet();
\r
153 this.seqs.setSeqs(seqarray);
\r
159 * @return true if getAlignment will return a valid alignment result.
\r
161 public boolean hasResults()
\r
165 && result.isFinished()
\r
166 && ((SeqSearchResult) result).getAlignment() != null
\r
167 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
\r
175 * return sequence search results for display
\r
177 * @return null or { Alignment(+features and annotation), NewickFile)}
\r
179 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
\r
182 if (result != null && result.isFinished())
\r
184 SequenceI[] alseqs = null;
\r
185 // char alseq_gapchar = '-';
\r
186 // int alseq_l = 0;
\r
187 if (((SeqSearchResult) result).getAlignment() != null)
\r
189 alseqs = getVamsasAlignment(((SeqSearchResult) result)
\r
191 // alseq_gapchar = ( (SeqSearchResult)
\r
192 // result).getAlignment().getGapchar().charAt(0);
\r
193 // alseq_l = alseqs.length;
\r
196 * what has to be done. 1 - annotate returned alignment with annotation
\r
197 * file and sequence features file, and associate any tree-nodes. 2.
\r
198 * connect alignment back to any associated dataset: 2.a. deuniquify
\r
199 * recovers sequence information - but additionally, relocations must be
\r
200 * made from the returned aligned sequence back to the dataset.
\r
202 // construct annotated alignment as it would be done by the jalview
\r
204 jalview.datamodel.Alignment al = new Alignment(alseqs);
\r
205 // al.setDataset(dataset);
\r
207 String inFile = null;
\r
210 inFile = ((SeqSearchResult) result).getAnnotation();
\r
211 if (inFile != null && inFile.length() > 0)
\r
213 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
\r
214 jalview.io.AppletFormatAdapter.PASTE);
\r
216 } catch (Exception e)
\r
219 .println("Failed to parse the annotation file associated with the alignment.");
\r
220 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
221 e.printStackTrace(System.err);
\r
226 inFile = ((SeqSearchResult) result).getFeatures();
\r
227 if (inFile != null && inFile.length() > 0)
\r
229 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
\r
230 inFile, jalview.io.AppletFormatAdapter.PASTE);
\r
231 ff.parse(al, featureColours, false);
\r
233 } catch (Exception e)
\r
236 .println("Failed to parse the Features file associated with the alignment.");
\r
237 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
238 e.printStackTrace(System.err);
\r
240 jalview.io.NewickFile nf = null;
\r
243 inFile = ((SeqSearchResult) result).getNewickTree();
\r
244 if (inFile != null && inFile.length() > 0)
\r
246 nf = new jalview.io.NewickFile(inFile,
\r
247 jalview.io.AppletFormatAdapter.PASTE);
\r
254 } catch (Exception e)
\r
257 .println("Failed to parse the treeFile associated with the alignment.");
\r
258 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
\r
259 e.printStackTrace(System.err);
\r
263 * TODO: housekeeping w.r.t. recovery of dataset and annotation
\r
264 * references for input sequences, and then dataset sequence creation
\r
265 * for new sequences retrieved from service // finally, attempt to
\r
266 * de-uniquify to recover input sequence identity, and try to map back
\r
267 * onto dataset Note: this
\r
268 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
\r
269 * NOT WORK - the returned alignment may contain multiple versions of
\r
270 * the input sequence, each being a subsequence of the original.
\r
271 * deuniquify also removes existing annotation and features added in the
\r
272 * previous step... al.setDataset(dataset); // add in new sequences
\r
273 * retrieved from sequence search which are not already in dataset. //
\r
274 * trigger a 'fetchDBids' to annotate sequences with database ids...
\r
277 return new Object[]
\r
284 * mark subjob as cancelled and set result object appropriatly
\r
289 subjobComplete = true;
\r
295 * @return boolean true if job can be submitted.
\r
297 boolean hasValidInput()
\r
299 if (seqs.getSeqs() != null)
\r
307 String alTitle; // name which will be used to form new alignment window.
\r
309 Alignment dataset; // dataset to which the new alignment will be
\r
313 ext.vamsas.SeqSearchI server = null;
\r
315 private String dbArg;
\r
318 * set basic options for this (group) of Msa jobs
\r
325 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
\r
326 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
\r
327 AlignmentView alview, String wsname, String db)
\r
329 super(alFrame, wsinfo, alview, wsname, wsUrl);
\r
330 this.server = server;
\r
335 * create one or more Msa jobs to align visible seuqences in _msa
\r
348 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
\r
349 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
\r
350 String wsname, String title, AlignmentView _msa, String db,
\r
353 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
\r
354 OutputHeader = wsInfo.getProgressText();
\r
358 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
\r
359 if (conmsa != null)
\r
361 int njobs = conmsa.length;
\r
362 jobs = new SeqSearchWSJob[njobs];
\r
363 for (int j = 0; j < njobs; j++)
\r
367 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
\r
371 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
\r
376 .setProgressName("region " + jobs[j].jobnum,
\r
379 wsinfo.setProgressText(jobs[j].jobnum, OutputHeader);
\r
384 public boolean isCancellable()
\r
389 public void cancelJob()
\r
391 if (!jobComplete && jobs != null)
\r
393 boolean cancelled = true;
\r
394 for (int job = 0; job < jobs.length; job++)
\r
396 if (jobs[job].submitted && !jobs[job].subjobComplete)
\r
398 String cancelledMessage = "";
\r
401 vamsas.objects.simple.WsJobId cancelledJob = server
\r
402 .cancel(jobs[job].jobId);
\r
403 if (cancelledJob.getStatus() == 2)
\r
406 cancelledMessage = "Job cancelled.";
\r
407 ((SeqSearchWSJob) jobs[job]).cancel();
\r
408 wsInfo.setStatus(jobs[job].jobnum,
\r
409 WebserviceInfo.STATE_CANCELLED_OK);
\r
411 else if (cancelledJob.getStatus() == 3)
\r
413 // VALID UNSTOPPABLE JOB
\r
414 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
\r
416 // wsInfo.setStatus(jobs[job].jobnum,
\r
417 // WebserviceInfo.STATE_RUNNING);
\r
420 if (cancelledJob.getJobId() != null)
\r
422 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
\r
425 cancelledMessage += "\n";
\r
426 } catch (Exception exc)
\r
428 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
\r
431 "Exception whilst cancelling " + jobs[job].jobId, exc);
\r
433 wsInfo.setProgressText(jobs[job].jobnum, OutputHeader
\r
434 + cancelledMessage + "\n");
\r
439 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
\r
440 jobComplete = true;
\r
442 this.interrupt(); // kick thread to update job states.
\r
449 .setProgressText(OutputHeader
\r
450 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
\r
455 void pollJob(WSJob job) throws Exception
\r
457 ((SeqSearchWSJob) job).result = server
\r
458 .getResult(((SeqSearchWSJob) job).jobId);
\r
461 void StartJob(WSJob job)
\r
463 if (!(job instanceof SeqSearchWSJob))
\r
465 throw new Error("StartJob(MsaWSJob) called on a WSJobInstance "
\r
468 SeqSearchWSJob j = (SeqSearchWSJob) job;
\r
471 if (Cache.log.isDebugEnabled())
\r
473 Cache.log.debug("Tried to submit an already submitted job "
\r
478 if (j.seqs.getSeqs() == null)
\r
480 // special case - selection consisted entirely of empty sequences...
\r
481 j.submitted = true;
\r
482 j.result = new MsaResult();
\r
483 j.result.setFinished(true);
\r
484 j.result.setStatus("Empty Alignment Job");
\r
485 ((MsaResult) j.result).setMsa(null);
\r
489 vamsas.objects.simple.WsJobId jobsubmit = server.search(j.seqs
\r
490 .getSeqs()[0], dbArg);
\r
492 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
\r
494 j.jobId = jobsubmit.getJobId();
\r
495 j.submitted = true;
\r
496 j.subjobComplete = false;
\r
497 // System.out.println(WsURL + " Job Id '" + jobId + "'");
\r
501 if (jobsubmit == null)
\r
503 throw new Exception(
\r
506 + " returned null object, it probably cannot be contacted. Try again later ?");
\r
509 throw new Exception(jobsubmit.getJobId());
\r
511 } catch (Exception e)
\r
513 // TODO: JBPNote catch timeout or other fault types explicitly
\r
514 // For unexpected errors
\r
516 .println(WebServiceName
\r
517 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
\r
518 + "When contacting Server:" + WsUrl + "\n"
\r
519 + e.toString() + "\n");
\r
520 j.allowedServerExceptions = 0;
\r
521 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
522 wsInfo.setStatus(j.jobnum, WebserviceInfo.STATE_STOPPED_SERVERERROR);
\r
524 .appendProgressText(
\r
526 "Failed to submit sequences for alignment.\n"
\r
527 + "It is most likely that there is a problem with the server.\n"
\r
528 + "Just close the window\n");
\r
530 // e.printStackTrace(); // TODO: JBPNote DEBUG
\r
534 private jalview.datamodel.Sequence[] getVamsasAlignment(
\r
535 vamsas.objects.simple.Alignment valign)
\r
537 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
\r
538 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
\r
540 for (int i = 0, j = seqs.length; i < j; i++)
\r
542 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(), seqs[i]
\r
551 int results = 0; // number of result sets received
\r
552 JobStateSummary finalState = new JobStateSummary();
\r
555 for (int j = 0; j < jobs.length; j++)
\r
557 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
\r
558 if (jobs[j].submitted && jobs[j].subjobComplete
\r
559 && jobs[j].hasResults())
\r
562 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) jobs[j].result)
\r
564 if (valign != null)
\r
566 wsInfo.appendProgressText(jobs[j].jobnum,
\r
567 "\nAlignment Object Method Notes\n");
\r
568 String[] lines = valign.getMethod();
\r
569 for (int line = 0; line < lines.length; line++)
\r
571 wsInfo.appendProgressText(jobs[j].jobnum, lines[line] + "\n");
\r
573 // JBPNote The returned files from a webservice could be
\r
574 // hidden behind icons in the monitor window that,
\r
575 // when clicked, pop up their corresponding data
\r
579 } catch (Exception ex)
\r
582 Cache.log.error("Unexpected exception when processing results for "
\r
584 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
\r
588 wsInfo.showResultsNewFrame
\r
589 .addActionListener(new java.awt.event.ActionListener()
\r
591 public void actionPerformed(java.awt.event.ActionEvent evt)
\r
593 displayResults(true);
\r
596 wsInfo.mergeResults
\r
597 .addActionListener(new java.awt.event.ActionListener()
\r
599 public void actionPerformed(java.awt.event.ActionEvent evt)
\r
601 displayResults(false);
\r
604 wsInfo.setResultsReady();
\r
608 wsInfo.setFinishedNoResults();
\r
612 void displayResults(boolean newFrame)
\r
616 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
\r
619 // each subjob is an independent alignment for the moment
\r
620 // Alignment al[] = new Alignment[jobs.length];
\r
621 // NewickFile nf[] = new NewickFile[jobs.length];
\r
622 for (int j = 0; j < jobs.length; j++)
\r
624 Hashtable featureColours = new Hashtable();
\r
625 Alignment al = null;
\r
626 NewickFile nf = null;
\r
627 if (jobs[j].hasResults())
\r
629 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
\r
636 al = (Alignment) res[0];
\r
637 nf = (NewickFile) res[1];
\r
646 * We can't map new alignment back with insertions from input's hidden
\r
647 * regions until dataset mapping is sorted out... but basically it goes
\r
648 * like this: 1. Merge each domain hit back onto the visible segments in
\r
649 * the same way as a Jnet prediction is mapped back
\r
651 * Object[] newview = input.getUpdatedView(results, orders, getGapChar()); //
\r
652 * trash references to original result data for (int j = 0; j <
\r
653 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
\r
654 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
\r
655 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
\r
657 * if (dataset != null) { al.setDataset(dataset); }
\r
659 * propagateDatasetMappings(al); }
\r
662 AlignFrame af = new AlignFrame(al,// columnselection,
\r
663 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
\r
666 af.ShowNewickTree(nf, "Tree from " + this.alTitle);
\r
668 // initialise with same renderer settings as in parent alignframe.
\r
669 af.getFeatureRenderer().transferSettings(this.featureSettings);
\r
670 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
\r
671 AlignFrame.DEFAULT_HEIGHT);
\r
675 public boolean canMergeResults()
\r