Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:12:26 GMT
  2. Package jalview.ws.jws1

File SeqSearchWSThread.java

 

Coverage histogram

../../../img/srcFileCovDistChart0.png
59% of files have more coverage

Code metrics

98
197
18
2
686
496
87
0.44
10.94
9
4.83

Classes

Class Line # Actions
SeqSearchWSThread 47 123 49
0.00%
SeqSearchWSThread.SeqSearchWSJob 53 74 38
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.ws.jws1;
22   
23    import jalview.analysis.AlignSeq;
24    import jalview.api.FeatureColourI;
25    import jalview.bin.Console;
26    import jalview.datamodel.Alignment;
27    import jalview.datamodel.AlignmentI;
28    import jalview.datamodel.AlignmentView;
29    import jalview.datamodel.SequenceI;
30    import jalview.gui.AlignFrame;
31    import jalview.gui.Desktop;
32    import jalview.gui.WebserviceInfo;
33    import jalview.io.NewickFile;
34    import jalview.util.MessageManager;
35    import jalview.ws.AWsJob;
36    import jalview.ws.JobStateSummary;
37    import jalview.ws.WSClientI;
38   
39    import java.util.HashMap;
40    import java.util.Hashtable;
41    import java.util.Map;
42    import java.util.Vector;
43   
44    import vamsas.objects.simple.MsaResult;
45    import vamsas.objects.simple.SeqSearchResult;
46   
 
