Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.ws.jws1

File SeqSearchWSThread.java

 

Coverage histogram

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

Code metrics

98
197
18
2
683
494
87
0.44
10.94
9
4.83

Classes

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