38 39 /** 40 * This is a utility class that can be used by a context that supports 41 * event notification. You can use an instance of this class as a member field 42 * of your context and delegate various work to it. 43 * It is currently structured so that each context should have its own 44 * EventSupport (instead of static version shared by all contexts 45 * of a service provider). 46 *<p> 47 * This class supports two types of listeners: those that register for 48 * NamingEvents, and those for UnsolicitedNotificationEvents (they can be mixed 49 * into the same listener). 50 * For NamingEvent listeners, it maintains a hashtable that maps 51 * registration requests--the key--to 52 * <em>notifiers</em>--the value. Each registration request consists of: 53 *<ul> 54 *<li>The name argument of the registration. 55 *<li>The filter (default is "(objectclass=*)"). 56 *<li>The search controls (default is null SearchControls). 57 *<li>The events that the listener is interested in. This is determined by 58 * finding out which <tt>NamingListener</tt> interface the listener supports. 59 *</ul> 60 *<p> 61 *A notifier (<tt>NamingEventNotifier</tt>) is a worker thread that is responsible 62 *for gathering information for generating events requested by its listeners. 63 *Each notifier maintains its own list of listeners; these listeners have 64 *all made the same registration request (at different times) and implements 65 *the same <tt>NamingListener</tt> interfaces. 66 *<p> 67 *For unsolicited listeners, this class maintains a vector, unsolicited. 68 *When an unsolicited listener is registered, this class adds itself 69 *to the context's LdapClient. When LdapClient receives an unsolicited 70 *notification, it notifies this EventSupport to fire an event to the 71 *the listeners. Special handling in LdapClient is done for the DISCONNECT 72 *notification. [It results in the EventSupport firing also a 73 *NamingExceptionEvent to the unsolicited listeners.] 74 *<p> 75 * 76 *When a context no longer needs this EventSupport, it should invoke 77 *cleanup() on it. 78 *<p> 79 *<h4>Registration</h4> 80 *When a registration request is made, this class attempts to find an 81 *existing notifier that's already working on the request. If one is 82 *found, the listener is added to the notifier's list. If one is not found, 83 *a new notifier is created for the listener. 84 * 85 *<h4>Deregistration</h4> 86 *When a deregistration request is made, this class attempts to find its 87 *corresponding notifier. If the notifier is found, the listener is removed 88 *from the notifier's list. If the listener is the last listener on the list, 89 *the notifier's thread is terminated and removed from this class's hashtable. 90 *Nothing happens if the notifier is not found. 91 * 92 *<h4>Event Dispatching</h4> 93 *The notifiers are responsible for gather information for generating events 94 *requested by their respective listeners. When a notifier gets sufficient 95 *information to generate an event, it creates invokes the 96 *appropriate <tt>fireXXXEvent</tt> on this class with the information and list of 97 *listeners. This causes an event and the list of listeners to be added 98 *to the <em>event queue</em>. 99 *This class maintains an event queue and a dispatching thread that dequeues 100 *events from the queue and dispatches them to the listeners. 101 * 102 *<h4>Synchronization</h4> 103 *This class is used by the main thread (LdapCtx) to add/remove listeners. 104 *It is also used asynchronously by NamingEventNotifiers threads and 105 *the context's Connection thread. It is used by the notifier threads to 106 *queue events and to update the notifiers list when the notifiers exit. 107 *It is used by the Connection thread to fire unsolicited notifications. 108 *Methods that access/update the 'unsolicited' and 'notifiers' lists are 109 *thread-safe. 110 * 111 * @author Rosanna Lee 112 */ 113 final class EventSupport { 114 final static private boolean debug = false; 115 116 private LdapCtx ctx; 121 private Hashtable<NotifierArgs, NamingEventNotifier> notifiers = 122 new Hashtable<>(11); 123 124 /** 125 * List of unsolicited notification listeners. 126 */ 127 private Vector<UnsolicitedNotificationListener> unsolicited = null; 128 129 /** 130 * Constructs EventSupport for ctx. 131 * <em>Do we need to record the name of the target context? 132 * Or can we assume that EventSupport is called on a resolved 133 * context? Do we need other add/remove-NamingListener methods? 134 * package private; 135 */ 136 EventSupport(LdapCtx ctx) { 137 this.ctx = ctx; 138 } 139 140 /** 141 * Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt>. 142 */ 143 /* 144 * Make the add/removeNamingListeners synchronized to: 145 * 1. protect usage of 'unsolicited', which may be read by 146 * the Connection thread when dispatching unsolicited notification. 147 * 2. ensure that NamingEventNotifier thread's access to 'notifiers' 148 * is safe 149 */ 150 synchronized void addNamingListener(String nm, int scope, 151 NamingListener l) throws NamingException { 152 153 if (l instanceof ObjectChangeListener || 154 l instanceof NamespaceChangeListener) { 155 NotifierArgs args = new NotifierArgs(nm, scope, l); 156 157 NamingEventNotifier notifier = notifiers.get(args); 158 if (notifier == null) { 159 notifier = new NamingEventNotifier(this, ctx, args, l); 160 notifiers.put(args, notifier); 161 } else { 162 notifier.addNamingListener(l); 163 } 164 } 165 if (l instanceof UnsolicitedNotificationListener) { 166 // Add listener to this's list of unsolicited notifiers 167 if (unsolicited == null) { 168 unsolicited = new Vector<>(3); 169 } 170 171 unsolicited.addElement((UnsolicitedNotificationListener)l); 172 } 173 } 174 175 /** 176 * Adds <tt>l</tt> to list of listeners interested in <tt>nm</tt> 177 * and filter. 178 */ 179 synchronized void addNamingListener(String nm, String filter, 180 SearchControls ctls, NamingListener l) throws NamingException { 181 182 if (l instanceof ObjectChangeListener || 183 l instanceof NamespaceChangeListener) { 184 NotifierArgs args = new NotifierArgs(nm, filter, ctls, l); 185 186 NamingEventNotifier notifier = notifiers.get(args); 187 if (notifier == null) { 188 notifier = new NamingEventNotifier(this, ctx, args, l); 189 notifiers.put(args, notifier); 190 } else { 191 notifier.addNamingListener(l); 192 } 193 } 194 if (l instanceof UnsolicitedNotificationListener) { 195 // Add listener to this's list of unsolicited notifiers 196 if (unsolicited == null) { 197 unsolicited = new Vector<>(3); 198 } 199 unsolicited.addElement((UnsolicitedNotificationListener)l); 200 } 201 } 202 203 /** 204 * Removes <tt>l</tt> from all notifiers in this context. 205 */ 206 synchronized void removeNamingListener(NamingListener l) { 207 if (debug) System.err.println("EventSupport removing listener"); 208 209 // Go through list of notifiers, remove 'l' from each. 210 // If 'l' is notifier's only listener, remove notifier too. 211 for (NamingEventNotifier notifier : notifiers.values()) { 212 if (notifier != null) { 213 if (debug) 214 System.err.println("EventSupport removing listener from notifier"); 215 notifier.removeNamingListener(l); 216 if (!notifier.hasNamingListeners()) { 217 if (debug) 218 System.err.println("EventSupport stopping notifier"); 219 notifier.stop(); 220 notifiers.remove(notifier.info); 221 } 222 } 223 } 224 | 38 39 /** 40 * This is a utility class that can be used by a context that supports 41 * event notification. You can use an instance of this class as a member field 42 * of your context and delegate various work to it. 43 * It is currently structured so that each context should have its own 44 * EventSupport (instead of static version shared by all contexts 45 * of a service provider). 46 *<p> 47 * This class supports two types of listeners: those that register for 48 * NamingEvents, and those for UnsolicitedNotificationEvents (they can be mixed 49 * into the same listener). 50 * For NamingEvent listeners, it maintains a hashtable that maps 51 * registration requests--the key--to 52 * <em>notifiers</em>--the value. Each registration request consists of: 53 *<ul> 54 *<li>The name argument of the registration. 55 *<li>The filter (default is "(objectclass=*)"). 56 *<li>The search controls (default is null SearchControls). 57 *<li>The events that the listener is interested in. This is determined by 58 * finding out which {@code NamingListener} interface the listener supports. 59 *</ul> 60 *<p> 61 *A notifier ({@code NamingEventNotifier}) is a worker thread that is responsible 62 *for gathering information for generating events requested by its listeners. 63 *Each notifier maintains its own list of listeners; these listeners have 64 *all made the same registration request (at different times) and implements 65 *the same {@code NamingListener} interfaces. 66 *<p> 67 *For unsolicited listeners, this class maintains a vector, unsolicited. 68 *When an unsolicited listener is registered, this class adds itself 69 *to the context's LdapClient. When LdapClient receives an unsolicited 70 *notification, it notifies this EventSupport to fire an event to the 71 *the listeners. Special handling in LdapClient is done for the DISCONNECT 72 *notification. [It results in the EventSupport firing also a 73 *NamingExceptionEvent to the unsolicited listeners.] 74 *<p> 75 * 76 *When a context no longer needs this EventSupport, it should invoke 77 *cleanup() on it. 78 *<p> 79 *<h4>Registration</h4> 80 *When a registration request is made, this class attempts to find an 81 *existing notifier that's already working on the request. If one is 82 *found, the listener is added to the notifier's list. If one is not found, 83 *a new notifier is created for the listener. 84 * 85 *<h4>Deregistration</h4> 86 *When a deregistration request is made, this class attempts to find its 87 *corresponding notifier. If the notifier is found, the listener is removed 88 *from the notifier's list. If the listener is the last listener on the list, 89 *the notifier's thread is terminated and removed from this class's hashtable. 90 *Nothing happens if the notifier is not found. 91 * 92 *<h4>Event Dispatching</h4> 93 *The notifiers are responsible for gather information for generating events 94 *requested by their respective listeners. When a notifier gets sufficient 95 *information to generate an event, it creates invokes the 96 *appropriate {@code fireXXXEvent} on this class with the information and list of 97 *listeners. This causes an event and the list of listeners to be added 98 *to the <em>event queue</em>. 99 *This class maintains an event queue and a dispatching thread that dequeues 100 *events from the queue and dispatches them to the listeners. 101 * 102 *<h4>Synchronization</h4> 103 *This class is used by the main thread (LdapCtx) to add/remove listeners. 104 *It is also used asynchronously by NamingEventNotifiers threads and 105 *the context's Connection thread. It is used by the notifier threads to 106 *queue events and to update the notifiers list when the notifiers exit. 107 *It is used by the Connection thread to fire unsolicited notifications. 108 *Methods that access/update the 'unsolicited' and 'notifiers' lists are 109 *thread-safe. 110 * 111 * @author Rosanna Lee 112 */ 113 final class EventSupport { 114 final static private boolean debug = false; 115 116 private LdapCtx ctx; 121 private Hashtable<NotifierArgs, NamingEventNotifier> notifiers = 122 new Hashtable<>(11); 123 124 /** 125 * List of unsolicited notification listeners. 126 */ 127 private Vector<UnsolicitedNotificationListener> unsolicited = null; 128 129 /** 130 * Constructs EventSupport for ctx. 131 * <em>Do we need to record the name of the target context? 132 * Or can we assume that EventSupport is called on a resolved 133 * context? Do we need other add/remove-NamingListener methods? 134 * package private; 135 */ 136 EventSupport(LdapCtx ctx) { 137 this.ctx = ctx; 138 } 139 140 /** 141 * Adds {@code l} to list of listeners interested in {@code nm}. 142 */ 143 /* 144 * Make the add/removeNamingListeners synchronized to: 145 * 1. protect usage of 'unsolicited', which may be read by 146 * the Connection thread when dispatching unsolicited notification. 147 * 2. ensure that NamingEventNotifier thread's access to 'notifiers' 148 * is safe 149 */ 150 synchronized void addNamingListener(String nm, int scope, 151 NamingListener l) throws NamingException { 152 153 if (l instanceof ObjectChangeListener || 154 l instanceof NamespaceChangeListener) { 155 NotifierArgs args = new NotifierArgs(nm, scope, l); 156 157 NamingEventNotifier notifier = notifiers.get(args); 158 if (notifier == null) { 159 notifier = new NamingEventNotifier(this, ctx, args, l); 160 notifiers.put(args, notifier); 161 } else { 162 notifier.addNamingListener(l); 163 } 164 } 165 if (l instanceof UnsolicitedNotificationListener) { 166 // Add listener to this's list of unsolicited notifiers 167 if (unsolicited == null) { 168 unsolicited = new Vector<>(3); 169 } 170 171 unsolicited.addElement((UnsolicitedNotificationListener)l); 172 } 173 } 174 175 /** 176 * Adds {@code l} to list of listeners interested in {@code nm} 177 * and filter. 178 */ 179 synchronized void addNamingListener(String nm, String filter, 180 SearchControls ctls, NamingListener l) throws NamingException { 181 182 if (l instanceof ObjectChangeListener || 183 l instanceof NamespaceChangeListener) { 184 NotifierArgs args = new NotifierArgs(nm, filter, ctls, l); 185 186 NamingEventNotifier notifier = notifiers.get(args); 187 if (notifier == null) { 188 notifier = new NamingEventNotifier(this, ctx, args, l); 189 notifiers.put(args, notifier); 190 } else { 191 notifier.addNamingListener(l); 192 } 193 } 194 if (l instanceof UnsolicitedNotificationListener) { 195 // Add listener to this's list of unsolicited notifiers 196 if (unsolicited == null) { 197 unsolicited = new Vector<>(3); 198 } 199 unsolicited.addElement((UnsolicitedNotificationListener)l); 200 } 201 } 202 203 /** 204 * Removes {@code l} from all notifiers in this context. 205 */ 206 synchronized void removeNamingListener(NamingListener l) { 207 if (debug) System.err.println("EventSupport removing listener"); 208 209 // Go through list of notifiers, remove 'l' from each. 210 // If 'l' is notifier's only listener, remove notifier too. 211 for (NamingEventNotifier notifier : notifiers.values()) { 212 if (notifier != null) { 213 if (debug) 214 System.err.println("EventSupport removing listener from notifier"); 215 notifier.removeNamingListener(l); 216 if (!notifier.hasNamingListeners()) { 217 if (debug) 218 System.err.println("EventSupport stopping notifier"); 219 notifier.stop(); 220 notifiers.remove(notifier.info); 221 } 222 } 223 } 224 |