Chapter 4. The EventBus

4.1. Introduction

In a de-coupled environment, its not always easy to let various components communicate with each other. In order to make this task slightly easier Spring Actionscript includes the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. class.

The EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. is a final class with only static methods. In Actionscript it is not possible to define an interface with static methods. In order to still provide an interface there does exist the IEventBus Describes an object that is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled manner.. This interface is implemented by the EventBusFacade Basic implementation of the <code>IEventBus</code> interface that acts as a facade for the static <code>EventBus</code> class., which re-routes all of its methods to their EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. equivalent. This way it is easier to mock up an IEventBus Describes an object that is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled manner. for unit testing purposes.

4.1.1. EventBus listening

There are a number of different ways to subscribe to events that are dispatched through the EventBus: The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way.

The first is to listen to all events that are dispatched through the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way.. This is possible through the EventBus.addListener Registers an ITypedCollectionListener listener method. This method expects an IEventBusListener Interface to be implemented by all objects that want to register themselves as listeners to all events dispatched from the event bus. as an argument. The IEventBusListener Interface to be implemented by all objects that want to register themselves as listeners to all events dispatched from the event bus. looks like this:

public interface IEventBusListener {

 function onEvent(event:Event):void;

}

Every event dispatched by the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. will be passed into the onEvent Handles an <code>Event</code> received from the event bus. method.

The second method is to only listen for events of a specific type. Use the EventBus.addEventListener Adds the given listener function as an event handler to the given event type. for this task. The addEventListener Adds the given listener function as an event handler to the given event type. method expects two arguments, the first is a string representing the event type, and the second is a Function instance which will be invoked with every event of the specified type.

Instead of a Function it is also possible to supply a proxy instead. This is what the addEventListenerProxy Adds a proxied event handler as a listener to the specified event type. method is for. Instead of a Function this expects a MethodInvoker instance. The MethodInvoker class is part of the as3-commons-reflect package.

The last option is to add a listener for events of a certain class. To get this to happen use the addEventClassListener Adds a listener function for events of a specific <code>Class</code>. or addEventClassListenerProxy Adds a proxied event handler as a listener for events of a specific <code>Class</code>. methods. The same arguments apply to these as for their addEventListener Adds the given listener function as an event handler to the given event type. and addEventListenerProxy Adds a proxied event handler as a listener to the specified event type. neighbours, except they expect a Class instance instead of a type.

All these methods naturally have a removal counterpart: removeListener Removes the given listener from the event bus., removeEventListener Removes the given listener function as an event handler from the given event type., removeEventListenerProxy Removes a proxied event handler as a listener from the specified event type., removeEventClassListener Removes a listener function for events of a specific Class. and removeEventClassListenerProxy Removes a proxied event handler as a listener for events of a specific <code>Class</code>..

To clear all types of registered eventlisteners at once simply call the removeAll() Clears the entire <code>IEventBus</code> by removing all types of listeners. method.

4.1.2. EventBus dispatching

This is the easiest part, to dispatch an event through the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. invoke either the dispatchEvent Dispatches the specified <code>Event</code> on the event bus. or dispatch methods. The former expects an Event instance while the latter expects a string that indicates a certain type of Event. This event will be created by this method and subsequently dispatched. For example:

EventBus.dispatchEvent(new MyCustomEvent("myCustomEventType"));

or

EventBus.dispatch("myCustomEventType");

4.1.3. EventBus event handling using metadata annotations

To prevent a lot of boilerplate code consisting of long lists of addEventListener* calls, Spring Actionscript includes an alternative way to define event handlers for events that are dispatched through the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way..

Instead of adding specific listeners functions through the addEventListener calls simply add a bit of metadata to the particular method:

[EventHandler]
protected function saveUserHandler(event:Event):void {
//implementation ommitted...
}

This is the most basic way of annotating a method and immediately implies certain assumptions. In this case it is assumed that the saveUser method will handle an event of the type "saveUser". Another valid method name for this handler could also be:

[EventHandler]
protected function saveUser(event:Event):void {
//implementation ommitted...
}

If, for some reason, this naming convention is not desired then add the name of the type of the specific event to the metadata:

