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.workers;
23 import jalview.api.AlignCalcManagerI;
24 import jalview.api.AlignCalcWorkerI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.AlignmentAnnotation;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.Hashtable;
33 import java.util.List;
37 public class AlignCalcManager implements AlignCalcManagerI
40 * list of registered workers
42 private final List<AlignCalcWorkerI> restartable = Collections
43 .synchronizedList(new ArrayList<AlignCalcWorkerI>());
46 * types of worker _not_ to run (for example, because they have
47 * previously thrown errors)
49 private final List<Class<? extends AlignCalcWorkerI>> blackList = Collections
50 .synchronizedList(new ArrayList<Class<? extends AlignCalcWorkerI>>());
53 * global record of calculations in progress
55 private final List<AlignCalcWorkerI> inProgress = Collections
56 .synchronizedList(new ArrayList<AlignCalcWorkerI>());
59 * record of calculations pending or in progress in the current context
61 private final Map<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>> updating =
62 new Hashtable<Class<? extends AlignCalcWorkerI>, List<AlignCalcWorkerI>>();
65 * workers that have run to completion so are candidates for visual-only
66 * update of their results
68 private HashSet<AlignCalcWorkerI> canUpdate = new HashSet<>();;
70 private static boolean listContains(List<AlignCalcWorkerI> upd,
71 AlignCalcWorkerI worker)
73 // avoid use of 'Contains' in case
74 for (AlignCalcWorkerI _otherworker : upd)
76 if (_otherworker == upd)
84 public void notifyStarted(AlignCalcWorkerI worker)
86 synchronized (updating)
88 List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
91 updating.put(worker.getClass(), upd = Collections
92 .synchronizedList(new ArrayList<AlignCalcWorkerI>()));
96 if (listContains(upd, worker))
99 "Ignoring second call to notifyStart for worker "
113 * @see jalview.api.AlignCalcManagerI#isPending(jalview.api.AlignCalcWorkerI)
116 public boolean isPending(AlignCalcWorkerI workingClass)
118 synchronized (updating)
120 List<AlignCalcWorkerI> upd = updating.get(workingClass.getClass());
121 return upd != null && upd.size() > 1;
126 public boolean notifyWorking(AlignCalcWorkerI worker)
128 synchronized (inProgress)
130 if (listContains(inProgress, worker))
132 return false; // worker is already working, so ask caller to wait around
136 inProgress.add(worker);
143 public void workerComplete(AlignCalcWorkerI worker)
145 synchronized (inProgress)
147 Cache.log.debug("Worker " + worker + " marked as complete.");
148 inProgress.remove(worker);
149 List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
156 canUpdate.add(worker);
162 public void disableWorker(AlignCalcWorkerI worker)
164 synchronized (blackList)
166 blackList.add(worker.getClass());
171 public boolean isDisabled(AlignCalcWorkerI worker)
173 synchronized (blackList)
175 return blackList.contains(worker.getClass());
180 public void startWorker(AlignCalcWorkerI worker)
182 if (!isDisabled(worker))
184 Thread tw = new Thread(() -> {
188 } catch (Throwable e)
193 tw.setName(worker.getClass().toString());
199 public boolean isWorking(AlignCalcWorkerI worker)
201 synchronized (inProgress)
202 {// System.err.println("isWorking : worker "+(worker!=null ?
203 // worker.getClass():"null")+ " "+hashCode());
204 return worker != null && inProgress.contains(worker);
209 public boolean isWorking()
211 synchronized (inProgress)
213 // System.err.println("isWorking "+hashCode());
214 return inProgress.size() > 0;
218 public int getQueueLength() {
219 return inProgress.size();
223 public void registerWorker(AlignCalcWorkerI worker)
225 synchronized (restartable)
227 if (!listContains(restartable, worker))
229 restartable.add(worker);
236 public void restartWorkers()
238 synchronized (restartable)
240 for (AlignCalcWorkerI worker : restartable)
248 public boolean workingInvolvedWith(
249 AlignmentAnnotation alignmentAnnotation)
251 synchronized (inProgress)
253 for (AlignCalcWorkerI worker : inProgress)
255 if (worker.involves(alignmentAnnotation))
261 synchronized (updating)
263 for (List<AlignCalcWorkerI> workers : updating.values())
265 for (AlignCalcWorkerI worker : workers)
267 if (worker.involves(alignmentAnnotation))
278 public void updateAnnotationFor(
279 Class<? extends AlignCalcWorkerI> workerClass)
282 AlignCalcWorkerI[] workers;
283 synchronized (canUpdate)
285 workers = canUpdate.toArray(new AlignCalcWorkerI[0]);
287 for (AlignCalcWorkerI worker : workers)
289 if (workerClass.equals(worker.getClass()))
291 worker.updateAnnotation();
297 public List<AlignCalcWorkerI> getRegisteredWorkersOfClass(
298 Class<? extends AlignCalcWorkerI> workerClass)
300 List<AlignCalcWorkerI> workingClass = new ArrayList<>();
301 synchronized (canUpdate)
303 for (AlignCalcWorkerI worker : canUpdate)
305 if (workerClass.equals(worker.getClass()))
307 workingClass.add(worker);
311 return (workingClass.size() == 0) ? null : workingClass;
315 public void enableWorker(AlignCalcWorkerI worker)
317 synchronized (blackList)
319 blackList.remove(worker.getClass());
324 public void removeWorkersOfClass(
325 Class<? extends AlignCalcWorkerI> typeToRemove)
327 List<AlignCalcWorkerI> removable = new ArrayList<>();
328 Set<AlignCalcWorkerI> toremovannot = new HashSet<>();
329 synchronized (restartable)
331 for (AlignCalcWorkerI worker : restartable)
333 if (typeToRemove.equals(worker.getClass()))
335 removable.add(worker);
336 toremovannot.add(worker);
339 restartable.removeAll(removable);
341 synchronized (canUpdate)
343 for (AlignCalcWorkerI worker : canUpdate)
345 if (typeToRemove.equals(worker.getClass()))
347 removable.add(worker);
348 toremovannot.add(worker);
351 canUpdate.removeAll(removable);
353 // TODO: finish testing this extension
356 * synchronized (inProgress) { // need to kill or mark as dead any running
357 * threads... (inProgress.get(typeToRemove)); }
359 * if (workers == null) { return; } for (AlignCalcWorkerI worker : workers)
362 * if (isPending(worker)) { worker.abortAndDestroy(); startWorker(worker); }
363 * else { System.err.println("Pending exists for " + workerClass); } }
368 * Deletes the worker that update the given annotation, provided it is marked
372 public void removeWorkerForAnnotation(AlignmentAnnotation ann)
375 * first just find those to remove (to avoid
376 * ConcurrentModificationException)
378 List<AlignCalcWorkerI> toRemove = new ArrayList<>();
379 for (AlignCalcWorkerI worker : restartable)
381 if (worker.involves(ann))
383 if (worker.isDeletable())
385 toRemove.add(worker);
391 * remove all references to deleted workers so any references
392 * they hold to annotation data can be garbage collected
394 for (AlignCalcWorkerI worker : toRemove)
396 restartable.remove(worker);
397 blackList.remove(worker.getClass());
398 inProgress.remove(worker);
399 canUpdate.remove(worker);
400 synchronized (updating)
402 List<AlignCalcWorkerI> upd = updating.get(worker.getClass());