Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 16:01:40 GMT
  2. Package jalview.ws.jws2

File AbstractJabaCalcWorker.java

 

Coverage histogram

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

Code metrics

108
187
15
1
662
504
99
0.53
12.47
15
6.6

Classes

Class Line # Actions
AbstractJabaCalcWorker 55 187 99
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.jws2;
22   
23    import jalview.analysis.AlignSeq;
24    import jalview.analysis.SeqsetUtils;
25    import jalview.api.AlignViewportI;
26    import jalview.api.AlignmentViewPanel;
27    import jalview.bin.Console;
28    import jalview.datamodel.AlignmentAnnotation;
29    import jalview.datamodel.AlignmentI;
30    import jalview.datamodel.AnnotatedCollectionI;
31    import jalview.datamodel.SequenceI;
32    import jalview.gui.AlignFrame;
33    import jalview.gui.IProgressIndicator;
34    import jalview.gui.IProgressIndicatorHandler;
35    import jalview.schemes.ResidueProperties;
36    import jalview.workers.AlignCalcWorker;
37    import jalview.ws.jws2.dm.AAConSettings;
38    import jalview.ws.jws2.dm.JabaWsParamSet;
39    import jalview.ws.jws2.jabaws2.Jws2Instance;
40    import jalview.ws.params.WsParamSetI;
41   
42    import java.util.ArrayList;
43    import java.util.HashMap;
44    import java.util.List;
45    import java.util.Map;
46   
47    import compbio.data.sequence.FastaSequence;
48    import compbio.metadata.Argument;
49    import compbio.metadata.ChunkHolder;
50    import compbio.metadata.JobStatus;
51    import compbio.metadata.JobSubmissionException;
52    import compbio.metadata.Option;
53    import compbio.metadata.ResultNotAvailableException;
54   
 
