2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ws.jws1;
23 import jalview.analysis.AlignSeq;
24 import jalview.api.FeatureColourI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentI;
28 import jalview.datamodel.AlignmentView;
29 import jalview.datamodel.SequenceI;
30 import jalview.gui.AlignFrame;
31 import jalview.gui.Desktop;
32 import jalview.gui.WebserviceInfo;
33 import jalview.io.NewickFile;
34 import jalview.util.MessageManager;
35 import jalview.ws.AWsJob;
36 import jalview.ws.JobStateSummary;
37 import jalview.ws.WSClientI;
39 import java.util.HashMap;
40 import java.util.Hashtable;
42 import java.util.Vector;
44 import vamsas.objects.simple.MsaResult;
45 import vamsas.objects.simple.SeqSearchResult;
47 class SeqSearchWSThread extends JWS1Thread implements WSClientI
51 boolean profile = false;
53 class SeqSearchWSJob extends WSJob
55 // hold special input for this
56 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
66 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
69 if (!prepareInput(inSeqs, 2))
72 subjobComplete = true;
73 result = new MsaResult();
74 result.setFinished(true);
75 result.setStatus(MessageManager.getString("label.job_never_ran"));
80 Hashtable SeqNames = new Hashtable();
82 Vector emptySeqs = new Vector();
85 * prepare input sequences for service
88 * jalview sequences to be prepared
90 * minimum number of residues required for this MsaWS service
91 * @return true if seqs contains sequences to be submitted to service.
93 private boolean prepareInput(SequenceI[] seqs, int minlen)
100 .getString("error.implementation_error_minlen_must_be_greater_zero"));
102 for (int i = 0; i < seqs.length; i++)
104 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
109 boolean valid = nseqs >= 1; // need at least one sequence for valid input
111 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
113 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
115 for (int i = 0, n = 0; i < seqs.length; i++)
118 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
122 SeqNames.put(newname,
123 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
124 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
126 seqarray[n] = new vamsas.objects.simple.Sequence();
127 seqarray[n].setId(newname);
128 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
129 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
130 seqs[i].getSequenceAsString()));
135 if (seqs[i].getEnd() >= seqs[i].getStart())
137 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
138 .extractGaps(jalview.util.Comparison.GapChars,
139 seqs[i].getSequenceAsString());
141 emptySeqs.add(new String[] { newname, empty });
146 // almost certainly have to remove gapped columns here
148 this.seqs = new vamsas.objects.simple.SequenceSet();
149 this.seqs.setSeqs(seqarray);
155 * @return true if getAlignment will return a valid alignment result.
158 public boolean hasResults()
162 && result.isFinished()
163 && ((SeqSearchResult) result).getAlignment() != null
164 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
172 * return sequence search results for display
174 * @return null or { Alignment(+features and annotation), NewickFile)}
176 public Object[] getAlignment(AlignmentI dataset,
177 Map<String, FeatureColourI> featureColours)
180 if (result != null && result.isFinished())
182 SequenceI[] alseqs = null;
183 // char alseq_gapchar = '-';
185 if (((SeqSearchResult) result).getAlignment() != null)
187 alseqs = getVamsasAlignment(((SeqSearchResult) result)
189 // alseq_gapchar = ( (SeqSearchResult)
190 // result).getAlignment().getGapchar().charAt(0);
191 // alseq_l = alseqs.length;
194 * what has to be done. 1 - annotate returned alignment with annotation
195 * file and sequence features file, and associate any tree-nodes. 2.
196 * connect alignment back to any associated dataset: 2.a. deuniquify
197 * recovers sequence information - but additionally, relocations must be
198 * made from the returned aligned sequence back to the dataset.
200 // construct annotated alignment as it would be done by the jalview
202 jalview.datamodel.Alignment al = new Alignment(alseqs);
203 // al.setDataset(dataset);
205 String inFile = null;
208 inFile = ((SeqSearchResult) result).getAnnotation();
209 if (inFile != null && inFile.length() > 0)
211 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
212 jalview.io.AppletFormatAdapter.PASTE);
214 } catch (Exception e)
217 .println("Failed to parse the annotation file associated with the alignment.");
218 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
219 e.printStackTrace(System.err);
224 inFile = ((SeqSearchResult) result).getFeatures();
225 if (inFile != null && inFile.length() > 0)
227 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
228 inFile, jalview.io.AppletFormatAdapter.PASTE);
229 ff.parse(al, featureColours, false);
231 } catch (Exception e)
234 .println("Failed to parse the Features file associated with the alignment.");
235 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
236 e.printStackTrace(System.err);
238 jalview.io.NewickFile nf = null;
241 inFile = ((SeqSearchResult) result).getNewickTree();
242 if (inFile != null && inFile.length() > 0)
244 nf = new jalview.io.NewickFile(inFile,
245 jalview.io.AppletFormatAdapter.PASTE);
252 } catch (Exception e)
255 .println("Failed to parse the treeFile associated with the alignment.");
256 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
257 e.printStackTrace(System.err);
261 * TODO: housekeeping w.r.t. recovery of dataset and annotation
262 * references for input sequences, and then dataset sequence creation
263 * for new sequences retrieved from service // finally, attempt to
264 * de-uniquify to recover input sequence identity, and try to map back
265 * onto dataset Note: this
266 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
267 * NOT WORK - the returned alignment may contain multiple versions of
268 * the input sequence, each being a subsequence of the original.
269 * deuniquify also removes existing annotation and features added in the
270 * previous step... al.setDataset(dataset); // add in new sequences
271 * retrieved from sequence search which are not already in dataset. //
272 * trigger a 'fetchDBids' to annotate sequences with database ids...
275 return new Object[] { al, nf };
281 * mark subjob as cancelled and set result object appropriatly
286 subjobComplete = true;
292 * @return boolean true if job can be submitted.
295 public boolean hasValidInput()
297 if (seqs.getSeqs() != null)
305 String alTitle; // name which will be used to form new alignment window.
307 AlignmentI dataset; // dataset to which the new alignment will be
311 ext.vamsas.SeqSearchI server = null;
313 private String dbArg;
316 * set basic options for this (group) of Msa jobs
323 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
324 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
325 AlignmentView alview, String wsname, String db)
327 super(alFrame, wsinfo, alview, wsname, wsUrl);
328 this.server = server;
333 * create one or more Msa jobs to align visible seuqences in _msa
346 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
347 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
348 String wsname, String title, AlignmentView _msa, String db,
351 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
352 OutputHeader = wsInfo.getProgressText();
356 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
359 int njobs = conmsa.length;
360 jobs = new SeqSearchWSJob[njobs];
361 for (int j = 0; j < njobs; j++)
365 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
369 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
373 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
374 jobs[j].getJobnum());
376 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
382 public boolean isCancellable()
388 public void cancelJob()
390 if (!jobComplete && jobs != null)
392 boolean cancelled = true;
393 for (int job = 0; job < jobs.length; job++)
395 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
397 String cancelledMessage = "";
400 vamsas.objects.simple.WsJobId cancelledJob = server
401 .cancel(jobs[job].getJobId());
402 if (cancelledJob.getStatus() == 2)
405 cancelledMessage = "Job cancelled.";
406 ((SeqSearchWSJob) jobs[job]).cancel();
407 wsInfo.setStatus(jobs[job].getJobnum(),
408 WebserviceInfo.STATE_CANCELLED_OK);
410 else if (cancelledJob.getStatus() == 3)
412 // VALID UNSTOPPABLE JOB
413 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
415 // wsInfo.setStatus(jobs[job].jobnum,
416 // WebserviceInfo.STATE_RUNNING);
419 if (cancelledJob.getJobId() != null)
421 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
424 cancelledMessage += "\n";
425 } catch (Exception exc)
427 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
430 "Exception whilst cancelling " + jobs[job].getJobId(),
433 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
434 + cancelledMessage + "\n");
439 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
442 this.interrupt(); // kick thread to update job states.
448 wsInfo.setProgressText(OutputHeader
449 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
455 public void pollJob(AWsJob job) throws Exception
457 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
462 public void StartJob(AWsJob job)
464 if (!(job instanceof SeqSearchWSJob))
466 throw new Error(MessageManager.formatMessage(
467 "error.implementation_error_msawbjob_called",
468 new String[] { job.getClass().toString() }));
470 SeqSearchWSJob j = (SeqSearchWSJob) job;
473 if (Cache.log.isDebugEnabled())
475 Cache.log.debug("Tried to submit an already submitted job "
480 if (j.seqs.getSeqs() == null)
482 // special case - selection consisted entirely of empty sequences...
483 j.setSubmitted(true);
484 j.result = new MsaResult();
485 j.result.setFinished(true);
486 j.result.setStatus(MessageManager
487 .getString("label.empty_alignment_job"));
488 ((MsaResult) j.result).setMsa(null);
492 vamsas.objects.simple.WsJobId jobsubmit = server.search(
493 j.seqs.getSeqs()[0], dbArg);
495 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
497 j.setJobId(jobsubmit.getJobId());
498 j.setSubmitted(true);
499 j.setSubjobComplete(false);
500 // System.out.println(WsURL + " Job Id '" + jobId + "'");
504 if (jobsubmit == null)
506 throw new Exception(MessageManager.formatMessage(
507 "exception.web_service_returned_null_try_later",
508 new String[] { WsUrl }));
511 throw new Exception(jobsubmit.getJobId());
513 } catch (Exception e)
515 // TODO: JBPNote catch timeout or other fault types explicitly
516 // For unexpected errors
518 .println(WebServiceName
519 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
520 + "When contacting Server:" + WsUrl + "\n"
521 + e.toString() + "\n");
522 j.setAllowedServerExceptions(0);
523 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
524 wsInfo.setStatus(j.getJobnum(),
525 WebserviceInfo.STATE_STOPPED_SERVERERROR);
526 wsInfo.appendProgressText(j.getJobnum(), MessageManager
527 .getString("info.failed_to_submit_sequences_for_alignment"));
529 // e.printStackTrace(); // TODO: JBPNote DEBUG
533 private jalview.datamodel.Sequence[] getVamsasAlignment(
534 vamsas.objects.simple.Alignment valign)
536 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
537 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
539 for (int i = 0, j = seqs.length; i < j; i++)
541 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
549 public void parseResult()
551 int results = 0; // number of result sets received
552 JobStateSummary finalState = new JobStateSummary();
555 for (int j = 0; j < jobs.length; j++)
557 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
558 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
559 && jobs[j].hasResults())
562 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
566 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
567 .getString("info.alignment_object_method_notes"));
568 String[] lines = valign.getMethod();
569 for (int line = 0; line < lines.length; line++)
571 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
574 // JBPNote The returned files from a webservice could be
575 // hidden behind icons in the monitor window that,
576 // when clicked, pop up their corresponding data
580 } catch (Exception ex)
583 Cache.log.error("Unexpected exception when processing results for "
585 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
589 wsInfo.showResultsNewFrame
590 .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()
602 public void actionPerformed(java.awt.event.ActionEvent evt)
604 displayResults(false);
607 wsInfo.setResultsReady();
611 wsInfo.setFinishedNoResults();
615 void displayResults(boolean newFrame)
619 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
622 // each subjob is an independent alignment for the moment
623 // Alignment al[] = new Alignment[jobs.length];
624 // NewickFile nf[] = new NewickFile[jobs.length];
625 for (int j = 0; j < jobs.length; j++)
627 Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
629 NewickFile nf = null;
630 if (jobs[j].hasResults())
632 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
639 al = (Alignment) res[0];
640 nf = (NewickFile) res[1];
649 * We can't map new alignment back with insertions from input's hidden
650 * regions until dataset mapping is sorted out... but basically it goes
651 * like this: 1. Merge each domain hit back onto the visible segments in
652 * the same way as a Jnet prediction is mapped back
654 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
655 * // trash references to original result data for (int j = 0; j <
656 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
657 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
658 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
660 * if (dataset != null) { al.setDataset(dataset); }
662 * propagateDatasetMappings(al); }
665 AlignFrame af = new AlignFrame(al,// columnselection,
666 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
669 af.ShowNewickTree(nf, MessageManager.formatMessage(
670 "label.tree_from", new String[] { this.alTitle }));
672 // initialise with same renderer settings as in parent alignframe.
673 af.getFeatureRenderer().transferSettings(this.featureSettings);
674 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
675 AlignFrame.DEFAULT_HEIGHT);
680 public boolean canMergeResults()