View Javadoc

1   /*
2    * $Id: ServerNotificationManager.java 7976 2007-08-21 14:26:13Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
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   * <code>ServerNotificationManager</code> manages all server listeners for a Mule
42   * instance.
43   */
44  public class ServerNotificationManager implements Work, Disposable
45  {
46      /**
47       * logger used by this class
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                     // TODO MULE-863: Is this sufficient?  Necessary?
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      * Exceptions should not be thrown from this method
168      * 
169      * @param notification
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      * When an object implementing interface <code>Runnable</code> is used to
195      * create a thread, starting the thread causes the object's <code>run</code>
196      * method to be called in that separately executing thread. <p/> The general
197      * contract of the method <code>run</code> is that it may take any action
198      * whatsoever.
199      * 
200      * @see Thread#run()
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                     // TODO MULE-863: Is this sufficient?  Necessary? 
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 }