| Event Notification

## Event Listeners

> A listener in the JNDI is represented by the `NamingListener` interface. This is the root interface for objects that handles events generated by the JNDI. Typically, an object implements a subinterface of `NamingListener` rather than directly implementing `NamingListener`.

> The `javax.naming.event` package contains two subinterfaces of `NamingListener`: `ObjectChangeListener` and `NamespaceChangeListener`. The `javax.naming.ldap` package contains one subinterface: `UnsolicitedNotificationListener`. This subinterface is discussed in the LDAP Unsolicited Notifications section.

> #### Handling Errors

> The `NamingListener` interface not only serves as the root interface but also specifies how a registered listener is to be notified of errors. It defines a single method: `namingExceptionThrown()`. This method is invoked by the service provider when an error occurs while the provider is collecting data for generating events that the listener is seeking. For example, the server might have gone offline or cannot collect any more data in that part of the directory. When that occurs, the service provider deregisters the listener and invokes `namingExceptionThrown()` on the listener to notify it of the problem. This allows the listener to take action, such as notifying the application's user that the lack of events is due to a problem rather than the nonoccurrence of events.

> See the Listener Registration section for details on how to handle errors when registering listeners.

> #### Handling Namespace Changes

> `NamespaceChangeListener` handles events that affect the namespace, including the addition, removal, and renaming of an object. An object that implements this interface must provide definitions for the three methods declared in the interface, as well as for `namingExceptionThrown()` (from the `NamingListener` interface).

> Here is an example of a `NamespaceChangeListener`.

> >     public class SampleNCListener implements NamespaceChangeListener {
> >         private String id;

> >         public SampleNCListener(String id) {
> >     	this.id = id;
> >         }

> >         public void objectAdded(NamingEvent evt) {
> >     	System.out.println(id + ">>> added: " + evt.getNewBinding());
> >         }
> >         public void objectRemoved(NamingEvent evt) {
> >     	System.out.println(id + ">>> removed: " + evt.getOldBinding());
> >         }

> >         public void objectRenamed(NamingEvent evt) {
> >     	System.out.println(id + ">>> renamed: " + evt.getNewBinding() + " from " +
> >     	    evt.getOldBinding());
> >         }

> >         public void namingExceptionThrown(NamingExceptionEvent evt) {
> >     	System.out.println(id + ">>> SampleNCListener got an exception");
> >     	evt.getException().printStackTrace();
> >         }
> >     }

> When an object has been added, `getOldBinding()` will always return `null` because it wasn't in the namespace prior to its being added. When an object has been removed, `getNewBinding()` will always be `null` because it won't be in the namespace after it has been removed. More details about the old and new bindings are in the Naming Event section.

> #### Handling Object Changes

> `ObjectChangeListener` handles events that affect an object's contents, for example, if an object's binding has been replaced with another or one of an object's attributes has been removed or replaced.

> An object that implements the `ObjectChangeListener` interface must provide definitions for `objectChanged()` as well as for `namingExceptionThrown()` (from the `NamingListener` interface).

> Here is an example of an `ObjectChangeListener`.

> >     public class SampleOCListener implements ObjectChangeListener {
> >         private String id;

> >         public SampleOCListener(String id) {
> >     	this.id = id;
> >         }

> >         public void objectChanged(NamingEvent evt) {
> >     	System.out.println(id + ">>> object changed: " + evt.getNewBinding() +
> >     	    " from " + evt.getOldBinding());
> >         }

> >         public void namingExceptionThrown(NamingExceptionEvent evt) {
> >     	System.out.println(id + ">>> SampleOCListener got an exception");
> >     	evt.getException().printStackTrace();
> >         }
> >     }

> Even though this example displays both the old and new bindings for an object that has changed, some or all of that information might not be available if it is not supplied by the service provider or naming/directory server. More details about the old and new bindings are given in the Naming Event section.

> Note that removing an object is a namespace change not an object content change. An application interested in both should use a listener that implements both `NamespaceChangeListener` and `ObjectChangeListener`, as described next.

> #### Handling More Than One Type of Changes

> If you are interested in both namespace changes and object content changes, then you should define one listener that implements both interfaces. In that way, the service provider might be able to optimize the resources used for the registration by collecting data about both types of change with one request to the server. It can also reduce the number of listeners the provider must manage as well as your application's code size.

> Here is an example of a listener that implements both `NamespaceChangeListener` and `ObjectChangeListener`.

> >     public class SampleListener
> >     implements NamespaceChangeListener, ObjectChangeListener {
> >         private String id;

> >         public SampleListener(String id) {
> >     	this.id = id;
> >         }

> >         public void objectAdded(NamingEvent evt) {
> >     	System.out.println(id + ">>> added: " + evt.getNewBinding());
> >         }
> >         public void objectRemoved(NamingEvent evt) {
> >     	System.out.println(id + ">>> removed: " + evt.getOldBinding());
> >         }

> >         public void objectRenamed(NamingEvent evt) {
> >     	System.out.println(id + ">>> renamed: " + evt.getNewBinding() + " from " +
> >     	    evt.getOldBinding());
> >         }

> >         public void objectChanged(NamingEvent evt) {
> >     	System.out.println(id + ">>> object changed: " + evt.getNewBinding() +
> >     	    " from " + evt.getOldBinding());
> >         }

> >         public void namingExceptionThrown(NamingExceptionEvent evt) {
> >     	System.out.println(id + ">>> SampleNCListener got an exception");
> >     	evt.getException().printStackTrace();
> >         }
> >     }

| Event Notification