[EventHandler(name="saveUser")]
protected function saveTheUserNow(event:Event):void {
//implementation ommitted...
}

By default, an event handler function is expected to have a single argument of type Event (or any subclass). It is however possible to let Spring Actionscript match the properties of the specified event with the arguments of the event handler. For instance, if the event passed to the saveUser event is not an ordinary event, but a subclass called SaveUserEvent with a property that is called "user" of the type "User". In this case an event handler with the following signature will work just a well:

[EventHandler]
protected function saveUser(user:User):void {
//implementation ommitted...
}

The property/argument matching is done by type, so this will fail in the case where an event has multiple properties of the same kind. If the SaveUserEvent should have two user properties, called userA or userB for example, the matching will fail. In that case it is possible to define the properties by name directly in the metadata:

[EventHandler(properties="userA,userB")]
protected function saveUser(userA:User, userB:User):void {
//implementation ommitted...
}

To annotate a handler for a certain event Class, define the fully qualified class name like this:

[EventHandler(clazz="com.classes.events.UserEvent")]
protected function saveTheUserNow(event:UserEvent):void {
//implementation ommitted...
}

To enable the processing of these kinds of annotations it is necessary to add an instance of the EventHandlerMetaDataPostProcessor <code>IObjectPostProcessor</code> implementation that adds <code>EventBus</code> event handlers based on the annotations found in the object's class. to the application context. The easiest way to do so is to add this bit of XML to the configuration:

<object id="eventhandlerProcessor" class="org.springextensions.actionscript.ioc.factory.config.EventHandlerMetaDataPostProcessor"/>

This will automatically register the processor with the application context.

Note

Do not forget to add the EventHandler metadata to the compiler arguments: -keep-as3-metadata+=EventHandler. Failing to do so will prevent the EventHandlerMetaDataPostProcessor <code>IObjectPostProcessor</code> implementation that adds <code>EventBus</code> event handlers based on the annotations found in the object's class. to do its work.

4.1.4. Routing other events through the EventBus

On the other side of the spectrum there is event dispatching and a way to avoid having to call EventBus.dispatch(someEvent) a zillion times. For this particular goal there is the [RouteEvents] metadata which can be handled by the RouteEventsMetaDataPostProcessor <code>IObjectPostProcessor</code> implementation that can re-route events from arbitrary objects through the <code>EventBus.dispatchEvent()</code> method.. Let's take a look at simple example, imagine a class that is able to dispatch a number of events:

[Event(name="eventName1",type="...")]
[Event(name="eventName2",type="...")]
[Event(name="eventName3",type="...")]
public class MyClass {
  //implementation omitted..
}

To let Spring Actionscript catch all these events, and redispatch them through the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way., all that is necessary is the addition of the [RouteEvents] metadata:

[RouteEvents]
[Event(name="eventName1",type="...")]
[Event(name="eventName2",type="...")]
[Event(name="eventName3",type="...")]
public class MyClass {
  //implementation omitted...
}

If not all events need to be re-routed then use the 'events' argument of the [RouteEvents] metadata:

[RouteEvents(events="eventName1,eventName2")]
[Event(name="eventName1",type="...")]
[Event(name="eventName2",type="...")]
[Event(name="eventName3",type="...")]
public class MyClass {
  //implementation omitted...
}

And that's all there is to it, now to enable this functionality add this object definition to the XML configuration:

<object id="routeEventsProcessor" class="org.springextensions.actionscript.ioc.factory.config.RouteEventsMetaDataPostProcessor"/>

This will automatically register the processor with the application context.

Note

Do not forget to add the RouteEvents metadata to the compiler arguments: -keep-as3-metadata+=RouteEvents. Failing to do so will prevent the RouteEventsMetaDataPostProcessor <code>IObjectPostProcessor</code> implementation that can re-route events from arbitrary objects through the <code>EventBus.dispatchEvent()</code> method. to do its work.

The combination of the [RouteEvents] and [EventHandler] enables a developer to leverage the EventBus The <code>EventBus</code> is used as a publish/subscribe event mechanism that lets objects communicate with eachother in a loosely coupled way. without directly depending on it.