47    class SeqSearchWSThread extends JWS1Thread implements WSClientI
48    {
49    String dbs = null;
50   
51    boolean profile = false;
52   
 
53    class SeqSearchWSJob extends WSJob
54    {
55    // hold special input for this
56    vamsas.objects.simple.SequenceSet seqs = new vamsas.objects.simple.SequenceSet();
57   
58    /**
59    * MsaWSJob
60    *
61    * @param jobNum
62    * int
63    * @param jobId
64    * String
65    */
 
66  0 toggle public SeqSearchWSJob(int jobNum, SequenceI[] inSeqs)
67    {
68  0 this.jobnum = jobNum;
69  0 if (!prepareInput(inSeqs, 2))
70    {
71  0 submitted = true;
72  0 subjobComplete = true;
73  0 result = new MsaResult();
74  0 result.setFinished(true);
75  0 result.setStatus(MessageManager.getString("label.job_never_ran"));
76    }
77   
78    }
79   
80    Hashtable SeqNames = new Hashtable();
81   
82    Vector emptySeqs = new Vector();
83   
84    /**
85    * prepare input sequences for service
86    *
87    * @param seqs
88    * jalview sequences to be prepared
89    * @param minlen
90    * minimum number of residues required for this MsaWS service
91    * @return true if seqs contains sequences to be submitted to service.
92    */
 
93  0 toggle private boolean prepareInput(SequenceI[] seqs, int minlen)
94    {
95  0 int nseqs = 0;
96  0 if (minlen < 0)
97    {
98  0 throw new Error(MessageManager.getString(
99    "error.implementation_error_minlen_must_be_greater_zero"));
100    }
101  0 for (int i = 0; i < seqs.length; i++)
102    {
103  0 if (seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
104    {
105  0 nseqs++;
106    }
107    }
108  0 boolean valid = nseqs >= 1; // need at least one sequence for valid input
109    // TODO: generalise
110  0 vamsas.objects.simple.Sequence[] seqarray = (valid)
111    ? new vamsas.objects.simple.Sequence[nseqs]
112    : null;
113  0 boolean submitGaps = (nseqs == 1) ? false : true; // profile is submitted
114    // with gaps
115  0 for (int i = 0, n = 0; i < seqs.length; i++)
116    {
117   
118  0 String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same
119    // for
120    // any
121    // subjob
122  0 SeqNames.put(newname,
123    jalview.analysis.SeqsetUtils.SeqCharacterHash(seqs[i]));
124  0 if (valid && seqs[i].getEnd() - seqs[i].getStart() > minlen - 1)
125    {
126  0 seqarray[n] = new vamsas.objects.simple.Sequence();
127  0 seqarray[n].setId(newname);
128  0 seqarray[n++].setSeq((submitGaps) ? seqs[i].getSequenceAsString()
129    : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
130    seqs[i].getSequenceAsString()));
131    }
132    else
133    {
134  0 String empty = null;
135  0 if (seqs[i].getEnd() >= seqs[i].getStart())
136    {
137  0 empty = (submitGaps) ? seqs[i].getSequenceAsString()
138    : AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
139    seqs[i].getSequenceAsString());
140    }
141  0 emptySeqs.add(new String[] { newname, empty });
142    }
143    }
144  0 if (submitGaps)
145    {
146    // almost certainly have to remove gapped columns here
147    }
148  0 this.seqs = new vamsas.objects.simple.SequenceSet();
149  0 this.seqs.setSeqs(seqarray);
150  0 return valid;
151    }
152   
153    /**
154    *
155    * @return true if getAlignment will return a valid alignment result.
156    */
 
157  0 toggle @Override
158    public boolean hasResults()
159    {
160  0 if (subjobComplete && result != null && result.isFinished()
161    && ((SeqSearchResult) result).getAlignment() != null
162    && ((SeqSearchResult) result).getAlignment()
163    .getSeqs() != null)
164    {
165  0 return true;
166    }
167  0 return false;
168    }
169   
170    /**
171    * return sequence search results for display
172    *
173    * @return null or { Alignment(+features and annotation), NewickFile)}
174    */
 
175  0 toggle public Object[] getAlignment(AlignmentI dataset,
176    Map<String, FeatureColourI> featureColours)
177    {
178   
179  0 if (result != null && result.isFinished())
180    {
181  0 SequenceI[] alseqs = null;
182    // char alseq_gapchar = '-';
183    // int alseq_l = 0;
184  0 if (((SeqSearchResult) result).getAlignment() != null)
185    {
186  0 alseqs = getVamsasAlignment(
187    ((SeqSearchResult) result).getAlignment());
188    // alseq_gapchar = ( (SeqSearchResult)
189    // result).getAlignment().getGapchar().charAt(0);
190    // alseq_l = alseqs.length;
191    }
192    /**
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.
198    */
199    // construct annotated alignment as it would be done by the jalview
200    // applet
201  0 jalview.datamodel.Alignment al = new Alignment(alseqs);
202    // al.setDataset(dataset);
203    // make dataset
204  0 String inFile = null;
205  0 try
206    {
207  0 inFile = ((SeqSearchResult) result).getAnnotation();
208  0 if (inFile != null && inFile.length() > 0)
209    {
210  0 new jalview.io.AnnotationFile().readAnnotationFile(al, inFile,
211    jalview.io.DataSourceType.PASTE);
212    }
213    } catch (Exception e)
214    {
215  0 jalview.bin.Console.errPrintln(
216    "Failed to parse the annotation file associated with the alignment.");
217  0 jalview.bin.Console.errPrintln(">>>EOF" + inFile + "\n<<<EOF\n");
218  0 e.printStackTrace(System.err);
219    }
220   
221  0 try
222    {
223  0 inFile = ((SeqSearchResult) result).getFeatures();
224  0 if (inFile != null && inFile.length() > 0)
225    {
226  0 jalview.io.FeaturesFile ff = new jalview.io.FeaturesFile(inFile,
227    jalview.io.DataSourceType.PASTE);
228  0 ff.parse(al, featureColours, false);
229    }
230    } catch (Exception e)
231    {
232  0 jalview.bin.Console.errPrintln(
233    "Failed to parse the Features file associated with the alignment.");
234  0 jalview.bin.Console.errPrintln(">>>EOF" + inFile + "\n<<<EOF\n");
235  0 e.printStackTrace(System.err);
236    }
237  0 jalview.io.NewickFile nf = null;
238  0 try
239    {
240  0 inFile = ((SeqSearchResult) result).getNewickTree();
241  0 if (inFile != null && inFile.length() > 0)
242    {
243  0 nf = new jalview.io.NewickFile(inFile,
244    jalview.io.DataSourceType.PASTE);
245  0 if (!nf.isValid())
246    {
247  0 nf.close();
248  0 nf = null;
249    }
250    }
251    } catch (Exception e)
252    {
253  0 jalview.bin.Console.errPrintln(
254    "Failed to parse the treeFile associated with the alignment.");
255  0 jalview.bin.Console.errPrintln(">>>EOF" + inFile + "\n<<<EOF\n");
256  0 e.printStackTrace(System.err);
257    }
258   
259    /*
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...
272    */
273   
274  0 return new Object[] { al, nf };
275    }
276  0 return null;
277    }
278   
279    /**
280    * mark subjob as cancelled and set result object appropriatly
281    */
 
282  0 toggle void cancel()
283    {
284  0 cancelled = true;
285  0 subjobComplete = true;
286  0 result = null;
287    }
288   
289    /**
290    *
291    * @return boolean true if job can be submitted.
292    */
 
293  0 toggle @Override
294    public boolean hasValidInput()
295    {
296  0 if (seqs.getSeqs() != null)
297    {
298  0 return true;
299    }
300  0 return false;
301    }
302    }
303   
304    String alTitle; // name which will be used to form new alignment window.
305   
306    AlignmentI dataset; // dataset to which the new alignment will be
307   
308    // associated.
309   
310    ext.vamsas.SeqSearchI server = null;
311   
312    private String dbArg;
313   
314    /**
315    * set basic options for this (group) of Msa jobs
316    *
317    * @param subgaps
318    * boolean
319    * @param presorder
320    * boolean
321    */
 
