![]() ![]() ![]() ![]() |
Event Notification |
To receive event notifications, a listener registers with an event source. In the JNDI, the event sources implement either the EventContextor EventDirContext
interface. To get an event source, you must lookup it up from the naming/directory service. That is, you perform a lookup()
on an object and then cast the result to an EventContext or EventDirContext. It is optional whether a context supports either of these interfaces. If a context supports neither interfaces, it does not support event notification.
Here is an example that looks up a name from the initial context and casts it to an EventDirContext:
// Get event DirContext for registering listener EventDirContext ctx = (EventDirContext) (new InitialDirContext(env).lookup("ou=People"));EventContext is intended for applications that can name the object of interest. You register a listener to receive notifications by using the EventContext.addNamingListener()
method.
Here is an example that registers a NamespaceChangeListener
with a context:
When you run this example, it will wait for one minute so that the main program (the listener) can receive notifications about the changes that a worker thread has made.// Get event context for registering listener EventContext ctx = (EventContext) (new InitialContext(env).lookup("ou=People")); // Create listener NamingListener listener = new SampleNCListener("nc1"); // Register listener for namespace change events ctx.addNamingListener("ou=Objects,cn=Rosanna Lee", EventContext.ONELEVEL_SCOPE, listener);Target and Scope
The object named by the name parameter to addNamingListener() is called the target. The second parameter specifies the scope, which identifies whether the listener is to receive notifications on:Here is an example that add listeners using the same target but three different scopes:
- Only the target, ( OBJECT_SCOPE
).
- The immediate children of the target (which must be a context) ( ONELEVEL_SCOPE
), or
- The target and all of its descendants ( SUBTREE_SCOPE
).
After registering the listeners, this program creates a thread that makes namespace changes to the LDAP server. It makes changes to the target, the children of the target, and the grandchildren of the target. The listener registered for object scope will receive the two notifications for changes applied to the target. The listener registered for one-level scope won't receives notifications for these two changes, but instead, receives notifications for the changes applied to the children. The listener registered for subtree scope will get notifications for all of the changes.// Get event context for registering listener EventContext ctx = (EventContext) (new InitialContext(env).lookup("ou=People")); String target = ...; // Create listeners NamingListener oneListener = new SampleListener("ONELEVEL"); NamingListener objListener = new SampleListener("OBJECT"); NamingListener subListener = new SampleListener("SUBTREE"); // Register listeners using different scopes ctx.addNamingListener(target, EventContext.ONELEVEL_SCOPE, oneListener); ctx.addNamingListener(target, EventContext.OBJECT_SCOPE, objListener); ctx.addNamingListener(target, entContext.SUBTREE_SCOPE, subListener);Registration Errors
The addNamingListener() can throw a NamingExceptionwhen it encounters an error while registering the listener. However, there is no guarantee that the data supplied will be verified immediately at registration time. For example, some verification might require possibly open-ended server interaction. When an error occurs in such a scenario, the service provider will invoke the listener's namingExceptionThrown()
method to notify it of the problem. Therefore, the application must be prepared to handle the error regardless of whether it occurs at registration time or asynchronously in the listener's code.
Nonexistent Targets
Some service providers/services might allow registration for nonexistent targets. That is, in the above example, the entry named by target might not need to exist at the time addNamingListener() is called. To check whether this feature is supported, you use targetMustExist()
. Here is an example:
This example does not want to register an ObjectChangeListener for a nonexistent object. Therefore, it first checks whether the context requires the object to exists. If the context does not require the object to exist, the program performs a lookup()). The example also uses a listener that implements NamespaceChangeListener so that it can detect when the object has disappeared, at which point the listener notifies the user and unregisters itself.// Get event context for registering listener EventContext ctx = (EventContext)new InitialContext(env).lookup(""); // Create listener NamingListener listener = new MyListener(); String target = ...; // Check whether object exists so that we don't wait // forever for nonexistent object if (!ctx.targetMustExist()) { // Check that object exists before continuing // If lookup fails, exception will be thrown and we'd skip registration ctx.lookup(target); } // Register listener ctx.addNamingListener(target, EventContext.ONELEVEL_SCOPE, listener);public void objectRemoved(NamingEvent evt) { System.out.println(">>> removed: " + evt.getOldBinding().getName()); deregisterSelf(evt.getEventContext()); } private void deregisterSelf(EventContext ctx) { System.out.println("Deregistering listener..."); synchronized (ctx) { try { ctx.removeNamingListener(this); } catch (NamingException e) { System.out.println("Listener removal problem: " + e); } } }Using Search Filters
If you want to be more selective about the objects for which you register interest, you can use a search filter. The EventDirContext interface contains addNamingListener() methods that accept a search filter, in the same way that some of the search methods in the DirContextinterface do. Here is an example that registers interest only in objects that have the object class "javaobject".
The filter applies to existing objects and those that come into existence after the registration.// Get event DirContext for registering listener EventDirContext ctx = (EventDirContext) (new InitialDirContext(env).lookup("ou=People")); // Create listener NamingListener listener = new SampleNCListener("nc1"); // Set up search constraints SearchControls constraints = new SearchControls(); constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); // Register listener for namespace change events for // entries identified using a search filter. // In this example, register interest in namespace changes to // objects that have the objectclass "javaobject". ctx.addNamingListener("cn=Rosanna Lee", "(objectclass=javaobject)", constraints, listener);Deregistration
There are three ways in which a registered listener becomes unregistered:There is an example of explicit deregistration in the nonexistent target example shown earlier.
- When Context.close()
is invoked on the event source, any registered listeners are automatically deregistered.
- When a listener receives an error notification via the namingExceptionThrown() method, it is automatically deregistered.
- When a listener is explicitly removed via a call to EventContext.removeNamingListener()
, it is deregistered.
![]() ![]() ![]() ![]() |
Event Notification |