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