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;
41 import java.util.Vector;
43 import vamsas.objects.simple.MsaResult;
44 import vamsas.objects.simple.SeqSearchResult;
46 class SeqSearchWSThread extends JWS1Thread implements WSClientI
50 boolean profile = false;
52 class SeqSearchWSJob extends WSJob
54 // hold special input for this
55 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
65 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
68 if (!prepareInput(inSeqs, 2))
71 subjobComplete = true;
72 result = new MsaResult();
73 result.setFinished(true);
74 result.setStatus(MessageManager.getString("label.job_never_ran"));
79 Vector emptySeqs = new Vector();
82 * prepare input sequences for service
85 * jalview sequences to be prepared
87 * minimum number of residues required for this MsaWS service
88 * @return true if seqs contains sequences to be submitted to service.
90 private boolean prepareInput(SequenceI[] seqs, int minlen)
95 throw new Error(MessageManager.getString(
96 "error.implementation_error_minlen_must_be_greater_zero"));
98 for (int i = 0; i < seqs.length; i++)
100 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
105 boolean valid = nseqs >= 1; // need at least one sequence for valid input
107 vamsas.objects.simple.Sequence[] seqarray = (valid)
108 ? new vamsas.objects.simple.Sequence[nseqs]
110 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
112 for (int i = 0, n = 0; i < seqs.length; i++)
115 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
119 SeqNames.put(newname,
120 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
121 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
123 seqarray[n] = new vamsas.objects.simple.Sequence();
124 seqarray[n].setId(newname);
125 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
126 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
127 seqs[i].getSequenceAsString()));
132 if (seqs[i].getEnd() >= seqs[i].getStart())
134 empty = (submitGaps) ? seqs[i].getSequenceAsString()
135 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
136 seqs[i].getSequenceAsString());
138 emptySeqs.add(new String[] { newname, empty });
143 // almost certainly have to remove gapped columns here
145 this.seqs = new vamsas.objects.simple.SequenceSet();
146 this.seqs.setSeqs(seqarray);
152 * @return true if getAlignment will return a valid alignment result.
155 public boolean hasResults()
157 if (subjobComplete && result != null && result.isFinished()
158 && ((SeqSearchResult) result).getAlignment() != null
159 && ((SeqSearchResult) result).getAlignment()
168 * return sequence search results for display
170 * @return null or { Alignment(+features and annotation), NewickFile)}
172 public Object[] getAlignment(AlignmentI dataset,
173 Map<String, FeatureColourI> featureColours)
176 if (result != null && result.isFinished())
178 SequenceI[] alseqs = null;
179 // char alseq_gapchar = '-';
181 if (((SeqSearchResult) result).getAlignment() != null)
183 alseqs = getVamsasAlignment(
184 ((SeqSearchResult) result).getAlignment());
185 // alseq_gapchar = ( (SeqSearchResult)
186 // result).getAlignment().getGapchar().charAt(0);
187 // alseq_l = alseqs.length;
190 * what has to be done. 1 - annotate returned alignment with annotation
191 * file and sequence features file, and associate any tree-nodes. 2.
192 * connect alignment back to any associated dataset: 2.a. deuniquify
193 * recovers sequence information - but additionally, relocations must be
194 * made from the returned aligned sequence back to the dataset.
196 // construct annotated alignment as it would be done by the jalview
198 jalview.datamodel.Alignment al = new Alignment(alseqs);
199 // al.setDataset(dataset);
201 String inFile = null;
204 inFile = ((SeqSearchResult) result).getAnnotation();
205 if (inFile != null && inFile.length() > 0)
207 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
208 jalview.io.DataSourceType.PASTE);
210 } catch (Exception e)
213 "Failed to parse the annotation file associated with the alignment.");
214 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
215 e.printStackTrace(System.err);
220 inFile = ((SeqSearchResult) result).getFeatures();
221 if (inFile != null && inFile.length() > 0)
223 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(inFile,
224 jalview.io.DataSourceType.PASTE);
225 ff.parse(al, featureColours, false);
227 } catch (Exception e)
230 "Failed to parse the Features file associated with the alignment.");
231 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
232 e.printStackTrace(System.err);
234 jalview.io.NewickFile nf = null;
237 inFile = ((SeqSearchResult) result).getNewickTree();
238 if (inFile != null && inFile.length() > 0)
240 nf = new jalview.io.NewickFile(inFile,
241 jalview.io.DataSourceType.PASTE);
248 } catch (Exception e)
251 "Failed to parse the treeFile associated with the alignment.");
252 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
253 e.printStackTrace(System.err);
257 * TODO: housekeeping w.r.t. recovery of dataset and annotation
258 * references for input sequences, and then dataset sequence creation
259 * for new sequences retrieved from service // finally, attempt to
260 * de-uniquify to recover input sequence identity, and try to map back
261 * onto dataset Note: this
262 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
263 * NOT WORK - the returned alignment may contain multiple versions of
264 * the input sequence, each being a subsequence of the original.
265 * deuniquify also removes existing annotation and features added in the
266 * previous step... al.setDataset(dataset); // add in new sequences
267 * retrieved from sequence search which are not already in dataset. //
268 * trigger a 'fetchDBids' to annotate sequences with database ids...
271 return new Object[] { al, nf };
277 * mark subjob as cancelled and set result object appropriatly
282 subjobComplete = true;
288 * @return boolean true if job can be submitted.
291 public boolean hasValidInput()
293 if (seqs.getSeqs() != null)
301 String alTitle; // name which will be used to form new alignment window.
303 AlignmentI dataset; // dataset to which the new alignment will be
307 ext.vamsas.SeqSearchI server = null;
309 private String dbArg;
312 * set basic options for this (group) of Msa jobs
319 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
320 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
321 AlignmentView alview, String wsname, String db)
323 super(alFrame, wsinfo, alview, wsname, wsUrl);
324 this.server = server;
329 * create one or more Msa jobs to align visible seuqences in _msa
342 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
343 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
344 String wsname, String title, AlignmentView _msa, String db,
347 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
348 OutputHeader = wsInfo.getProgressText();
352 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
355 int njobs = conmsa.length;
356 jobs = new SeqSearchWSJob[njobs];
357 for (int j = 0; j < njobs; j++)
361 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
365 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
369 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
370 jobs[j].getJobnum());
372 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
378 public boolean isCancellable()
384 public void cancelJob()
386 if (!jobComplete && jobs != null)
388 boolean cancelled = true;
389 for (int job = 0; job < jobs.length; job++)
391 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
393 String cancelledMessage = "";
396 vamsas.objects.simple.WsJobId cancelledJob = server
397 .cancel(jobs[job].getJobId());
398 if (cancelledJob.getStatus() == 2)
401 cancelledMessage = "Job cancelled.";
402 ((SeqSearchWSJob) jobs[job]).cancel();
403 wsInfo.setStatus(jobs[job].getJobnum(),
404 WebserviceInfo.STATE_CANCELLED_OK);
406 else if (cancelledJob.getStatus() == 3)
408 // VALID UNSTOPPABLE JOB
409 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
411 // wsInfo.setStatus(jobs[job].jobnum,
412 // WebserviceInfo.STATE_RUNNING);
415 if (cancelledJob.getJobId() != null)
417 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
420 cancelledMessage += "\n";
421 } catch (Exception exc)
423 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
426 "Exception whilst cancelling " + jobs[job].getJobId(),
429 wsInfo.setProgressText(jobs[job].getJobnum(),
430 OutputHeader + cancelledMessage + "\n");
435 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
438 this.interrupt(); // kick thread to update job states.
444 wsInfo.setProgressText(OutputHeader
445 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
451 public void pollJob(AWsJob job) throws Exception
453 ((SeqSearchWSJob) job).result = server
454 .getResult(((SeqSearchWSJob) job).getJobId());
458 public void StartJob(AWsJob job)
460 if (!(job instanceof SeqSearchWSJob))
462 throw new Error(MessageManager.formatMessage(
463 "error.implementation_error_msawbjob_called", new String[]
464 { job.getClass().toString() }));
466 SeqSearchWSJob j = (SeqSearchWSJob) job;
469 if (Cache.log.isDebugEnabled())
472 "Tried to submit an already submitted job " + j.getJobId());
476 if (j.seqs.getSeqs() == null)
478 // special case - selection consisted entirely of empty sequences...
479 j.setSubmitted(true);
480 j.result = new MsaResult();
481 j.result.setFinished(true);
483 MessageManager.getString("label.empty_alignment_job"));
484 ((MsaResult) j.result).setMsa(null);
488 vamsas.objects.simple.WsJobId jobsubmit = server
489 .search(j.seqs.getSeqs()[0], dbArg);
491 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
493 j.setJobId(jobsubmit.getJobId());
494 j.setSubmitted(true);
495 j.setSubjobComplete(false);
496 // System.out.println(WsURL + " Job Id '" + jobId + "'");
500 if (jobsubmit == null)
502 throw new Exception(MessageManager.formatMessage(
503 "exception.web_service_returned_null_try_later",
508 throw new Exception(jobsubmit.getJobId());
510 } catch (Exception e)
512 // TODO: JBPNote catch timeout or other fault types explicitly
513 // For unexpected errors
514 System.err.println(WebServiceName
515 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
516 + "When contacting Server:" + WsUrl + "\n" + e.toString()
518 j.setAllowedServerExceptions(0);
519 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
520 wsInfo.setStatus(j.getJobnum(),
521 WebserviceInfo.STATE_STOPPED_SERVERERROR);
522 wsInfo.appendProgressText(j.getJobnum(), MessageManager
523 .getString("info.failed_to_submit_sequences_for_alignment"));
525 // e.printStackTrace(); // TODO: JBPNote DEBUG
529 private jalview.datamodel.Sequence[] getVamsasAlignment(
530 vamsas.objects.simple.Alignment valign)
532 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
533 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
535 for (int i = 0, j = seqs.length; i < j; i++)
537 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
545 public void parseResult()
547 int results = 0; // number of result sets received
548 JobStateSummary finalState = new JobStateSummary();
551 for (int j = 0; j < jobs.length; j++)
553 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
554 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
555 && jobs[j].hasResults())
558 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
562 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
563 .getString("info.alignment_object_method_notes"));
564 String[] lines = valign.getMethod();
565 for (int line = 0; line < lines.length; line++)
567 wsInfo.appendProgressText(jobs[j].getJobnum(),
570 // JBPNote The returned files from a webservice could be
571 // hidden behind icons in the monitor window that,
572 // when clicked, pop up their corresponding data
576 } catch (Exception ex)
580 "Unexpected exception when processing results for " + alTitle,
582 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
586 wsInfo.showResultsNewFrame
587 .addActionListener(new java.awt.event.ActionListener()
590 public void actionPerformed(java.awt.event.ActionEvent evt)
592 displayResults(true);
596 .addActionListener(new java.awt.event.ActionListener()
599 public void actionPerformed(java.awt.event.ActionEvent evt)
601 displayResults(false);
604 wsInfo.setResultsReady();
608 wsInfo.setFinishedNoResults();
612 void displayResults(boolean newFrame)
616 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
619 // each subjob is an independent alignment for the moment
620 // Alignment al[] = new Alignment[jobs.length];
621 // NewickFile nf[] = new NewickFile[jobs.length];
622 for (int j = 0; j < jobs.length; j++)
624 Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
626 NewickFile nf = null;
627 if (jobs[j].hasResults())
629 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
636 al = (Alignment) res[0];
637 nf = (NewickFile) res[1];
646 * We can't map new alignment back with insertions from input's hidden
647 * regions until dataset mapping is sorted out... but basically it goes
648 * like this: 1. Merge each domain hit back onto the visible segments in
649 * the same way as a Jnet prediction is mapped back
651 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
652 * // trash references to original result data for (int j = 0; j <
653 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
654 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
655 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
657 * if (dataset != null) { al.setDataset(dataset); }
659 * propagateDatasetMappings(al); }
662 AlignFrame af = new AlignFrame(al, // columnselection,
663 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
666 af.showNewickTree(nf,
667 MessageManager.formatMessage("label.tree_from", new String[]
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);
678 public boolean canMergeResults()