1 package cz.cuni.amis.utils.listener;
2
3 import java.lang.ref.WeakReference;
4 import java.util.EventListener;
5 import java.util.Iterator;
6 import java.util.concurrent.ConcurrentLinkedQueue;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
9
10 import cz.cuni.amis.utils.ExceptionToString;
11 import cz.cuni.amis.utils.NullCheck;
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 @SuppressWarnings("hiding")
34 public class Listeners<Listener extends EventListener> {
35
36
37
38
39
40
41
42
43 public static interface ListenerNotifier<Listener extends EventListener> {
44
45 public Object getEvent();
46
47 public void notify(Listener listener);
48
49 }
50
51 public static class AdaptableListenerNotifier<LISTENER extends IListener> implements ListenerNotifier<LISTENER> {
52
53 private Object event;
54
55 public AdaptableListenerNotifier<LISTENER> setEvent(Object event) {
56 this.event = event;
57 return this;
58 }
59
60 @Override
61 public Object getEvent() {
62 return event;
63 }
64
65 @Override
66 public void notify(LISTENER listener) {
67 listener.notify(event);
68 }
69
70 }
71
72
73
74
75
76
77
78
79 public static interface ListenerRemover {
80
81
82
83
84
85
86 public boolean remove(EventListener listener);
87
88 }
89
90
91
92
93
94 private static abstract class ListenerStore<Listener extends EventListener> {
95
96
97
98
99
100
101
102 public abstract Listener getListener();
103
104 public abstract void clearListener();
105
106 }
107
108
109
110
111
112 private static class StrongListenerStore<Listener extends EventListener> extends ListenerStore<Listener> {
113
114 private Listener listener;
115
116 public StrongListenerStore(Listener listener) {
117 this.listener = listener;
118 }
119
120 @Override
121 public Listener getListener() {
122 return listener;
123 }
124
125 @Override
126 public void clearListener() {
127 this.listener = null;
128 }
129
130 }
131
132
133
134
135
136
137
138 private static class WeakListenerStore<Listener extends EventListener> extends ListenerStore<Listener> {
139
140 private WeakReference<Listener> listenerReference = null;
141
142 public WeakListenerStore(Listener listener) {
143 this.listenerReference = new WeakReference<Listener>(listener);
144 }
145
146 @Override
147 public Listener getListener() {
148 return listenerReference.get();
149 }
150
151 @Override
152 public void clearListener() {
153 this.listenerReference.clear();
154 }
155
156 }
157
158
159
160
161 private Logger log;
162
163
164
165
166 private String name;
167
168
169
170
171 private ConcurrentLinkedQueue<ListenerStore<Listener>> listeners = new ConcurrentLinkedQueue<ListenerStore<Listener>>();
172
173
174
175
176
177 private boolean listenersIteration = false;
178
179
180
181
182
183 public Logger getLog() {
184 return log;
185 }
186
187
188
189
190
191 public void setLog(Logger log, String name) {
192 this.log = log;
193 this.name = name;
194 }
195
196
197
198
199
200 public void addStrongListener(Listener listener) {
201 NullCheck.check(listener, "listener");
202 synchronized(listeners) {
203 listeners.add(new StrongListenerStore<Listener>(listener));
204 }
205 }
206
207
208
209
210
211 public void addWeakListener(Listener listener) {
212 NullCheck.check(listener, "listener");
213 synchronized(listeners) {
214 listeners.add(new WeakListenerStore<Listener>(listener));
215 }
216 }
217
218
219
220
221
222
223 public int removeEqualListener(EventListener listener) {
224 if (listener == null) return 0;
225 int removed = 0;
226 synchronized(listeners) {
227
228 boolean listenersIterationOriginal = listenersIteration;
229 listenersIteration = true;
230
231 try {
232 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
233 while(iterator.hasNext()) {
234 ListenerStore<Listener> store = iterator.next();
235 Listener storedListener = store.getListener();
236 if (storedListener == null) {
237 if (!listenersIterationOriginal) {
238 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
239 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
240 }
241 iterator.remove();
242 }
243 continue;
244 }
245 if (listener.equals(storedListener)) {
246 store.clearListener();
247 ++removed;
248 }
249 }
250 } finally {
251 listenersIteration = listenersIterationOriginal;
252 }
253 }
254 return removed;
255 }
256
257
258
259
260
261
262 public int removeListener(EventListener listener) {
263 if (listener == null) return 0;
264 int removed = 0;
265 synchronized(listeners) {
266 boolean listenersIterationOriginal = listenersIteration;
267 listenersIteration = true;
268
269 try {
270 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
271 while(iterator.hasNext()) {
272 ListenerStore<Listener> store = iterator.next();
273 Listener storedListener = store.getListener();
274 if (storedListener == null) {
275 if (!listenersIterationOriginal) {
276 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
277 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
278 }
279 iterator.remove();
280 }
281 continue;
282 }
283 if (listener == storedListener) {
284 store.clearListener();
285 ++removed;
286 }
287 }
288 } finally {
289 listenersIteration = listenersIterationOriginal;
290 }
291 }
292 return removed;
293 }
294
295
296
297
298
299
300
301 public void notify(ListenerNotifier<Listener> notifier) {
302
303 synchronized(listeners) {
304 boolean listenersIterationOriginal = listenersIteration;
305 listenersIteration = true;
306
307 try {
308 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
309 while(iterator.hasNext()) {
310 ListenerStore<Listener> store = iterator.next();
311 Listener storedListener = store.getListener();
312 if (storedListener == null) {
313 if (!listenersIterationOriginal) {
314 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
315 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
316 }
317 iterator.remove();
318 }
319 continue;
320 }
321 notifier.notify(storedListener);
322 }
323 } finally {
324 listenersIteration = listenersIterationOriginal;
325 }
326 }
327 }
328
329
330
331
332
333
334
335
336
337
338
339
340 public boolean notifySafe(ListenerNotifier<Listener> notifier, Logger exceptionLog) {
341
342 boolean noException = true;
343
344 synchronized(listeners) {
345 boolean listenersIterationOriginal = listenersIteration;
346 listenersIteration = true;
347 try {
348 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
349 while(iterator.hasNext()) {
350 ListenerStore<Listener> store = iterator.next();
351 Listener storedListener = store.getListener();
352 if (storedListener == null) {
353 if (!listenersIterationOriginal) {
354 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
355 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
356 }
357 iterator.remove();
358 }
359 continue;
360 }
361 try {
362 notifier.notify(storedListener);
363 } catch (Exception e) {
364 noException = false;
365 if (exceptionLog != null) {
366 if (exceptionLog.isLoggable(Level.SEVERE)) exceptionLog.severe(ExceptionToString.process("Exception during event processing (" + notifier.getEvent() + ").", e));
367 }
368 }
369 }
370 } finally {
371 listenersIteration = listenersIterationOriginal;
372 }
373 }
374
375 return noException;
376 }
377
378
379
380
381
382
383
384 public boolean isEqualListening(EventListener listener) {
385 if (listener == null) return false;
386 synchronized(listeners) {
387 boolean listenersIterationOriginal = listenersIteration;
388 listenersIteration = true;
389
390 try {
391 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
392 while(iterator.hasNext()) {
393 ListenerStore<Listener> store = iterator.next();
394 Listener storedListener = store.getListener();
395 if (storedListener == null) {
396 if (!listenersIterationOriginal) {
397 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
398 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
399 }
400 iterator.remove();
401 }
402 continue;
403 }
404 if (listener.equals(storedListener)) {
405 return true;
406 }
407 }
408 } finally {
409 listenersIteration = listenersIterationOriginal;
410 }
411 }
412 return false;
413 }
414
415
416
417
418
419
420
421
422
423 public boolean isListening(EventListener listener) {
424 if (listener == null) return false;
425 synchronized(listeners) {
426 boolean listenersIterationOriginal = listenersIteration;
427 listenersIteration = true;
428
429 try {
430 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
431 while(iterator.hasNext()) {
432 ListenerStore<Listener> store = iterator.next();
433 Listener storedListener = store.getListener();
434 if (storedListener == null) {
435 if (!listenersIterationOriginal) {
436 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
437 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
438 }
439 iterator.remove();
440 }
441 continue;
442 }
443 if (listener == storedListener) {
444 return true;
445 }
446 }
447 } finally {
448 listenersIteration = listenersIterationOriginal;
449 }
450 }
451 return false;
452 }
453
454 public void clearListeners() {
455 synchronized(listeners) {
456 if (!listenersIteration) {
457 listeners.clear();
458 } else {
459 for (ListenerStore store : listeners) {
460 store.clearListener();
461 }
462 }
463 }
464 }
465
466
467
468
469
470
471
472
473
474
475
476
477
478 public int count() {
479 synchronized(listeners) {
480 int count = 0;
481 for (ListenerStore store : listeners) {
482 if (store.getListener() != null) ++count;
483 }
484 return count;
485 }
486 }
487
488
489
490
491
492
493
494
495
496
497 public void remove(ListenerRemover remover) {
498 synchronized(listeners) {
499 boolean listenersIterationOriginal = listenersIteration;
500 listenersIteration = true;
501 try {
502 Iterator<ListenerStore<Listener>> iterator = listeners.iterator();
503 while(iterator.hasNext()) {
504 ListenerStore<Listener> store = iterator.next();
505 Listener storedListener = store.getListener();
506 if (storedListener == null) {
507 if (!listenersIterationOriginal) {
508 if ((store instanceof WeakListenerStore) && log != null && log.isLoggable(Level.FINE)) {
509 log.fine((name == null ? "" : name + ": ") + "Weakly referenced listener was GC()ed.");
510 }
511 iterator.remove();
512 }
513 continue;
514 }
515 if (remover.remove(storedListener)) {
516 if (!listenersIterationOriginal) iterator.remove();
517 else store.clearListener();
518 }
519 }
520 } finally {
521 listenersIteration = listenersIterationOriginal;
522 }
523 }
524 }
525
526 }