55    public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
56    {
57   
58    protected Jws2Instance service;
59   
60    protected WsParamSetI preset;
61   
62    protected List<Argument> arguments;
63   
64    protected IProgressIndicator guiProgress;
65   
66    protected boolean submitGaps = true;
67   
68    /**
69    * by default, we filter out non-standard residues before submission
70    */
71    protected boolean filterNonStandardResidues = true;
72   
73    /**
74    * Recover any existing parameters for this service
75    */
 
76  0 toggle protected void initViewportParams()
77    {
78  0 if (getCalcId() != null)
79    {
80  0 ((jalview.gui.AlignViewport) alignViewport).setCalcIdSettingsFor(
81    getCalcId(),
82    new AAConSettings(true, service, this.preset,
83  0 (arguments != null)
84    ? JabaParamStore.getJwsArgsfromJaba(arguments)
85    : null),
86    true);
87    }
88    }
89   
90    /**
91    *
92    * @return null or a string used to recover all annotation generated by this
93    * worker
94    */
95    public abstract String getCalcId();
96   
 
97  0 toggle public WsParamSetI getPreset()
98    {
99  0 return preset;
100    }
101   
 
102  0 toggle public List<Argument> getArguments()
103    {
104  0 return arguments;
105    }
106   
107    /**
108    * reconfigure and restart the AAConClient. This method will spawn a new
109    * thread that will wait until any current jobs are finished, modify the
110    * parameters and restart the conservation calculation with the new values.
111    *
112    * @param newpreset
113    * @param newarguments
114    */
 
115  0 toggle public void updateParameters(final WsParamSetI newpreset,
116    final List<Argument> newarguments)
117    {
118  0 preset = newpreset;
119  0 arguments = newarguments;
120  0 calcMan.startWorker(this);
121  0 initViewportParams();
122    }
123   
 
124  0 toggle public List<Option> getJabaArguments()
125    {
126  0 List<Option> newargs = new ArrayList<>();
127  0 if (preset != null && preset instanceof JabaWsParamSet)
128    {
129  0 newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
130    }
131  0 if (arguments != null && arguments.size() > 0)
132    {
133  0 for (Argument rg : arguments)
134    {
135  0 if (Option.class.isAssignableFrom(rg.getClass()))
136    {
137  0 newargs.add((Option) rg);
138    }
139    }
140    }
141  0 return newargs;
142    }
143   
144    protected boolean alignedSeqs = true;
145   
146    protected boolean nucleotidesAllowed = false;
147   
148    protected boolean proteinAllowed = false;
149   
150    /**
151    * record sequences for mapping result back to afterwards
152    */
153    protected boolean bySequence = false;
154   
155    protected Map<String, SequenceI> seqNames;
156   
157    protected boolean[] gapMap;
158   
159    int realw;
160   
161    protected int start;
162   
163    int end;
164   
 
165  0 toggle public AbstractJabaCalcWorker(AlignViewportI alignViewport,
166    AlignmentViewPanel alignPanel)
167    {
168  0 super(alignViewport, alignPanel);
169    }
170   
 
171  0 toggle public AbstractJabaCalcWorker(Jws2Instance service, AlignFrame alignFrame,
172    WsParamSetI preset, List<Argument> paramset)
173    {
174  0 this(alignFrame.getCurrentView(), alignFrame.alignPanel);
175  0 this.guiProgress = alignFrame;
176  0 this.preset = preset;
177  0 this.arguments = paramset;
178  0 this.service = service;
179    }
180   
181    /**
182    *
183    * @return true if the submission thread should attempt to submit data
184    */
185    abstract boolean hasService();
186   
187    volatile String rslt = "JOB NOT DEFINED";
188   
 
189  0 toggle @Override
190    public void run()
191    {
192  0 if (!hasService())
193    {
194  0 return;
195    }
196  0 long progressId = -1;
197   
198  0 int serverErrorsLeft = 3;
199   
200  0 StringBuffer msg = new StringBuffer();
201  0 try
202    {
203  0 if (checkDone())
204    {
205  0 return;
206    }
207  0 List<compbio.data.sequence.FastaSequence> seqs = getInputSequences(
208    alignViewport.getAlignment(),
209  0 bySequence ? alignViewport.getSelectionGroup() : null);
210   
211  0 if (seqs == null || !checkValidInputSeqs(true, seqs))
212    {
213  0 calcMan.workerComplete(this);
214  0 return;
215    }
216   
217  0 AlignmentAnnotation[] aa = alignViewport.getAlignment()
218    .getAlignmentAnnotation();
219  0 if (guiProgress != null)
220    {
221  0 guiProgress.setProgressBar("JABA " + getServiceActionText(),
222    progressId = System.currentTimeMillis());
223    }
224  0 rslt = submitToService(seqs);
225  0 if (guiProgress != null)
226    {
227  0 guiProgress.registerHandler(progressId,
228    new IProgressIndicatorHandler()
229    {
230   
 
231  0 toggle @Override
232    public boolean cancelActivity(long id)
233    {
234  0 cancelCurrentJob();
235  0 return true;
236    }
237   
 
238  0 toggle @Override
239    public boolean canCancel()
240    {
241  0 return true;
242    }
243    });
244    }
245  0 boolean finished = false;
246  0 long rpos = 0;
247  0 do
248    {
249  0 JobStatus status = getJobStatus(rslt);
250  0 if (status.equals(JobStatus.FINISHED))
251    {
252  0 finished = true;
253    }
254  0 if (calcMan.isPending(this) && isInteractiveUpdate())
255    {
256  0 finished = true;
257    // cancel this job and yield to the new job
258  0 try
259    {
260  0 if (cancelJob(rslt))
261    {
262  0 jalview.bin.Console
263    .errPrintln("Cancelled AACon job: " + rslt);
264    }
265    else
266    {
267  0 jalview.bin.Console
268    .errPrintln("FAILED TO CANCEL AACon job: " + rslt);
269    }
270   
271    } catch (Exception x)
272    {
273   
274    }
275  0 rslt = "CANCELLED JOB";
276  0 return;
277    }
278  0 long cpos;
279  0 ChunkHolder stats = null;
280  0 do
281    {
282  0 cpos = rpos;
283  0 boolean retry = false;
284  0 do
285    {
286  0 try
287    {
288  0 stats = pullExecStatistics(rslt, rpos);
289    } catch (Exception x)
290    {
291   
292  0 if (x.getMessage().contains(
293    "Position in a file could not be negative!"))
294    {
295    // squash index out of bounds exception- seems to happen for
296    // disorder predictors which don't (apparently) produce any
297    // progress information and JABA server throws an exception
298    // because progress length is -1.
299  0 stats = null;
300    }
301    else
302    {
303  0 if (--serverErrorsLeft > 0)
304    {
305  0 retry = true;
306  0 try
307    {
308  0 Thread.sleep(200);
309    } catch (InterruptedException q)
310    {
311    }
312  0 ;
313    }
314    else
315    {
316  0 throw x;
317    }
318    }
319    }
320  0 } while (retry);
321  0 if (stats != null)
322    {
323  0 System.out.print(stats.getChunk());
324  0 msg.append(stats);
325  0 rpos = stats.getNextPosition();
326    }
327  0 } while (stats != null && rpos > cpos);
328   
329  0 if (!finished && status.equals(JobStatus.FAILED))
330    {
331  0 try
332    {
333  0 Thread.sleep(200);
334    } catch (InterruptedException x)
335    {
336    }
337  0 ;
338    }
339  0 } while (!finished);
340  0 if (serverErrorsLeft > 0)
341    {
342  0 try
343    {
344  0 Thread.sleep(200);
345    } catch (InterruptedException x)
346    {
347    }
348  0 if (collectAnnotationResultsFor(rslt))
349    {
350  0 Console.debug("Updating result annotation from Job " + rslt
351    + " at " + service.getUri());
352  0 updateResultAnnotation(true);
353  0 ap.adjustAnnotationHeight();
354    }
355    }
356    }
357   
358    catch (JobSubmissionException x)
359    {
360   
361  0 jalview.bin.Console.errPrintln(
362    "submission error with " + getServiceActionText() + " :");
363  0 x.printStackTrace();
364  0 calcMan.disableWorker(this);
365    } catch (ResultNotAvailableException x)
366    {
367  0 jalview.bin.Console.errPrintln("collection error:\nJob ID: " + rslt);
368  0 x.printStackTrace();
369  0 calcMan.disableWorker(this);
370   
371    } catch (OutOfMemoryError error)
372    {
373  0 calcMan.disableWorker(this);
374   
375    // consensus = null;
376    // hconsensus = null;
377  0 ap.raiseOOMWarning(getServiceActionText(), error);
378    } catch (Exception x)
379    {
380  0 calcMan.disableWorker(this);
381   
382    // consensus = null;
383    // hconsensus = null;
384  0 System.err
385    .println("Blacklisting worker due to unexpected exception:");
386  0 x.printStackTrace();
387    } finally
388    {
389   
390  0 calcMan.workerComplete(this);
391  0 if (ap != null)
392    {
393  0 calcMan.workerComplete(this);
394  0 if (guiProgress != null && progressId != -1)
395    {
396  0 guiProgress.setProgressBar("", progressId);
397    }
398    // TODO: may not need to paintAlignment again !
399  0 ap.paintAlignment(false, false);
400    }
401  0 if (msg.length() > 0)
402    {
403    // TODO: stash message somewhere in annotation or alignment view.
404    // code below shows result in a text box popup
405    /*
406    * jalview.gui.CutAndPasteTransfer cap = new
407    * jalview.gui.CutAndPasteTransfer(); cap.setText(msg.toString());
408    * jalview.gui.Desktop.addInternalFrame(cap,
409    * "Job Status for "+getServiceActionText(), 600, 400);
410    */
411    }
412    }
413   
414    }
415   
416    /**
417    * validate input for dynamic/non-dynamic update context
418    *
419    * @param dynamic
420    * @param seqs
421    * @return true if input is valid
422    */
423    abstract boolean checkValidInputSeqs(boolean dynamic,
424    List<FastaSequence> seqs);
425   
426    abstract String submitToService(
427    List<compbio.data.sequence.FastaSequence> seqs)
428    throws JobSubmissionException;
429   
430    abstract boolean cancelJob(String rslt) throws Exception;
431   
432    abstract JobStatus getJobStatus(String rslt) throws Exception;
433   
434    abstract ChunkHolder pullExecStatistics(String rslt, long rpos);
435   
436    abstract boolean collectAnnotationResultsFor(String rslt)
437    throws ResultNotAvailableException;
438   
 
439  0 toggle public void cancelCurrentJob()
440    {
441  0 try
442    {
443  0 String id = rslt;
444  0 if (cancelJob(rslt))
445    {
446  0 jalview.bin.Console.errPrintln("Cancelled job " + id);
447    }
448    else
449    {
450  0 jalview.bin.Console
451    .errPrintln("Job " + id + " couldn't be cancelled.");
452    }
453    } catch (Exception q)
454    {
455  0 q.printStackTrace();
456    }
457    }
458   
459    /**
460    * Interactive updating. Analysis calculations that work on the currently
461    * displayed alignment data should cancel existing jobs when the input data
462    * has changed.
463    *
464    * @return true if a running job should be cancelled because new input data is
465    * available for analysis
466    */
467    abstract boolean isInteractiveUpdate();
468   
 
469  0 toggle public List<FastaSequence> getInputSequences(AlignmentI alignment,
470    AnnotatedCollectionI inputSeqs)
471    {
472  0 if (alignment == null || alignment.getWidth() <= 0
473    || alignment.getSequences() == null || alignment.isNucleotide()
474    ? !nucleotidesAllowed
475    : !proteinAllowed)
476    {
477  0 return null;
478    }
479  0 if (inputSeqs == null || inputSeqs.getWidth() <= 0
480    || inputSeqs.getSequences() == null
481    || inputSeqs.getSequences().size() < 1)
482    {
483  0 inputSeqs = alignment;
484    }
485   
486  0 List<compbio.data.sequence.FastaSequence> seqs = new ArrayList<>();
487   
488  0 int minlen = 10;
489  0 int ln = -1;
490  0 if (bySequence)
491    {
492  0 seqNames = new HashMap<>();
493    }
494  0 gapMap = new boolean[0];
495  0 start = inputSeqs.getStartRes();
496  0 end = inputSeqs.getEndRes();
497   
498  0 for (SequenceI sq : (inputSeqs.getSequences()))
499    {
500  0 if (bySequence
501    ? sq.findPosition(end + 1)
502    - sq.findPosition(start + 1) > minlen - 1
503    : sq.getEnd() - sq.getStart() > minlen - 1)
504    {
505  0 String newname = SeqsetUtils.unique_name(seqs.size() + 1);
506    // make new input sequence with or without gaps
507  0 if (seqNames != null)
508    {
509  0 seqNames.put(newname, sq);
510    }
511  0 FastaSequence seq;
512  0 if (submitGaps)
513    {
514  0 seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
515    sq.getSequenceAsString()));
516  0 if (gapMap == null || gapMap.length < seq.getSequence().length())
517    {
518  0 boolean[] tg = gapMap;
519  0 gapMap = new boolean[seq.getLength()];
520  0 System.arraycopy(tg, 0, gapMap, 0, tg.length);
521  0 for (int p = tg.length; p < gapMap.length; p++)
522    {
523  0 gapMap[p] = false; // init as a gap
524    }
525    }
526  0 for (int apos : sq.gapMap())
527    {
528  0 char sqc = sq.getCharAt(apos);
529  0 if (!filterNonStandardResidues
530  0 || (sq.isProtein() ? ResidueProperties.aaIndex[sqc] < 20
531    : ResidueProperties.nucleotideIndex[sqc] < 5))
532    {
533  0 gapMap[apos] = true; // aligned and real amino acid residue
534    }
535  0 ;
536    }
537    }
538    else
539    {
540  0 seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
541    AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
542    sq.getSequenceAsString(start, end + 1))));
543    }
544  0 if (seq.getSequence().length() > ln)
545    {
546  0 ln = seq.getSequence().length();
547    }
548    }
549    }
550  0 if (alignedSeqs && submitGaps)
551    {
552  0 realw = 0;
553  0 for (int i = 0; i < gapMap.length; i++)
554    {
555  0 if (gapMap[i])
556    {
557  0 realw++;
558    }
559    }
560    // try real hard to return something submittable
561    // TODO: some of AAcon measures need a minimum of two or three amino
562    // acids at each position, and AAcon doesn't gracefully degrade.
563  0 for (int p = 0; p < seqs.size(); p++)
564    {
565  0 FastaSequence sq = seqs.get(p);
566  0 int l = sq.getSequence().length();
567    // strip gapped columns
568  0 char[] padded = new char[realw],
569    orig = sq.getSequence().toCharArray();
570  0 for (int i = 0, pp = 0; i < realw; pp++)
571    {
572  0 if (gapMap[pp])
573    {
574  0 if (orig.length > pp)
575    {
576  0 padded[i++] = orig[pp];
577    }
578    else
579    {
580  0 padded[i++] = '-';
581    }
582    }
583    }
584  0 seqs.set(p, new compbio.data.sequence.FastaSequence(sq.getId(),
585    new String(padded)));
586    }
587    }
588  0 return seqs;
589    }
590   
 
