$URL: svn+ssh://christianc@svn.forge.objectweb.org/svnroot/barracudamvc/Barracuda2/trunk/WEB-INF/src_docs/architecture/comp/overview.html $ - $Revision: 125 $

Event Model Topology

The Event Model interfaces each play a specific role in the event delivery process. We'll describe the basic responsibilities of each entity here. You should use this in conjunction with the Events UML diagram.
  1. ApplicationGateway
  2. EventGateway
  3. EventPool
  4. BaseEvent
  5. EventBroker
  6. DispatcherFactory
  7. EventDispatcher
  8. DispatchQueue
  9. EventContext
  10. ListenerFactory
  11. BaseEventListener
  12. ApplicationAssembler

ApplicationGateway

An ApplicationGateway is a servlet that acts as the primary interface between the URL request that represents a WebEvent, and the EventBroker that dispatches the event. The gateway has three primary tasks:

  1. Define implementation specifics - By this, we mean that the Application Gateway is the class that defines which implementations we are going to use within a running instance of the event model. For example, the gateway is responsible for instantiating the EventBroker, the EventPool, and the Dispatcher Factory. This makes it easy to plug in new functionality--all the developer has to do is override the specific method that instanstantiates these objects.
  2. Provide lifecycle services for EventGateways - An Application Gateway is also responsible for causing all known event handlers to be registered/deregistered with the event broker. This actually happens when the servlet itself is init'ed or destroyed. More on EventGateways below.
  3. Convert HTTP Requests to Events and Dispatch to the system -  In short, the Application Gateway tells the servlet container (via the web.xml file) that it is capable of handling all URLs ending in a particular event extension (ie. *.event).  When a URL is received, the event broker servlet converts the URL string into the appropriate event name, which it can either instantiate directly or retrieve from the EventPool. The gateway dispatches the event through the EventBroker, and if there is an error or no one handles the event, it generates the default error response.

EventGateway

An EventGateway simply represents an interface to all known event handlers within a system. Gateways are heirarchical in nature: they may contain other EventGateways. In other words, an EventGateway knows about local event listeners plus child event gateways.  Invoking register on a gateway should cause it to register all known enties that are interested in receiving events from the EventBroker, PLUS invoke register for any child gateways it contains. Invoking deregister has the opposite effect.

Any class that has BaseEventListeners should implement EventGateway (usually by extending DefaultEventGateway). The registerLocalEventInterests() and deregisterLocalEventInterests() are the methods that should register/dergister local event listeners.

EventPool

