This is the fifth entry in the JSF 2.0 New Feature Preview Series. The last entry wrapped up the new application resource handling. We'll now switch focus to the new publish/subscribe event system.
Several component and application level APIs have been added to enable a robust event system for component and application developers to take advantage of. Please note that this blog is based on EDR1 and as such the signatures of the APIs will change. When this is the case, I'll try to remember to update the blog accordingly.
Let's start with the changes to javax.faces.component.UIComponent.
public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass, ComponentSystemEventListener componentListener) public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass, ComponentSystemEventListener listener) public List<SystemEventListener> getListenersForEventClass(Class<? extends SystemEvent> systemEventClass)
The signatures are fairly straight forward. The API allows a developer to, on this single component instance, associate/disassocaite a ComponentSystemEventListener with some event type extending SystemEvent. The method, getListenersForEventClass() is leveraged by the Application implementation when an event is published.
The other class central to the event system is javax.faces.application.Application. The following methods have been added:
public void subscribeToEvent(Class<? extends SystemEvent> systemEventClass,
public void publishEvent(Class<? extends SystemEvent> systemEventClass,
public void unsubscribeFromEvent(Class<? extends SystemEvent> systemEventClass,
The subscripbe/unsubscribe methods are similar to those define on UIComponent, however, these are application-wide instead of per-component. It should be noted that an optional sourceClass can be provided so that the listener will only be invoked when the source of the event is of the configured type. I should note, that there is a two argument version of the subscribe and publish methods on Application that do not have sourceClass in their signature. These merely call through to the three argument version passing null as the sourceClass.
Now, publishEvent is where all the work happens. As currently spec'd, publishEvent will look for any listeners defined within the provided SystemEventListenerHolder (UIComponent implements this interface, hence the description of the methods on UIComponent) interested in the provided SystemEvent type. Following that, publishEvent will invoke any listeners interested in both the provided SystemEvent and source type. Lastly, publishEvent will invoke any listeners interested in received the specified SystemEvent type regardless of the source.
The spec includes several new events:
- AfterAddToParentEvent. This event will be published under the following circumstances:
- When UIComponent.getChildren().add(childToAdd) is called (*)
- When UIComponent.getFacets().put(facetName, facetChildToAdd) is called (*)
- After the the view has been built
- BeforeRenderEvent. This event will be published when UIComponent.encodeBegin() is called.
- ViewMapCreatedEvent. This event will be published when UIViewRoot.getViewMap() or UIViewRoot.getViewMap(true) has been called (this is the basis for the new view scope).
- ViewMapDestroyedEvent. This event will be published by the default NavigationHandler when the view is being transitioned to a new view (i.e. the view IDs are not equal) and the view map has been used by the application
More events may be added by the time the JSF 2.0 specification is completed.
As you can see, the new event system is quite flexible and extensible enough to be adapted for many uses. For example, the jsf-guessNumber2.0 demo application (to be included with the Mojarra 2.0.0 EDR1 release some time this week) leverages the BeforeRenderEvent to perform a hybrid of client/server-side validation. Having this system in place also allows for another new feature which I will be discussing in the next entry, resource relocation. I won't give too many details here, but resource relocation is the facility that allows stylesheets or scripts to be rendered in one of several locations independent of where actual tag was placed within the view definition.
(*) - This event will not be published when restoring the view from a post-back.