JAL-961 JAL-976 kill any existing AACon job if a new AACon worker is started due...
[jalview.git] / src / jalview / ws / jws2 / JabawsAlignCalcWorker.java
1 package jalview.ws.jws2;
2
3 import jalview.analysis.AlignSeq;
4 import jalview.analysis.SeqsetUtils;
5 import jalview.api.AlignViewportI;
6 import jalview.api.AlignmentViewPanel;
7 import jalview.datamodel.AlignmentAnnotation;
8 import jalview.datamodel.AlignmentI;
9 import jalview.datamodel.SequenceI;
10 import jalview.gui.AlignFrame;
11 import jalview.gui.IProgressIndicator;
12 import jalview.workers.AlignCalcWorker;
13 import jalview.ws.jws2.dm.JabaWsParamSet;
14 import jalview.ws.jws2.jabaws2.Jws2Instance;
15 import jalview.ws.params.WsParamSetI;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import compbio.data.msa.SequenceAnnotation;
23 import compbio.data.sequence.FastaSequence;
24 import compbio.data.sequence.ScoreManager;
25 import compbio.metadata.Argument;
26 import compbio.metadata.ChunkHolder;
27 import compbio.metadata.JobStatus;
28 import compbio.metadata.JobSubmissionException;
29 import compbio.metadata.Option;
30 import compbio.metadata.ResultNotAvailableException;
31 import compbio.metadata.WrongParameterException;
32
33 public abstract class JabawsAlignCalcWorker extends AlignCalcWorker
34 {
35
36   @SuppressWarnings("unchecked")
37   protected SequenceAnnotation aaservice;
38
39   protected ScoreManager scoremanager;
40
41   protected WsParamSetI preset;
42
43   protected List<Argument> arguments;
44
45   public JabawsAlignCalcWorker(AlignViewportI alignViewport,
46           AlignmentViewPanel alignPanel)
47   {
48     super(alignViewport, alignPanel);
49   }
50
51   IProgressIndicator guiProgress;
52
53   public JabawsAlignCalcWorker(Jws2Instance service, AlignFrame alignFrame,
54           WsParamSetI preset, List<Argument> paramset)
55   {
56     this(alignFrame.getCurrentView(), alignFrame.alignPanel);
57     this.guiProgress = alignFrame;
58     this.preset = preset;
59     this.arguments = paramset;
60     aaservice = (SequenceAnnotation) service.service;
61
62   }
63
64   public WsParamSetI getPreset()
65   {
66     return preset;
67   }
68
69   public List<Argument> getArguments()
70   {
71     return arguments;
72   }
73
74   /**
75    * reconfigure and restart the AAConsClient. This method will spawn a new
76    * thread that will wait until any current jobs are finished, modify the
77    * parameters and restart the conservation calculation with the new values.
78    *
79    * @param newpreset
80    * @param newarguments
81    */
82   public void updateParameters(final WsParamSetI newpreset,
83           final List<Argument> newarguments)
84   {
85     if (false) // || calcMan.isWorking(this))
86     {
87       new Thread(new Runnable()
88       {
89         @Override
90         public void run()
91         {
92
93           try
94           {
95             Thread.sleep(200);
96           } catch (InterruptedException x)
97           {
98           }
99           ;
100           updateParameters(newpreset, newarguments);
101         }
102       }).start();
103     }
104     else
105     {
106       preset = newpreset;
107       arguments = newarguments;
108       calcMan.startWorker(this);
109     }
110   }
111
112   public List<Option> getJabaArguments()
113   {
114     List<Option> newargs = new ArrayList<Option>();
115     if (preset != null && preset instanceof JabaWsParamSet)
116     {
117       newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
118     }
119     if (arguments != null && arguments.size() > 0)
120     {
121       for (Argument rg : arguments)
122       {
123         if (Option.class.isAssignableFrom(rg.getClass()))
124         {
125           newargs.add((Option) rg);
126         }
127       }
128     }
129     return newargs;
130   }
131
132   @Override
133   public void run()
134   {
135     if (aaservice == null)
136     {
137       return;
138     }
139     long progressId = -1;
140
141     String rslt = "JOB NOT DEFINED";
142
143     try
144     {
145       if (checkDone())
146       {
147         return;
148       }
149       List<compbio.data.sequence.FastaSequence> seqs = getInputSequences(alignViewport
150               .getAlignment());
151
152       if (seqs == null)
153       {
154         calcMan.workerComplete(this);
155         return;
156       }
157
158       AlignmentAnnotation[] aa = alignViewport.getAlignment()
159               .getAlignmentAnnotation();
160       if (guiProgress != null)
161       {
162         guiProgress.setProgressBar("JABA " + getServiceActionText(),
163                 progressId = System.currentTimeMillis());
164       }
165       if (preset == null)
166       {
167         rslt = aaservice.analize(seqs);
168       }
169       else
170       {
171         try
172         {
173           rslt = aaservice.customAnalize(seqs, getJabaArguments());
174         } catch (WrongParameterException x)
175         {
176           throw new JobSubmissionException(
177                   "Invalid paremeter set. Check Jalview implementation.", x);
178
179         }
180       }
181       boolean finished = false;
182       long rpos = 0;
183       do
184       {
185         JobStatus status = aaservice.getJobStatus(rslt);
186         if (status.equals(JobStatus.FINISHED))
187         {
188           finished = true;
189         }
190         if (calcMan.isPending(this) && this instanceof AAConsClient)
191         {
192           finished = true;
193           // cancel this job and yield to the new job
194           try
195           {
196             if (aaservice.cancelJob(rslt))
197             {
198               System.err.println("Cancelled AACon job: " + rslt);
199             }
200             else
201             {
202               System.err.println("FAILED TO CANCELL AACon job: " + rslt);
203             }
204
205           } catch (Exception x)
206           {
207
208           }
209
210           return;
211         }
212         long cpos;
213         ChunkHolder stats;
214         do
215         {
216           cpos = rpos;
217           try
218           {
219             stats = aaservice.pullExecStatistics(rslt, rpos);
220           } catch (Exception x)
221           {
222
223             if (x.getMessage().contains(
224                     "Position in a file could not be negative!"))
225             {
226               // squash index out of bounds exception- seems to happen for
227               // disorder predictors which don't (apparently) produce any
228               // progress information and JABA server throws an exception
229               // because progress length is -1.
230               stats = null;
231             }
232             else
233             {
234               throw x;
235             }
236           }
237           if (stats != null)
238           {
239             System.out.print(stats.getChunk());
240             rpos = stats.getNextPosition();
241           }
242         } while (stats != null && rpos > cpos);
243
244         if (!finished && status.equals(JobStatus.FAILED))
245         {
246           try
247           {
248             Thread.sleep(200);
249           } catch (InterruptedException x)
250           {
251           }
252           ;
253         }
254
255       } while (!finished);
256       try
257       {
258         Thread.sleep(200);
259       } catch (InterruptedException x)
260       {
261       }
262       ;
263       scoremanager = aaservice.getAnnotation(rslt);
264       if (scoremanager != null)
265       {
266         updateResultAnnotation(true);
267       }
268     } catch (JobSubmissionException x)
269     {
270
271       System.err.println("submission error:");
272       x.printStackTrace();
273       calcMan.workerCannotRun(this);
274     } catch (ResultNotAvailableException x)
275     {
276       System.err.println("collection error:\nJob ID: " + rslt);
277       x.printStackTrace();
278       calcMan.workerCannotRun(this);
279
280     } catch (OutOfMemoryError error)
281     {
282       calcMan.workerCannotRun(this);
283
284       // consensus = null;
285       // hconsensus = null;
286       ap.raiseOOMWarning(getServiceActionText(), error);
287     } catch (Exception x)
288     {
289       calcMan.workerCannotRun(this);
290
291       // consensus = null;
292       // hconsensus = null;
293       System.err
294               .println("Blacklisting worker due to unexpected exception:");
295       x.printStackTrace();
296     } finally
297     {
298
299       calcMan.workerComplete(this);
300       if (ap != null)
301       {
302         calcMan.workerComplete(this);
303         if (guiProgress != null)
304         {
305           guiProgress.setProgressBar("", progressId);
306         }
307         ap.paintAlignment(true);
308       }
309     }
310
311   }
312
313   @Override
314   public void updateAnnotation()
315   {
316     updateResultAnnotation(false);
317   }
318
319   public abstract void updateResultAnnotation(boolean immediate);
320
321   public abstract String getServiceActionText();
322
323   boolean submitGaps = true;
324
325   boolean alignedSeqs = true;
326
327   boolean nucleotidesAllowed = false;
328
329   boolean proteinAllowed = false;
330
331   /**
332    * record sequences for mapping result back to afterwards
333    */
334   protected boolean bySequence = false;
335
336   Map<String, SequenceI> seqNames;
337
338   public List<FastaSequence> getInputSequences(AlignmentI alignment)
339   {
340
341     if (alignment == null || alignment.getWidth() <= 0
342             || alignment.getSequences() == null
343             // || (alignedSeqs && !alignment.isAligned() && !submitGaps)
344             || alignment.isNucleotide() ? !nucleotidesAllowed
345             : !proteinAllowed)
346     {
347       return null;
348     }
349     List<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
350
351     int minlen = 10;
352     int ln = -1;
353     if (bySequence)
354     {
355       seqNames = new HashMap<String, SequenceI>();
356     }
357     for (SequenceI sq : ((List<SequenceI>) alignment.getSequences()))
358     {
359
360       if (sq.getEnd() - sq.getStart() > minlen - 1)
361       {
362         String newname = SeqsetUtils.unique_name(seqs.size() + 1);
363         // make new input sequence with or without gaps
364         if (seqNames != null)
365         {
366           seqNames.put(newname, sq);
367         }
368         FastaSequence seq;
369         seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
370                 (submitGaps) ? sq.getSequenceAsString() : AlignSeq
371                         .extractGaps(jalview.util.Comparison.GapChars,
372                                 sq.getSequenceAsString())));
373         if (seq.getSequence().length() > ln)
374         {
375           ln = seq.getSequence().length();
376         }
377       }
378     }
379     if (alignedSeqs && submitGaps)
380     {
381       // try real hard to return something submittable
382       // TODO: some of AAcons measures need a minimum of two or three amino
383       // acids at each position, and aacons doesn't gracefully degrade.
384       for (int p = 0; p < seqs.size(); p++)
385       {
386         FastaSequence sq = seqs.get(p);
387         int l = sq.getSequence().length();
388         if (l < ln)
389         {
390           char[] padded = new char[ln];
391           System.arraycopy(sq.getSequence().toCharArray(), 0, padded, 0, sq
392                   .getSequence().length());
393           while (l < ln)
394           {
395             padded[l++] = '-';
396           }
397           seqs.set(p, new compbio.data.sequence.FastaSequence(sq.getId(),
398                   new String(padded)));
399         }
400       }
401
402     }
403     return seqs;
404   }
405
406   /**
407    * notify manager that we have started, and wait for a free calculation slot
408    *
409    * @return true if slot is obtained and work still valid, false if another
410    *         thread has done our work for us.
411    */
412   boolean checkDone()
413   {
414     calcMan.notifyStart(this);
415     // ap.paintAlignment(false);
416     while (!calcMan.notifyWorking(this))
417     {
418       if (calcMan.isWorking(this))
419       {
420         return true;
421       }
422       try
423       {
424         if (ap != null)
425         {
426           ap.paintAlignment(false);
427         }
428
429         Thread.sleep(200);
430       } catch (Exception ex)
431       {
432         ex.printStackTrace();
433       }
434     }
435     if (alignViewport.isClosed())
436     {
437       abortAndDestroy();
438       return true;
439     }
440     return false;
441   }
442
443 }