Event Listener & Event Source Components
To define a JavaBean event listener, you must implement the java.util.EventListener
interface along with the event interfaces in which it is interested. Event source components deliver events by calling the methods defined by the event interface on each event listener component.
Using the Event Distributor from an event listener is simple. Make the following enhancements to your event listener code to receive remote Java events:
- Import the com.DistributedEvents package.
- Extend the EventListenerDist base class.
These modifications are minor, and they don't expose any implementation details about how the events will be received remotely.
Once you've instantiated the listener object, the Event Distributor automatically calls the EventListenerDist constructor. This constructor gets a reference to the Event Distributor singleton object and calls a method that notifies it about the new listener. The Event Distributor then uses Java reflection to get the name of each interface the listener object implements.
Listing 4 shows how to use reflection to get the names of an object's implemented interfaces.
Listing 4. Discovering an Object's Interfaces|
Java reflection allows you to discover at runtime which interfaces are implemented on an object. The following code illustrates how easy it is to do this:
public void onNewListener(EventListenerDist listener)
Class listenerClass = listener.getClass();
Class interfaces = listenerClass.getInterfaces();
String interfaceNames =
for ( int n = 0; n < interfaces.length; n++ )
interfaceNames[n] = interfaces[n].getName();
For each interface the listener implements, the Event Distributor creates a JMS Topic and Subscriber object if it doesn't already exist. It then adds the listener object to a Vector
of listeners for each interface. The Event Distributor stores this Vector
in a HashMap
where the key is the interface name itself (see Figure 3
|Figure 3: Storing References to Event Listeners|
The Event Distributor creates only one JMS Topic and Subscriber object for an interface regardless of how many listeners implement that interface. The Event Distributor multicasts each message it receives to all the listeners it has for that event interface (see Figure 4).
Event Source Components
The implementation of a listener registration method defines a JavaBean event source. This method accepts references to objects that implement a particular event interface.
Make the following enhancements to your event source code to send remote events:
- Import the com.DistributedEvents package.
- Extend the EventSourceDist base class.
- Define a method named getInterfaceNames that returns a String array. The array should contain the name of each interface for which the event source produces events.
- Define a method named addListener, which allows listener objects to register for the events the source component produces. Regardless of whether you use the Event Distributor, your event source components need to define a similar method.
These modifications are similar to those outlined for listener components, with the addition of two methods. Still, no implementation details about sending the events remotely via JMS are exposed.
Again, once you've instantiated the listener object, the Event Distributor automatically calls the EventListenerDist constructor. This constructor gets a reference to the Event Distributor singleton object and calls a method that notifies it about the new listener. The Event Distributor then uses Java reflection to get the name of each interface the listener object implements.
Using Java reflection, the Event Distributor dynamically examines each interface and creates a proxy event listener object (I'll describe this later). For each event interface, the Event Distributor also does the following:
- Provides the appropriate proxy listener object to the event source component that is to receive events
- Creates a JMS Topic and Producer for the interface
At the end of this process, the Event Distributor registers with the event source as a listener for each event interface, and all the JMS plumbing is in place to remotely distribute the events (see Figure 5).
|Figure 5: Creating a Proxy Listener for Each Source|
As a result, when an event source component produces an event, one of the listeners it will call is the proxy object that the Event Distributor created. All of the details of the event - the method name, parameters, and parameter types - are wrapped in a serializable object and sent out over JMS (see Figure 6). I describe the details of how this is done further in the section titled "Using Java Reflection."
The Event Distributor reads a configuration file when it is instantiated. This file contains all of the details needed to connect to a JMS provider, allowing you to specify the vendor-specific details for the JMS provider you use.