HST Spring ComponentManager event publishing
HST provides a very generic and simple way to publish/subscribe application events between modules and components by using the Google Guava EventBus. By using @Subscribe annotation of Google Guava, you can easily implement an application event subscriber component. The internal event dispatching in the HST through the event bus is synchronous and all listeners are invokek by the same thread that publishes the event. The event dispatching is also within a single HST webapp only and thus not suited for cross web application or cluster wide events. For the latter use cases, you require the Hippo Event Bus.
If you want to subscribe a specific application event, then you have to register your subscriber implementation to the ComponentManager by invoking #registerEventSubscriber() and you are responsible for unregistering your application event subscribing component by invoking #unregisterEventSubscriber() when your application stops or no more event subscription is needed.
HST provides two built-in event objects for HTTP session creation and destruction, which can be subscribed by your component at any time if you want.
Introduction
ComponentManager of HST supports application event publishing, event subscription and event listener registration.
org.hippoecm.hst.core.container.ComponentManager support some operations for this feature:
package org.hippoecm.hst.core.container; import java.util.EventObject; public interface ComponentManager { // <SNIP> /** * Publish the given event to all components which wants to listen to. * @param event the event to publish (may be an application-specific or * built-in HST event) */ void publishEvent(EventObject event); /** * Registers event subscriber object to receive events. * @param subscriber */ void registerEventSubscriber(Object subscriber); /** * Unregisters event subscriber object. * @param subscriber */ void unregisterEventSubscriber(Object subscriber); // <SNIP> }
As described in the javadocs above, if one of your application component wants to publish an application event, then you should get a ComponentManager instance and invoke #publishEvent(EventObject) operation with a java.util.EventObject instance. And the subscribing component can subscribe the specific event by registering a subscriber instance through #registerEventSubscriber(Object subscriber) operation. You can also unregister the subscriber instance by invoking #unregisterEventSubscriber(Object subscriber).
The application events handling of HST ComponentManager actually wraps the Google Guava EventBus internally. HST ComponentManager recognizes any event subscribers with @Subscribe annotation of Google Guava EventBus. So, the event subscriber must implement methods annotated by @com.google.common.eventbus.Subscribe annotation. For more detail on how to subscribe events with Google Guava EventBus, see the "Subscribing For Events" section of the following article:
Also, note that an event object published and subscribed must be a child class of java.util.EventObject. You might want to wrap your own domain event object by java.utill.EventObject to use with HST ComponentManager.
HST provides a very generic way to publish/subscribe application events with annotations of Google Guave EventBus and simple generic event objects ( java.util.EventObject).
The Built-in HTTP Session Events and a Subscription Example
There are two built-in event objects which are provided by HST Container: org.hippoecm.hst.container.event.HttpSessionCreatedEvent and org.hippoecm.hst.container.event.HttpSessionDestroyedEvent. The first event object gets published by HST Container whenever an HTTP session instance is created by the servlet container, and the second one gets published by HST Container whenever an HTTP session instance is destroyed by the servlet container.
Therefore, if you want to subscribe those HTTP session events, then you can create a subscriber component and register the component to the ComponentManager.
Here's an example subscriber component:
package example.events; import java.util.List; import org.hippoecm.hst.container.event.HttpSessionCreatedEvent; import org.hippoecm.hst.container.event.HttpSessionDestroyedEvent; import org.hippoecm.hst.core.container.ComponentManager; import org.hippoecm.hst.core.container.ComponentManagerAware; import com.google.common.eventbus.Subscribe; /** * This example subscriber simply store the http session ids into an internal * list just for demonstration purpose. */ public class SessionIdStoringApplicationListener implements ComponentManagerAware { private List<String> sessionIdStore; private ComponentManager componentManager; public SessionIdStoringApplicationListener(List<String> sessionIdStore) { if (null == sessionIdStore) { throw new IllegalArgumentException("Set non null set."); } this.sessionIdStore = sessionIdStore; } @Override public void setComponentManager(ComponentManager componentManager) { this.componentManager = componentManager; } public void init() { componentManager.registerEventSubscriber(this); } public void destroy() { componentManager.unregisterEventSubscriber(this); } @Subscribe public void onHttpSessionCreatedEvent(HttpSessionCreatedEvent event) { sessionIdStore.add(event.getSession().getId()); } @Subscribe public void onHttpSessionDestroyedEvent(HttpSessionDestroyedEvent event) { sessionIdStore.remove(event.getSession().getId()); } }
As a Google Guava EventBus based application event subscriber, it has a @Subscribe annotation for the HttpSessionCreatedEvent event instance on #onHttpSessionCreatedEvent() and another @Subscribe annotation for the HttpSessionDestroyedEvent event instance on #onHttpSessionDestroyedEvent(). So, ComponentManager will invoke one of those method whenever HttpSessionCreated event instance or HttpSessionDestroyed event instance is published through ComponentManager#publishEvent(EventObject) method from somewhere.
However, please note that you have to register the subscriber component in order to subscribe the events. That is why the above code invokes componentManager.registerEventSubscriber(this) in its init() method.
Also, please do not forget that you should unregister the subscriber component in order to clean up the event subscribers in the ComponentManager. See the #destroy() method unregister it.
In the example above, the SessionIdStoringApplicationListener component is supposed to be loaded as a spring bean through HST ComponentManager. Here's a spring bean XML definition example for the component:
<bean class="example.events.SessionIdStoringApplicationListener" init-method="init" destroy-method="destroy" />
If the above bean is loaded by HST ComponentManager (e.g., by adding the bean definition in a file in classpath:META-INF/hst-assembly/overrides/*.xml, for instance), then HST ComponentManager will invoke #setComponentManasger(ComponentManager) on any beans which implements org.hippoecm.hst.core.container.ComponentManagerAware.
Also, the Spring ApplicationContext of the ComponentManager will invoke #init() method and #destroy() method on each lifecycle phase as configured with init-method and destroy-method attributes of the bean definition, and so you will have chances to register your subscriber component and unregister it.
If you want to register and unregister your subscriber component programmatically, then it is also possible to get the ComponentManager by invoking HstServices.getComponentManager() for instance.
Summary
HST provides a very generic and simple way to publish/subscribe application events between modules and components. By using @Subscribe annotation of Google Guava EventBus, you can easily implement an application event subscriber component.
If you want to subscribe a specific application event, then you have to register your subscriber implementation to the ComponentManager by invoking #registerEventSubscriber() and you are responsible for unregistering your application event subscribing component by invoking #unregisterEventSubscriber() when your application stops or no more event subscription is needed.
HST provides two built-in event objects for HTTP session creation and destruction, which can be subscribed by your component at any time if you want as shown above with an example.