View Javadoc

1   /*
2    * $Id: Policy.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.context.notification;
12  
13  import org.mule.api.context.notification.ServerNotification;
14  import org.mule.api.context.notification.ServerNotificationListener;
15  
16  import java.util.ArrayList;
17  import java.util.Collection;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.Map;
21  import java.util.Set;
22  
23  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
24  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
25  
26  /**
27   * For a particular configuration, this describes what events should be delivered where.
28   * It is read-only and a lazy instance is cached by the
29   * {@link Configuration}
30   */
31  class Policy
32  {
33  
34      // map from event to set of senders
35      private Map<Class<? extends ServerNotification>, Collection<Sender>> eventToSenders = new HashMap<Class<? extends ServerNotification>, Collection<Sender>>();
36  
37      // these are cumulative - set values should never change, they are just a cache of known info
38      // they are co and contra-variant wrt to exact event type (see code below).
39      private ConcurrentMap knownEventsExact = new ConcurrentHashMap();
40      private ConcurrentMap knownEventsSuper = new ConcurrentHashMap();
41  
42      /**
43       * For each listener, we check each interface and see what events can be delivered.
44       */
45      Policy(Map<Class<? extends ServerNotificationListener>, Set<Class<? extends ServerNotification>>> interfaceToEvents, 
46          Set<ListenerSubscriptionPair> listenerSubscriptionPairs, 
47          Set<Class<? extends ServerNotificationListener>> disabledInterfaces, 
48          Set<Class<? extends ServerNotification>> disabledEvents)
49      {
50          for (ListenerSubscriptionPair pair : listenerSubscriptionPairs)
51          {
52              ServerNotificationListener listener = pair.getListener();
53              for (Class<? extends ServerNotificationListener> iface : interfaceToEvents.keySet())
54              {
55                  if (notASubclassOfAnyClassInSet(disabledInterfaces, iface))
56                  {
57                      if (iface.isAssignableFrom(listener.getClass()))
58                      {
59                          Set<Class<? extends ServerNotification>> events = interfaceToEvents.get(iface);
60                          for (Class<? extends ServerNotification> event : events)
61                          {
62                              if (notASubclassOfAnyClassInSet(disabledEvents, event))
63                              {
64                                  knownEventsExact.put(event, Boolean.TRUE);
65                                  knownEventsSuper.put(event, Boolean.TRUE);
66                                  if (!eventToSenders.containsKey(event))
67                                  {
68                                      // use a collection with predictable iteration order
69                                      eventToSenders.put(event, new ArrayList<Sender>());
70                                  }
71                                  eventToSenders.get(event).add(new Sender(pair));
72                              }
73                          }
74                      }
75                  }
76              }
77          }
78      }
79  
80      protected static boolean notASubclassOfAnyClassInSet(Set set,  Class clazz)
81      {
82          for (Iterator iterator = set.iterator(); iterator.hasNext();)
83          {
84              Class disabled = (Class) iterator.next();
85              if (disabled.isAssignableFrom(clazz))
86              {
87                  return false;
88              }
89          }
90          return true;
91      }
92  
93      protected static boolean notASuperclassOfAnyClassInSet(Set set, Class clazz)
94      {
95          for (Iterator iterator = set.iterator(); iterator.hasNext();)
96          {
97              Class disabled = (Class) iterator.next();
98              if (clazz.isAssignableFrom(disabled))
99              {
100                 return false;
101             }
102         }
103         return true;
104     }
105 
106     void dispatch(ServerNotification notification)
107     {
108         if (null != notification)
109         {
110             Class notfnClass = notification.getClass();
111             // search if we don't know about this event, or if we do know it is used
112             if ((!knownEventsExact.containsKey(notfnClass))
113                     || ((Boolean) knownEventsExact.get(notfnClass)).booleanValue())
114             {
115                 boolean found = false;
116                 for (Class<? extends ServerNotification> event : eventToSenders.keySet())
117                 {
118                     if (event.isAssignableFrom(notfnClass))
119                     {
120                         found = true;
121                         for (Iterator senders = ((Collection) eventToSenders.get(event)).iterator(); senders.hasNext();)
122                         {
123                             ((Sender) senders.next()).dispatch(notification);
124                         }
125                     }
126                 }
127                 knownEventsExact.put(notfnClass, Boolean.valueOf(found));
128             }
129         }
130     }
131 
132     /**
133      * This returns a very "conservative" value - it is true if the notification or any subclass would be
134      * accepted.  So if it returns false then you can be sure that there is no need to send the
135      * notification.  On the other hand, if it returns true there is no guarantee that the notification
136      * "really" will be dispatched to any listener.
137      *
138      * @param notfnClass Either the notification class being generated or some superclass
139      * @return false if there is no need to dispatch the notification
140      */
141     boolean isNotificationEnabled(Class notfnClass)
142     {
143         if (!knownEventsSuper.containsKey(notfnClass))
144         {
145             boolean found = false;
146             // this is exhaustive because we initialise to include all events handled.
147             for (Iterator events = knownEventsSuper.keySet().iterator(); events.hasNext() && !found;)
148             {
149                 Class event = (Class) events.next();
150                 found = ((Boolean) knownEventsSuper.get(event)).booleanValue() && notfnClass.isAssignableFrom(event);
151             }
152             knownEventsSuper.put(notfnClass, Boolean.valueOf(found));
153         }
154         if (!knownEventsExact.containsKey(notfnClass))
155         {
156             boolean found = false;
157             for (Iterator events = eventToSenders.keySet().iterator(); events.hasNext() && !found;)
158             {
159                 Class event = (Class) events.next();
160                 found = event.isAssignableFrom(notfnClass);
161             }
162             knownEventsExact.put(notfnClass, Boolean.valueOf(found));
163 
164         }
165         return ((Boolean) knownEventsSuper.get(notfnClass)).booleanValue()
166                 || ((Boolean) knownEventsExact.get(notfnClass)).booleanValue();
167     }
168 
169 }