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.api.FeatureColourI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.Alignment;
27 import jalview.datamodel.AlignmentView;
28 import jalview.datamodel.SequenceI;
29 import jalview.gui.AlignFrame;
30 import jalview.gui.Desktop;
31 import jalview.gui.WebserviceInfo;
32 import jalview.io.NewickFile;
33 import jalview.util.MessageManager;
34 import jalview.ws.AWsJob;
35 import jalview.ws.JobStateSummary;
36 import jalview.ws.WSClientI;
38 import java.util.HashMap;
39 import java.util.Hashtable;
41 import java.util.Vector;
43 import vamsas.objects.simple.MsaResult;
44 import vamsas.objects.simple.SeqSearchResult;
46 class SeqSearchWSThread extends JWS1Thread implements WSClientI
50 boolean profile = false;
52 class SeqSearchWSJob extends WSJob
54 // hold special input for this
55 vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
65 public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
68 if (!prepareInput(inSeqs, 2))
71 subjobComplete = true;
72 result = new MsaResult();
73 result.setFinished(true);
74 result.setStatus(MessageManager.getString("label.job_never_ran"));
79 Hashtable SeqNames = new Hashtable();
81 Vector emptySeqs = new Vector();
84 * prepare input sequences for service
87 * jalview sequences to be prepared
89 * minimum number of residues required for this MsaWS service
90 * @return true if seqs contains sequences to be submitted to service.
92 private boolean prepareInput(SequenceI[] seqs, int minlen)
99 .getString("error.implementation_error_minlen_must_be_greater_zero"));
101 for (int i = 0; i < seqs.length; i++)
103 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
108 boolean valid = nseqs >= 1; // need at least one sequence for valid input
110 vamsas.objects.simple.Sequence[] seqarray = (valid) ? new vamsas.objects.simple.Sequence[nseqs]
112 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
114 for (int i = 0, n = 0; i < seqs.length; i++)
117 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
121 SeqNames.put(newname,
122 jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
123 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
125 seqarray[n] = new vamsas.objects.simple.Sequence();
126 seqarray[n].setId(newname);
127 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
128 : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
129 seqs[i].getSequenceAsString()));
134 if (seqs[i].getEnd() >= seqs[i].getStart())
136 empty = (submitGaps) ? seqs[i].getSequenceAsString() : AlignSeq
137 .extractGaps(jalview.util.Comparison.GapChars,
138 seqs[i].getSequenceAsString());
140 emptySeqs.add(new String[] { newname, empty });
145 // almost certainly have to remove gapped columns here
147 this.seqs = new vamsas.objects.simple.SequenceSet();
148 this.seqs.setSeqs(seqarray);
154 * @return true if getAlignment will return a valid alignment result.
157 public boolean hasResults()
161 && result.isFinished()
162 && ((SeqSearchResult) result).getAlignment() != null
163 && ((SeqSearchResult) result).getAlignment().getSeqs() != null)
171 * return sequence search results for display
173 * @return null or { Alignment(+features and annotation), NewickFile)}
175 public Object[] getAlignment(Alignment dataset,
176 Map<String, FeatureColourI> featureColours)
179 if (result != null && result.isFinished())
181 SequenceI[] alseqs = null;
182 // char alseq_gapchar = '-';
184 if (((SeqSearchResult) result).getAlignment() != null)
186 alseqs = getVamsasAlignment(((SeqSearchResult) result)
188 // alseq_gapchar = ( (SeqSearchResult)
189 // result).getAlignment().getGapchar().charAt(0);
190 // alseq_l = alseqs.length;
193 * what has to be done. 1 - annotate returned alignment with annotation
194 * file and sequence features file, and associate any tree-nodes. 2.
195 * connect alignment back to any associated dataset: 2.a. deuniquify
196 * recovers sequence information - but additionally, relocations must be
197 * made from the returned aligned sequence back to the dataset.
199 // construct annotated alignment as it would be done by the jalview
201 jalview.datamodel.Alignment al = new Alignment(alseqs);
202 // al.setDataset(dataset);
204 String inFile = null;
207 inFile = ((SeqSearchResult) result).getAnnotation();
208 if (inFile != null && inFile.length() > 0)
210 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
211 jalview.io.AppletFormatAdapter.PASTE);
213 } catch (Exception e)
216 .println("Failed to parse the annotation file associated with the alignment.");
217 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
218 e.printStackTrace(System.err);
223 inFile = ((SeqSearchResult) result).getFeatures();
224 if (inFile != null && inFile.length() > 0)
226 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(
227 inFile, jalview.io.AppletFormatAdapter.PASTE);
228 ff.parse(al, featureColours, false);
230 } catch (Exception e)
233 .println("Failed to parse the Features file associated with the alignment.");
234 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
235 e.printStackTrace(System.err);
237 jalview.io.NewickFile nf = null;
240 inFile = ((SeqSearchResult) result).getNewickTree();
241 if (inFile != null && inFile.length() > 0)
243 nf = new jalview.io.NewickFile(inFile,
244 jalview.io.AppletFormatAdapter.PASTE);
251 } catch (Exception e)
254 .println("Failed to parse the treeFile associated with the alignment.");
255 System.err.println(">>>EOF" + inFile + "\n<<<EOF\n");
256 e.printStackTrace(System.err);
260 * TODO: housekeeping w.r.t. recovery of dataset and annotation
261 * references for input sequences, and then dataset sequence creation
262 * for new sequences retrieved from service // finally, attempt to
263 * de-uniquify to recover input sequence identity, and try to map back
264 * onto dataset Note: this
265 * jalview.analysis.SeqsetUtils.deuniquify(SeqNames, alseqs, true); will
266 * NOT WORK - the returned alignment may contain multiple versions of
267 * the input sequence, each being a subsequence of the original.
268 * deuniquify also removes existing annotation and features added in the
269 * previous step... al.setDataset(dataset); // add in new sequences
270 * retrieved from sequence search which are not already in dataset. //
271 * trigger a 'fetchDBids' to annotate sequences with database ids...
274 return new Object[] { al, nf };
280 * mark subjob as cancelled and set result object appropriatly
285 subjobComplete = true;
291 * @return boolean true if job can be submitted.
294 public boolean hasValidInput()
296 if (seqs.getSeqs() != null)
304 String alTitle; // name which will be used to form new alignment window.
306 Alignment dataset; // dataset to which the new alignment will be
310 ext.vamsas.SeqSearchI server = null;
312 private String dbArg;
315 * set basic options for this (group) of Msa jobs
322 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
323 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
324 AlignmentView alview, String wsname, String db)
326 super(alFrame, wsinfo, alview, wsname, wsUrl);
327 this.server = server;
332 * create one or more Msa jobs to align visible seuqences in _msa
345 SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
346 WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
347 String wsname, String title, AlignmentView _msa, String db,
350 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
351 OutputHeader = wsInfo.getProgressText();
355 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
358 int njobs = conmsa.length;
359 jobs = new SeqSearchWSJob[njobs];
360 for (int j = 0; j < njobs; j++)
364 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
368 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
372 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
373 jobs[j].getJobnum());
375 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
381 public boolean isCancellable()
387 public void cancelJob()
389 if (!jobComplete && jobs != null)
391 boolean cancelled = true;
392 for (int job = 0; job < jobs.length; job++)
394 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
396 String cancelledMessage = "";
399 vamsas.objects.simple.WsJobId cancelledJob = server
400 .cancel(jobs[job].getJobId());
401 if (cancelledJob.getStatus() == 2)
404 cancelledMessage = "Job cancelled.";
405 ((SeqSearchWSJob) jobs[job]).cancel();
406 wsInfo.setStatus(jobs[job].getJobnum(),
407 WebserviceInfo.STATE_CANCELLED_OK);
409 else if (cancelledJob.getStatus() == 3)
411 // VALID UNSTOPPABLE JOB
412 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
414 // wsInfo.setStatus(jobs[job].jobnum,
415 // WebserviceInfo.STATE_RUNNING);
418 if (cancelledJob.getJobId() != null)
420 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
423 cancelledMessage += "\n";
424 } catch (Exception exc)
426 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
429 "Exception whilst cancelling " + jobs[job].getJobId(),
432 wsInfo.setProgressText(jobs[job].getJobnum(), OutputHeader
433 + cancelledMessage + "\n");
438 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
441 this.interrupt(); // kick thread to update job states.
447 wsInfo.setProgressText(OutputHeader
448 + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
454 public void pollJob(AWsJob job) throws Exception
456 ((SeqSearchWSJob) job).result = server.getResult(((SeqSearchWSJob) job)
461 public void StartJob(AWsJob job)
463 if (!(job instanceof SeqSearchWSJob))
465 throw new Error(MessageManager.formatMessage(
466 "error.implementation_error_msawbjob_called",
467 new String[] { job.getClass().toString() }));
469 SeqSearchWSJob j = (SeqSearchWSJob) job;
472 if (Cache.log.isDebugEnabled())
474 Cache.log.debug("Tried to submit an already submitted job "
479 if (j.seqs.getSeqs() == null)
481 // special case - selection consisted entirely of empty sequences...
482 j.setSubmitted(true);
483 j.result = new MsaResult();
484 j.result.setFinished(true);
485 j.result.setStatus(MessageManager
486 .getString("label.empty_alignment_job"));
487 ((MsaResult) j.result).setMsa(null);
491 vamsas.objects.simple.WsJobId jobsubmit = server.search(
492 j.seqs.getSeqs()[0], dbArg);
494 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
496 j.setJobId(jobsubmit.getJobId());
497 j.setSubmitted(true);
498 j.setSubjobComplete(false);
499 // System.out.println(WsURL + " Job Id '" + jobId + "'");
503 if (jobsubmit == null)
505 throw new Exception(MessageManager.formatMessage(
506 "exception.web_service_returned_null_try_later",
507 new String[] { WsUrl }));
510 throw new Exception(jobsubmit.getJobId());
512 } catch (Exception e)
514 // TODO: JBPNote catch timeout or other fault types explicitly
515 // For unexpected errors
517 .println(WebServiceName
518 + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
519 + "When contacting Server:" + WsUrl + "\n"
520 + e.toString() + "\n");
521 j.setAllowedServerExceptions(0);
522 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
523 wsInfo.setStatus(j.getJobnum(),
524 WebserviceInfo.STATE_STOPPED_SERVERERROR);
525 wsInfo.appendProgressText(j.getJobnum(), MessageManager
526 .getString("info.failed_to_submit_sequences_for_alignment"));
528 // e.printStackTrace(); // TODO: JBPNote DEBUG
532 private jalview.datamodel.Sequence[] getVamsasAlignment(
533 vamsas.objects.simple.Alignment valign)
535 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
536 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
538 for (int i = 0, j = seqs.length; i < j; i++)
540 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
548 public void parseResult()
550 int results = 0; // number of result sets received
551 JobStateSummary finalState = new JobStateSummary();
554 for (int j = 0; j < jobs.length; j++)
556 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
557 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
558 && jobs[j].hasResults())
561 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
565 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
566 .getString("info.alignment_object_method_notes"));
567 String[] lines = valign.getMethod();
568 for (int line = 0; line < lines.length; line++)
570 wsInfo.appendProgressText(jobs[j].getJobnum(), lines[line]
573 // JBPNote The returned files from a webservice could be
574 // hidden behind icons in the monitor window that,
575 // when clicked, pop up their corresponding data
579 } catch (Exception ex)
582 Cache.log.error("Unexpected exception when processing results for "
584 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
588 wsInfo.showResultsNewFrame
589 .addActionListener(new java.awt.event.ActionListener()
592 public void actionPerformed(java.awt.event.ActionEvent evt)
594 displayResults(true);
598 .addActionListener(new java.awt.event.ActionListener()
601 public void actionPerformed(java.awt.event.ActionEvent evt)
603 displayResults(false);
606 wsInfo.setResultsReady();
610 wsInfo.setFinishedNoResults();
614 void displayResults(boolean newFrame)
618 System.err.println("MERGE WITH OLD FRAME NOT IMPLEMENTED");
621 // each subjob is an independent alignment for the moment
622 // Alignment al[] = new Alignment[jobs.length];
623 // NewickFile nf[] = new NewickFile[jobs.length];
624 for (int j = 0; j < jobs.length; j++)
626 Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
628 NewickFile nf = null;
629 if (jobs[j].hasResults())
631 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
638 al = (Alignment) res[0];
639 nf = (NewickFile) res[1];
648 * We can't map new alignment back with insertions from input's hidden
649 * regions until dataset mapping is sorted out... but basically it goes
650 * like this: 1. Merge each domain hit back onto the visible segments in
651 * the same way as a Jnet prediction is mapped back
653 * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
654 * // trash references to original result data for (int j = 0; j <
655 * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
656 * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
657 * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
659 * if (dataset != null) { al.setDataset(dataset); }
661 * propagateDatasetMappings(al); }
664 AlignFrame af = new AlignFrame(al,// columnselection,
665 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
668 af.ShowNewickTree(nf, MessageManager.formatMessage(
669 "label.tree_from", new String[] { this.alTitle }));
671 // initialise with same renderer settings as in parent alignframe.
672 af.getFeatureRenderer().transferSettings(this.featureSettings);
673 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
674 AlignFrame.DEFAULT_HEIGHT);
679 public boolean canMergeResults()