Event Bus

Overview

The Event Bus in Bloomreach Content enables applications to listen for and respond to events that occur within the platform, such as user logins or document publications. You can use the Event Bus to trigger additional processing, such as sending notification emails when an author requests document publication.

The Event Bus supports two primary use cases:

  • Listening for events within a single JVM and cluster node (local events)
  • Responding to events across all cluster nodes by processing persisted events in the repository event log (cluster-wide events)

This page explains how to implement both local and cluster-wide event listeners. For a detailed example, see Respond to Workflow Events. For a list of available events, see Overview of Event Bus Events.

Local vs. Cluster-Wide Event Listeners

The Event Bus operates within the scope of a single JVM. A listener registered directly with the Event Bus receives only events generated within the same JVM and cluster node. This approach is suitable for most use cases. See Local Event Listener for implementation details.

To respond to events across the entire cluster, you can listen for persisted events in the repository event log. This method allows you to receive events from all cluster nodes, including those that occurred while your listener was not registered. See Cluster-Wide Event Listener for details.

The HippoEvent Class

Events posted to the Event Bus are represented by org.onehippo.cms7.event.HippoEvent objects.

Event Properties

A HippoEvent object provides several methods to access event details:

MethodDescription
actionReturns the action that triggered the event.
categoryReturns the event category.
userReturns the user who initiated the action.

For more information, refer to the Hippo Commons API javadoc for org.onehippo.cms7.event.HippoEvent.

Subclasses of HippoEvent may provide additional methods.

Event Categories

Events are grouped into five categories, defined as constants in org.onehippo.cms7.event.HippoEventConstants. Some categories use specific subclasses of HippoEvent.

Event CategoryConstantClass
WorkflowCATEGORY_WORKFLOWorg.onehippo.repository.events.HippoWorkflowEvent
SecurityCATEGORY_SECURITYorg.onehippo.cms7.event.HippoSecurityEvent
User managementCATEGORY_USER_MANAGEMENTorg.onehippo.cms7.event.HippoEvent
Group managementCATEGORY_GROUP_MANAGEMENTorg.onehippo.cms7.event.HippoEvent
Permissions managementCATEGORY_PERMISSIONS_MANAGEMENTorg.onehippo.cms7.event.HippoEvent

Local Event Listener

Implementing a Listener

To create a local event listener, implement a method with the signature public void handleEvent(HippoEvent event) and annotate it with org.onehippo.cms7.services.eventbus.Subscribe.

Example:
cms/src/main/java/org/example/MyListener.java

