HST Spring ComponentManager Event Publishing
Bloomreach Content's delivery framework (HST) uses the Google Guava EventBus to enable publishing and subscribing to application events between modules and components. You can implement an event subscriber by annotating methods with Guava's @Subscribe. Event dispatching in HST is synchronous and all listeners are invoked by the same thread that publishes the event. Event dispatching is limited to a single HST web application and does not support cross-application or cluster-wide events. For those scenarios, use the Hippo Event Bus.
To subscribe to a specific application event, register your subscriber implementation with the ComponentManager using #registerEventSubscriber(). You must also unregister your subscriber using #unregisterEventSubscriber() when your application stops or when event subscription is no longer required.
HST provides two built-in event objects for HTTP session creation and destruction. Your components can subscribe to these events at any time.
Introduction
The HST ComponentManager supports application event publishing, event subscription, and event listener registration.
The org.hippoecm.hst.core.container.ComponentManager interface includes the following relevant methods:
package org.hippoecm.hst.core.container; import java.util.EventObject; public interface ComponentManager { // <SNIP> /** * Publish the given event to all components which want to listen to it. * @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> }
To publish an application event, obtain a ComponentManager instance and call publishEvent(EventObject) with a java.util.EventObject instance. To subscribe to events, register your subscriber instance using registerEventSubscriber(Object subscriber). To stop receiving events, unregister the subscriber with unregisterEventSubscriber(Object subscriber).
Internally, the HST ComponentManager wraps the Google Guava EventBus. The ComponentManager recognizes event subscribers by the presence of the Guava @Subscribe annotation. Your subscriber must implement methods annotated with @com.google.common.eventbus.Subscribe. For details on using Guava EventBus for event subscription, see Subscribing For Events.
All event objects published and subscribed to must extend java.util.EventObject. If you have your own domain event object, wrap it in a subclass of EventObject to use it with the HST ComponentManager.
Built-in HTTP Session Events and Subscription Example
HST provides two built-in event objects:
org.hippoecm.hst.container.event.HttpSessionCreatedEventorg.hippoecm.hst.container.event.HttpSessionDestroyedEvent
The HST Container publishes HttpSessionCreatedEvent when the servlet container creates an HTTP session. It publishes HttpSessionDestroyedEvent when the servlet container destroys an HTTP session.
To subscribe to these events, create a subscriber component and register it with the ComponentManager.
Note: Use
com.google.common.eventbus.Subscribefor the Guava EventBus. Do not useorg.onehippo.cms7.services.eventbus.Subscribe, which is intended for the Hippo Event Bus for cross-application or cluster-wide events.
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; /** * Example subscriber that stores HTTP session IDs in an internal list. */ 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()); } }
This subscriber uses @Subscribe annotations for both HttpSessionCreatedEvent and HttpSessionDestroyedEvent. The ComponentManager invokes the corresponding method when the event is published via ComponentManager#publishEvent(EventObject).
You must register the subscriber component to receive events. In the example, componentManager.registerEventSubscriber(this) is called in the init() method.
You must also unregister the subscriber to clean up event subscriptions. The destroy() method handles this.
The SessionIdStoringApplicationListener component should be loaded as a Spring bean through the HST ComponentManager. The following example shows a Spring bean XML definition for this component:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="example.events.SessionIdStoringApplicationListener" init-method="init" destroy-method="destroy"> <constructor-arg name="sessionIdStore"> <list /> </constructor-arg> </bean> </beans>
When the HST ComponentManager loads this bean (for example, by adding the bean definition to a file in classpath:META-INF/hst-assembly/overrides/*.xml), it calls setComponentManager(ComponentManager) on any beans that implement org.hippoecm.hst.core.container.ComponentManagerAware.
The Spring ApplicationContext managed by the ComponentManager invokes the init() and destroy() methods during the bean lifecycle, as configured in the init-method and destroy-method attributes. This allows you to register and unregister your subscriber component at the appropriate times.
You can also register and unregister your subscriber programmatically by obtaining the ComponentManager via HstServices.getComponentManager().
Summary
HST enables publishing and subscribing to application events between modules and components using the Google Guava EventBus. Implement subscriber components by annotating methods with @Subscribe and register them with the ComponentManager using registerEventSubscriber(). Unregister them with unregisterEventSubscriber() when event subscription is no longer required.
HST provides built-in event objects for HTTP session creation and destruction. You can subscribe to these events as shown in the example above.