An EventPool is a optional mechanism to offset the penalty of instantiating real event objects from a URL string. In a nutshell, it allows you to checkout events, use them, and then check them back in when you are done with them. Events that are not checked back in eventually time out, and are returned to the active pool by a background thread that runs on a period basis (configurable). By default, the ApplicationGateway is the only class that actually uses the EventPool. Custom event listeners that wish to post additional events would probably just instantiate the event objects directly (since they wouldn't need to use reflection in the first place).

BaseEvent

All events in the system extend from BaseEvent. Events are used to notify listeners that something happened.

In general, events are very lightweight and should carry as little state information as possible (although they are capable of it). It is much better to pass state information between event handlers by storing it in the event queue. An event has one basic state: handled or unhandled. It may be addressed to specific listeners, or just to any parties interested in this class of event. All events are nestable, and may contain a reference to the object which created them. In addition, these events are designed to be reusable -- they may be reset to their default state.

There are two kinds of BaseEvents: ControlEvents and ViewEvents.* Control events indicate something happened; view events indicate that not only did something happen, but a response is required (usually to generate a view). For an HTTP interface to the event model, we extend from these event classes to create an HttpRequestEvent and an HttpResponseEvent. If we ever need to interface with another type of gateway (ie. SMTP, SNMP, etc) we would create new event hierarchies at the same level.

The request event structure represents the "API" we expose to the HTTP gateway; the response event structure represents what gets sent back to the client in "response" to various requests. HTTP clients can invoke any event that extends from HttpRequestEvent.  Response events are generated by the listeners which process these requests. There are obvious parallels here to both the HTTP request-response structure AND the Model 2 Controller/View roles: request events loosely correspond with "controller" while response events represent the "views".

It should also be noted that HttpRequestEvents are Polymorphic. This means that when a polymorphic event is dispatched it's parent events should be fired first, because the event "is an instance" of the parent events. Likewise, HttpResponseEvents are Exceptional, which means that they must be handled. When an exceptional event is dispatched if it is not handled it's parent event will be added to the queue. Exceptional is essentially of the opposite of Polymorphic.

*Note: previously ControlEvents and ViewEvents were each called RequestEvents and ResponseEvents respectively. Just keep this in mind in case you encounter the older terminology.

EventBroker

The EventBroker is responsible for two tasks:

  1. keeping track of which listeners are interested in which events
  2. providing an interface to dispatch events to interested listeners

There are two ways for listeners to register with the EventBroker. They may simply register their event listener ID, so that any events addressed specifically to them (ie. from client side components) may be delivered, OR, they may express an interest in a particular type of event, in which case they will be notified anytime that event is generated (provided it is not already addressed to specific listeners).

When an event is dispatched, the EventBroker uses an EventDispatcher to actually do the dirty work. Consequently, a broker can be modified to use different dispatch policies simply by binding it to a different event dispatcher. The dispatcher being used receives the event to be dispatched, as well as a reference to the broker, which it may need to query in order to find listeners for a specific event.

DispatcherFactory

A DispatcherFactory is simply responsible for providing an instance of EventDispatcher. It should either return a new EventDispatcher for each request, or it should use a static synchronized copy to ensure threadsafety.

EventDispatcher

The EventDispatcher implements the a given event dispatching policy. The default implementation works something like this.

The dispatcher receives a queue of events, which it will faithfully attempt to deliver.  While the event interfaces themselves are not tied to any particular dispatching pattern, the DefaultEventDispatcher makes specific use of a Model 2 pattern to deliver events. The process is really a 2 phased dispatch, and looks something like this:

In terms of actually dispatching an event, when the dispatcher removes an event from the queue, it first looks to see if the event is addressed to specific listeners. If not, then it queries the event broker for a list of interested listeners. Once it has this information, it notifies all listeners until someone handles the event (it also notifies those request notifyAlways()).

If the event implements Polymorphic, all it's parent events are dispatched first since the event "is an instance" of all its parents. This gives developers the ability to install listeners on a whole hierarchy of events, which has some very powerful implications.  If the event implements Exceptional, this tells the dispatcher that the event must be handled. If it is not, it is treated like an Exception, and it's immediate parent event is added to the queue. This has some very useful implications for error handling.

Note that events may either be Polymorphic or Exceptional (or neither), but they may never implement both. Fortunately, the interfaces preclude this by intentionally defining the same method.

DispatchQueue

The DispatchQueue is a very simple interface: there are only a few methods that are exposed publically: addEvent and listEvents are the most important. This allows listeners to add events to the queue, without modifying it in any other way. The event queue is intelligent enough to collapse multiple events (just like Swing does) so that if three listeners each generate a "RedrawView" event, there will only be one instance of the event in the queue.

It should be noted that the DefaultDispatchQueue internally stores events in different locations depending on their type (ResponseEvents vs. every other kind of event). This allows the dispatcher to use a 2 Phase dispatching mechanism to dispatch non-Response events first and Response events second. The queue, however, could still be used for single phased dispatch: the application gateway would simply define the queue as not requiring a response and then it would not add any response events to the queue.

As a final note, we should point out that the dispatch queue implements the Stated interface, which makes it useful for passing state between handlers. Keep in mind however, that a new queue is created for every HTTP request, so state information will not carry over between subsequent requests.

EventContext

When the EventDispatcher notifies event listeners, it packages all the information relating to the event in an EventContext object. The context contains of the actual event thatwas fired, a reference to the event queue, as well as references to the ServletRequest, ServletResponse, and ServletConfig objects (whether or not these objects are accessible depends on the type of the event). The event context also implements StateMap, meaning it can carry state information. If you need to pass information between event handlers, this is not the preferred mechanism for doing so.

ListenerFactory

Much like the DispatcherFactory, a ListenerFactory is responsible for provide an instance of BaseEventListener. It should either provide a new instance each time, or use a static synchronized copy to ensure threadsafety.

BaseEventListener

A BaseEventListener is an interface that allows an implementor to handle all BaseEvents. Typically, a listener will express interest in an event by registering with an EventBroker. The EventBroker is responsible for delivering events to the interested parties. When the listener handles an event, it receives several pieces of information, including a reference to the event itself, as well as a handle to the EventQueue. If the listener wishes to fire additional events, this is typically done by adding them to the EventQueue.

Also notice that a listener can tell the broker what kind of delivery policy it prefers. By default, only unhandled events are delivered to listeners. However, listeners can get all applicable events (handled or not) by overriding the notifyAlways() method. This makes it possible to implement logging mechanism, etc.

Finally, we should note that an event listener must be capable of providing a listener ID. This value is used by both client components and the event broker to specify direct delivery of events to a specific listener(s).

ApplicationAssembler

With the latest Barracuda release, there is a new interface in the event package called ApplicationAssembler. This interface is invoked by the ApplicationGateway if the web.xml file contains 2 key parameters: ApplicationAssembler (the name of the assembler class) and AssemblyDescriptor (the name of the XML file to be used by the assembler). This makes it possible for you to create custom assemblers which dynamically create your Barracuda system from an XML file, rather than requiring you to extend ApplicationGateway, etc. There is currently a very basic implementation of ApplicationAssembler available in org.barracudamvc.experimental.assembler.DefaultApplicationAssembler.

NOTE: ApplicationAssembler should be considered deprecated for scripting purposes - the replacement scripting mechanism is ObjectRepositoryAssembler.

This covers all the basic roles in the current event model implementation.

 

 


$Date: 2006-01-02 15:59:13 -0500 (Mon, 02 Jan 2006) $