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