|
Java example source code file (EventSupport.java)
The EventSupport.java Java example source code/* * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jndi.ldap; import java.util.Hashtable; import java.util.Vector; import java.util.EventObject; import javax.naming.*; import javax.naming.event.*; import javax.naming.directory.SearchControls; import javax.naming.ldap.UnsolicitedNotificationListener; import javax.naming.ldap.UnsolicitedNotificationEvent; import javax.naming.ldap.UnsolicitedNotification; /** * This is a utility class that can be used by a context that supports * event notification. You can use an instance of this class as a member field * of your context and delegate various work to it. * It is currently structured so that each context should have its own * EventSupport (instead of static version shared by all contexts * of a service provider). *<p> * This class supports two types of listeners: those that register for * NamingEvents, and those for UnsolicitedNotificationEvents (they can be mixed * into the same listener). * For NamingEvent listeners, it maintains a hashtable that maps * registration requests--the key--to * <em>notifiers--the value. Each registration request consists of: *<ul> *<li>The name argument of the registration. *<li>The filter (default is "(objectclass=*)"). *<li>The search controls (default is null SearchControls). *<li>The events that the listener is interested in. This is determined by * finding out which <tt>NamingListener interface the listener supports. *</ul> *<p> *A notifier (<tt>NamingEventNotifier) is a worker thread that is responsible *for gathering information for generating events requested by its listeners. *Each notifier maintains its own list of listeners; these listeners have *all made the same registration request (at different times) and implements *the same <tt>NamingListener interfaces. *<p> *For unsolicited listeners, this class maintains a vector, unsolicited. *When an unsolicited listener is registered, this class adds itself *to the context's LdapClient. When LdapClient receives an unsolicited *notification, it notifies this EventSupport to fire an event to the *the listeners. Special handling in LdapClient is done for the DISCONNECT *notification. [It results in the EventSupport firing also a *NamingExceptionEvent to the unsolicited listeners.] *<p> * *When a context no longer needs this EventSupport, it should invoke *cleanup() on it. *<p> *<h4>Registration *When a registration request is made, this class attempts to find an *existing notifier that's already working on the request. If one is *found, the listener is added to the notifier's list. If one is not found, *a new notifier is created for the listener. * *<h4>Deregistration *When a deregistration request is made, this class attemps to find its *corresponding notifier. If the notifier is found, the listener is removed *from the notifier's list. If the listener is the last listener on the list, *the notifier's thread is terminated and removed from this class's hashtable. *Nothing happens if the notifier is not found. * *<h4>Event Dispatching *The notifiers are responsible for gather information for generating events *requested by their respective listeners. When a notifier gets sufficient *information to generate an event, it creates invokes the *appropriate <tt>fireXXXEvent on this class with the information and list of *listeners. This causes an event and the list of listeners to be added *to the <em>event queue. *This class maintains an event queue and a dispatching thread that dequeues *events from the queue and dispatches them to the listeners. * *<h4>Synchronization *This class is used by the main thread (LdapCtx) to add/remove listeners. *It is also used asynchronously by NamingEventNotifiers threads and *the context's Connection thread. It is used by the notifier threads to *queue events and to update the notifiers list when the notifiers exit. *It is used by the Connection thread to fire unsolicited notifications. *Methods that access/update the 'unsolicited' and 'notifiers' lists are *thread-safe. * * @author Rosanna Lee */ final class EventSupport { final static private boolean debug = false; private LdapCtx ctx; /** * NamingEventNotifiers; hashed by search arguments; */ private Hashtable<NotifierArgs, NamingEventNotifier> notifiers = new Hashtable<>(11); /** * List of unsolicited notification listeners. */ private Vector<UnsolicitedNotificationListener> unsolicited = null; /** * Constructs EventSupport for ctx. * <em>Do we need to record the name of the target context? * Or can we assume that EventSupport is called on a resolved * context? Do we need other add/remove-NamingListener methods? * package private; */ EventSupport(LdapCtx ctx) { this.ctx = ctx; } /** * Adds <tt>l to list of listeners interested in nm. */ /* * Make the add/removeNamingListeners synchronized to: * 1. protect usage of 'unsolicited', which may be read by * the Connection thread when dispatching unsolicited notification. * 2. ensure that NamingEventNotifier thread's access to 'notifiers' * is safe */ synchronized void addNamingListener(String nm, int scope, NamingListener l) throws NamingException { if (l instanceof ObjectChangeListener || l instanceof NamespaceChangeListener) { NotifierArgs args = new NotifierArgs(nm, scope, l); NamingEventNotifier notifier = notifiers.get(args); if (notifier == null) { notifier = new NamingEventNotifier(this, ctx, args, l); notifiers.put(args, notifier); } else { notifier.addNamingListener(l); } } if (l instanceof UnsolicitedNotificationListener) { // Add listener to this's list of unsolicited notifiers if (unsolicited == null) { unsolicited = new Vector<>(3); } unsolicited.addElement((UnsolicitedNotificationListener)l); } } /** * Adds <tt>l to list of listeners interested in nm * and filter. */ synchronized void addNamingListener(String nm, String filter, SearchControls ctls, NamingListener l) throws NamingException { if (l instanceof ObjectChangeListener || l instanceof NamespaceChangeListener) { NotifierArgs args = new NotifierArgs(nm, filter, ctls, l); NamingEventNotifier notifier = notifiers.get(args); if (notifier == null) { notifier = new NamingEventNotifier(this, ctx, args, l); notifiers.put(args, notifier); } else { notifier.addNamingListener(l); } } if (l instanceof UnsolicitedNotificationListener) { // Add listener to this's list of unsolicited notifiers if (unsolicited == null) { unsolicited = new Vector<>(3); } unsolicited.addElement((UnsolicitedNotificationListener)l); } } /** * Removes <tt>l from all notifiers in this context. */ synchronized void removeNamingListener(NamingListener l) { if (debug) System.err.println("EventSupport removing listener"); // Go through list of notifiers, remove 'l' from each. // If 'l' is notifier's only listener, remove notifier too. for (NamingEventNotifier notifier : notifiers.values()) { if (notifier != null) { if (debug) System.err.println("EventSupport removing listener from notifier"); notifier.removeNamingListener(l); if (!notifier.hasNamingListeners()) { if (debug) System.err.println("EventSupport stopping notifier"); notifier.stop(); notifiers.remove(notifier.info); } } } // Remove from list of unsolicited notifier if (debug) System.err.println("EventSupport removing unsolicited: " + unsolicited); if (unsolicited != null) { unsolicited.removeElement(l); } } synchronized boolean hasUnsolicited() { return (unsolicited != null && unsolicited.size() > 0); } /** * package private; * Called by NamingEventNotifier to remove itself when it encounters * a NamingException. */ synchronized void removeDeadNotifier(NotifierArgs info) { if (debug) { System.err.println("EventSupport.removeDeadNotifier: " + info.name); } notifiers.remove(info); } /** * Fire an event to unsolicited listeners. * package private; * Called by LdapCtx when its clnt receives an unsolicited notification. */ synchronized void fireUnsolicited(Object obj) { if (debug) { System.err.println("EventSupport.fireUnsolicited: " + obj + " " + unsolicited); } if (unsolicited == null || unsolicited.size() == 0) { // This shouldn't really happen, but might in case // there is a timing problem that removes a listener // before a fired event event reaches here. return; } if (obj instanceof UnsolicitedNotification) { // Fire UnsolicitedNotification to unsolicited listeners UnsolicitedNotificationEvent evt = new UnsolicitedNotificationEvent(ctx, (UnsolicitedNotification)obj); queueEvent(evt, unsolicited); } else if (obj instanceof NamingException) { // Fire NamingExceptionEvent to unsolicited listeners. NamingExceptionEvent evt = new NamingExceptionEvent(ctx, (NamingException)obj); queueEvent(evt, unsolicited); // When an exception occurs, the unsolicited listeners // are automatically deregistered. // When LdapClient.processUnsolicited() fires a NamingException, // it will update its listener list so we don't have to. // Likewise for LdapCtx. unsolicited = null; } } /** * Stops notifier threads that are collecting event data and * stops the event queue from dispatching events. * Package private; used by LdapCtx. */ synchronized void cleanup() { if (debug) System.err.println("EventSupport clean up"); if (notifiers != null) { for (NamingEventNotifier notifier : notifiers.values()) { notifier.stop(); } notifiers = null; } if (eventQueue != null) { eventQueue.stop(); eventQueue = null; } // %%% Should we fire NamingExceptionEvents to unsolicited listeners? } /* * The queue of events to be delivered. */ private EventQueue eventQueue; /** * Add the event and vector of listeners to the queue to be delivered. * An event dispatcher thread dequeues events from the queue and dispatches * them to the registered listeners. * Package private; used by NamingEventNotifier to fire events */ synchronized void queueEvent(EventObject event, Vector<? extends NamingListener> vector) { if (eventQueue == null) eventQueue = new EventQueue(); /* * Copy the vector in order to freeze the state of the set * of EventListeners the event should be delivered to prior * to delivery. This ensures that any changes made to the * Vector from a target listener's method during the delivery * of this event will not take effect until after the event is * delivered. */ @SuppressWarnings("unchecked") // clone() Vector<NamingListener> v = (Vector<NamingListener>)vector.clone(); eventQueue.enqueue(event, v); } // No finalize() needed because EventSupport is always owned by // an LdapCtx. LdapCtx's finalize() and close() always call cleanup() so // there is no need for EventSupport to have a finalize(). } Other Java examples (source code examples)Here is a short list of links related to this Java EventSupport.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.