322  0 toggle SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
323    WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
324    AlignmentView alview, String wsname, String db)
325    {
326  0 super(alFrame, wsinfo, alview, wsname, wsUrl);
327  0 this.server = server;
328  0 this.dbArg = db;
329    }
330   
331    /**
332    * create one or more Msa jobs to align visible seuqences in _msa
333    *
334    * @param title
335    * String
336    * @param _msa
337    * AlignmentView
338    * @param subgaps
339    * boolean
340    * @param presorder
341    * boolean
342    * @param seqset
343    * Alignment
344    */
 
345  0 toggle SeqSearchWSThread(ext.vamsas.SeqSearchI server, String wsUrl,
346    WebserviceInfo wsinfo, jalview.gui.AlignFrame alFrame,
347    String wsname, String title, AlignmentView _msa, String db,
348    AlignmentI seqset)
349    {
350  0 this(server, wsUrl, wsinfo, alFrame, _msa, wsname, db);
351  0 OutputHeader = wsInfo.getProgressText();
352  0 alTitle = title;
353  0 dataset = seqset;
354   
355  0 SequenceI[][] conmsa = _msa.getVisibleContigs('-');
356  0 if (conmsa != null)
357    {
358  0 int njobs = conmsa.length;
359  0 jobs = new SeqSearchWSJob[njobs];
360  0 for (int j = 0; j < njobs; j++)
361    {
362  0 if (j != 0)
363    {
364  0 jobs[j] = new SeqSearchWSJob(wsinfo.addJobPane(), conmsa[j]);
365    }
366    else
367    {
368  0 jobs[j] = new SeqSearchWSJob(0, conmsa[j]);
369    }
370  0 if (njobs > 0)
371    {
372  0 wsinfo.setProgressName("region " + jobs[j].getJobnum(),
373    jobs[j].getJobnum());
374    }
375  0 wsinfo.setProgressText(jobs[j].getJobnum(), OutputHeader);
376    }
377    }
378    }
379   
 
380  0 toggle @Override
381    public boolean isCancellable()
382    {
383  0 return true;
384    }
385   
 
386  0 toggle @Override
387    public void cancelJob()
388    {
389  0 if (!jobComplete && jobs != null)
390    {
391  0 boolean cancelled = true;
392  0 for (int job = 0; job < jobs.length; job++)
393    {
394  0 if (jobs[job].isSubmitted() && !jobs[job].isSubjobComplete())
395    {
396  0 String cancelledMessage = "";
397  0 try
398    {
399  0 vamsas.objects.simple.WsJobId cancelledJob = server
400    .cancel(jobs[job].getJobId());
401  0 if (cancelledJob.getStatus() == 2)
402    {
403    // CANCELLED_JOB
404  0 cancelledMessage = "Job cancelled.";
405  0 ((SeqSearchWSJob) jobs[job]).cancel();
406  0 wsInfo.setStatus(jobs[job].getJobnum(),
407    WebserviceInfo.STATE_CANCELLED_OK);
408    }
409  0 else if (cancelledJob.getStatus() == 3)
410    {
411    // VALID UNSTOPPABLE JOB
412  0 cancelledMessage += "Server cannot cancel this job. just close the window.\n";
413  0 cancelled = false;
414    // wsInfo.setStatus(jobs[job].jobnum,
415    // WebserviceInfo.STATE_RUNNING);
416    }
417   
418  0 if (cancelledJob.getJobId() != null)
419    {
420  0 cancelledMessage += ("[" + cancelledJob.getJobId() + "]");
421    }
422   
423  0 cancelledMessage += "\n";
424    } catch (Exception exc)
425    {
426  0 cancelledMessage += ("\nProblems cancelling the job : Exception received...\n"
427    + exc + "\n");
428  0 Console.warn(
429    "Exception whilst cancelling " + jobs[job].getJobId(),
430    exc);
431    }
432  0 wsInfo.setProgressText(jobs[job].getJobnum(),
433    OutputHeader + cancelledMessage + "\n");
434    }
435    }
436  0 if (cancelled)
437    {
438  0 wsInfo.setStatus(WebserviceInfo.STATE_CANCELLED_OK);
439  0 jobComplete = true;
440    }
441  0 this.interrupt(); // kick thread to update job states.
442    }
443    else
444    {
445  0 if (!jobComplete)
446    {
447  0 wsInfo.setProgressText(OutputHeader
448    + "Server cannot cancel this job because it has not been submitted properly. just close the window.\n");
449    }
450    }
451    }
452   
 
