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.bin.Cache;
25 import jalview.datamodel.Alignment;
26 import jalview.datamodel.AlignmentView;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.AlignFrame;
29 import jalview.gui.Desktop;
30 import jalview.gui.WebserviceInfo;
31 import jalview.io.NewickFile;
32 import jalview.util.MessageManager;
33 import jalview.ws.AWsJob;
34 import jalview.ws.JobStateSummary;
35 import jalview.ws.WSClientI;
37 import java.util.HashMap;
38 import java.util.Hashtable;
40 import java.util.Vector;
42 import vamsas.objects.simple.MsaResult;
43 import vamsas.objects.simple.SeqSearchResult;
45 class SeqSearchWSThread extends JWS1Thread implements WSClientI
49 boolean profile = false;
51 class SeqSearchWSJob extends WSJob
53 // hold special input for this
54 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
64 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
67 if (!prepareInput(inSeqs, 2))
70 subjobComplete = true;
71 result = new MsaResult();
72 result.setFinished(true);
73 result.setStatus(MessageManager.getString("label.job_never_ran"));
78 Hashtable SeqNames = new Hashtable();
80 Vector emptySeqs = new Vector();
83 * prepare input sequences for service
86 * jalview sequences to be prepared
88 * minimum number of residues required for this MsaWS service
89 * @return true if seqs contains sequences to be submitted to service.
91 private boolean prepareInput(SequenceI[] seqs, int minlen)
98 .getString("error.implementation_error_minlen_must_be_greater_zero"));
100 for (int i = 0; i < seqs.length; i++)
102 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
107 boolean valid = nseqs >= 1; // need at least one sequence for valid input
109 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
111 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
113 for (int i = 0, n = 0; i < seqs.length; i++)
116 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
120 SeqNames.put(newname,
121 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
122 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
124 seqarray[n] = new vamsas.objects.simple.Sequence();
125 seqarray[n].setId(newname);
126 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
127 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
128 seqs[i].getSequenceAsString()));
133 if (seqs[i].getEnd() >= seqs[i].getStart())
135 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
136 .extractGaps(jalview.util.Comparison.GapChars,
137 seqs[i].getSequenceAsString());
139 emptySeqs.add(new String[] { newname, empty });
144 // almost certainly have to remove gapped columns here
146 this.seqs = new vamsas.objects.simple.SequenceSet();
147 this.seqs.setSeqs(seqarray);
153 * @return true if getAlignment will return a valid alignment result.
156 public boolean hasResults()
160 && result.isFinished()
161 && ((SeqSearchResult) result).getAlignment() != null
162 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
170 * return sequence search results for display
172 * @return null or { Alignment(+features and annotation), NewickFile)}
174 public Object[] getAlignment(Alignment dataset,
175 Map<String, Object> 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 jalview.datamodel.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 jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
210 jalview.io.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 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
226 inFile, jalview.io.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 jalview.io.NewickFile nf = null;
239 inFile = ((SeqSearchResult) result).getNewickTree();
240 if (inFile != null && inFile.length() > 0)
242 nf = new jalview.io.NewickFile(inFile,
243 jalview.io.AppletFormatAdapter.PASTE);
250 } catch (Exception e)
253 .println("Failed to parse the treeFile associated with the alignment.");
254 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
255 e.printStackTrace(System.err);
259 * TODO: housekeeping w.r.t. recovery of dataset and annotation
260 * references for input sequences, and then dataset sequence creation
261 * for new sequences retrieved from service // finally, attempt to
262 * de-uniquify to recover input sequence identity, and try to map back
263 * onto dataset Note: this
264 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
265 * NOT WORK - the returned alignment may contain multiple versions of
266 * the input sequence, each being a subsequence of the original.
267 * deuniquify also removes existing annotation and features added in the
268 * previous step... al.setDataset(dataset); // add in new sequences
269 * retrieved from sequence search which are not already in dataset. //
270 * trigger a 'fetchDBids' to annotate sequences with database ids...
273 return new Object[] { al, nf };
279 * mark subjob as cancelled and set result object appropriatly
284 subjobComplete = true;
290 * @return boolean true if job can be submitted.
293 public boolean hasValidInput()
295 if (seqs.getSeqs() != null)
303 String alTitle; // name which will be used to form new alignment window.
305 Alignment dataset; // dataset to which the new alignment will be
309 ext.vamsas.SeqSearchI server = null;
311 private String dbArg;
314 * set basic options for this (group) of Msa jobs
321 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
322 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
323 AlignmentView alview, String wsname, String db)
325 super(alFrame, wsinfo, alview, wsname, wsUrl);
326 this.server = server;
331 * create one or more Msa jobs to align visible seuqences in _msa
344 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
345 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
346 String wsname, String title, AlignmentView _msa, String db,
349 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
350 OutputHeader = wsInfo.getProgressText();
354 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
357 int njobs = conmsa.length;
358 jobs = new SeqSearchWSJob[njobs];
359 for (int j = 0; j < njobs; j++)
363 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
367 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
371 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
372 jobs[j].getJobnum());
374 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
380 public boolean isCancellable()
386 public void cancelJob()
388 if (!jobComplete && jobs != null)
390 boolean cancelled = true;
391 for (int job = 0; job < jobs.length; job++)
393 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
395 String cancelledMessage = "";
398 vamsas.objects.simple.WsJobId cancelledJob = server
399 .cancel(jobs[job].getJobId());
400 if (cancelledJob.getStatus() == 2)
403 cancelledMessage = "Job cancelled.";
404 ((SeqSearchWSJob) jobs[job]).cancel();
405 wsInfo.setStatus(jobs[job].getJobnum(),
406 WebserviceInfo.STATE_CANCELLED_OK);
408 else if (cancelledJob.getStatus() == 3)
410 // VALID UNSTOPPABLE JOB
411 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
413 // wsInfo.setStatus(jobs[job].jobnum,
414 // WebserviceInfo.STATE_RUNNING);
417 if (cancelledJob.getJobId() != null)
419 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
422 cancelledMessage += "\n";
423 } catch (Exception exc)
425 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
428 "Exception whilst cancelling " + jobs[job].getJobId(),
431 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
432 + cancelledMessage + "\n");
437 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
440 this.interrupt(); // kick thread to update job states.
446 wsInfo.setProgressText(OutputHeader
447 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
453 public void pollJob(AWsJob job) throws Exception
455 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
460 public void StartJob(AWsJob job)
462 if (!(job instanceof SeqSearchWSJob))
464 throw new Error(MessageManager.formatMessage(
465 "error.implementation_error_msawbjob_called",
466 new String[] { job.getClass().toString() }));
468 SeqSearchWSJob j = (SeqSearchWSJob) job;
471 if (Cache.log.isDebugEnabled())
473 Cache.log.debug("Tried to submit an already submitted job "
478 if (j.seqs.getSeqs() == null)
480 // special case - selection consisted entirely of empty sequences...
481 j.setSubmitted(true);
482 j.result = new MsaResult();
483 j.result.setFinished(true);
484 j.result.setStatus(MessageManager
485 .getString("label.empty_alignment_job"));
486 ((MsaResult) j.result).setMsa(null);
490 vamsas.objects.simple.WsJobId jobsubmit = server.search(
491 j.seqs.getSeqs()[0], dbArg);
493 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
495 j.setJobId(jobsubmit.getJobId());
496 j.setSubmitted(true);
497 j.setSubjobComplete(false);
498 // System.out.println(WsURL + " Job Id '" + jobId + "'");
502 if (jobsubmit == null)
504 throw new Exception(MessageManager.formatMessage(
505 "exception.web_service_returned_null_try_later",
506 new String[] { WsUrl }));
509 throw new Exception(jobsubmit.getJobId());
511 } catch (Exception e)
513 // TODO: JBPNote catch timeout or other fault types explicitly
514 // For unexpected errors
516 .println(WebServiceName
517 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
518 + "When contacting Server:" + WsUrl + "\n"
519 + e.toString() + "\n");
520 j.setAllowedServerExceptions(0);
521 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
522 wsInfo.setStatus(j.getJobnum(),
523 WebserviceInfo.STATE_STOPPED_SERVERERROR);
524 wsInfo.appendProgressText(j.getJobnum(), MessageManager
525 .getString("info.failed_to_submit_sequences_for_alignment"));
527 // e.printStackTrace(); // TODO: JBPNote DEBUG
531 private jalview.datamodel.Sequence[] getVamsasAlignment(
532 vamsas.objects.simple.Alignment valign)
534 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
535 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
537 for (int i = 0, j = seqs.length; i < j; i++)
539 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
547 public void parseResult()
549 int results = 0; // number of result sets received
550 JobStateSummary finalState = new JobStateSummary();
553 for (int j = 0; j < jobs.length; j++)
555 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
556 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
557 && jobs[j].hasResults())
560 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
564 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
565 .getString("info.alignment_object_method_notes"));
566 String[] lines = valign.getMethod();
567 for (int line = 0; line < lines.length; line++)
569 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
572 // JBPNote The returned files from a webservice could be
573 // hidden behind icons in the monitor window that,
574 // when clicked, pop up their corresponding data
578 } catch (Exception ex)
581 Cache.log.error("Unexpected exception when processing results for "
583 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
587 wsInfo.showResultsNewFrame
588 .addActionListener(new java.awt.event.ActionListener()
591 public void actionPerformed(java.awt.event.ActionEvent evt)
593 displayResults(true);
597 .addActionListener(new java.awt.event.ActionListener()
600 public void actionPerformed(java.awt.event.ActionEvent evt)
602 displayResults(false);
605 wsInfo.setResultsReady();
609 wsInfo.setFinishedNoResults();
613 void displayResults(boolean newFrame)
617 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
620 // each subjob is an independent alignment for the moment
621 // Alignment al[] = new Alignment[jobs.length];
622 // NewickFile nf[] = new NewickFile[jobs.length];
623 for (int j = 0; j < jobs.length; j++)
625 Map<String, Object> featureColours = new HashMap<String, Object>();
627 NewickFile nf = null;
628 if (jobs[j].hasResults())
630 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
637 al = (Alignment) res[0];
638 nf = (NewickFile) res[1];
647 * We can't map new alignment back with insertions from input's hidden
648 * regions until dataset mapping is sorted out... but basically it goes
649 * like this: 1. Merge each domain hit back onto the visible segments in
650 * the same way as a Jnet prediction is mapped back
652 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
653 * // trash references to original result data for (int j = 0; j <
654 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
655 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
656 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
658 * if (dataset != null) { al.setDataset(dataset); }
660 * propagateDatasetMappings(al); }
663 AlignFrame af = new AlignFrame(al,// columnselection,
664 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
667 af.ShowNewickTree(nf, MessageManager.formatMessage(
668 "label.tree_from", new String[] { this.alTitle }));
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()