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.Hashtable;
38 import java.util.Vector;
40 import vamsas.objects.simple.MsaResult;
41 import vamsas.objects.simple.SeqSearchResult;
43 class SeqSearchWSThread extends JWS1Thread implements WSClientI
47 boolean profile = false;
49 class SeqSearchWSJob extends WSJob
51 // hold special input for this
52 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
62 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
65 if (!prepareInput(inSeqs, 2))
68 subjobComplete = true;
69 result = new MsaResult();
70 result.setFinished(true);
71 result.setStatus(MessageManager.getString("label.job_never_ran"));
76 Hashtable SeqNames = new Hashtable();
78 Vector emptySeqs = new Vector();
81 * prepare input sequences for service
84 * jalview sequences to be prepared
86 * minimum number of residues required for this MsaWS service
87 * @return true if seqs contains sequences to be submitted to service.
89 private boolean prepareInput(SequenceI[] seqs, int minlen)
96 .getString("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) ? new vamsas.objects.simple.Sequence[nseqs]
109 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
111 for (int i = 0, n = 0; i < seqs.length; i++)
114 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
118 SeqNames.put(newname,
119 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
120 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
122 seqarray[n] = new vamsas.objects.simple.Sequence();
123 seqarray[n].setId(newname);
124 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
125 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
126 seqs[i].getSequenceAsString()));
131 if (seqs[i].getEnd() >= seqs[i].getStart())
133 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
134 .extractGaps(jalview.util.Comparison.GapChars,
135 seqs[i].getSequenceAsString());
137 emptySeqs.add(new String[] { newname, empty });
142 // almost certainly have to remove gapped columns here
144 this.seqs = new vamsas.objects.simple.SequenceSet();
145 this.seqs.setSeqs(seqarray);
151 * @return true if getAlignment will return a valid alignment result.
153 public boolean hasResults()
157 && result.isFinished()
158 && ((SeqSearchResult) result).getAlignment() != null
159 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
167 * return sequence search results for display
169 * @return null or { Alignment(+features and annotation), NewickFile)}
171 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
174 if (result != null && result.isFinished())
176 SequenceI[] alseqs = null;
177 // char alseq_gapchar = '-';
179 if (((SeqSearchResult) result).getAlignment() != null)
181 alseqs = getVamsasAlignment(((SeqSearchResult) result)
183 // alseq_gapchar = ( (SeqSearchResult)
184 // result).getAlignment().getGapchar().charAt(0);
185 // alseq_l = alseqs.length;
188 * what has to be done. 1 - annotate returned alignment with annotation
189 * file and sequence features file, and associate any tree-nodes. 2.
190 * connect alignment back to any associated dataset: 2.a. deuniquify
191 * recovers sequence information - but additionally, relocations must be
192 * made from the returned aligned sequence back to the dataset.
194 // construct annotated alignment as it would be done by the jalview
196 jalview.datamodel.Alignment al = new Alignment(alseqs);
197 // al.setDataset(dataset);
199 String inFile = null;
202 inFile = ((SeqSearchResult) result).getAnnotation();
203 if (inFile != null && inFile.length() > 0)
205 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
206 jalview.io.AppletFormatAdapter.PASTE);
208 } catch (Exception e)
211 .println("Failed to parse the annotation file associated with the alignment.");
212 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
213 e.printStackTrace(System.err);
218 inFile = ((SeqSearchResult) result).getFeatures();
219 if (inFile != null && inFile.length() > 0)
221 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
222 inFile, jalview.io.AppletFormatAdapter.PASTE);
223 ff.parse(al, featureColours, false);
225 } catch (Exception e)
228 .println("Failed to parse the Features file associated with the alignment.");
229 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
230 e.printStackTrace(System.err);
232 jalview.io.NewickFile nf = null;
235 inFile = ((SeqSearchResult) result).getNewickTree();
236 if (inFile != null && inFile.length() > 0)
238 nf = new jalview.io.NewickFile(inFile,
239 jalview.io.AppletFormatAdapter.PASTE);
246 } catch (Exception e)
249 .println("Failed to parse the treeFile associated with the alignment.");
250 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
251 e.printStackTrace(System.err);
255 * TODO: housekeeping w.r.t. recovery of dataset and annotation
256 * references for input sequences, and then dataset sequence creation
257 * for new sequences retrieved from service // finally, attempt to
258 * de-uniquify to recover input sequence identity, and try to map back
259 * onto dataset Note: this
260 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
261 * NOT WORK - the returned alignment may contain multiple versions of
262 * the input sequence, each being a subsequence of the original.
263 * deuniquify also removes existing annotation and features added in the
264 * previous step... al.setDataset(dataset); // add in new sequences
265 * retrieved from sequence search which are not already in dataset. //
266 * trigger a 'fetchDBids' to annotate sequences with database ids...
269 return new Object[] { al, nf };
275 * mark subjob as cancelled and set result object appropriatly
280 subjobComplete = true;
286 * @return boolean true if job can be submitted.
288 public boolean hasValidInput()
290 if (seqs.getSeqs() != null)
298 String alTitle; // name which will be used to form new alignment window.
300 Alignment dataset; // dataset to which the new alignment will be
304 ext.vamsas.SeqSearchI server = null;
306 private String dbArg;
309 * set basic options for this (group) of Msa jobs
316 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
317 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
318 AlignmentView alview, String wsname, String db)
320 super(alFrame, wsinfo, alview, wsname, wsUrl);
321 this.server = server;
326 * create one or more Msa jobs to align visible seuqences in _msa
339 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
340 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
341 String wsname, String title, AlignmentView _msa, String db,
344 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
345 OutputHeader = wsInfo.getProgressText();
349 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
352 int njobs = conmsa.length;
353 jobs = new SeqSearchWSJob[njobs];
354 for (int j = 0; j < njobs; j++)
358 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
362 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
366 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
367 jobs[j].getJobnum());
369 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
374 public boolean isCancellable()
379 public void cancelJob()
381 if (!jobComplete && jobs != null)
383 boolean cancelled = true;
384 for (int job = 0; job < jobs.length; job++)
386 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
388 String cancelledMessage = "";
391 vamsas.objects.simple.WsJobId cancelledJob = server
392 .cancel(jobs[job].getJobId());
393 if (cancelledJob.getStatus() == 2)
396 cancelledMessage = "Job cancelled.";
397 ((SeqSearchWSJob) jobs[job]).cancel();
398 wsInfo.setStatus(jobs[job].getJobnum(),
399 WebserviceInfo.STATE_CANCELLED_OK);
401 else if (cancelledJob.getStatus() == 3)
403 // VALID UNSTOPPABLE JOB
404 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
406 // wsInfo.setStatus(jobs[job].jobnum,
407 // WebserviceInfo.STATE_RUNNING);
410 if (cancelledJob.getJobId() != null)
412 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
415 cancelledMessage += "\n";
416 } catch (Exception exc)
418 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
421 "Exception whilst cancelling " + jobs[job].getJobId(),
424 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
425 + cancelledMessage + "\n");
430 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
433 this.interrupt(); // kick thread to update job states.
439 wsInfo.setProgressText(OutputHeader
440 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
445 public void pollJob(AWsJob job) throws Exception
447 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
451 public void StartJob(AWsJob job)
453 if (!(job instanceof SeqSearchWSJob))
455 throw new Error(MessageManager.formatMessage(
456 "error.implementation_error_msawbjob_called",
457 new String[] { job.getClass().toString() }));
459 SeqSearchWSJob j = (SeqSearchWSJob) job;
462 if (Cache.log.isDebugEnabled())
464 Cache.log.debug("Tried to submit an already submitted job "
469 if (j.seqs.getSeqs() == null)
471 // special case - selection consisted entirely of empty sequences...
472 j.setSubmitted(true);
473 j.result = new MsaResult();
474 j.result.setFinished(true);
475 j.result.setStatus(MessageManager
476 .getString("label.empty_alignment_job"));
477 ((MsaResult) j.result).setMsa(null);
481 vamsas.objects.simple.WsJobId jobsubmit = server.search(
482 j.seqs.getSeqs()[0], dbArg);
484 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
486 j.setJobId(jobsubmit.getJobId());
487 j.setSubmitted(true);
488 j.setSubjobComplete(false);
489 // System.out.println(WsURL + " Job Id '" + jobId + "'");
493 if (jobsubmit == null)
495 throw new Exception(MessageManager.formatMessage(
496 "exception.web_service_returned_null_try_later",
497 new String[] { WsUrl }));
500 throw new Exception(jobsubmit.getJobId());
502 } catch (Exception e)
504 // TODO: JBPNote catch timeout or other fault types explicitly
505 // For unexpected errors
507 .println(WebServiceName
508 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
509 + "When contacting Server:" + WsUrl + "\n"
510 + e.toString() + "\n");
511 j.setAllowedServerExceptions(0);
512 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
513 wsInfo.setStatus(j.getJobnum(),
514 WebserviceInfo.STATE_STOPPED_SERVERERROR);
515 wsInfo.appendProgressText(j.getJobnum(), MessageManager
516 .getString("info.failed_to_submit_sequences_for_alignment"));
518 // e.printStackTrace(); // TODO: JBPNote DEBUG
522 private jalview.datamodel.Sequence[] getVamsasAlignment(
523 vamsas.objects.simple.Alignment valign)
525 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
526 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
528 for (int i = 0, j = seqs.length; i < j; i++)
530 msa[i] = new jalview.datamodel.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(), MessageManager
555 .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(
656 "label.tree_from", new String[] { this.alTitle }));
658 // initialise with same renderer settings as in parent alignframe.
659 af.getFeatureRenderer().transferSettings(this.featureSettings);
660 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
661 AlignFrame.DEFAULT_HEIGHT);
665 public boolean canMergeResults()