package org.example; import org.onehippo.cms7.event.HippoEvent; import org.onehippo.cms7.event.HippoEventConstants; import org.onehippo.cms7.services.eventbus.Subscribe; public class MyListener { @Subscribe public void handleEvent(HippoEvent event) { if (HippoEventConstants.CATEGORY_WORKFLOW.equals(event.category())) { // respond to event } } }

You can also subscribe to a specific subclass of HippoEvent, such as HippoWorkflowEvent:

@Subscribe public void handleEvent(HippoWorkflowEvent event) { // respond to event }

Registering the Listener

The Event Bus uses the whiteboard pattern for listener registration. This approach decouples the lifecycle of the listener from the event bus, so the order in which applications start does not matter.

Register the listener using HippoEventListenerRegistry.get().register(listener).

Using a Repository-Managed Component

A common approach is to use a repository-managed component (daemon module) packaged with the cms application to handle listener registration and unregistration.

Example:
cms/src/main/java/org/example/ListenerModule.java

package org.example; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.onehippo.cms7.services.eventbus.HippoEventListenerRegistry; import org.onehippo.repository.modules.DaemonModule; public class ListenerModule implements DaemonModule { private MyListener listener; @Override public void initialize(Session session) throws RepositoryException { listener = new MyListener(); HippoEventListenerRegistry.get().register(listener); } @Override public void shutdown() { HippoEventListenerRegistry.get().unregister(listener); } }

Configure the component in the repository at /hippo:configuration/hippo:modules:

/hippo:configuration/hippo:modules: /listener: jcr:primaryType: hipposys:module hipposys:className: org.example.ListenerModule

Using a Delivery Tier Component

You can also implement and register a listener in the site application, which typically runs in the same JVM as the cms application. This is useful if the listener needs access to the HST API. In this scenario, a Spring component can manage the listener registration.

Example:
site/components/src/main/java/org/example/MyComponent.java

package org.example; import org.onehippo.cms7.services.eventbus.HippoEventListenerRegistry; public class MyComponent { private MyListener listener; public void init() { listener = new MyListener(); HippoEventListenerRegistry.get().register(listener); } public void destroy() { HippoEventListenerRegistry.get().unregister(listener); } }

Spring configuration:
site/components/src/main/resources/META-INF/hst-assembly/overrides/listener.xml

<?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 id="org.example.MyComponent" class="org.example.MyComponent" init-method="init" destroy-method="destroy" /> </beans>

Cluster-Wide Event Listener

While the Event Bus itself is limited to a single cluster node, you can respond to events across the entire cluster by listening for persisted events in the repository event log. This approach allows your listener to receive all events, including those generated on other cluster nodes and those that occurred while the listener was offline.

Important:
A cluster-wide event listener will process the same event on each cluster node, which can result in duplicate actions (such as sending multiple notifications). Use a local event listener if you want to avoid duplicate responses.

Implementing a Cluster-Wide Listener

Example:
cms/src/main/java/org/example/MyPersistedEventListener.java

package org.example; import org.onehippo.cms7.event.HippoEvent; import org.onehippo.cms7.event.HippoEventConstants; import org.onehippo.repository.events.HippoWorkflowEvent; import org.onehippo.repository.events.PersistedHippoEventListener; public class MyPersistedEventListener implements PersistedHippoEventListener { @Override public String getEventCategory() { return HippoEventConstants.CATEGORY_WORKFLOW; } @Override public String getChannelName() { return "my-publication-listener"; } @Override public boolean onlyNewEvents() { return true; } @Override public void onHippoEvent(final HippoEvent event) { HippoWorkflowEvent workflowEvent = new HippoWorkflowEvent(event); // respond to event } }
  • The getChannelName() method must return a unique channel name within the container. No two listeners in the same cluster node should use the same channel name.
  • The getEventCategory() method restricts the events delivered to the listener.
  • In the onHippoEvent method, do not cast the HippoEvent directly to a HippoWorkflowEvent. Instead, create a new HippoWorkflowEvent using the constructor.

Registering the Cluster-Wide Listener

Register a cluster-wide listener using the PersistedHippoEventListenerRegistry service.

Example:
cms/src/main/java/org/example/ListenerModule.java

package org.example; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.onehippo.repository.events.PersistedHippoEventListenerRegistry; import org.onehippo.repository.modules.DaemonModule; public class ListenerModule implements DaemonModule { private MyPersistedEventListener persistedListener; @Override public void initialize(Session session) throws RepositoryException { persistedListener = new MyPersistedEventListener(); PersistedHippoEventListenerRegistry.get().register(persistedListener); } @Override public void shutdown() { PersistedHippoEventListenerRegistry.get().unregister(persistedListener); } }

Cluster-Wide Event Dispatch Configuration

When a cluster node is offline, events are delivered locally when the node comes back online.

The repository tracks the timestamp of the last processed event for each combination of repository cluster ID and persisted listener channel name. All events with a greater timestamp are dispatched to the listener, subject to certain limits to prevent excessive event processing.

You can adjust the event broadcasting mechanism using parameters in the following repository node:

/hippo:configuration/hippo:modules/broadcast/hippo:moduleconfig

Available parameters (default values in parentheses):

  • pollingTime (5000): Interval in milliseconds between polls for updates. Each poll queries for recent events.
  • queryLimit (500): Maximum number of events to retrieve and deliver per poll.
  • maxEventAge (24): Maximum age, in hours, of events to publish.
Share Feedback
Page: /build/spring-services/event-bus
Section: Build
Category *