JAL-4199 Fix interactive jobs not being stopped
[jalview.git] / src / jalview / ws2 / actions / annotation / AlignCalcWorkerAdapter.java
1 package jalview.ws2.actions.annotation;
2
3 import java.util.Collections;
4 import java.util.List;
5 import java.util.concurrent.CopyOnWriteArrayList;
6
7 import jalview.api.AlignViewportI;
8 import jalview.api.AlignmentViewPanel;
9 import jalview.api.PollableAlignCalcWorkerI;
10 import jalview.datamodel.AlignmentAnnotation;
11 import jalview.datamodel.AlignmentI;
12 import jalview.workers.AlignCalcWorker;
13 import jalview.ws.params.ArgumentI;
14 import jalview.ws2.actions.api.TaskEventListener;
15 import jalview.ws2.actions.api.TaskI;
16 import jalview.ws2.api.Credentials;
17
18 public class AlignCalcWorkerAdapter extends AlignCalcWorker implements PollableAlignCalcWorkerI
19 {
20   private final AnnotationAction action;
21
22   private final List<ArgumentI> args;
23
24   private final Credentials credentials;
25
26   private TaskI<AnnotationResult> currentTask = null;
27
28   private TaskEventListener<AnnotationResult> internalTaskListener = new TaskEventListener<>()
29   {
30     @Override
31     public void taskCompleted(TaskI source, AnnotationResult result)
32     {
33       updateOurAnnots(result.getAnnotations());
34     }
35   };
36
37   // task event listeners managed by this worker, passed to each creates task
38   private List<TaskEventListener<AnnotationResult>> taskListeners = new CopyOnWriteArrayList<>();
39   {
40     taskListeners.add(internalTaskListener);
41   }
42
43   public AlignCalcWorkerAdapter(AlignViewportI alignViewport, AlignmentViewPanel alignPanel, AnnotationAction action,
44       List<ArgumentI> args, Credentials credentials)
45   {
46     super(alignViewport, alignPanel);
47     this.action = action;
48     this.args = args;
49     this.credentials = credentials;
50   }
51
52   @Override
53   public String getCalcName()
54   {
55     return action.getWebService().getName();
56   }
57
58   @Override
59   public void updateAnnotation()
60   {
61
62   }
63
64   private void updateOurAnnots(List<AlignmentAnnotation> newAnnots)
65   {
66     List<AlignmentAnnotation> oldAnnots = ourAnnots != null ? ourAnnots : List.of();
67     AlignmentI alignment = alignViewport.getAlignment();
68     for (AlignmentAnnotation annotation : oldAnnots)
69       if (!newAnnots.contains(annotation))
70         alignment.deleteAnnotation(annotation);
71     for (AlignmentAnnotation annotation : newAnnots)
72       alignment.validateAnnotation(annotation);
73     ap.adjustAnnotationHeight();
74     ourAnnots = Collections.synchronizedList(newAnnots);
75   }
76
77   @Override
78   public synchronized void startUp() throws Throwable
79   {
80     if (alignViewport.isClosed())
81     {
82       calcMan.disableWorker(this);
83       abortAndDestroy();
84       throw new IllegalStateException("Starting calculation for closed viewport");
85     }
86     currentTask = action.createTask(alignViewport, args, credentials);
87     for (var listener : taskListeners)
88       currentTask.addTaskEventListener(listener);
89     currentTask.init();
90   }
91
92   @Override
93   public boolean poll() throws Throwable
94   {
95     return currentTask.poll();
96   }
97
98   @Override
99   public synchronized void cancel()
100   {
101     try
102     {
103       currentTask.cancel();
104     } finally
105     {
106       for (var listener : taskListeners)
107         currentTask.removeTaskEventListener(listener);
108     }
109   }
110
111   @Override
112   public synchronized void done()
113   {
114     try
115     {
116       currentTask.complete();
117     } catch (Exception e)
118     {
119     } finally
120     {
121       for (var listener : taskListeners)
122         currentTask.removeTaskEventListener(listener);
123     }
124   }
125
126   public void addTaskEventListener(TaskEventListener<AnnotationResult> listener)
127   {
128     taskListeners.add(listener);
129     if (currentTask != null)
130       currentTask.addTaskEventListener(listener);
131   }
132
133   public void removeTaskEventListener(TaskEventListener<AnnotationResult> listener)
134   {
135     taskListeners.remove(listener);
136     if (currentTask != null)
137       currentTask.removeTaskEventListener(listener);
138   }
139
140   @Override
141   public String toString()
142   {
143     return "AlignCalcWorkerAdapter for " + getCalcName();
144   }
145 }