JAL-961 potentially helpful println statements when debugging alignment calculation...
[jalview.git] / src / jalview / workers / AlignCalcManager.java
1 package jalview.workers;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.HashSet;
6 import java.util.Hashtable;
7 import java.util.List;
8 import java.util.Map;
9
10 import jalview.api.AlignCalcManagerI;
11 import jalview.api.AlignCalcWorkerI;
12 import jalview.datamodel.AlignmentAnnotation;
13
14 public class AlignCalcManager implements AlignCalcManagerI
15 {
16   private volatile List<AlignCalcWorkerI> restartable = Collections
17           .synchronizedList(new ArrayList<AlignCalcWorkerI>());
18
19   private volatile List<Class> blackList = Collections
20           .synchronizedList(new ArrayList<Class>());
21
22   /**
23    * global record of calculations in progress
24    */
25   private volatile Map<Class, AlignCalcWorkerI> inProgress = Collections
26           .synchronizedMap(new Hashtable<Class, AlignCalcWorkerI>());
27
28   /**
29    * record of calculations pending or in progress in the current context
30    */
31   private volatile Map<Class, List<AlignCalcWorkerI>> updating = Collections
32           .synchronizedMap(new Hashtable<Class, List<AlignCalcWorkerI>>());
33
34   @Override
35   public void notifyStart(AlignCalcWorkerI worker)
36   {
37     synchronized (updating)
38     {
39       List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
40       if (upd == null)
41       {
42         updating.put(
43                 worker.getClass(),
44                 upd = Collections
45                         .synchronizedList(new ArrayList<AlignCalcWorkerI>()));
46       }
47       synchronized (upd)
48       {
49         upd.add(worker);
50       }
51     }
52   }
53
54   @Override
55   public boolean alreadyDoing(AlignCalcWorkerI worker)
56   {
57     synchronized (inProgress)
58     {
59       return inProgress.containsKey(worker.getClass());
60     }
61   }
62
63   /*
64    * (non-Javadoc)
65    *
66    * @see jalview.api.AlignCalcManagerI#isPending(jalview.api.AlignCalcWorkerI)
67    */
68   @Override
69   public boolean isPending(AlignCalcWorkerI workingClass)
70   {
71     List<AlignCalcWorkerI> upd;
72     synchronized (updating)
73     {
74       upd = updating.get(workingClass.getClass());
75       if (upd == null)
76       {
77         return false;
78       }
79       synchronized (upd)
80       {
81         if (upd.size() > 1)
82         {
83           return true;
84         }
85       }
86       return false;
87     }
88   }
89
90   // TODO make into api method if needed ?
91   public int numberLive(AlignCalcWorkerI worker)
92   {
93     synchronized (updating)
94     {
95       List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
96       if (upd == null)
97       {
98         return 0;
99       }
100       ;
101       return upd.size();
102     }
103   }
104
105   @Override
106   public boolean notifyWorking(AlignCalcWorkerI worker)
107   {
108     synchronized (inProgress)
109     {
110       // TODO: decide if we should throw exceptions here if multiple workers
111       // start to work
112       if (inProgress.get(worker.getClass()) != null)
113       {
114         if (false)
115         {
116           System.err
117                   .println("Warning: Multiple workers are running of type "
118                           + worker.getClass());
119         }
120         return false;
121       }
122       inProgress.put(worker.getClass(), worker);
123     }
124     return true;
125   }
126
127   private final HashSet<AlignCalcWorkerI> canUpdate = new HashSet<AlignCalcWorkerI>();
128
129   @Override
130   public void workerComplete(AlignCalcWorkerI worker)
131   {
132     synchronized (inProgress)
133     {
134 //      System.err.println("Worker "+worker.getClass()+" marked as complete.");
135       inProgress.remove(worker.getClass());
136       List<AlignCalcWorkerI> upd = updating.get(worker.getClass());
137       if (upd != null)
138       {
139         synchronized (upd)
140         {
141           upd.remove(worker);
142         }
143         canUpdate.add(worker);
144       }
145     }
146   }
147
148   @Override
149   public void workerCannotRun(AlignCalcWorkerI worker)
150   {
151     synchronized (blackList)
152     {
153       blackList.add(worker.getClass());
154     }
155   }
156
157   public boolean isBlackListed(Class workerType)
158   {
159     synchronized (blackList)
160     {
161       return blackList.contains(workerType);
162     }
163   }
164
165   @Override
166   public void startWorker(AlignCalcWorkerI worker)
167   {
168 //    System.err.println("Starting "+worker.getClass());
169 //    new Exception("").printStackTrace();
170     Thread tw = new Thread(worker);
171     tw.setName(worker.getClass().toString());
172     tw.start();
173   }
174
175   @Override
176   public boolean isWorking(AlignCalcWorkerI worker)
177   {
178     synchronized (inProgress)
179     {// System.err.println("isWorking : worker "+(worker!=null ?
180      // worker.getClass():"null")+ " "+hashCode());
181       return worker != null && inProgress.get(worker.getClass()) == worker;
182     }
183   }
184
185   @Override
186   public boolean isWorking()
187   {
188     synchronized (inProgress)
189     {
190       // System.err.println("isWorking "+hashCode());
191       return inProgress.size() > 0;
192     }
193   }
194
195   @Override
196   public void registerWorker(AlignCalcWorkerI worker)
197   {
198     synchronized (restartable)
199     {
200       if (!restartable.contains(worker))
201       {
202         restartable.add(worker);
203       }
204       startWorker(worker);
205     }
206   }
207
208   @Override
209   public void restartWorkers()
210   {
211     synchronized (restartable)
212     {
213       for (AlignCalcWorkerI worker : restartable)
214       {
215         startWorker(worker);
216       }
217     }
218   }
219
220   @Override
221   public boolean workingInvolvedWith(AlignmentAnnotation alignmentAnnotation)
222   {
223     synchronized (inProgress)
224     {
225       for (AlignCalcWorkerI worker : inProgress.values())
226       {
227         if (worker.involves(alignmentAnnotation))
228         {
229           return true;
230         }
231       }
232     }
233     synchronized (updating)
234     {
235       for (List<AlignCalcWorkerI> workers : updating.values())
236       {
237         for (AlignCalcWorkerI worker : workers)
238           if (worker.involves(alignmentAnnotation))
239           {
240             return true;
241           }
242       }
243     }
244     return false;
245   }
246
247   @Override
248   public void updateAnnotationFor(Class workerClass)
249   {
250
251     AlignCalcWorkerI[] workers;
252     synchronized (canUpdate)
253     {
254       workers = canUpdate.toArray(new AlignCalcWorkerI[0]);
255     }
256     for (AlignCalcWorkerI worker : workers)
257     {
258       if (workerClass.equals(worker.getClass()))
259       {
260         worker.updateAnnotation();
261       }
262     }
263   }
264
265   @Override
266   public List<AlignCalcWorkerI> getRegisteredWorkersOfClass(
267           Class workerClass)
268   {
269     List<AlignCalcWorkerI> workingClass = new ArrayList<AlignCalcWorkerI>();
270     AlignCalcWorkerI[] workers;
271     synchronized (canUpdate)
272     {
273       workers = canUpdate.toArray(new AlignCalcWorkerI[0]);
274     }
275     for (AlignCalcWorkerI worker : workers)
276     {
277       if (workerClass.equals(worker.getClass()))
278       {
279         workingClass.add(worker);
280       }
281     }
282     return (workingClass.size() == 0) ? null : workingClass;
283   }
284
285   @Override
286   public boolean startRegisteredWorkersOfClass(Class workerClass)
287   {
288     List<AlignCalcWorkerI> workers = getRegisteredWorkersOfClass(workerClass);
289     if (workers == null)
290     {
291       return false;
292     }
293     for (AlignCalcWorkerI worker : workers)
294     {
295       if (!isPending(worker))
296       {
297         startWorker(worker);
298       }
299       else
300       {
301         System.err.println("Pending exists for " + workerClass);
302       }
303     }
304     return true;
305   }
306
307   @Override
308   public void workerMayRun(AlignCalcWorkerI worker)
309   {
310     synchronized (blackList)
311     {
312       if (blackList.contains(worker.getClass()))
313       {
314         blackList.remove(worker.getClass());
315       }
316     }
317   }
318 }