1
2
3
4
5
6
7
8
9
10
11 package org.mule.impl.internal.notifications;
12
13 import org.mule.MuleManager;
14 import org.mule.config.i18n.CoreMessages;
15 import org.mule.routing.filters.WildcardFilter;
16 import org.mule.umo.lifecycle.Disposable;
17 import org.mule.umo.lifecycle.LifecycleException;
18 import org.mule.umo.manager.UMOServerNotification;
19 import org.mule.umo.manager.UMOServerNotificationListener;
20 import org.mule.umo.manager.UMOWorkManager;
21 import org.mule.util.concurrent.ConcurrentHashSet;
22
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Set;
27
28 import javax.resource.spi.work.Work;
29 import javax.resource.spi.work.WorkException;
30 import javax.resource.spi.work.WorkListener;
31 import javax.resource.spi.work.WorkManager;
32
33 import edu.emory.mathcs.backport.java.util.concurrent.BlockingDeque;
34 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
35 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
36 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingDeque;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40
41
42
43
44 public class ServerNotificationManager implements Work, Disposable
45 {
46
47
48
49 protected static final Log logger = LogFactory.getLog(ServerNotificationManager.class);
50
51 public static final String NULL_SUBSCRIPTION = "NULL";
52
53 private ConcurrentMap eventsMap;
54 private BlockingDeque eventQueue;
55 private Set listeners;
56 private WorkListener workListener;
57 private volatile boolean disposed = false;
58
59 public ServerNotificationManager()
60 {
61 eventsMap = new ConcurrentHashMap();
62 eventQueue = new LinkedBlockingDeque();
63 listeners = new ConcurrentHashSet();
64 workListener = MuleManager.getConfiguration().getWorkListener();
65 }
66
67 public void start(UMOWorkManager workManager) throws LifecycleException
68 {
69 try
70 {
71 workManager.scheduleWork(this, WorkManager.INDEFINITE, null, workListener);
72 }
73 catch (WorkException e)
74 {
75 throw new LifecycleException(e, this);
76 }
77 }
78
79 public void registerEventType(Class eventType, Class listenerType)
80 {
81 if (UMOServerNotification.class.isAssignableFrom(eventType))
82 {
83 Class previousEventType = (Class) eventsMap.putIfAbsent(listenerType, eventType);
84 if (previousEventType != null)
85 {
86 eventType = previousEventType;
87 }
88 else
89 {
90 if (logger.isDebugEnabled())
91 {
92 logger.debug("Registered event type: " + eventType);
93 logger.debug("Binding listener type '" + listenerType + "' to event type '" + eventType + "'");
94 }
95 }
96 }
97 else
98 {
99 throw new IllegalArgumentException(
100 CoreMessages.propertyIsNotSupportedType("eventType",
101 UMOServerNotification.class, eventType).getMessage());
102 }
103 }
104
105 public void registerListener(UMOServerNotificationListener listener) throws NotificationException
106 {
107 this.registerListener(listener, null);
108 }
109
110 public void registerListener(UMOServerNotificationListener listener, String subscription)
111 throws NotificationException
112 {
113 listeners.add(new Listener(listener, subscription));
114 }
115
116 public void unregisterListener(UMOServerNotificationListener listener)
117 {
118 for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
119 {
120 Listener l = (Listener) iterator.next();
121 if (l.getListenerObject().equals(listener))
122 {
123 listeners.remove(l);
124 break;
125 }
126 }
127 }
128
129 public void fireEvent(UMOServerNotification notification)
130 {
131 if (disposed)
132 {
133 return;
134 }
135
136 if (notification instanceof BlockingServerEvent)
137 {
138 this.notifyListeners(notification);
139 }
140 else
141 {
142 try
143 {
144 eventQueue.put(notification);
145 }
146 catch (InterruptedException e)
147 {
148 if (!disposed)
149 {
150
151 logger.error("Failed to queue notification: " + notification, e);
152 }
153 }
154 }
155 }
156
157 public void dispose()
158 {
159 disposed = true;
160 eventsMap.clear();
161 eventQueue.clear();
162 listeners.clear();
163 workListener = null;
164 }
165
166
167
168
169
170
171 protected void notifyListeners(UMOServerNotification notification)
172 {
173 if (disposed)
174 {
175 return;
176 }
177
178 for (Iterator iterator = listeners.iterator(); iterator.hasNext();)
179 {
180 Listener listener = (Listener) iterator.next();
181 if (listener.matches(notification))
182 {
183 listener.getListenerObject().onNotification(notification);
184 }
185 }
186 }
187
188 public void release()
189 {
190 this.dispose();
191 }
192
193
194
195
196
197
198
199
200
201
202 public void run()
203 {
204 while (!disposed)
205 {
206 try
207 {
208 UMOServerNotification notification = (UMOServerNotification) eventQueue.take();
209 if (notification != null)
210 {
211 this.notifyListeners(notification);
212 }
213 }
214 catch (InterruptedException e)
215 {
216 if (!disposed)
217 {
218
219 logger.error("Failed to take notification from queue", e);
220 }
221 }
222 }
223 }
224
225 protected class Listener
226 {
227 private final UMOServerNotificationListener listener;
228 private final List notificationClasses;
229 private final String subscription;
230 private final WildcardFilter subscriptionFilter;
231
232 public Listener(UMOServerNotificationListener listener, String subscription)
233 {
234 this.listener = listener;
235 this.subscription = (subscription == null ? NULL_SUBSCRIPTION : subscription);
236
237 subscriptionFilter = new WildcardFilter(this.subscription);
238 subscriptionFilter.setCaseSensitive(false);
239
240 notificationClasses = new ArrayList();
241
242 for (Iterator iterator = eventsMap.keySet().iterator(); iterator.hasNext();)
243 {
244 Class clazz = (Class) iterator.next();
245 if (clazz.isAssignableFrom(listener.getClass()))
246 {
247 notificationClasses.add(eventsMap.get(clazz));
248 }
249 }
250 }
251
252 public UMOServerNotificationListener getListenerObject()
253 {
254 return listener;
255 }
256
257 public List getNotificationClasses()
258 {
259 return notificationClasses;
260 }
261
262 public String getSubscription()
263 {
264 return subscription;
265 }
266
267 public boolean matches(UMOServerNotification notification)
268 {
269 if (this.subscriptionMatches(notification))
270 {
271 for (Iterator iterator = notificationClasses.iterator(); iterator.hasNext();)
272 {
273 Class notificationClass = (Class) iterator.next();
274 if (notificationClass.isAssignableFrom(notification.getClass()))
275 {
276 return true;
277 }
278 }
279 }
280
281 return false;
282 }
283
284 public boolean subscriptionMatches(UMOServerNotification notification)
285 {
286 String resourceId = notification.getResourceIdentifier();
287 if (NULL_SUBSCRIPTION.equals(subscription) || subscriptionFilter.accept(resourceId))
288 {
289 return true;
290 }
291 else
292 {
293 return false;
294 }
295 }
296 }
297
298 public WorkListener getWorkListener()
299 {
300 return workListener;
301 }
302
303 public void setWorkListener(WorkListener workListener)
304 {
305 if (workListener == null)
306 {
307 throw new IllegalArgumentException("workListener may not be null");
308 }
309 this.workListener = workListener;
310 }
311 }