2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
21 package jalview.ws.jws2;
23 import jalview.analysis.AlignSeq;
24 import jalview.analysis.SeqsetUtils;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.AlignmentI;
29 import jalview.datamodel.AnnotatedCollectionI;
30 import jalview.datamodel.SequenceI;
31 import jalview.gui.AlignFrame;
32 import jalview.gui.IProgressIndicator;
33 import jalview.workers.AlignCalcWorker;
34 import jalview.ws.jws2.dm.AAConSettings;
35 import jalview.ws.jws2.dm.JabaWsParamSet;
36 import jalview.ws.jws2.jabaws2.Jws2Instance;
37 import jalview.ws.params.WsParamSetI;
39 import java.util.ArrayList;
40 import java.util.HashMap;
41 import java.util.List;
44 import compbio.data.sequence.FastaSequence;
45 import compbio.metadata.Argument;
46 import compbio.metadata.ChunkHolder;
47 import compbio.metadata.JobStatus;
48 import compbio.metadata.JobSubmissionException;
49 import compbio.metadata.Option;
50 import compbio.metadata.ResultNotAvailableException;
52 public abstract class AbstractJabaCalcWorker extends AlignCalcWorker
55 protected Jws2Instance service;
57 protected WsParamSetI preset;
59 protected List<Argument> arguments;
61 protected IProgressIndicator guiProgress;
63 protected boolean submitGaps = true;
66 * Recover any existing parameters for this service
68 protected void initViewportParams()
70 if (getCalcId() != null)
72 ((jalview.gui.AlignViewport) alignViewport).setCalcIdSettingsFor(
74 new AAConSettings(true, service, this.preset,
75 (arguments != null) ? JabaParamStore
76 .getJwsArgsfromJaba(arguments) : null), true);
82 * @return null or a string used to recover all annotation generated by this
85 public abstract String getCalcId();
87 public WsParamSetI getPreset()
92 public List<Argument> getArguments()
98 * reconfigure and restart the AAConClient. This method will spawn a new
99 * thread that will wait until any current jobs are finished, modify the
100 * parameters and restart the conservation calculation with the new values.
103 * @param newarguments
105 public void updateParameters(final WsParamSetI newpreset,
106 final List<Argument> newarguments)
109 arguments = newarguments;
110 calcMan.startWorker(this);
111 initViewportParams();
114 public List<Option> getJabaArguments()
116 List<Option> newargs = new ArrayList<Option>();
117 if (preset != null && preset instanceof JabaWsParamSet)
119 newargs.addAll(((JabaWsParamSet) preset).getjabaArguments());
121 if (arguments != null && arguments.size() > 0)
123 for (Argument rg : arguments)
125 if (Option.class.isAssignableFrom(rg.getClass()))
127 newargs.add((Option) rg);
134 protected boolean alignedSeqs = true;
136 protected boolean nucleotidesAllowed = false;
138 protected boolean proteinAllowed = false;
141 * record sequences for mapping result back to afterwards
143 protected boolean bySequence = false;
145 protected Map<String, SequenceI> seqNames;
147 protected boolean[] gapMap;
155 public AbstractJabaCalcWorker(AlignViewportI alignViewport,
156 AlignmentViewPanel alignPanel)
158 super(alignViewport, alignPanel);
161 public AbstractJabaCalcWorker(Jws2Instance service,
162 AlignFrame alignFrame, WsParamSetI preset, List<Argument> paramset)
164 this(alignFrame.getCurrentView(), alignFrame.alignPanel);
165 this.guiProgress = alignFrame;
166 this.preset = preset;
167 this.arguments = paramset;
168 this.service = service;
173 * @return true if the submission thread should attempt to submit data
175 abstract boolean hasService();
177 volatile String rslt = "JOB NOT DEFINED";
186 long progressId = -1;
188 int serverErrorsLeft = 3;
190 StringBuffer msg = new StringBuffer();
197 List<compbio.data.sequence.FastaSequence> seqs = getInputSequences(
198 alignViewport.getAlignment(),
199 bySequence ? alignViewport.getSelectionGroup() : null);
201 if (seqs == null || !checkValidInputSeqs(true, seqs))
203 calcMan.workerComplete(this);
207 AlignmentAnnotation[] aa = alignViewport.getAlignment()
208 .getAlignmentAnnotation();
209 if (guiProgress != null)
211 guiProgress.setProgressBar("JABA " + getServiceActionText(),
212 progressId = System.currentTimeMillis());
214 rslt = submitToService(seqs);
216 boolean finished = false;
220 JobStatus status = getJobStatus(rslt);
221 if (status.equals(JobStatus.FINISHED))
225 if (calcMan.isPending(this) && isInteractiveUpdate())
228 // cancel this job and yield to the new job
233 System.err.println("Cancelled AACon job: " + rslt);
237 System.err.println("FAILED TO CANCEL AACon job: " + rslt);
240 } catch (Exception x)
244 rslt = "CANCELLED JOB";
248 ChunkHolder stats = null;
252 boolean retry = false;
257 stats = pullExecStatistics(rslt, rpos);
258 } catch (Exception x)
261 if (x.getMessage().contains(
262 "Position in a file could not be negative!"))
264 // squash index out of bounds exception- seems to happen for
265 // disorder predictors which don't (apparently) produce any
266 // progress information and JABA server throws an exception
267 // because progress length is -1.
272 if (--serverErrorsLeft > 0)
278 } catch (InterruptedException q)
292 System.out.print(stats.getChunk());
294 rpos = stats.getNextPosition();
296 } while (stats != null && rpos > cpos);
298 if (!finished && status.equals(JobStatus.FAILED))
303 } catch (InterruptedException x)
309 if (serverErrorsLeft > 0)
314 } catch (InterruptedException x)
317 if (collectAnnotationResultsFor(rslt))
319 jalview.bin.Cache.log
320 .debug("Updating result annotation from Job " + rslt
321 + " at " + service.getUri());
322 updateResultAnnotation(true);
323 ap.adjustAnnotationHeight();
328 catch (JobSubmissionException x)
331 System.err.println("submission error with " + getServiceActionText()
334 calcMan.workerCannotRun(this);
335 } catch (ResultNotAvailableException x)
337 System.err.println("collection error:\nJob ID: " + rslt);
339 calcMan.workerCannotRun(this);
341 } catch (OutOfMemoryError error)
343 calcMan.workerCannotRun(this);
346 // hconsensus = null;
347 ap.raiseOOMWarning(getServiceActionText(), error);
348 } catch (Exception x)
350 calcMan.workerCannotRun(this);
353 // hconsensus = null;
355 .println("Blacklisting worker due to unexpected exception:");
360 calcMan.workerComplete(this);
363 calcMan.workerComplete(this);
364 if (guiProgress != null && progressId != -1)
366 guiProgress.setProgressBar("", progressId);
368 ap.paintAlignment(true);
370 if (msg.length() > 0)
372 // TODO: stash message somewhere in annotation or alignment view.
373 // code below shows result in a text box popup
375 * jalview.gui.CutAndPasteTransfer cap = new
376 * jalview.gui.CutAndPasteTransfer(); cap.setText(msg.toString());
377 * jalview.gui.Desktop.addInternalFrame(cap,
378 * "Job Status for "+getServiceActionText(), 600, 400);
386 * validate input for dynamic/non-dynamic update context
390 * @return true if input is valid
392 abstract boolean checkValidInputSeqs(boolean dynamic,
393 List<FastaSequence> seqs);
395 abstract String submitToService(
396 List<compbio.data.sequence.FastaSequence> seqs)
397 throws JobSubmissionException;
399 abstract boolean cancelJob(String rslt) throws Exception;
401 abstract JobStatus getJobStatus(String rslt) throws Exception;
403 abstract ChunkHolder pullExecStatistics(String rslt, long rpos);
405 abstract boolean collectAnnotationResultsFor(String rslt)
406 throws ResultNotAvailableException;
408 public void cancelCurrentJob()
415 System.err.println("Cancelled job " + id);
419 System.err.println("Job " + id + " couldn't be cancelled.");
421 } catch (Exception q)
428 * Interactive updating. Analysis calculations that work on the currently
429 * displayed alignment data should cancel existing jobs when the input data
432 * @return true if a running job should be cancelled because new input data is
433 * available for analysis
435 abstract boolean isInteractiveUpdate();
437 public List<FastaSequence> getInputSequences(AlignmentI alignment,
438 AnnotatedCollectionI inputSeqs)
440 if (alignment == null || alignment.getWidth() <= 0
441 || alignment.getSequences() == null || alignment.isNucleotide() ? !nucleotidesAllowed
446 if (inputSeqs == null || inputSeqs.getWidth() <= 0
447 || inputSeqs.getSequences() == null
448 || inputSeqs.getSequences().size() < 1)
450 inputSeqs = alignment;
453 List<compbio.data.sequence.FastaSequence> seqs = new ArrayList<compbio.data.sequence.FastaSequence>();
459 seqNames = new HashMap<String, SequenceI>();
461 gapMap = new boolean[0];
462 start = inputSeqs.getStartRes();
463 end = inputSeqs.getEndRes();
465 for (SequenceI sq : ((List<SequenceI>) inputSeqs.getSequences()))
467 if (bySequence ? sq.findPosition(end + 1)
468 - sq.findPosition(start + 1) > minlen - 1 : sq.getEnd()
469 - sq.getStart() > minlen - 1)
471 String newname = SeqsetUtils.unique_name(seqs.size() + 1);
472 // make new input sequence with or without gaps
473 if (seqNames != null)
475 seqNames.put(newname, sq);
480 seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
481 sq.getSequenceAsString()));
482 if (gapMap == null || gapMap.length < seq.getSequence().length())
484 boolean[] tg = gapMap;
485 gapMap = new boolean[seq.getLength()];
486 System.arraycopy(tg, 0, gapMap, 0, tg.length);
487 for (int p = tg.length; p < gapMap.length; p++)
489 gapMap[p] = false; // init as a gap
492 for (int apos : sq.gapMap())
494 gapMap[apos] = true; // aligned.
499 seqs.add(seq = new compbio.data.sequence.FastaSequence(newname,
500 AlignSeq.extractGaps(jalview.util.Comparison.GapChars,
501 sq.getSequenceAsString(start, end + 1))));
503 if (seq.getSequence().length() > ln)
505 ln = seq.getSequence().length();
509 if (alignedSeqs && submitGaps)
512 for (int i = 0; i < gapMap.length; i++)
519 // try real hard to return something submittable
520 // TODO: some of AAcon measures need a minimum of two or three amino
521 // acids at each position, and AAcon doesn't gracefully degrade.
522 for (int p = 0; p < seqs.size(); p++)
524 FastaSequence sq = seqs.get(p);
525 int l = sq.getSequence().length();
526 // strip gapped columns
527 char[] padded = new char[realw], orig = sq.getSequence()
529 for (int i = 0, pp = 0; i < realw; pp++)
533 if (orig.length > pp)
535 padded[i++] = orig[pp];
543 seqs.set(p, new compbio.data.sequence.FastaSequence(sq.getId(),
544 new String(padded)));
551 public void updateAnnotation()
553 updateResultAnnotation(false);
556 public abstract void updateResultAnnotation(boolean immediate);
558 public abstract String getServiceActionText();
561 * notify manager that we have started, and wait for a free calculation slot
563 * @return true if slot is obtained and work still valid, false if another
564 * thread has done our work for us.
566 protected boolean checkDone()
568 calcMan.notifyStart(this);
569 ap.paintAlignment(false);
570 while (!calcMan.notifyWorking(this))
572 if (calcMan.isWorking(this))
580 ap.paintAlignment(false);
584 } catch (Exception ex)
586 ex.printStackTrace();
589 if (alignViewport.isClosed())
597 protected void updateOurAnnots(List<AlignmentAnnotation> ourAnnot)
599 List<AlignmentAnnotation> our = ourAnnots;
600 ourAnnots = ourAnnot;
601 AlignmentI alignment = alignViewport.getAlignment();
606 for (AlignmentAnnotation an : our)
608 if (!ourAnnots.contains(an))
610 // remove the old annotation
611 alignment.deleteAnnotation(an);
617 ap.adjustAnnotationHeight();