Page 3 of 4
Initially, the private variable wizardListener of class Wizard is null. So when a call is made to WizardEventMulticaster.add(WizardListener, WizardListener), the first argument, wizardListener, is null and the second is not (it does not make sense to add a null listener). The add method, in turn, calls addInternal. Since one of the arguments is null, the return of addInternal is the non-null listener. The return propagates to the add method that returns the non-null listener to the addWizardListener method. There the wizardListener variable is set to the new listener being added.
This is exactly what we expected: If there are no listeners and a new listener is added, assign it to the wizardListener variable. Note that at this point, wizardListener holds a reference to a WizardListener object that is not a multicaster (it is not necessary to use a multicaster if only one listener is registered).
When a second call is made to the addWizardListener method, both arguments passed to WizardEventMulticaster.add are not null. In order to hold two listeners, we need a multicaster, so an instance of WizardEventMulticaster is returned by the addInternal method and therefore by WizardEventMulticaster.add. The new multicaster object is assigned to the wizardListener variable, which now holds a chain of two listeners.
When a third listener is added, the procedure is the same as for adding the second listener.
At this point, if the NEXT button is pressed on the wizard panel, it is enough to invoke the nextSelected method on a WizardListener object represented by a wizardListener variable to send a WizardEvent to all listeners in the chain (see sample code above).
The removal of listeners is achieved by searching the listener chain in a recursive fashion: Event-specific remove calls removeInternal and that may call the protected remove method.
I think developing custom event types in JDK 1.1 is a non-trivial process. It requires a lot of (mostly) simple coding. The interaction between different events and event support classes is often intricate and difficult to follow (although, I must say, quite ingenuous).
The good news is that you do not have to create a new multicaster for every new event type developed. Since one multicaster can extend several listener interfaces, it is enough just to add listener and event-specific methods to an existing multicaster to make it handle more event types.
Please remember that we have not talked about support for event queuing on the system queue, nor have we mentioned event enabling.
In the case of the Wizard class, such event queuing and enabling support would involve the addition of processEvent and processWizardEvent. Both of these deal with events delivered to a component from the queue. Event masks also need to be investigated and assigned
with caution to avoid potential conflicts with events that are already part of AWT.
Finally, the way in which events are dispatched would need to be changed: Currently, a call is made to listeners right where
the triggering action occurs (for example, from the actionPerformed method for the NEXT button). It appears that components in AWT first post an event to the queue. The event is then received
by a processEvent method of the source component, which in turn calls the event-specific processor (in our case that would be processWizardEvent), which calls the appropriate listener method, thus triggering event delivery.