1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| package org.jboss.cache.notifications; |
8 |
| |
9 |
| import org.apache.commons.logging.Log; |
10 |
| import org.apache.commons.logging.LogFactory; |
11 |
| import org.jboss.cache.Cache; |
12 |
| import org.jboss.cache.CacheException; |
13 |
| import org.jboss.cache.CacheSPI; |
14 |
| import org.jboss.cache.Fqn; |
15 |
| import org.jboss.cache.InvocationContext; |
16 |
| import org.jboss.cache.notifications.annotation.*; |
17 |
| import org.jboss.cache.notifications.event.*; |
18 |
| import static org.jboss.cache.notifications.event.Event.Type.*; |
19 |
| import org.jboss.cache.util.MapCopy; |
20 |
| import org.jgroups.View; |
21 |
| |
22 |
| import javax.transaction.Transaction; |
23 |
| import java.lang.reflect.InvocationTargetException; |
24 |
| import java.lang.reflect.Method; |
25 |
| import java.lang.reflect.Modifier; |
26 |
| import java.util.Collections; |
27 |
| import java.util.HashSet; |
28 |
| import java.util.List; |
29 |
| import java.util.Map; |
30 |
| import java.util.Set; |
31 |
| import java.util.concurrent.ConcurrentHashMap; |
32 |
| import java.util.concurrent.CopyOnWriteArrayList; |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| public class Notifier |
40 |
| { |
41 |
| private Cache cache; |
42 |
| |
43 |
| private static final Log log = LogFactory.getLog(Notifier.class); |
44 |
| |
45 |
| private static Class emptyMap = Collections.emptyMap().getClass(); |
46 |
| private static Class singletonMap = Collections.singletonMap(null, null).getClass(); |
47 |
| private static final Class[] allowedMethodAnnotations = |
48 |
| { |
49 |
| CacheStarted.class, CacheStopped.class, CacheBlocked.class, CacheUnblocked.class, NodeCreated.class, NodeRemoved.class, NodeVisited.class, NodeModified.class, NodeMoved.class, |
50 |
| NodeActivated.class, NodePassivated.class, NodeLoaded.class, NodeEvicted.class, TransactionRegistered.class, TransactionCompleted.class, ViewChanged.class |
51 |
| }; |
52 |
| private static final Class[] parameterTypes = |
53 |
| { |
54 |
| CacheStartedEvent.class, CacheStoppedEvent.class, CacheBlockedEvent.class, CacheUnblockedEvent.class, NodeCreatedEvent.class, NodeRemovedEvent.class, NodeVisitedEvent.class, NodeModifiedEvent.class, NodeMovedEvent.class, |
55 |
| NodeActivatedEvent.class, NodePassivatedEvent.class, NodeLoadedEvent.class, NodeEvictedEvent.class, TransactionRegisteredEvent.class, TransactionCompletedEvent.class, ViewChangedEvent.class |
56 |
| }; |
57 |
| final Map<Class, List<ListenerInvocation>> listenerInvocations = new ConcurrentHashMap<Class, List<ListenerInvocation>>(); |
58 |
| |
59 |
2911
| public Notifier(Cache cache)
|
60 |
| { |
61 |
2911
| this.cache = cache;
|
62 |
| } |
63 |
| |
64 |
| |
65 |
| |
66 |
| |
67 |
| |
68 |
| |
69 |
| |
70 |
428
| private void validateAndAddListenerInvocation(Object listener)
|
71 |
| { |
72 |
428
| testListenerClassValidity(listener.getClass());
|
73 |
| |
74 |
420
| boolean foundMethods = false;
|
75 |
| |
76 |
420
| for (Method m : listener.getClass().getMethods())
|
77 |
| { |
78 |
| |
79 |
4823
| for (int i = 0; i < allowedMethodAnnotations.length; i++)
|
80 |
| { |
81 |
77078
| if (m.isAnnotationPresent(allowedMethodAnnotations[i]))
|
82 |
| { |
83 |
1306
| testListenerMethodValidity(m, parameterTypes[i], allowedMethodAnnotations[i].getName());
|
84 |
1300
| addListenerInvocation(allowedMethodAnnotations[i], new ListenerInvocation(listener, m));
|
85 |
1300
| foundMethods = true;
|
86 |
| } |
87 |
| } |
88 |
| } |
89 |
| |
90 |
414
| if (!foundMethods && log.isWarnEnabled())
|
91 |
2
| log.warn("Attempted to register listener of class " + listener.getClass() + ", but no valid, public methods annotated with method-level event annotations found! Ignoring listener.");
|
92 |
| } |
93 |
| |
94 |
428
| private void testListenerClassValidity(Class listenerClass)
|
95 |
| { |
96 |
428
| if (!listenerClass.isAnnotationPresent(CacheListener.class))
|
97 |
1
| throw new IncorrectCacheListenerException("Cache listener class MUST be annotated with org.jboss.cache.notifications.annotation.CacheListener");
|
98 |
427
| if (!Modifier.isPublic(listenerClass.getModifiers()))
|
99 |
7
| throw new IncorrectCacheListenerException("Cache listener class MUST be public!");
|
100 |
| } |
101 |
| |
102 |
1306
| private void testListenerMethodValidity(Method m, Class allowedParameter, String annotationName)
|
103 |
| { |
104 |
1306
| if (m.getParameterTypes().length != 1 || !m.getParameterTypes()[0].isAssignableFrom(allowedParameter))
|
105 |
5
| throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " must accept exactly one parameter, of assignable from type " + allowedParameter.getName());
|
106 |
1301
| if (!m.getReturnType().equals(void.class))
|
107 |
1
| throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " should have a return type of void.");
|
108 |
| } |
109 |
| |
110 |
1300
| private void addListenerInvocation(Class annotation, ListenerInvocation li)
|
111 |
| { |
112 |
1300
| synchronized (listenerInvocations)
|
113 |
| { |
114 |
1300
| List<ListenerInvocation> l = listenerInvocations.get(annotation);
|
115 |
1300
| if (l == null)
|
116 |
| { |
117 |
1299
| l = new CopyOnWriteArrayList<ListenerInvocation>();
|
118 |
1299
| listenerInvocations.put(annotation, l);
|
119 |
| } |
120 |
1300
| l.add(li);
|
121 |
| } |
122 |
| } |
123 |
| |
124 |
| |
125 |
| |
126 |
| |
127 |
| |
128 |
| |
129 |
428
| public void addCacheListener(Object listener)
|
130 |
| { |
131 |
428
| validateAndAddListenerInvocation(listener);
|
132 |
| } |
133 |
| |
134 |
| |
135 |
| |
136 |
| |
137 |
| |
138 |
| |
139 |
308
| public void removeCacheListener(Object listener)
|
140 |
| { |
141 |
308
| synchronized (listenerInvocations)
|
142 |
| { |
143 |
4928
| for (Class annotation : allowedMethodAnnotations) removeListenerInvocation(annotation, listener);
|
144 |
| } |
145 |
| } |
146 |
| |
147 |
4928
| private void removeListenerInvocation(Class annotation, Object listener)
|
148 |
| { |
149 |
4928
| List<ListenerInvocation> l = listenerInvocations.get(annotation);
|
150 |
4928
| Set<Object> markedForRemoval = new HashSet<Object>();
|
151 |
4928
| if (l != null)
|
152 |
| { |
153 |
226
| for (ListenerInvocation li : l)
|
154 |
| { |
155 |
226
| if (listener.equals(li.target)) markedForRemoval.add(li);
|
156 |
| } |
157 |
| |
158 |
226
| l.removeAll(markedForRemoval);
|
159 |
| |
160 |
226
| if (l.size() == 0) listenerInvocations.remove(annotation);
|
161 |
| } |
162 |
| } |
163 |
| |
164 |
| |
165 |
| |
166 |
| |
167 |
2779
| public void removeAllCacheListeners()
|
168 |
| { |
169 |
2783
| synchronized (listenerInvocations)
|
170 |
| { |
171 |
2783
| listenerInvocations.clear();
|
172 |
| } |
173 |
| } |
174 |
| |
175 |
| |
176 |
| |
177 |
| |
178 |
19
| public Set<Object> getCacheListeners()
|
179 |
| { |
180 |
19
| Set<Object> s = new HashSet<Object>();
|
181 |
19
| synchronized (listenerInvocations)
|
182 |
| { |
183 |
19
| for (Class annotation : allowedMethodAnnotations)
|
184 |
| { |
185 |
304
| List<ListenerInvocation> l = listenerInvocations.get(annotation);
|
186 |
304
| if (l != null)
|
187 |
| { |
188 |
10
| for (ListenerInvocation li : l) s.add(li.target);
|
189 |
| } |
190 |
| } |
191 |
| } |
192 |
19
| return Collections.unmodifiableSet(s);
|
193 |
| } |
194 |
| |
195 |
| |
196 |
| |
197 |
| |
198 |
| |
199 |
| |
200 |
| |
201 |
| |
202 |
357251
| public void notifyNodeCreated(Fqn fqn, boolean pre, InvocationContext ctx)
|
203 |
| { |
204 |
357251
| boolean originLocal = ctx.isOriginLocal();
|
205 |
357251
| Transaction tx = ctx.getTransaction();
|
206 |
| |
207 |
357251
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeCreated.class);
|
208 |
| |
209 |
357251
| if (listeners != null && listeners.size() > 0)
|
210 |
| { |
211 |
1089
| InvocationContext backup = resetInvocationContext(ctx);
|
212 |
1089
| EventImpl e = new EventImpl();
|
213 |
1089
| e.setCache(cache);
|
214 |
1089
| e.setOriginLocal(originLocal);
|
215 |
1089
| e.setPre(pre);
|
216 |
1089
| e.setFqn(fqn);
|
217 |
1089
| e.setTransaction(tx);
|
218 |
1089
| e.setType(NODE_CREATED);
|
219 |
1089
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
220 |
1088
| restoreInvocationContext(backup);
|
221 |
| } |
222 |
| } |
223 |
| |
224 |
| |
225 |
| |
226 |
| |
227 |
| |
228 |
| |
229 |
| |
230 |
| |
231 |
| |
232 |
| |
233 |
848956
| public void notifyNodeModified(Fqn fqn, boolean pre, NodeModifiedEvent.ModificationType modificationType, Map data, InvocationContext ctx)
|
234 |
| { |
235 |
848956
| boolean originLocal = ctx.isOriginLocal();
|
236 |
848956
| Map dataCopy = copy(data);
|
237 |
848956
| Transaction tx = ctx.getTransaction();
|
238 |
| |
239 |
848956
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeModified.class);
|
240 |
| |
241 |
848956
| if (listeners != null && listeners.size() > 0)
|
242 |
| { |
243 |
1887
| InvocationContext backup = resetInvocationContext(ctx);
|
244 |
1887
| EventImpl e = new EventImpl();
|
245 |
1887
| e.setCache(cache);
|
246 |
1887
| e.setOriginLocal(originLocal);
|
247 |
1887
| e.setPre(pre);
|
248 |
1887
| e.setFqn(fqn);
|
249 |
1887
| e.setTransaction(tx);
|
250 |
1887
| e.setModificationType(modificationType);
|
251 |
1887
| e.setData(dataCopy);
|
252 |
1887
| e.setType(NODE_MODIFIED);
|
253 |
1887
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
254 |
1887
| restoreInvocationContext(backup);
|
255 |
| } |
256 |
| } |
257 |
| |
258 |
| |
259 |
| |
260 |
| |
261 |
| |
262 |
| |
263 |
| |
264 |
| |
265 |
| |
266 |
28610
| public void notifyNodeRemoved(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
|
267 |
| { |
268 |
28610
| boolean originLocal = ctx.isOriginLocal();
|
269 |
28610
| Map dataCopy = copy(data);
|
270 |
28610
| Transaction tx = ctx.getTransaction();
|
271 |
| |
272 |
28610
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeRemoved.class);
|
273 |
| |
274 |
28610
| if (listeners != null && listeners.size() > 0)
|
275 |
| { |
276 |
48
| InvocationContext backup = resetInvocationContext(ctx);
|
277 |
48
| EventImpl e = new EventImpl();
|
278 |
48
| e.setCache(cache);
|
279 |
48
| e.setOriginLocal(originLocal);
|
280 |
48
| e.setPre(pre);
|
281 |
48
| e.setFqn(fqn);
|
282 |
48
| e.setTransaction(tx);
|
283 |
48
| e.setData(dataCopy);
|
284 |
48
| e.setType(NODE_REMOVED);
|
285 |
48
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
286 |
48
| restoreInvocationContext(backup);
|
287 |
| } |
288 |
| } |
289 |
| |
290 |
| |
291 |
| |
292 |
| |
293 |
| |
294 |
| |
295 |
| |
296 |
| |
297 |
2991817
| public void notifyNodeVisited(Fqn fqn, boolean pre, InvocationContext ctx)
|
298 |
| { |
299 |
2991817
| Transaction tx = ctx.getTransaction();
|
300 |
| |
301 |
2991817
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeVisited.class);
|
302 |
| |
303 |
2991817
| if (listeners != null && listeners.size() > 0)
|
304 |
| { |
305 |
138
| InvocationContext backup = resetInvocationContext(ctx);
|
306 |
138
| EventImpl e = new EventImpl();
|
307 |
138
| e.setCache(cache);
|
308 |
138
| e.setPre(pre);
|
309 |
138
| e.setFqn(fqn);
|
310 |
138
| e.setTransaction(tx);
|
311 |
138
| e.setType(NODE_VISITED);
|
312 |
138
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
313 |
138
| restoreInvocationContext(backup);
|
314 |
| } |
315 |
| } |
316 |
| |
317 |
158
| public void notifyNodeMoved(Fqn originalFqn, Fqn newFqn, boolean pre, InvocationContext ctx)
|
318 |
| { |
319 |
158
| boolean originLocal = ctx.isOriginLocal();
|
320 |
158
| Transaction tx = ctx.getTransaction();
|
321 |
| |
322 |
158
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeMoved.class);
|
323 |
| |
324 |
158
| if (listeners != null && listeners.size() > 0)
|
325 |
| { |
326 |
40
| InvocationContext backup = resetInvocationContext(ctx);
|
327 |
40
| EventImpl e = new EventImpl();
|
328 |
40
| e.setCache(cache);
|
329 |
40
| e.setOriginLocal(originLocal);
|
330 |
40
| e.setPre(pre);
|
331 |
40
| e.setFqn(originalFqn);
|
332 |
40
| e.setTargetFqn(newFqn);
|
333 |
40
| e.setTransaction(tx);
|
334 |
40
| e.setType(NODE_MOVED);
|
335 |
40
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
336 |
40
| restoreInvocationContext(backup);
|
337 |
| } |
338 |
| } |
339 |
| |
340 |
| |
341 |
| |
342 |
| |
343 |
| |
344 |
| |
345 |
| |
346 |
| |
347 |
| |
348 |
175870
| public void notifyNodeEvicted(final Fqn fqn, final boolean pre, InvocationContext ctx)
|
349 |
| { |
350 |
175870
| final boolean originLocal = ctx.isOriginLocal();
|
351 |
175870
| Transaction tx = ctx.getTransaction();
|
352 |
| |
353 |
175870
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeEvicted.class);
|
354 |
| |
355 |
175870
| if (listeners != null && listeners.size() > 0)
|
356 |
| { |
357 |
102
| InvocationContext backup = resetInvocationContext(ctx);
|
358 |
102
| EventImpl e = new EventImpl();
|
359 |
102
| e.setCache(cache);
|
360 |
102
| e.setOriginLocal(originLocal);
|
361 |
102
| e.setPre(pre);
|
362 |
102
| e.setFqn(fqn);
|
363 |
102
| e.setTransaction(tx);
|
364 |
102
| e.setType(NODE_EVICTED);
|
365 |
102
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
366 |
102
| restoreInvocationContext(backup);
|
367 |
| } |
368 |
| } |
369 |
| |
370 |
| |
371 |
| |
372 |
| |
373 |
| |
374 |
| |
375 |
| |
376 |
| |
377 |
| |
378 |
4448
| public void notifyNodeLoaded(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
|
379 |
| { |
380 |
4448
| boolean originLocal = ctx.isOriginLocal();
|
381 |
4448
| Map dataCopy = copy(data);
|
382 |
4448
| Transaction tx = ctx.getTransaction();
|
383 |
| |
384 |
4448
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeLoaded.class);
|
385 |
| |
386 |
4448
| if (listeners != null && listeners.size() > 0)
|
387 |
| { |
388 |
62
| InvocationContext backup = resetInvocationContext(ctx);
|
389 |
62
| EventImpl e = new EventImpl();
|
390 |
62
| e.setCache(cache);
|
391 |
62
| e.setOriginLocal(originLocal);
|
392 |
62
| e.setPre(pre);
|
393 |
62
| e.setFqn(fqn);
|
394 |
62
| e.setTransaction(tx);
|
395 |
62
| e.setData(dataCopy);
|
396 |
62
| e.setType(NODE_LOADED);
|
397 |
62
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
398 |
62
| restoreInvocationContext(backup);
|
399 |
| } |
400 |
| } |
401 |
| |
402 |
| |
403 |
| |
404 |
| |
405 |
| |
406 |
| |
407 |
| |
408 |
| |
409 |
| |
410 |
4360
| public void notifyNodeActivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
|
411 |
| { |
412 |
4360
| boolean originLocal = ctx.isOriginLocal();
|
413 |
4360
| Map dataCopy = copy(data);
|
414 |
4360
| Transaction tx = ctx.getTransaction();
|
415 |
| |
416 |
4360
| List<ListenerInvocation> listeners = listenerInvocations.get(NodeActivated.class);
|
417 |
| |
418 |
4360
| if (listeners != null && listeners.size() > 0)
|
419 |
| { |
420 |
228
| InvocationContext backup = resetInvocationContext(ctx);
|
421 |
228
| EventImpl e = new EventImpl();
|
422 |
228
| e.setCache(cache);
|
423 |
228
| e.setOriginLocal(originLocal);
|
424 |
228
| e.setPre(pre);
|
425 |
228
| e.setFqn(fqn);
|
426 |
228
| e.setTransaction(tx);
|
427 |
228
| e.setData(dataCopy);
|
428 |
228
| e.setType(NODE_ACTIVATED);
|
429 |
228
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
430 |
228
| restoreInvocationContext(backup);
|
431 |
| } |
432 |
| } |
433 |
| |
434 |
| |
435 |
| |
436 |
| |
437 |
| |
438 |
| |
439 |
| |
440 |
| |
441 |
| |
442 |
3122
| public void notifyNodePassivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
|
443 |
| { |
444 |
3122
| Map dataCopy = copy(data);
|
445 |
3122
| Transaction tx = ctx.getTransaction();
|
446 |
| |
447 |
3122
| List<ListenerInvocation> listeners = listenerInvocations.get(NodePassivated.class);
|
448 |
| |
449 |
3122
| if (listeners != null && listeners.size() > 0)
|
450 |
| { |
451 |
188
| InvocationContext backup = resetInvocationContext(ctx);
|
452 |
188
| EventImpl e = new EventImpl();
|
453 |
188
| e.setCache(cache);
|
454 |
188
| e.setPre(pre);
|
455 |
188
| e.setFqn(fqn);
|
456 |
188
| e.setTransaction(tx);
|
457 |
188
| e.setData(dataCopy);
|
458 |
188
| e.setType(NODE_PASSIVATED);
|
459 |
188
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
460 |
188
| restoreInvocationContext(backup);
|
461 |
| } |
462 |
| } |
463 |
| |
464 |
| |
465 |
| |
466 |
| |
467 |
| |
468 |
| |
469 |
| |
470 |
2811
| public void notifyCacheStarted(final CacheSPI cache, InvocationContext ctx)
|
471 |
| { |
472 |
2811
| List<ListenerInvocation> listeners = listenerInvocations.get(CacheStarted.class);
|
473 |
| |
474 |
2811
| if (listeners != null && listeners.size() > 0)
|
475 |
| { |
476 |
30
| InvocationContext backup = resetInvocationContext(ctx);
|
477 |
30
| EventImpl e = new EventImpl();
|
478 |
30
| e.setCache(cache);
|
479 |
30
| e.setType(CACHE_STARTED);
|
480 |
30
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
481 |
28
| restoreInvocationContext(backup);
|
482 |
| } |
483 |
| } |
484 |
| |
485 |
| |
486 |
| |
487 |
| |
488 |
| |
489 |
| |
490 |
| |
491 |
2781
| public void notifyCacheStopped(final CacheSPI cache, InvocationContext ctx)
|
492 |
| { |
493 |
2785
| List<ListenerInvocation> listeners = listenerInvocations.get(CacheStopped.class);
|
494 |
| |
495 |
2785
| if (listeners != null && listeners.size() > 0)
|
496 |
| { |
497 |
32
| InvocationContext backup = resetInvocationContext(ctx);
|
498 |
32
| EventImpl e = new EventImpl();
|
499 |
32
| e.setCache(cache);
|
500 |
32
| e.setType(CACHE_STOPPED);
|
501 |
32
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
502 |
30
| restoreInvocationContext(backup);
|
503 |
| } |
504 |
| } |
505 |
| |
506 |
| |
507 |
| |
508 |
| |
509 |
| |
510 |
| |
511 |
| |
512 |
| |
513 |
2473
| public void notifyViewChange(final View new_view, InvocationContext ctx)
|
514 |
| { |
515 |
2473
| List<ListenerInvocation> listeners = listenerInvocations.get(ViewChanged.class);
|
516 |
| |
517 |
2473
| if (listeners != null && listeners.size() > 0)
|
518 |
| { |
519 |
246
| InvocationContext backup = resetInvocationContext(ctx);
|
520 |
246
| EventImpl e = new EventImpl();
|
521 |
246
| e.setCache(cache);
|
522 |
246
| e.setNewView(new_view);
|
523 |
246
| e.setType(VIEW_CHANGED);
|
524 |
246
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
525 |
246
| restoreInvocationContext(backup);
|
526 |
| } |
527 |
| } |
528 |
| |
529 |
| |
530 |
| |
531 |
| |
532 |
| |
533 |
| |
534 |
| |
535 |
1121666
| public void notifyTransactionCompleted(Transaction transaction, boolean successful, InvocationContext ctx)
|
536 |
| { |
537 |
1121666
| Transaction tx = ctx.getTransaction();
|
538 |
1121666
| boolean isOriginLocal = ctx.isOriginLocal();
|
539 |
1121666
| List<ListenerInvocation> listeners = listenerInvocations.get(TransactionCompleted.class);
|
540 |
| |
541 |
1121666
| if (listeners != null && listeners.size() > 0)
|
542 |
| { |
543 |
224
| InvocationContext backup = resetInvocationContext(ctx);
|
544 |
224
| EventImpl e = new EventImpl();
|
545 |
224
| e.setCache(cache);
|
546 |
224
| e.setOriginLocal(isOriginLocal);
|
547 |
224
| e.setTransaction(tx);
|
548 |
224
| e.setSuccessful(successful);
|
549 |
224
| e.setType(TRANSACTION_COMPLETED);
|
550 |
224
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
551 |
224
| restoreInvocationContext(backup);
|
552 |
| } |
553 |
| } |
554 |
| |
555 |
| |
556 |
| |
557 |
| |
558 |
| |
559 |
| |
560 |
1121827
| public void notifyTransactionRegistered(Transaction transaction, InvocationContext ctx)
|
561 |
| { |
562 |
1121827
| Transaction tx = ctx.getTransaction();
|
563 |
1121827
| boolean isOriginLocal = ctx.isOriginLocal();
|
564 |
1121827
| List<ListenerInvocation> listeners = listenerInvocations.get(TransactionRegistered.class);
|
565 |
| |
566 |
1121827
| if (listeners != null && listeners.size() > 0)
|
567 |
| { |
568 |
224
| InvocationContext backup = resetInvocationContext(ctx);
|
569 |
224
| EventImpl e = new EventImpl();
|
570 |
224
| e.setCache(cache);
|
571 |
224
| e.setOriginLocal(isOriginLocal);
|
572 |
224
| e.setTransaction(tx);
|
573 |
224
| e.setType(TRANSACTION_REGISTERED);
|
574 |
224
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
575 |
224
| restoreInvocationContext(backup);
|
576 |
| } |
577 |
| } |
578 |
| |
579 |
5876
| public void notifyCacheBlocked(CacheSPI cache, boolean pre)
|
580 |
| { |
581 |
5876
| List<ListenerInvocation> listeners = listenerInvocations.get(CacheBlocked.class);
|
582 |
| |
583 |
5876
| if (listeners != null && listeners.size() > 0)
|
584 |
| { |
585 |
0
| EventImpl e = new EventImpl();
|
586 |
0
| e.setCache(cache);
|
587 |
0
| e.setPre(pre);
|
588 |
0
| e.setType(CACHE_BLOCKED);
|
589 |
0
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
590 |
| } |
591 |
| } |
592 |
| |
593 |
5178
| public void notifyCacheUnblocked(CacheSPI cache, boolean pre)
|
594 |
| { |
595 |
5178
| List<ListenerInvocation> listeners = listenerInvocations.get(CacheUnblocked.class);
|
596 |
| |
597 |
5178
| if (listeners != null && listeners.size() > 0)
|
598 |
| { |
599 |
0
| EventImpl e = new EventImpl();
|
600 |
0
| e.setCache(cache);
|
601 |
0
| e.setPre(pre);
|
602 |
0
| e.setType(CACHE_UNBLOCKED);
|
603 |
0
| for (ListenerInvocation listener : listeners) listener.invoke(e);
|
604 |
| } |
605 |
| } |
606 |
| |
607 |
| |
608 |
889496
| private Map copy(Map data)
|
609 |
| { |
610 |
884007
| if (safe(data)) return data;
|
611 |
5489
| return new MapCopy(data);
|
612 |
| } |
613 |
| |
614 |
4533
| private void restoreInvocationContext(InvocationContext backup)
|
615 |
| { |
616 |
4533
| cache.setInvocationContext(backup);
|
617 |
| } |
618 |
| |
619 |
| |
620 |
| |
621 |
| |
622 |
| |
623 |
| |
624 |
| |
625 |
| |
626 |
4538
| private InvocationContext resetInvocationContext(InvocationContext ctx)
|
627 |
| { |
628 |
| |
629 |
4538
| cache.setInvocationContext(null);
|
630 |
4538
| return ctx;
|
631 |
| } |
632 |
| |
633 |
| |
634 |
| |
635 |
| |
636 |
| |
637 |
| |
638 |
| |
639 |
| |
640 |
| |
641 |
| |
642 |
| |
643 |
| |
644 |
| |
645 |
889496
| private boolean safe(Map map)
|
646 |
| { |
647 |
889496
| return map == null || map instanceof MapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
|
648 |
| } |
649 |
| |
650 |
| |
651 |
| |
652 |
| |
653 |
| |
654 |
| class ListenerInvocation |
655 |
| { |
656 |
| private Object target; |
657 |
| private Method method; |
658 |
| |
659 |
1300
| public ListenerInvocation(Object target, Method method)
|
660 |
| { |
661 |
1300
| this.target = target;
|
662 |
1300
| this.method = method;
|
663 |
| } |
664 |
| |
665 |
4538
| public void invoke(Event e)
|
666 |
| { |
667 |
4538
| try
|
668 |
| { |
669 |
4538
| method.invoke(target, e);
|
670 |
| } |
671 |
| catch (InvocationTargetException e1) |
672 |
| { |
673 |
5
| Throwable cause = e1.getCause();
|
674 |
5
| if (cause != null)
|
675 |
5
| throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, cause);
|
676 |
| else |
677 |
0
| throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, e1);
|
678 |
| } |
679 |
| catch (IllegalAccessException e1) |
680 |
| { |
681 |
0
| log.warn("Unable to invoke method " + method + " on Object instance " + target + " - removing this target object from list of listeners!", e1);
|
682 |
0
| removeCacheListener(this.target);
|
683 |
| } |
684 |
| } |
685 |
| } |
686 |
| |
687 |
| } |