2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3 * Copyright (C) 2014 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;
25 import jalview.analysis.*;
27 import jalview.datamodel.*;
29 import jalview.io.NewickFile;
30 import jalview.util.MessageManager;
31 import jalview.ws.AWsJob;
32 import jalview.ws.JobStateSummary;
33 import jalview.ws.WSClientI;
34 import vamsas.objects.simple.MsaResult;
35 import vamsas.objects.simple.SeqSearchResult;
37 class SeqSearchWSThread extends JWS1Thread implements WSClientI
41 boolean profile = false;
43 class SeqSearchWSJob extends WSJob
45 // hold special input for this
46 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
56 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
59 if (!prepareInput(inSeqs, 2))
62 subjobComplete = true;
63 result = new MsaResult();
64 result.setFinished(true);
65 result.setStatus(MessageManager.getString("label.job_never_ran"));
70 Hashtable SeqNames = new Hashtable();
72 Vector emptySeqs = new Vector();
75 * prepare input sequences for service
78 * jalview sequences to be prepared
80 * minimum number of residues required for this MsaWS service
81 * @return true if seqs contains sequences to be submitted to service.
83 private boolean prepareInput(SequenceI[] seqs, int minlen)
88 throw new Error(MessageManager.getString("error.implementation_error_minlen_must_be_greater_zero"));
90 for (int i = 0; i < seqs.length; i++)
92 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
97 boolean valid = nseqs >= 1; // need at least one sequence for valid input
99 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
101 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
103 for (int i = 0, n = 0; i < seqs.length; i++)
106 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
110 SeqNames.put(newname,
111 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
112 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
114 seqarray[n] = new vamsas.objects.simple.Sequence();
115 seqarray[n].setId(newname);
116 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
117 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
118 seqs[i].getSequenceAsString()));
123 if (seqs[i].getEnd() >= seqs[i].getStart())
125 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
126 .extractGaps(jalview.util.Comparison.GapChars,
127 seqs[i].getSequenceAsString());
129 emptySeqs.add(new String[]
135 // almost certainly have to remove gapped columns here
137 this.seqs = new vamsas.objects.simple.SequenceSet();
138 this.seqs.setSeqs(seqarray);
144 * @return true if getAlignment will return a valid alignment result.
146 public boolean hasResults()
150 && result.isFinished()
151 && ((SeqSearchResult) result).getAlignment() != null
152 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
160 * return sequence search results for display
162 * @return null or { Alignment(+features and annotation), NewickFile)}
164 public Object[] getAlignment(Alignment dataset, Hashtable featureColours)
167 if (result != null && result.isFinished())
169 SequenceI[] alseqs = null;
170 // char alseq_gapchar = '-';
172 if (((SeqSearchResult) result).getAlignment() != null)
174 alseqs = getVamsasAlignment(((SeqSearchResult) result)
176 // alseq_gapchar = ( (SeqSearchResult)
177 // result).getAlignment().getGapchar().charAt(0);
178 // alseq_l = alseqs.length;
181 * what has to be done. 1 - annotate returned alignment with annotation
182 * file and sequence features file, and associate any tree-nodes. 2.
183 * connect alignment back to any associated dataset: 2.a. deuniquify
184 * recovers sequence information - but additionally, relocations must be
185 * made from the returned aligned sequence back to the dataset.
187 // construct annotated alignment as it would be done by the jalview
189 jalview.datamodel.Alignment al = new Alignment(alseqs);
190 // al.setDataset(dataset);
192 String inFile = null;
195 inFile = ((SeqSearchResult) result).getAnnotation();
196 if (inFile != null && inFile.length() > 0)
198 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
199 jalview.io.AppletFormatAdapter.PASTE);
201 } catch (Exception e)
204 .println("Failed to parse the annotation file associated with the alignment.");
205 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
206 e.printStackTrace(System.err);
211 inFile = ((SeqSearchResult) result).getFeatures();
212 if (inFile != null && inFile.length() > 0)
214 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
215 inFile, jalview.io.AppletFormatAdapter.PASTE);
216 ff.parse(al, featureColours, false);
218 } catch (Exception e)
221 .println("Failed to parse the Features file associated with the alignment.");
222 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
223 e.printStackTrace(System.err);
225 jalview.io.NewickFile nf = null;
228 inFile = ((SeqSearchResult) result).getNewickTree();
229 if (inFile != null && inFile.length() > 0)
231 nf = new jalview.io.NewickFile(inFile,
232 jalview.io.AppletFormatAdapter.PASTE);
239 } catch (Exception e)
242 .println("Failed to parse the treeFile associated with the alignment.");
243 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
244 e.printStackTrace(System.err);
248 * TODO: housekeeping w.r.t. recovery of dataset and annotation
249 * references for input sequences, and then dataset sequence creation
250 * for new sequences retrieved from service // finally, attempt to
251 * de-uniquify to recover input sequence identity, and try to map back
252 * onto dataset Note: this
253 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
254 * NOT WORK - the returned alignment may contain multiple versions of
255 * the input sequence, each being a subsequence of the original.
256 * deuniquify also removes existing annotation and features added in the
257 * previous step... al.setDataset(dataset); // add in new sequences
258 * retrieved from sequence search which are not already in dataset. //
259 * trigger a 'fetchDBids' to annotate sequences with database ids...
269 * mark subjob as cancelled and set result object appropriatly
274 subjobComplete = true;
280 * @return boolean true if job can be submitted.
282 public boolean hasValidInput()
284 if (seqs.getSeqs() != null)
292 String alTitle; // name which will be used to form new alignment window.
294 Alignment dataset; // dataset to which the new alignment will be
298 ext.vamsas.SeqSearchI server = null;
300 private String dbArg;
303 * set basic options for this (group) of Msa jobs
310 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
311 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
312 AlignmentView alview, String wsname, String db)
314 super(alFrame, wsinfo, alview, wsname, wsUrl);
315 this.server = server;
320 * create one or more Msa jobs to align visible seuqences in _msa
333 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
334 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
335 String wsname, String title, AlignmentView _msa, String db,
338 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
339 OutputHeader = wsInfo.getProgressText();
343 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
346 int njobs = conmsa.length;
347 jobs = new SeqSearchWSJob[njobs];
348 for (int j = 0; j < njobs; j++)
352 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
356 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
360 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
361 jobs[j].getJobnum());
363 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
368 public boolean isCancellable()
373 public void cancelJob()
375 if (!jobComplete && jobs != null)
377 boolean cancelled = true;
378 for (int job = 0; job < jobs.length; job++)
380 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
382 String cancelledMessage = "";
385 vamsas.objects.simple.WsJobId cancelledJob = server
386 .cancel(jobs[job].getJobId());
387 if (cancelledJob.getStatus() == 2)
390 cancelledMessage = "Job cancelled.";
391 ((SeqSearchWSJob) jobs[job]).cancel();
392 wsInfo.setStatus(jobs[job].getJobnum(),
393 WebserviceInfo.STATE_CANCELLED_OK);
395 else if (cancelledJob.getStatus() == 3)
397 // VALID UNSTOPPABLE JOB
398 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
400 // wsInfo.setStatus(jobs[job].jobnum,
401 // WebserviceInfo.STATE_RUNNING);
404 if (cancelledJob.getJobId() != null)
406 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
409 cancelledMessage += "\n";
410 } catch (Exception exc)
412 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
415 "Exception whilst cancelling " + jobs[job].getJobId(),
418 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
419 + cancelledMessage + "\n");
424 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
427 this.interrupt(); // kick thread to update job states.
433 wsInfo.setProgressText(OutputHeader
434 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
439 public void pollJob(AWsJob job) throws Exception
441 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
445 public void StartJob(AWsJob job)
447 if (!(job instanceof SeqSearchWSJob))
449 throw new Error(MessageManager.formatMessage("error.implementation_error_msawbjob_called", new String[]{job.getClass().toString()}));
451 SeqSearchWSJob j = (SeqSearchWSJob) job;
454 if (Cache.log.isDebugEnabled())
456 Cache.log.debug("Tried to submit an already submitted job "
461 if (j.seqs.getSeqs() == null)
463 // special case - selection consisted entirely of empty sequences...
464 j.setSubmitted(true);
465 j.result = new MsaResult();
466 j.result.setFinished(true);
467 j.result.setStatus(MessageManager.getString("label.empty_alignment_job"));
468 ((MsaResult) j.result).setMsa(null);
472 vamsas.objects.simple.WsJobId jobsubmit = server.search(
473 j.seqs.getSeqs()[0], dbArg);
475 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
477 j.setJobId(jobsubmit.getJobId());
478 j.setSubmitted(true);
479 j.setSubjobComplete(false);
480 // System.out.println(WsURL + " Job Id '" + jobId + "'");
484 if (jobsubmit == null)
486 throw new Exception(MessageManager.formatMessage("exception.web_service_returned_null_try_later", new String[]{WsUrl}));
489 throw new Exception(jobsubmit.getJobId());
491 } catch (Exception e)
493 // TODO: JBPNote catch timeout or other fault types explicitly
494 // For unexpected errors
496 .println(WebServiceName
497 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
498 + "When contacting Server:" + WsUrl + "\n"
499 + e.toString() + "\n");
500 j.setAllowedServerExceptions(0);
501 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
502 wsInfo.setStatus(j.getJobnum(),
503 WebserviceInfo.STATE_STOPPED_SERVERERROR);
504 wsInfo.appendProgressText(
506 MessageManager.getString("info.failed_to_submit_sequences_for_alignment"));
508 // e.printStackTrace(); // TODO: JBPNote DEBUG
512 private jalview.datamodel.Sequence[] getVamsasAlignment(
513 vamsas.objects.simple.Alignment valign)
515 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
516 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
518 for (int i = 0, j = seqs.length; i < j; i++)
520 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
527 public void parseResult()
529 int results = 0; // number of result sets received
530 JobStateSummary finalState = new JobStateSummary();
533 for (int j = 0; j < jobs.length; j++)
535 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
536 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
537 && jobs[j].hasResults())
540 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
544 wsInfo.appendProgressText(jobs[j].getJobnum(),
545 MessageManager.getString("info.alignment_object_method_notes"));
546 String[] lines = valign.getMethod();
547 for (int line = 0; line < lines.length; line++)
549 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
552 // JBPNote The returned files from a webservice could be
553 // hidden behind icons in the monitor window that,
554 // when clicked, pop up their corresponding data
558 } catch (Exception ex)
561 Cache.log.error("Unexpected exception when processing results for "
563 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
567 wsInfo.showResultsNewFrame
568 .addActionListener(new java.awt.event.ActionListener()
570 public void actionPerformed(java.awt.event.ActionEvent evt)
572 displayResults(true);
576 .addActionListener(new java.awt.event.ActionListener()
578 public void actionPerformed(java.awt.event.ActionEvent evt)
580 displayResults(false);
583 wsInfo.setResultsReady();
587 wsInfo.setFinishedNoResults();
591 void displayResults(boolean newFrame)
595 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
598 // each subjob is an independent alignment for the moment
599 // Alignment al[] = new Alignment[jobs.length];
600 // NewickFile nf[] = new NewickFile[jobs.length];
601 for (int j = 0; j < jobs.length; j++)
603 Hashtable featureColours = new Hashtable();
605 NewickFile nf = null;
606 if (jobs[j].hasResults())
608 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
615 al = (Alignment) res[0];
616 nf = (NewickFile) res[1];
625 * We can't map new alignment back with insertions from input's hidden
626 * regions until dataset mapping is sorted out... but basically it goes
627 * like this: 1. Merge each domain hit back onto the visible segments in
628 * the same way as a Jnet prediction is mapped back
630 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
631 * // trash references to original result data for (int j = 0; j <
632 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
633 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
634 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
636 * if (dataset != null) { al.setDataset(dataset); }
638 * propagateDatasetMappings(al); }
641 AlignFrame af = new AlignFrame(al,// columnselection,
642 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
645 af.ShowNewickTree(nf, MessageManager.formatMessage("label.tree_from", new String[]{this.alTitle}));
647 // initialise with same renderer settings as in parent alignframe.
648 af.getFeatureRenderer().transferSettings(this.featureSettings);
649 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
650 AlignFrame.DEFAULT_HEIGHT);
654 public boolean canMergeResults()