453  0 toggle @Override
454    public void pollJob(AWsJob job) throws Exception
455    {
456  0 ((SeqSearchWSJob) job).result = server
457    .getResult(((SeqSearchWSJob) job).getJobId());
458    }
459   
 
460  0 toggle @Override
461    public void StartJob(AWsJob job)
462    {
463  0 if (!(job instanceof SeqSearchWSJob))
464    {
465  0 throw new Error(MessageManager.formatMessage(
466    "error.implementation_error_msawbjob_called", new String[]
467    { job.getClass().toString() }));
468    }
469  0 SeqSearchWSJob j = (SeqSearchWSJob) job;
470  0 if (j.isSubmitted())
471    {
472  0 if (Console.isDebugEnabled())
473    {
474  0 Console.debug(
475    "Tried to submit an already submitted job " + j.getJobId());
476    }
477  0 return;
478    }
479  0 if (j.seqs.getSeqs() == null)
480    {
481    // special case - selection consisted entirely of empty sequences...
482  0 j.setSubmitted(true);
483  0 j.result = new MsaResult();
484  0 j.result.setFinished(true);
485  0 j.result.setStatus(
486    MessageManager.getString("label.empty_alignment_job"));
487  0 ((MsaResult) j.result).setMsa(null);
488    }
489  0 try
490    {
491  0 vamsas.objects.simple.WsJobId jobsubmit = server
492    .search(j.seqs.getSeqs()[0], dbArg);
493   
494  0 if ((jobsubmit != null) && (jobsubmit.getStatus() == 1))
495    {
496  0 j.setJobId(jobsubmit.getJobId());
497  0 j.setSubmitted(true);
498  0 j.setSubjobComplete(false);
499    // jalview.bin.Console.outPrintln(WsURL + " Job Id '" + jobId + "'");
500    }
501    else
502    {
503  0 if (jobsubmit == null)
504    {
505  0 throw new Exception(MessageManager.formatMessage(
506    "exception.web_service_returned_null_try_later",
507    new String[]
508    { WsUrl }));
509    }
510   
511  0 throw new Exception(jobsubmit.getJobId());
512    }
513    } catch (Exception e)
514    {
515    // TODO: JBPNote catch timeout or other fault types explicitly
516    // For unexpected errors
517  0 jalview.bin.Console.errPrintln(WebServiceName
518    + "Client: Failed to submit the sequences for alignment (probably a server side problem)\n"
519    + "When contacting Server:" + WsUrl + "\n" + e.toString()
520    + "\n");
521  0 j.setAllowedServerExceptions(0);
522  0 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_SERVERERROR);
523  0 wsInfo.setStatus(j.getJobnum(),
524    WebserviceInfo.STATE_STOPPED_SERVERERROR);
525  0 wsInfo.appendProgressText(j.getJobnum(), MessageManager
526    .getString("info.failed_to_submit_sequences_for_alignment"));
527   
528    // e.printStackTrace(); // TODO: JBPNote DEBUG
529    }
530    }
531   
 
532  0 toggle private jalview.datamodel.Sequence[] getVamsasAlignment(
533    vamsas.objects.simple.Alignment valign)
534    {
535  0 vamsas.objects.simple.Sequence[] seqs = valign.getSeqs().getSeqs();
536  0 jalview.datamodel.Sequence[] msa = new jalview.datamodel.Sequence[seqs.length];
537   
538  0 for (int i = 0, j = seqs.length; i < j; i++)
539    {
540  0 msa[i] = new jalview.datamodel.Sequence(seqs[i].getId(),
541    seqs[i].getSeq());
542    }
543   
544  0 return msa;
545    }
546   
 
