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.ws.AWsJob;
31 import jalview.ws.JobStateSummary;
32 import jalview.ws.WSClientI;
33 import vamsas.objects.simple.MsaResult;
34 import vamsas.objects.simple.SeqSearchResult;
36 class SeqSearchWSThread extends JWS1Thread implements WSClientI
40 boolean profile = false;
42 class SeqSearchWSJob extends WSJob
44 // hold special input for this
45 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
55 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
58 if (!prepareInput(inSeqs, 2))
61 subjobComplete = true;
62 result = new MsaResult();
63 result.setFinished(true);
64 result.setStatus("Job never ran - input returned to user.");
69 Hashtable SeqNames = new Hashtable();
71 Vector emptySeqs = new Vector();
74 * prepare input sequences for service
77 * jalview sequences to be prepared
79 * minimum number of residues required for this MsaWS service
80 * @return true if seqs contains sequences to be submitted to service.
82 private boolean prepareInput(SequenceI[] seqs, int minlen)
88 "Implementation error: minlen must be zero or more.");
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("StartJob(MsaWSJob) called on a WSJobInstance "
452 SeqSearchWSJob j = (SeqSearchWSJob) job;
455 if (Cache.log.isDebugEnabled())
457 Cache.log.debug("Tried to submit an already submitted job "
462 if (j.seqs.getSeqs() == null)
464 // special case - selection consisted entirely of empty sequences...
465 j.setSubmitted(true);
466 j.result = new MsaResult();
467 j.result.setFinished(true);
468 j.result.setStatus("Empty Alignment Job");
469 ((MsaResult) j.result).setMsa(null);
473 vamsas.objects.simple.WsJobId jobsubmit = server.search(
474 j.seqs.getSeqs()[0], dbArg);
476 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
478 j.setJobId(jobsubmit.getJobId());
479 j.setSubmitted(true);
480 j.setSubjobComplete(false);
481 // System.out.println(WsURL + " Job Id '" + jobId + "'");
485 if (jobsubmit == null)
490 + " returned null object, it probably cannot be contacted. Try again later ?");
493 throw new Exception(jobsubmit.getJobId());
495 } catch (Exception e)
497 // TODO: JBPNote catch timeout or other fault types explicitly
498 // For unexpected errors
500 .println(WebServiceName
501 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
502 + "When contacting Server:" + WsUrl + "\n"
503 + e.toString() + "\n");
504 j.setAllowedServerExceptions(0);
505 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
506 wsInfo.setStatus(j.getJobnum(),
507 WebserviceInfo.STATE_STOPPED_SERVERERROR);
508 wsInfo.appendProgressText(
510 "Failed to submit sequences for alignment.\n"
511 + "It is most likely that there is a problem with the server.\n"
512 + "Just close the window\n");
514 // e.printStackTrace(); // TODO: JBPNote DEBUG
518 private jalview.datamodel.Sequence[] getVamsasAlignment(
519 vamsas.objects.simple.Alignment valign)
521 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
522 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
524 for (int i = 0, j = seqs.length; i < j; i++)
526 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
533 public void parseResult()
535 int results = 0; // number of result sets received
536 JobStateSummary finalState = new JobStateSummary();
539 for (int j = 0; j < jobs.length; j++)
541 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
542 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
543 && jobs[j].hasResults())
546 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
550 wsInfo.appendProgressText(jobs[j].getJobnum(),
551 "\nAlignment Object Method Notes\n");
552 String[] lines = valign.getMethod();
553 for (int line = 0; line < lines.length; line++)
555 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
558 // JBPNote The returned files from a webservice could be
559 // hidden behind icons in the monitor window that,
560 // when clicked, pop up their corresponding data
564 } catch (Exception ex)
567 Cache.log.error("Unexpected exception when processing results for "
569 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
573 wsInfo.showResultsNewFrame
574 .addActionListener(new java.awt.event.ActionListener()
576 public void actionPerformed(java.awt.event.ActionEvent evt)
578 displayResults(true);
582 .addActionListener(new java.awt.event.ActionListener()
584 public void actionPerformed(java.awt.event.ActionEvent evt)
586 displayResults(false);
589 wsInfo.setResultsReady();
593 wsInfo.setFinishedNoResults();
597 void displayResults(boolean newFrame)
601 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
604 // each subjob is an independent alignment for the moment
605 // Alignment al[] = new Alignment[jobs.length];
606 // NewickFile nf[] = new NewickFile[jobs.length];
607 for (int j = 0; j < jobs.length; j++)
609 Hashtable featureColours = new Hashtable();
611 NewickFile nf = null;
612 if (jobs[j].hasResults())
614 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
621 al = (Alignment) res[0];
622 nf = (NewickFile) res[1];
631 * We can't map new alignment back with insertions from input's hidden
632 * regions until dataset mapping is sorted out... but basically it goes
633 * like this: 1. Merge each domain hit back onto the visible segments in
634 * the same way as a Jnet prediction is mapped back
636 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
637 * // trash references to original result data for (int j = 0; j <
638 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
639 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
640 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
642 * if (dataset != null) { al.setDataset(dataset); }
644 * propagateDatasetMappings(al); }
647 AlignFrame af = new AlignFrame(al,// columnselection,
648 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
651 af.ShowNewickTree(nf, "Tree from " + this.alTitle);
653 // initialise with same renderer settings as in parent alignframe.
654 af.getFeatureRenderer().transferSettings(this.featureSettings);
655 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
656 AlignFrame.DEFAULT_HEIGHT);
660 public boolean canMergeResults()