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)
98 throw new Error(MessageManager.getString(
99 "error.implementation_error_minlen_must_be_greater_zero"));
101 for (int i = 0; i < seqs.length; i++)
103 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
108 boolean valid = nseqs >= 1; // need at least one sequence for valid input
110 vamsas.objects.simple.Sequence[] seqarray = (valid)
111 ? 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()
138 : AlignSeq.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()
160 if (subjobComplete && result != null && result.isFinished()
161 && ((SeqSearchResult) result).getAlignment() != null
162 && ((SeqSearchResult) result).getAlignment()
171 * return sequence search results for display
173 * @return null or { Alignment(+features and annotation), NewickFile)}
175 public Object[] getAlignment(AlignmentI dataset,
176 Map<String, FeatureColourI> featureColours)
179 if (result != null && result.isFinished())
181 SequenceI[] alseqs = null;
182 // char alseq_gapchar = '-';
184 if (((SeqSearchResult) result).getAlignment() != null)
186 alseqs = getVamsasAlignment(
187 ((SeqSearchResult) result).getAlignment());
188 // alseq_gapchar = ( (SeqSearchResult)
189 // result).getAlignment().getGapchar().charAt(0);
190 // alseq_l = alseqs.length;
193 * what has to be done. 1 - annotate returned alignment with annotation
194 * file and sequence features file, and associate any tree-nodes. 2.
195 * connect alignment back to any associated dataset: 2.a. deuniquify
196 * recovers sequence information - but additionally, relocations must be
197 * made from the returned aligned sequence back to the dataset.
199 // construct annotated alignment as it would be done by the jalview
201 jalview.datamodel.Alignment al = new Alignment(alseqs);
202 // al.setDataset(dataset);
204 String inFile = null;
207 inFile = ((SeqSearchResult) result).getAnnotation();
208 if (inFile != null && inFile.length() > 0)
210 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
211 jalview.io.DataSourceType.PASTE);
213 } catch (Exception e)
216 "Failed to parse the annotation file associated with the alignment.");
217 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
218 e.printStackTrace(System.err);
223 inFile = ((SeqSearchResult) result).getFeatures();
224 if (inFile != null && inFile.length() > 0)
226 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(inFile,
227 jalview.io.DataSourceType.PASTE);
228 ff.parse(al, featureColours, false);
230 } catch (Exception e)
233 "Failed to parse the Features file associated with the alignment.");
234 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
235 e.printStackTrace(System.err);
237 jalview.io.NewickFile nf = null;
240 inFile = ((SeqSearchResult) result).getNewickTree();
241 if (inFile != null && inFile.length() > 0)
243 nf = new jalview.io.NewickFile(inFile,
244 jalview.io.DataSourceType.PASTE);
251 } catch (Exception e)
254 "Failed to parse the treeFile associated with the alignment.");
255 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
256 e.printStackTrace(System.err);
260 * TODO: housekeeping w.r.t. recovery of dataset and annotation
261 * references for input sequences, and then dataset sequence creation
262 * for new sequences retrieved from service // finally, attempt to
263 * de-uniquify to recover input sequence identity, and try to map back
264 * onto dataset Note: this
265 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
266 * NOT WORK - the returned alignment may contain multiple versions of
267 * the input sequence, each being a subsequence of the original.
268 * deuniquify also removes existing annotation and features added in the
269 * previous step... al.setDataset(dataset); // add in new sequences
270 * retrieved from sequence search which are not already in dataset. //
271 * trigger a 'fetchDBids' to annotate sequences with database ids...
274 return new Object[] { al, nf };
280 * mark subjob as cancelled and set result object appropriatly
285 subjobComplete = true;
291 * @return boolean true if job can be submitted.
294 public boolean hasValidInput()
296 if (seqs.getSeqs() != null)
304 String alTitle; // name which will be used to form new alignment window.
306 AlignmentI dataset; // dataset to which the new alignment will be
310 ext.vamsas.SeqSearchI server = null;
312 private String dbArg;
315 * set basic options for this (group) of Msa jobs
322 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
323 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
324 AlignmentView alview, String wsname, String db)
326 super(alFrame, wsinfo, alview, wsname, wsUrl);
327 this.server = server;
332 * create one or more Msa jobs to align visible seuqences in _msa
345 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
346 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
347 String wsname, String title, AlignmentView _msa, String db,
350 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
351 OutputHeader = wsInfo.getProgressText();
355 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
358 int njobs = conmsa.length;
359 jobs = new SeqSearchWSJob[njobs];
360 for (int j = 0; j < njobs; j++)
364 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
368 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
372 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
373 jobs[j].getJobnum());
375 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
381 public boolean isCancellable()
387 public void cancelJob()
389 if (!jobComplete && jobs != null)
391 boolean cancelled = true;
392 for (int job = 0; job < jobs.length; job++)
394 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
396 String cancelledMessage = "";
399 vamsas.objects.simple.WsJobId cancelledJob = server
400 .cancel(jobs[job].getJobId());
401 if (cancelledJob.getStatus() == 2)
404 cancelledMessage = "Job cancelled.";
405 ((SeqSearchWSJob) jobs[job]).cancel();
406 wsInfo.setStatus(jobs[job].getJobnum(),
407 WebserviceInfo.STATE_CANCELLED_OK);
409 else if (cancelledJob.getStatus() == 3)
411 // VALID UNSTOPPABLE JOB
412 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
414 // wsInfo.setStatus(jobs[job].jobnum,
415 // WebserviceInfo.STATE_RUNNING);
418 if (cancelledJob.getJobId() != null)
420 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
423 cancelledMessage += "\n";
424 } catch (Exception exc)
426 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
429 "Exception whilst cancelling " + jobs[job].getJobId(),
432 wsInfo.setProgressText(jobs[job].getJobnum(),
433 OutputHeader + cancelledMessage + "\n");
438 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
441 this.interrupt(); // kick thread to update job states.
447 wsInfo.setProgressText(OutputHeader
448 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
454 public void pollJob(AWsJob job) throws Exception
456 ((SeqSearchWSJob) job).result = server
457 .getResult(((SeqSearchWSJob) job).getJobId());
461 public void StartJob(AWsJob job)
463 if (!(job instanceof SeqSearchWSJob))
465 throw new Error(MessageManager.formatMessage(
466 "error.implementation_error_msawbjob_called", new String[]
467 { job.getClass().toString() }));
469 SeqSearchWSJob j = (SeqSearchWSJob) job;
472 if (Cache.log.isDebugEnabled())
475 "Tried to submit an already submitted job " + j.getJobId());
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);
486 MessageManager.getString("label.empty_alignment_job"));
487 ((MsaResult) j.result).setMsa(null);
491 vamsas.objects.simple.WsJobId jobsubmit = server
492 .search(j.seqs.getSeqs()[0], dbArg);
494 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
496 j.setJobId(jobsubmit.getJobId());
497 j.setSubmitted(true);
498 j.setSubjobComplete(false);
499 // System.out.println(WsURL + " Job Id '" + jobId + "'");
503 if (jobsubmit == null)
505 throw new Exception(MessageManager.formatMessage(
506 "exception.web_service_returned_null_try_later",
511 throw new Exception(jobsubmit.getJobId());
513 } catch (Exception e)
515 // TODO: JBPNote catch timeout or other fault types explicitly
516 // For unexpected errors
517 System.err.println(WebServiceName
518 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
519 + "When contacting Server:" + WsUrl + "\n" + e.toString()
521 j.setAllowedServerExceptions(0);
522 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
523 wsInfo.setStatus(j.getJobnum(),
524 WebserviceInfo.STATE_STOPPED_SERVERERROR);
525 wsInfo.appendProgressText(j.getJobnum(), MessageManager
526 .getString("info.failed_to_submit_sequences_for_alignment"));
528 // e.printStackTrace(); // TODO: JBPNote DEBUG
532 private jalview.datamodel.Sequence[] getVamsasAlignment(
533 vamsas.objects.simple.Alignment valign)
535 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
536 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
538 for (int i = 0, j = seqs.length; i < j; i++)
540 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
548 public void parseResult()
550 int results = 0; // number of result sets received
551 JobStateSummary finalState = new JobStateSummary();
554 for (int j = 0; j < jobs.length; j++)
556 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
557 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
558 && jobs[j].hasResults())
561 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
565 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
566 .getString("info.alignment_object_method_notes"));
567 String[] lines = valign.getMethod();
568 for (int line = 0; line < lines.length; line++)
570 wsInfo.appendProgressText(jobs[j].getJobnum(),
573 // JBPNote The returned files from a webservice could be
574 // hidden behind icons in the monitor window that,
575 // when clicked, pop up their corresponding data
579 } catch (Exception ex)
583 "Unexpected exception when processing results for " + alTitle,
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,
670 MessageManager.formatMessage("label.tree_from", new String[]
673 // initialise with same renderer settings as in parent alignframe.
674 af.getFeatureRenderer().transferSettings(this.featureSettings);
675 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
676 AlignFrame.DEFAULT_HEIGHT);
681 public boolean canMergeResults()