1 package jalview.workers;
5 import java.util.concurrent.Callable;
6 import java.util.concurrent.CancellationException;
7 import java.util.concurrent.CopyOnWriteArrayList;
8 import java.util.concurrent.ExecutionException;
9 import java.util.concurrent.ExecutorService;
10 import java.util.concurrent.Executors;
11 import java.util.concurrent.FutureTask;
12 import java.util.concurrent.atomic.AtomicInteger;
13 import java.util.stream.Collectors;
15 import jalview.api.AlignCalcListener;
16 import jalview.api.AlignCalcManagerI;
17 import jalview.api.AlignCalcManagerI2;
18 import jalview.api.AlignCalcWorkerI;
19 import jalview.datamodel.AlignmentAnnotation;
21 import static java.util.Collections.synchronizedList;
22 import static java.util.Collections.synchronizedSet;
23 import static java.util.Collections.unmodifiableList;
25 import java.util.ArrayList;
26 import java.util.HashSet;
28 public class AlignCalcManager2 implements AlignCalcManagerI2
30 class AlignCalcTask extends FutureTask<Void>
32 final AlignCalcWorkerI worker;
34 public AlignCalcTask(AlignCalcWorkerI worker)
36 super(new Callable<Void>() {
37 public Void call() throws Exception {
38 notifyStarted(worker);
46 public AlignCalcWorkerI getWorker()
54 boolean success = false;
55 Throwable exception = null;
60 } catch (ExecutionException e)
62 exception = e.getCause();
63 if (exception instanceof OutOfMemoryError) {
64 disableWorker(getWorker());
71 inProgress.remove(getWorker());
75 notifyCompleted(worker);
77 notifyExceptional(worker, exception);
81 // main executor for running workers one-by-one
82 private final ExecutorService executor = Executors.newSingleThreadExecutor();
84 private final List<AlignCalcListener> listeners = new CopyOnWriteArrayList<AlignCalcListener>();
86 // list of all registered workers (other collections are subsets of this)
87 private final List<AlignCalcWorkerI> registered = synchronizedList(new ArrayList<>());
89 // list of tasks holding queued and running workers
90 private final List<AlignCalcTask> tasks = synchronizedList(new ArrayList<>());
92 // the collection of currently running workers
93 private final Set<AlignCalcWorkerI> inProgress = synchronizedSet(new HashSet<>());
95 // the collection of workers that will not be started
96 private final Set<AlignCalcWorkerI> disabled = synchronizedSet(new HashSet<>());
99 * Register the worker with this manager and scheduler for execution.
102 public void registerWorker(AlignCalcWorkerI worker)
104 synchronized (registered)
106 if (!registered.contains(worker))
107 registered.add(worker);
113 public List<AlignCalcWorkerI> getWorkers()
115 return unmodifiableList(new ArrayList<>(registered));
119 public List<AlignCalcWorkerI> getWorkersOfClass(
120 Class<? extends AlignCalcWorkerI> cls)
122 synchronized (registered)
124 return registered.stream()
125 .filter(worker -> worker.getClass().equals(cls))
126 .collect(Collectors.toUnmodifiableList());
131 public void removeWorker(AlignCalcWorkerI worker)
133 registered.remove(worker);
134 disabled.remove(worker);
138 public void removeWorkersOfClass(Class<? extends AlignCalcWorkerI> cls)
140 synchronized (registered)
142 for (var it = registered.iterator(); it.hasNext();)
144 var worker = it.next();
145 if (worker.getClass().equals(cls))
148 disabled.remove(worker);
155 public void removeWorkerForAnnotation(AlignmentAnnotation annot)
157 synchronized (registered)
159 for (var it = registered.iterator(); it.hasNext();)
161 var worker = it.next();
162 if (worker.involves(annot) && worker.isDeletable())
165 disabled.remove(worker);
172 public void disableWorker(AlignCalcWorkerI worker)
174 assert registered.contains(worker);
175 disabled.add(worker);
179 public void enableWorker(AlignCalcWorkerI worker)
181 disabled.remove(worker);
185 public void restartWorkers()
187 synchronized (registered)
189 for (AlignCalcWorkerI worker : registered)
191 if (!isDisabled(worker))
198 public void startWorker(AlignCalcWorkerI worker)
200 assert registered.contains(worker);
201 synchronized (tasks) {
202 for (var task : tasks)
204 if (task.getWorker().equals(worker))
208 AlignCalcTask newTask = new AlignCalcTask(worker);
210 notifyQueued(worker);
211 executor.execute(newTask);
215 public void cancelWorker(AlignCalcWorkerI worker)
217 if (isWorking(worker))
221 for (var task : tasks)
223 if (task.getWorker().equals(worker))
231 public boolean isDisabled(AlignCalcWorkerI worker)
233 return disabled.contains(worker);
237 public boolean isWorking(AlignCalcWorkerI worker)
239 return inProgress.contains(worker);
243 public boolean isWorking()
245 return !inProgress.isEmpty();
249 public boolean isWorkingWithAnnotation(AlignmentAnnotation annot)
251 synchronized (inProgress)
253 for (AlignCalcWorkerI worker : inProgress)
255 if (worker.involves(annot))
264 private void notifyQueued(AlignCalcWorkerI worker)
266 for (AlignCalcListener listener : listeners)
268 listener.workerQueued(worker);
272 private void notifyStarted(AlignCalcWorkerI worker)
274 for (AlignCalcListener listener : listeners)
276 listener.workerStarted(worker);
280 private void notifyCompleted(AlignCalcWorkerI worker)
282 for (AlignCalcListener listener : listeners)
285 listener.workerCompleted(worker);
286 } catch (RuntimeException e)
293 private void notifyExceptional(AlignCalcWorkerI worker,
296 for (AlignCalcListener listener : listeners)
299 listener.workerExceptional(worker, throwable);
300 } catch (RuntimeException e)
308 public void addAlignCalcListener(AlignCalcListener listener)
310 listeners.add(listener);
314 public void removeAlignCalcListener(AlignCalcListener listener)
316 listeners.remove(listener);