547  0 toggle @Override
548    public void parseResult()
549    {
550  0 int results = 0; // number of result sets received
551  0 JobStateSummary finalState = new JobStateSummary();
552  0 try
553    {
554  0 for (int j = 0; j < jobs.length; j++)
555    {
556  0 finalState.updateJobPanelState(wsInfo, OutputHeader, jobs[j]);
557  0 if (jobs[j].isSubmitted() && jobs[j].isSubjobComplete()
558    && jobs[j].hasResults())
559    {
560  0 results++;
561  0 vamsas.objects.simple.Alignment valign = ((SeqSearchResult) ((SeqSearchWSJob) jobs[j]).result)
562    .getAlignment();
563  0 if (valign != null)
564    {
565  0 wsInfo.appendProgressText(jobs[j].getJobnum(), MessageManager
566    .getString("info.alignment_object_method_notes"));
567  0 String[] lines = valign.getMethod();
568  0 for (int line = 0; line < lines.length; line++)
569    {
570  0 wsInfo.appendProgressText(jobs[j].getJobnum(),
571    lines[line] + "\n");
572    }
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
576    }
577    }
578    }
579    } catch (Exception ex)
580    {
581   
582  0 Console.error(
583    "Unexpected exception when processing results for " + alTitle,
584    ex);
585  0 wsInfo.setStatus(WebserviceInfo.STATE_STOPPED_ERROR);
586    }
587  0 if (results > 0)
588    {
589  0 wsInfo.showResultsNewFrame
590    .addActionListener(new java.awt.event.ActionListener()
591    {
 
592  0 toggle @Override
593    public void actionPerformed(java.awt.event.ActionEvent evt)
594    {
595  0 displayResults(true);
596    }
597    });
598  0 wsInfo.mergeResults
599    .addActionListener(new java.awt.event.ActionListener()
600    {
 
601  0 toggle @Override
602    public void actionPerformed(java.awt.event.ActionEvent evt)
603    {
604  0 displayResults(false);
605    }
606    });
607  0 wsInfo.setResultsReady();
608    }
609    else
610    {
611  0 wsInfo.setFinishedNoResults();
612    }
613    }
614   
 
615  0 toggle void displayResults(boolean newFrame)
616    {
617  0 if (!newFrame)
618    {
619  0 jalview.bin.Console
620    .errPrintln("MERGE WITH OLD FRAME NOT IMPLEMENTED");
621  0 return;
622    }
623    // each subjob is an independent alignment for the moment
624    // Alignment al[] = new Alignment[jobs.length];
625    // NewickFile nf[] = new NewickFile[jobs.length];
626  0 for (int j = 0; j < jobs.length; j++)
627    {
628  0 Map<String, FeatureColourI> featureColours = new HashMap<String, FeatureColourI>();
629  0 Alignment al = null;
630  0 NewickFile nf = null;
631  0 if (jobs[j].hasResults())
632    {
633  0 Object[] res = ((SeqSearchWSJob) jobs[j]).getAlignment(dataset,
634    featureColours);
635  0 if (res == null)
636    {
637  0 continue;
638    }
639  0 ;
640  0 al = (Alignment) res[0];
641  0 nf = (NewickFile) res[1];
642    }
643    else
644    {
645  0 al = null;
646  0 nf = null;
647  0 continue;
648    }
649    /*
650    * We can't map new alignment back with insertions from input's hidden
651    * regions until dataset mapping is sorted out... but basically it goes
652    * like this: 1. Merge each domain hit back onto the visible segments in
653    * the same way as a Jnet prediction is mapped back
654    *
655    * Object[] newview = input.getUpdatedView(results, orders, getGapChar());
656    * // trash references to original result data for (int j = 0; j <
657    * jobs.length; j++) { results[j] = null; orders[j] = null; } SequenceI[]
658    * alignment = (SequenceI[]) newview[0]; ColumnSelection columnselection =
659    * (ColumnSelection) newview[1]; Alignment al = new Alignment(alignment);
660    *
661    * if (dataset != null) { al.setDataset(dataset); }
662    *
663    * propagateDatasetMappings(al); }
664    */
665   
666  0 AlignFrame af = new AlignFrame(al, // columnselection,
667    AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
668  0 if (nf != null)
669    {
670  0 af.showNewickTree(nf,
671    MessageManager.formatMessage("label.tree_from", new String[]
672    { this.alTitle }));
673    }
674    // initialise with same renderer settings as in parent alignframe.
675  0 af.getFeatureRenderer().transferSettings(this.featureSettings);
676  0 Desktop.addInternalFrame(af, alTitle, AlignFrame.DEFAULT_WIDTH,
677    AlignFrame.DEFAULT_HEIGHT);
678    }
679    }
680   
 
681  0 toggle @Override
682    public boolean canMergeResults()
683    {
684  0 return false;
685    }
686    }