View Javadoc

1   /*
2    * $Id: Policy.java 10489 2008-01-23 17:53:38Z dfeist $
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.context.notification;
12  
13  import org.mule.api.context.notification.ServerNotification;
14  import org.mule.api.context.notification.ServerNotificationListener;
15  
16  import java.util.Collection;
17  import java.util.HashMap;
18  import java.util.HashSet;
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 eventToSenders = new HashMap();
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       * @param interfaceToEvents
46       * @param listenerSubscriptionPairs
47       * @param disabledInterfaces
48       * @param disabledEvents
49       */
50      Policy(Map interfaceToEvents, Set listenerSubscriptionPairs, Set disabledInterfaces, Set disabledEvents)
51      {
52          for (Iterator pairs = listenerSubscriptionPairs.iterator(); pairs.hasNext();)
53          {
54              ListenerSubscriptionPair pair = (ListenerSubscriptionPair) pairs.next();
55              ServerNotificationListener listener = pair.getListener();
56              for (Iterator interfaces = interfaceToEvents.keySet().iterator(); interfaces.hasNext();)
57              {
58                  Class iface = (Class) interfaces.next();
59                  if (notASubclassOfAnyClassInSet(disabledInterfaces, iface))
60                  {
61                      if (iface.isAssignableFrom(listener.getClass()))
62                      {
63                          for (Iterator events = ((Collection) interfaceToEvents.get(iface)).iterator(); events.hasNext();)
64                          {
65                              Class event = (Class) events.next();
66                              if (notASubclassOfAnyClassInSet(disabledEvents, event))
67                              {
68                                  knownEventsExact.put(event, Boolean.TRUE);
69                                  knownEventsSuper.put(event, Boolean.TRUE);
70                                  if (!eventToSenders.containsKey(event))
71                                  {
72                                      eventToSenders.put(event, new HashSet());
73                                  }
74                                  ((Collection) eventToSenders.get(event)).add(new Sender(pair));
75                              }
76                          }
77                      }
78                  }
79              }
80          }
81      }
82  
83      protected static boolean notASubclassOfAnyClassInSet(Set set, Class clazz)
84      {
85          for (Iterator iterator = set.iterator(); iterator.hasNext();)
86          {
87              Class disabled = (Class) iterator.next();
88              if (disabled.isAssignableFrom(clazz))
89              {
90                  return false;
91              }
92          }
93          return true;
94      }
95  
96      protected static boolean notASuperclassOfAnyClassInSet(Set set, Class clazz)
97      {
98          for (Iterator iterator = set.iterator(); iterator.hasNext();)
99          {
100             Class disabled = (Class) iterator.next();
101             if (clazz.isAssignableFrom(disabled))
102             {
103                 return false;
104             }
105         }
106         return true;
107     }
108 
109     void dispatch(ServerNotification notification)
110     {
111         if (null != notification)
112         {
113             Class notfnClass = notification.getClass();
114             // search if we don't know about this event, or if we do know it is used
115             if ((!knownEventsExact.containsKey(notfnClass))
116                     || ((Boolean) knownEventsExact.get(notfnClass)).booleanValue())
117             {
118                 boolean found = false;
119                 for (Iterator events = eventToSenders.keySet().iterator(); events.hasNext();)
120                 {
121                     Class event = (Class) events.next();
122                     if (event.isAssignableFrom(notfnClass))
123                     {
124                         found = true;
125                         for (Iterator senders = ((Collection) eventToSenders.get(event)).iterator(); senders.hasNext();)
126                         {
127                             ((Sender) senders.next()).dispatch(notification);
128                         }
129                     }
130                 }
131                 knownEventsExact.put(notfnClass, Boolean.valueOf(found));
132             }
133         }
134     }
135 
136     /**
137      * This returns a very "conservative" value - it is true if the notification or any subclass would be
138      * accepted.  So if it returns false then you can be sure that there is no need to send the
139      * notification.  On the other hand, if it returns true there is no guarantee that the notification
140      * "really" will be dispatched to any listener.
141      *
142      * @param notfnClass Either the notification class being generated or some superclass
143      * @return false if there is no need to dispatch the notification
144      */
145     boolean isNotificationEnabled(Class notfnClass)
146     {
147         if (!knownEventsSuper.containsKey(notfnClass))
148         {
149             boolean found = false;
150             // this is exhaustive because we initialise to include all events handled.
151             for (Iterator events = knownEventsSuper.keySet().iterator(); events.hasNext() && !found;)
152             {
153                 Class event = (Class) events.next();
154                 found = ((Boolean) knownEventsSuper.get(event)).booleanValue() && notfnClass.isAssignableFrom(event);
155             }
156             knownEventsSuper.put(notfnClass, Boolean.valueOf(found));
157         }
158         if (!knownEventsExact.containsKey(notfnClass))
159         {
160             boolean found = false;
161             for (Iterator events = eventToSenders.keySet().iterator(); events.hasNext() && !found;)
162             {
163                 Class event = (Class) events.next();
164                 found = event.isAssignableFrom(notfnClass);
165             }
166             knownEventsExact.put(notfnClass, Boolean.valueOf(found));
167 
168         }
169         return ((Boolean) knownEventsSuper.get(notfnClass)).booleanValue()
170                 || ((Boolean) knownEventsExact.get(notfnClass)).booleanValue();
171     }
172 
173 }