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.
155 public boolean hasResults()
159 && result.isFinished()
160 && ((SeqSearchResult) result).getAlignment() != null
161 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
169 * return sequence search results for display
171 * @return null or { Alignment(+features and annotation), NewickFile)}
173 public Object[] getAlignment(Alignment dataset, Map featureColours)
176 if (result != null && result.isFinished())
178 SequenceI[] alseqs = null;
179 // char alseq_gapchar = '-';
181 if (((SeqSearchResult) result).getAlignment() != null)
183 alseqs = getVamsasAlignment(((SeqSearchResult) result)
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.AppletFormatAdapter.PASTE);
210 } catch (Exception e)
213 .println("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(
224 inFile, jalview.io.AppletFormatAdapter.PASTE);
225 ff.parse(al, featureColours, false);
227 } catch (Exception e)
230 .println("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.AppletFormatAdapter.PASTE);
248 } catch (Exception e)
251 .println("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.
290 public boolean hasValidInput()
292 if (seqs.getSeqs() != null)
300 String alTitle; // name which will be used to form new alignment window.
302 Alignment dataset; // dataset to which the new alignment will be
306 ext.vamsas.SeqSearchI server = null;
308 private String dbArg;
311 * set basic options for this (group) of Msa jobs
318 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
319 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
320 AlignmentView alview, String wsname, String db)
322 super(alFrame, wsinfo, alview, wsname, wsUrl);
323 this.server = server;
328 * create one or more Msa jobs to align visible seuqences in _msa
341 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
342 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
343 String wsname, String title, AlignmentView _msa, String db,
346 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
347 OutputHeader = wsInfo.getProgressText();
351 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
354 int njobs = conmsa.length;
355 jobs = new SeqSearchWSJob[njobs];
356 for (int j = 0; j < njobs; j++)
360 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
364 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
368 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
369 jobs[j].getJobnum());
371 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
376 public boolean isCancellable()
381 public void cancelJob()
383 if (!jobComplete && jobs != null)
385 boolean cancelled = true;
386 for (int job = 0; job < jobs.length; job++)
388 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
390 String cancelledMessage = "";
393 vamsas.objects.simple.WsJobId cancelledJob = server
394 .cancel(jobs[job].getJobId());
395 if (cancelledJob.getStatus() == 2)
398 cancelledMessage = "Job cancelled.";
399 ((SeqSearchWSJob) jobs[job]).cancel();
400 wsInfo.setStatus(jobs[job].getJobnum(),
401 WebserviceInfo.STATE_CANCELLED_OK);
403 else if (cancelledJob.getStatus() == 3)
405 // VALID UNSTOPPABLE JOB
406 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
408 // wsInfo.setStatus(jobs[job].jobnum,
409 // WebserviceInfo.STATE_RUNNING);
412 if (cancelledJob.getJobId() != null)
414 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
417 cancelledMessage += "\n";
418 } catch (Exception exc)
420 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
423 "Exception whilst cancelling " + jobs[job].getJobId(),
426 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
427 + cancelledMessage + "\n");
432 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
435 this.interrupt(); // kick thread to update job states.
441 wsInfo.setProgressText(OutputHeader
442 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
447 public void pollJob(AWsJob job) throws Exception
449 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
453 public void StartJob(AWsJob job)
455 if (!(job instanceof SeqSearchWSJob))
457 throw new Error(MessageManager.formatMessage(
458 "error.implementation_error_msawbjob_called",
459 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
478 .getString("label.empty_alignment_job"));
479 ((MsaResult) j.result).setMsa(null);
483 vamsas.objects.simple.WsJobId jobsubmit = server.search(
484 j.seqs.getSeqs()[0], dbArg);
486 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
488 j.setJobId(jobsubmit.getJobId());
489 j.setSubmitted(true);
490 j.setSubjobComplete(false);
491 // System.out.println(WsURL + " Job Id '" + jobId + "'");
495 if (jobsubmit == null)
497 throw new Exception(MessageManager.formatMessage(
498 "exception.web_service_returned_null_try_later",
499 new String[] { WsUrl }));
502 throw new Exception(jobsubmit.getJobId());
504 } catch (Exception e)
506 // TODO: JBPNote catch timeout or other fault types explicitly
507 // For unexpected errors
509 .println(WebServiceName
510 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
511 + "When contacting Server:" + WsUrl + "\n"
512 + e.toString() + "\n");
513 j.setAllowedServerExceptions(0);
514 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
515 wsInfo.setStatus(j.getJobnum(),
516 WebserviceInfo.STATE_STOPPED_SERVERERROR);
517 wsInfo.appendProgressText(j.getJobnum(), MessageManager
518 .getString("info.failed_to_submit_sequences_for_alignment"));
520 // e.printStackTrace(); // TODO: JBPNote DEBUG
524 private jalview.datamodel.Sequence[] getVamsasAlignment(
525 vamsas.objects.simple.Alignment valign)
527 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
528 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
530 for (int i = 0, j = seqs.length; i < j; i++)
532 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
539 public void parseResult()
541 int results = 0; // number of result sets received
542 JobStateSummary finalState = new JobStateSummary();
545 for (int j = 0; j < jobs.length; j++)
547 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
548 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
549 && jobs[j].hasResults())
552 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
556 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
557 .getString("info.alignment_object_method_notes"));
558 String[] lines = valign.getMethod();
559 for (int line = 0; line < lines.length; line++)
561 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
564 // JBPNote The returned files from a webservice could be
565 // hidden behind icons in the monitor window that,
566 // when clicked, pop up their corresponding data
570 } catch (Exception ex)
573 Cache.log.error("Unexpected exception when processing results for "
575 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
579 wsInfo.showResultsNewFrame
580 .addActionListener(new java.awt.event.ActionListener()
582 public void actionPerformed(java.awt.event.ActionEvent evt)
584 displayResults(true);
588 .addActionListener(new java.awt.event.ActionListener()
590 public void actionPerformed(java.awt.event.ActionEvent evt)
592 displayResults(false);
595 wsInfo.setResultsReady();
599 wsInfo.setFinishedNoResults();
603 void displayResults(boolean newFrame)
607 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
610 // each subjob is an independent alignment for the moment
611 // Alignment al[] = new Alignment[jobs.length];
612 // NewickFile nf[] = new NewickFile[jobs.length];
613 for (int j = 0; j < jobs.length; j++)
615 Map featureColours = new HashMap();
617 NewickFile nf = null;
618 if (jobs[j].hasResults())
620 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
627 al = (Alignment) res[0];
628 nf = (NewickFile) res[1];
637 * We can't map new alignment back with insertions from input's hidden
638 * regions until dataset mapping is sorted out... but basically it goes
639 * like this: 1. Merge each domain hit back onto the visible segments in
640 * the same way as a Jnet prediction is mapped back
642 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
643 * // trash references to original result data for (int j = 0; j <
644 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
645 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
646 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
648 * if (dataset != null) { al.setDataset(dataset); }
650 * propagateDatasetMappings(al); }
653 AlignFrame af = new AlignFrame(al,// columnselection,
654 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
657 af.ShowNewickTree(nf, MessageManager.formatMessage(
658 "label.tree_from", new String[] { this.alTitle }));
660 // initialise with same renderer settings as in parent alignframe.
661 af.getFeatureRenderer().transferSettings(this.featureSettings);
662 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
663 AlignFrame.DEFAULT_HEIGHT);
667 public boolean canMergeResults()