View Javadoc

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