1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| |
16 |
| |
17 |
| |
18 |
| |
19 |
| |
20 |
| |
21 |
| |
22 |
| |
23 |
| package org.jboss.cache.pojo.impl; |
24 |
| |
25 |
| import static org.jboss.cache.pojo.impl.InternalConstant.POJOCACHE_OPERATION; |
26 |
| import static org.jboss.cache.pojo.impl.InternalConstant.POJOCACHE_STATUS; |
27 |
| import static org.jboss.cache.notifications.event.Event.Type.TRANSACTION_COMPLETED; |
28 |
| import static org.jboss.cache.notifications.event.Event.Type.TRANSACTION_REGISTERED; |
29 |
| |
30 |
| import java.lang.reflect.Field; |
31 |
| import java.util.Collection; |
32 |
| import java.util.HashSet; |
33 |
| import java.util.List; |
34 |
| import java.util.Map; |
35 |
| import java.util.Set; |
36 |
| import java.util.regex.Pattern; |
37 |
| |
38 |
| import javax.transaction.Transaction; |
39 |
| |
40 |
| import org.apache.commons.logging.Log; |
41 |
| import org.apache.commons.logging.LogFactory; |
42 |
| import org.jboss.cache.Fqn; |
43 |
| import org.jboss.cache.notifications.annotation.CacheListener; |
44 |
| import org.jboss.cache.notifications.annotation.NodeModified; |
45 |
| import org.jboss.cache.notifications.annotation.TransactionCompleted; |
46 |
| import org.jboss.cache.notifications.annotation.TransactionRegistered; |
47 |
| import org.jboss.cache.notifications.event.NodeModifiedEvent; |
48 |
| import org.jboss.cache.notifications.event.TransactionalEvent; |
49 |
| import org.jboss.cache.notifications.event.NodeModifiedEvent.ModificationType; |
50 |
| import org.jboss.cache.pojo.PojoCache; |
51 |
| import org.jboss.cache.pojo.interceptors.PojoTxLockInterceptor; |
52 |
| import org.jboss.cache.pojo.notification.NotificationContext; |
53 |
| import org.jboss.cache.pojo.notification.event.AttachedEvent; |
54 |
| import org.jboss.cache.pojo.notification.event.DetachedEvent; |
55 |
| import org.jboss.cache.pojo.notification.event.Event; |
56 |
| import org.jboss.cache.pojo.notification.event.FieldModifiedEvent; |
57 |
| import org.jboss.cache.pojo.notification.event.ListModifiedEvent; |
58 |
| import org.jboss.cache.pojo.notification.event.MapModifiedEvent; |
59 |
| import org.jboss.cache.pojo.notification.event.SetModifiedEvent; |
60 |
| import org.jboss.cache.pojo.notification.event.TransactionCompletedEvent; |
61 |
| import org.jboss.cache.pojo.notification.event.TransactionRegisteredEvent; |
62 |
| |
63 |
| |
64 |
| |
65 |
| |
66 |
| |
67 |
| |
68 |
| |
69 |
| |
70 |
| @CacheListener |
71 |
| public class CacheListenerAdaptor |
72 |
| { |
73 |
| private static final HashSet<String> internalKeys = new HashSet<String>(); |
74 |
| private static final Log log = LogFactory.getLog(CacheListenerAdaptor.class); |
75 |
| |
76 |
| static |
77 |
| { |
78 |
77
| internalKeys.add(POJOCACHE_STATUS);
|
79 |
77
| internalKeys.add(POJOCACHE_OPERATION);
|
80 |
77
| internalKeys.add(PojoInstance.KEY);
|
81 |
77
| internalKeys.add(PojoReference.KEY);
|
82 |
77
| internalKeys.add(PojoTxLockInterceptor.LOCK_KEY);
|
83 |
| } |
84 |
| |
85 |
| private PojoCacheImpl cache; |
86 |
| private NotificationDispatcher dispatcher = new NotificationDispatcher(); |
87 |
| |
88 |
499
| public CacheListenerAdaptor(PojoCacheImpl cache)
|
89 |
| { |
90 |
499
| this.cache = cache;
|
91 |
| } |
92 |
| |
93 |
174
| public PojoCache getPojoCache()
|
94 |
| { |
95 |
174
| return this.cache;
|
96 |
| } |
97 |
| |
98 |
4
| private FieldModifiedEvent createModifyEvent(NotificationContext context, Fqn fqn, String key, Object value, boolean local)
|
99 |
| { |
100 |
4
| if (value instanceof PojoReference)
|
101 |
2
| value = cache.find(((PojoReference) value).getFqn().toString());
|
102 |
| |
103 |
4
| Object o = cache.find(fqn.toString());
|
104 |
| |
105 |
4
| if (o == null)
|
106 |
0
| return null;
|
107 |
| |
108 |
4
| Field f;
|
109 |
4
| try
|
110 |
| { |
111 |
4
| f = o.getClass().getDeclaredField(key);
|
112 |
| } |
113 |
| catch (NoSuchFieldException e) |
114 |
| { |
115 |
0
| if (log.isWarnEnabled())
|
116 |
0
| log.warn("Could not get field " + key + " on class " + o.getClass());
|
117 |
0
| return null;
|
118 |
| } |
119 |
| |
120 |
4
| return new FieldModifiedEvent(context, o, f, value, local);
|
121 |
| } |
122 |
| |
123 |
272
| private NotificationContext createContext(final TransactionalEvent event)
|
124 |
| { |
125 |
272
| return new NotificationContext()
|
126 |
| { |
127 |
| |
128 |
174
| public PojoCache getPojoCache()
|
129 |
| { |
130 |
174
| return CacheListenerAdaptor.this.getPojoCache();
|
131 |
| } |
132 |
| |
133 |
112
| public Transaction getTransaction()
|
134 |
| { |
135 |
112
| return event.getTransaction();
|
136 |
| } |
137 |
| }; |
138 |
| } |
139 |
| |
140 |
272
| private void sendNotification(Event notification, Set<NotificationDispatcher.Entry> listeners)
|
141 |
| { |
142 |
272
| if (notification == null)
|
143 |
0
| return;
|
144 |
| |
145 |
272
| if (listeners == null)
|
146 |
272
| dispatcher.dispatch(notification);
|
147 |
| else |
148 |
0
| dispatcher.dispatch(notification, listeners);
|
149 |
| } |
150 |
| |
151 |
98
| @TransactionCompleted
|
152 |
| @TransactionRegistered |
153 |
| public void handleTransaction(TransactionalEvent event) |
154 |
| { |
155 |
98
| if (event.getType() == TRANSACTION_COMPLETED)
|
156 |
| { |
157 |
49
| boolean successful = ((org.jboss.cache.notifications.event.TransactionCompletedEvent) event).isSuccessful();
|
158 |
49
| sendNotification(new TransactionCompletedEvent(createContext(event), successful, event.isOriginLocal()), null);
|
159 |
| } |
160 |
49
| else if (event.getType() == TRANSACTION_REGISTERED)
|
161 |
| { |
162 |
49
| sendNotification(new TransactionRegisteredEvent(createContext(event), event.isOriginLocal()), null);
|
163 |
| } |
164 |
| } |
165 |
| |
166 |
1198
| @NodeModified
|
167 |
| public void nodeModified(NodeModifiedEvent event) |
168 |
| { |
169 |
1198
| Map<Object, Object> data = event.getData();
|
170 |
1198
| boolean pre = event.isPre();
|
171 |
1198
| Fqn fqn = event.getFqn();
|
172 |
1198
| ModificationType modType = event.getModificationType();
|
173 |
1198
| boolean isLocal = event.isOriginLocal();
|
174 |
| |
175 |
1198
| if (pre)
|
176 |
600
| return;
|
177 |
| |
178 |
| |
179 |
| |
180 |
| |
181 |
598
| Set<NotificationDispatcher.Entry> matched = null;
|
182 |
598
| if (dispatcher.hasFilters())
|
183 |
| { |
184 |
0
| matched = matchListeners(fqn);
|
185 |
0
| if (matched != null && matched.isEmpty())
|
186 |
0
| return;
|
187 |
| } |
188 |
| |
189 |
598
| if (modType == ModificationType.PUT_DATA)
|
190 |
| { |
191 |
508
| if ("ATTACHED".equals(data.get(POJOCACHE_STATUS)))
|
192 |
| { |
193 |
97
| Object o = cache.find(fqn.toString());
|
194 |
97
| sendNotification(new AttachedEvent(createContext(event), o, isLocal), matched);
|
195 |
| } |
196 |
411
| else if ("DETACHING".equals(data.get(POJOCACHE_STATUS)))
|
197 |
| { |
198 |
14
| Object o = cache.find(fqn.toString());
|
199 |
14
| sendNotification(new DetachedEvent(createContext(event), o, isLocal), matched);
|
200 |
| } |
201 |
397
| else if (data.containsKey(POJOCACHE_OPERATION))
|
202 |
| { |
203 |
59
| Object collection = cache.find(fqn.getParent().toString());
|
204 |
59
| if (collection instanceof List)
|
205 |
| { |
206 |
45
| int i = Integer.parseInt(fqn.getLastElementAsString());
|
207 |
45
| ListModifiedEvent.Operation operation = ListModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
|
208 |
45
| Object value = cache.find(fqn.toString());
|
209 |
45
| sendNotification(new ListModifiedEvent(createContext(event), (List) collection, operation, i, value, isLocal), matched);
|
210 |
| } |
211 |
14
| else if (collection instanceof Set)
|
212 |
| { |
213 |
7
| SetModifiedEvent.Operation operation = SetModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
|
214 |
7
| Object value = cache.find(fqn.toString());
|
215 |
7
| sendNotification(new SetModifiedEvent(createContext(event), (Set) collection, operation, value, isLocal), matched);
|
216 |
| } |
217 |
7
| else if (collection instanceof Map)
|
218 |
| { |
219 |
7
| MapModifiedEvent.Operation operation = MapModifiedEvent.Operation.valueOf(data.get(POJOCACHE_OPERATION).toString());
|
220 |
7
| Object value = cache.find(fqn.toString());
|
221 |
7
| sendNotification(new MapModifiedEvent(createContext(event), (Map) collection, operation, fqn.getLastElement(), value, isLocal), matched);
|
222 |
| } |
223 |
| } |
224 |
338
| else if ("ATTACHED".equals(cache.getCache().get(fqn, POJOCACHE_STATUS)))
|
225 |
| { |
226 |
21
| for (Map.Entry entry : data.entrySet())
|
227 |
| { |
228 |
21
| String key = entry.getKey().toString();
|
229 |
21
| Object value = entry.getValue();
|
230 |
| |
231 |
21
| if (internalKeys.contains(key))
|
232 |
17
| continue;
|
233 |
| |
234 |
4
| sendNotification(createModifyEvent(createContext(event), fqn, key, value, isLocal), matched);
|
235 |
| } |
236 |
| } |
237 |
| } |
238 |
90
| else if (modType == ModificationType.REMOVE_DATA)
|
239 |
| { |
240 |
0
| for (Map.Entry entry : data.entrySet())
|
241 |
| { |
242 |
0
| String key = entry.getKey().toString();
|
243 |
0
| if (internalKeys.contains(key))
|
244 |
0
| continue;
|
245 |
| |
246 |
0
| sendNotification(createModifyEvent(createContext(event), fqn, key, null, isLocal), matched);
|
247 |
| } |
248 |
| } |
249 |
| } |
250 |
| |
251 |
0
| private Set<NotificationDispatcher.Entry> matchListeners(Fqn fqn)
|
252 |
| { |
253 |
0
| PojoInstance instance = (PojoInstance) cache.getCache().get(fqn, PojoInstance.KEY);
|
254 |
0
| if (instance != null)
|
255 |
0
| return dispatcher.getListenerEntries(instance.getReferences());
|
256 |
| |
257 |
0
| return null;
|
258 |
| } |
259 |
| |
260 |
0
| public boolean isEmpty()
|
261 |
| { |
262 |
0
| return dispatcher.isEmpty();
|
263 |
| } |
264 |
| |
265 |
0
| public Collection<Object> getListeners()
|
266 |
| { |
267 |
0
| return dispatcher.getListeners();
|
268 |
| } |
269 |
| |
270 |
0
| public void addListener(Object listener)
|
271 |
| { |
272 |
0
| dispatcher.add(listener);
|
273 |
| } |
274 |
| |
275 |
50
| public void addListener(Object listener, Pattern pattern)
|
276 |
| { |
277 |
50
| if (pattern == null)
|
278 |
50
| dispatcher.add(listener);
|
279 |
| else |
280 |
0
| dispatcher.add(listener, pattern);
|
281 |
| } |
282 |
| |
283 |
0
| public void removeListener(Object listener)
|
284 |
| { |
285 |
0
| dispatcher.remove(listener);
|
286 |
| } |
287 |
| } |