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.analysis.SeqsetUtils;
25 import jalview.bin.Cache;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentView;
28 import jalview.datamodel.Sequence;
29 import jalview.datamodel.SequenceI;
30 import jalview.gui.AlignFrame;
31 import jalview.gui.Desktop;
32 import jalview.gui.WebserviceInfo;
33 import jalview.io.AnnotationFile;
34 import jalview.io.AppletFormatAdapter;
35 import jalview.io.FeaturesFile;
36 import jalview.io.NewickFile;
37 import jalview.util.Comparison;
38 import jalview.util.MessageManager;
39 import jalview.ws.AWsJob;
40 import jalview.ws.JobStateSummary;
41 import jalview.ws.WSClientI;
43 import java.util.Hashtable;
44 import java.util.Vector;
46 import vamsas.objects.simple.MsaResult;
47 import vamsas.objects.simple.SeqSearchResult;
49 class SeqSearchWSThread extends JWS1Thread implements WSClientI
53 boolean profile = false;
55 class SeqSearchWSJob extends WSJob
57 // hold special input for this
58 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
68 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
71 if (!prepareInput(inSeqs, 2))
74 subjobComplete = true;
75 result = new MsaResult();
76 result.setFinished(true);
77 result.setStatus(MessageManager.getString("label.job_never_ran"));
82 Hashtable SeqNames = new Hashtable();
84 Vector emptySeqs = new Vector();
87 * prepare input sequences for service
90 * jalview sequences to be prepared
92 * minimum number of residues required for this MsaWS service
93 * @return true if seqs contains sequences to be submitted to service.
95 private boolean prepareInput(SequenceI[] seqs, int minlen)
100 throw new Error(MessageManager.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 = SeqsetUtils.unique_name(i); // same
122 SeqNames.put(newname, SeqsetUtils.SeqCharacterHash(seqs[i]));
123 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
125 seqarray[n] = new vamsas.objects.simple.Sequence();
126 seqarray[n].setId(newname);
127 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
128 : AlignSeq.extractGaps(Comparison.GapChars,
129 seqs[i].getSequenceAsString()));
134 if (seqs[i].getEnd() >= seqs[i].getStart())
136 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
137 .extractGaps(Comparison.GapChars,
138 seqs[i].getSequenceAsString());
140 emptySeqs.add(new String[]
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.
157 public boolean hasResults()
161 && result.isFinished()
162 && ((SeqSearchResult) result).getAlignment() != null
163 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
171 * return sequence search results for display
173 * @return null or { Alignment(+features and annotation), NewickFile)}
175 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
178 if (result != null && result.isFinished())
180 SequenceI[] alseqs = null;
181 // char alseq_gapchar = '-';
183 if (((SeqSearchResult) result).getAlignment() != null)
185 alseqs = getVamsasAlignment(((SeqSearchResult) result)
187 // alseq_gapchar = ( (SeqSearchResult)
188 // result).getAlignment().getGapchar().charAt(0);
189 // alseq_l = alseqs.length;
192 * what has to be done. 1 - annotate returned alignment with annotation
193 * file and sequence features file, and associate any tree-nodes. 2.
194 * connect alignment back to any associated dataset: 2.a. deuniquify
195 * recovers sequence information - but additionally, relocations must be
196 * made from the returned aligned sequence back to the dataset.
198 // construct annotated alignment as it would be done by the jalview
200 Alignment al = new Alignment(alseqs);
201 // al.setDataset(dataset);
203 String inFile = null;
206 inFile = ((SeqSearchResult) result).getAnnotation();
207 if (inFile != null && inFile.length() > 0)
209 new AnnotationFile().readAnnotationFile(al, inFile,
210 AppletFormatAdapter.PASTE);
212 } catch (Exception e)
215 .println("Failed to parse the annotation file associated with the alignment.");
216 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
217 e.printStackTrace(System.err);
222 inFile = ((SeqSearchResult) result).getFeatures();
223 if (inFile != null && inFile.length() > 0)
225 FeaturesFile ff = new FeaturesFile(inFile,
226 AppletFormatAdapter.PASTE);
227 ff.parse(al, featureColours, false);
229 } catch (Exception e)
232 .println("Failed to parse the Features file associated with the alignment.");
233 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
234 e.printStackTrace(System.err);
236 NewickFile nf = null;
239 inFile = ((SeqSearchResult) result).getNewickTree();
240 if (inFile != null && inFile.length() > 0)
242 nf = new NewickFile(inFile, AppletFormatAdapter.PASTE);
249 } catch (Exception e)
252 .println("Failed to parse the treeFile associated with the alignment.");
253 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
254 e.printStackTrace(System.err);
258 * TODO: housekeeping w.r.t. recovery of dataset and annotation
259 * references for input sequences, and then dataset sequence creation
260 * for new sequences retrieved from service // finally, attempt to
261 * de-uniquify to recover input sequence identity, and try to map back
262 * onto dataset Note: this
263 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
264 * NOT WORK - the returned alignment may contain multiple versions of
265 * the input sequence, each being a subsequence of the original.
266 * deuniquify also removes existing annotation and features added in the
267 * previous step... al.setDataset(dataset); // add in new sequences
268 * retrieved from sequence search which are not already in dataset. //
269 * trigger a 'fetchDBids' to annotate sequences with database ids...
279 * mark subjob as cancelled and set result object appropriatly
284 subjobComplete = true;
290 * @return boolean true if job can be submitted.
292 public boolean hasValidInput()
294 if (seqs.getSeqs() != null)
302 String alTitle; // name which will be used to form new alignment window.
304 Alignment dataset; // dataset to which the new alignment will be
308 ext.vamsas.SeqSearchI server = null;
310 private String dbArg;
313 * set basic options for this (group) of Msa jobs
320 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
321 WebserviceInfo wsinfo, AlignFrame alFrame,
322 AlignmentView alview, String wsname, String db)
324 super(alFrame, wsinfo, alview, wsname, wsUrl);
325 this.server = server;
330 * create one or more Msa jobs to align visible seuqences in _msa
343 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
344 WebserviceInfo wsinfo, AlignFrame alFrame,
345 String wsname, String title, AlignmentView _msa, String db,
348 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
349 OutputHeader = wsInfo.getProgressText();
353 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
356 int njobs = conmsa.length;
357 jobs = new SeqSearchWSJob[njobs];
358 for (int j = 0; j < njobs; j++)
362 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
366 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
370 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
371 jobs[j].getJobnum());
373 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
378 public boolean isCancellable()
383 public void cancelJob()
385 if (!jobComplete && jobs != null)
387 boolean cancelled = true;
388 for (int job = 0; job < jobs.length; job++)
390 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
392 String cancelledMessage = "";
395 vamsas.objects.simple.WsJobId cancelledJob = server
396 .cancel(jobs[job].getJobId());
397 if (cancelledJob.getStatus() == 2)
400 cancelledMessage = "Job cancelled.";
401 ((SeqSearchWSJob) jobs[job]).cancel();
402 wsInfo.setStatus(jobs[job].getJobnum(),
403 WebserviceInfo.STATE_CANCELLED_OK);
405 else if (cancelledJob.getStatus() == 3)
407 // VALID UNSTOPPABLE JOB
408 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
410 // wsInfo.setStatus(jobs[job].jobnum,
411 // WebserviceInfo.STATE_RUNNING);
414 if (cancelledJob.getJobId() != null)
416 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
419 cancelledMessage += "\n";
420 } catch (Exception exc)
422 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
425 "Exception whilst cancelling " + jobs[job].getJobId(),
428 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
429 + cancelledMessage + "\n");
434 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
437 this.interrupt(); // kick thread to update job states.
443 wsInfo.setProgressText(OutputHeader
444 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
449 public void pollJob(AWsJob job) throws Exception
451 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
455 public void StartJob(AWsJob job)
457 if (!(job instanceof SeqSearchWSJob))
459 throw new Error(MessageManager.formatMessage("error.implementation_error_msawbjob_called", new String[]{job.getClass().toString()}));
461 SeqSearchWSJob j = (SeqSearchWSJob) job;
464 if (Cache.log.isDebugEnabled())
466 Cache.log.debug("Tried to submit an already submitted job "
471 if (j.seqs.getSeqs() == null)
473 // special case - selection consisted entirely of empty sequences...
474 j.setSubmitted(true);
475 j.result = new MsaResult();
476 j.result.setFinished(true);
477 j.result.setStatus(MessageManager.getString("label.empty_alignment_job"));
478 ((MsaResult) j.result).setMsa(null);
482 vamsas.objects.simple.WsJobId jobsubmit = server.search(
483 j.seqs.getSeqs()[0], dbArg);
485 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
487 j.setJobId(jobsubmit.getJobId());
488 j.setSubmitted(true);
489 j.setSubjobComplete(false);
490 // System.out.println(WsURL + " Job Id '" + jobId + "'");
494 if (jobsubmit == null)
496 throw new Exception(MessageManager.formatMessage("exception.web_service_returned_null_try_later", new String[]{WsUrl}));
499 throw new Exception(jobsubmit.getJobId());
501 } catch (Exception e)
503 // TODO: JBPNote catch timeout or other fault types explicitly
504 // For unexpected errors
506 .println(WebServiceName
507 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
508 + "When contacting Server:" + WsUrl + "\n"
509 + e.toString() + "\n");
510 j.setAllowedServerExceptions(0);
511 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
512 wsInfo.setStatus(j.getJobnum(),
513 WebserviceInfo.STATE_STOPPED_SERVERERROR);
514 wsInfo.appendProgressText(
516 MessageManager.getString("info.failed_to_submit_sequences_for_alignment"));
518 // e.printStackTrace(); // TODO: JBPNote DEBUG
522 private Sequence[] getVamsasAlignment(
523 vamsas.objects.simple.Alignment valign)
525 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
526 Sequence[] msa = new Sequence[seqs.length];
528 for (int i = 0, j = seqs.length; i < j; i++)
530 msa[i] = new Sequence(seqs[i].getId(),
537 public void parseResult()
539 int results = 0; // number of result sets received
540 JobStateSummary finalState = new JobStateSummary();
543 for (int j = 0; j < jobs.length; j++)
545 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
546 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
547 && jobs[j].hasResults())
550 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
554 wsInfo.appendProgressText(jobs[j].getJobnum(),
555 MessageManager.getString("info.alignment_object_method_notes"));
556 String[] lines = valign.getMethod();
557 for (int line = 0; line < lines.length; line++)
559 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
562 // JBPNote The returned files from a webservice could be
563 // hidden behind icons in the monitor window that,
564 // when clicked, pop up their corresponding data
568 } catch (Exception ex)
571 Cache.log.error("Unexpected exception when processing results for "
573 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
577 wsInfo.showResultsNewFrame
578 .addActionListener(new java.awt.event.ActionListener()
580 public void actionPerformed(java.awt.event.ActionEvent evt)
582 displayResults(true);
586 .addActionListener(new java.awt.event.ActionListener()
588 public void actionPerformed(java.awt.event.ActionEvent evt)
590 displayResults(false);
593 wsInfo.setResultsReady();
597 wsInfo.setFinishedNoResults();
601 void displayResults(boolean newFrame)
605 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
608 // each subjob is an independent alignment for the moment
609 // Alignment al[] = new Alignment[jobs.length];
610 // NewickFile nf[] = new NewickFile[jobs.length];
611 for (int j = 0; j < jobs.length; j++)
613 Hashtable featureColours = new Hashtable();
615 NewickFile nf = null;
616 if (jobs[j].hasResults())
618 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
625 al = (Alignment) res[0];
626 nf = (NewickFile) res[1];
635 * We can't map new alignment back with insertions from input's hidden
636 * regions until dataset mapping is sorted out... but basically it goes
637 * like this: 1. Merge each domain hit back onto the visible segments in
638 * the same way as a Jnet prediction is mapped back
640 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
641 * // trash references to original result data for (int j = 0; j <
642 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
643 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
644 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
646 * if (dataset != null) { al.setDataset(dataset); }
648 * propagateDatasetMappings(al); }
651 AlignFrame af = new AlignFrame(al,// columnselection,
652 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
655 af.ShowNewickTree(nf, MessageManager.formatMessage("label.tree_from", new String[]{this.alTitle}));
657 // initialise with same renderer settings as in parent alignframe.
658 af.getFeatureRenderer().transferSettings(this.featureSettings);
659 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
660 AlignFrame.DEFAULT_HEIGHT);
664 public boolean canMergeResults()