591  0 toggle @Override
592    public void updateAnnotation()
593    {
594  0 updateResultAnnotation(false);
595    }
596   
597    public abstract void updateResultAnnotation(boolean immediate);
598   
599    public abstract String getServiceActionText();
600   
601    /**
602    * notify manager that we have started, and wait for a free calculation slot
603    *
604    * @return true if slot is obtained and work still valid, false if another
605    * thread has done our work for us.
606    */
 
607  0 toggle protected boolean checkDone()
608    {
609  0 calcMan.notifyStart(this);
610  0 ap.paintAlignment(false, false);
611  0 while (!calcMan.notifyWorking(this))
612    {
613  0 if (calcMan.isWorking(this))
614    {
615  0 return true;
616    }
617  0 try
618    {
619  0 if (ap != null)
620    {
621  0 ap.paintAlignment(false, false);
622    }
623   
624  0 Thread.sleep(200);
625    } catch (Exception ex)
626    {
627  0 ex.printStackTrace();
628    }
629    }
630  0 if (alignViewport.isClosed())
631    {
632  0 abortAndDestroy();
633  0 return true;
634    }
635  0 return false;
636    }
637   
 
638  0 toggle protected void updateOurAnnots(List<AlignmentAnnotation> ourAnnot)
639    {
640  0 List<AlignmentAnnotation> our = ourAnnots;
641  0 ourAnnots = ourAnnot;
642  0 AlignmentI alignment = alignViewport.getAlignment();
643  0 if (our != null)
644    {
645  0 if (our.size() > 0)
646    {
647  0 for (AlignmentAnnotation an : our)
648    {
649  0 if (!ourAnnots.contains(an))
650    {
651    // remove the old annotation
652  0 alignment.deleteAnnotation(an);
653    }
654    }
655    }
656  0 our.clear();
657   
658  0 ap.adjustAnnotationHeight();
659    }
660    }
661   
662    }