Respond to Workflow Events
Overview
This page explains how to execute custom logic when a specific publication workflow step occurs in Bloomreach Content. You will learn how to subscribe to workflow events and respond to them using a repository-managed component.
When to Use
Implement this approach when you need to trigger additional processing—such as sending notifications—whenever a workflow step, like document publication, is performed.
Workflow Events in Bloomreach Content
Documents move through a publication workflow in Bloomreach Content. When a workflow step occurs, the system posts a workflow event to the Event Bus. You can subscribe to these events and execute custom logic in response.
For a general overview of the event bus, event types, and listener mechanisms, see Event Bus.
HippoWorkflowEvent Properties
Workflow events are represented by org.onehippo.repository.events.HippoWorkflowEvent objects. These objects provide the following information:
| Property | Description |
|---|---|
subjectId | UUID of the content item involved in the event. For documents, this is the document handle. |
subjectPath | Repository path of the content item. |
interaction | The user interaction that triggered the event. A single interaction can generate multiple workflow actions (see action). Each action results in a separate event. |
action | The workflow action that triggered the event. Actions are part of an interaction. |
user | The user who initiated the interaction. |
documentType | The document type of the content item. |
success | Indicates if the interaction succeeded. |
For details, refer to org.onehippo.repository.events.HippoWorkflowEvent in the Hippo Commons API documentation.
Implementation Example
This example demonstrates how to create a repository-managed component that listens for workflow events. When a publication event occurs, the component retrieves information about the published document and logs a message in the format: "[User] published [document title]".
Note: This example uses a local, non-clustered event listener. It only responds to workflow operations on the same cluster node. In most cases, this is sufficient because each node runs its own event bus and listener. For cluster-wide listeners, see Event Bus.
Prerequisites
- Access to the
cmsmodule of your implementation project. - Familiarity with Java and the Bloomreach Content module system.
Step 1: Create a Repository-Managed Component
Add a new Java class, org.example.PublicationPostProcessingModule, in the cms module. Implement the org.onehippo.repository.modules.DaemonModule interface.
cms/src/main/java/org/example/PublicationPostProcessingModule.java
package org.example; import org.onehippo.repository.modules.DaemonModule; public class PublicationPostProcessingModule implements DaemonModule { @Override public void initialize(final Session session) throws RepositoryException { } @Override public void shutdown() { } }
This class serves as the repository-managed component. Implement the event listener logic directly in this class. The component has access to the JCR session, which is required to retrieve document information.
Step 2: Implement the Event Listener
Follow the event listener pattern described in Event Bus:
- Add a
handleEvent(final HippoWorkflowEvent event)method and annotate it with@Subscribe. - Register the listener in the
initializemethod. - Unregister the listener in the
shutdownmethod.
cms/src/main/java/org/example/PublicationPostProcessingModule.java
package org.example; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.onehippo.cms7.services.eventbus.HippoEventListenerRegistry; import org.onehippo.cms7.services.eventbus.Subscribe; import org.onehippo.repository.events.HippoWorkflowEvent; import org.onehippo.repository.modules.DaemonModule; public class PublicationPostProcessingModule implements DaemonModule { public static final String PUBLICATION_INTERACTION = "default:handle:publish"; @Override public void initialize(final Session session) throws RepositoryException { HippoEventListenerRegistry.get().register(this); } @Override public void shutdown() { HippoEventListenerRegistry.get().unregister(this); } @Subscribe public void handleEvent(final HippoWorkflowEvent event) { if (event.success() && PUBLICATION_INTERACTION.equals(event.interaction())) { // post-processing to be implemented here } } }
This listener subscribes only to workflow events by specifying HippoWorkflowEvent as the method argument. The logic checks for the relevant interaction (default:handle:publish) and verifies that the interaction succeeded. This prevents handling unsuccessful workflow operations.
Step 3: Implement Publication Post-Processing
Add logic to process publication events:
- Store the JCR session in a member variable during initialization.
- Use the session to retrieve the document handle from the event.
- Retrieve the published document variant from the handle.
- Output a message with the user and document title.
cms/src/main/java/org/example/PublicationPostProcessingModule.java
package org.example; import javax.jcr.ItemNotFoundException; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.hippoecm.repository.HippoStdNodeType; import org.hippoecm.repository.api.HippoNode; import org.hippoecm.repository.util.JcrUtils; import org.hippoecm.repository.util.NodeIterable; import org.onehippo.cms7.services.eventbus.HippoEventListenerRegistry; import org.onehippo.cms7.services.eventbus.Subscribe; import org.onehippo.repository.events.HippoWorkflowEvent; import org.onehippo.repository.modules.DaemonModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PublicationPostProcessingModule implements DaemonModule { private static final Logger log = LoggerFactory.getLogger(PublicationPostProcessingModule.class); public static final String PUBLICATION_INTERACTION = "default:handle:publish"; public static final String TITLE_PROPERTY = "myproject:title"; private Session session; @Override public void initialize(final Session session) throws RepositoryException { this.session = session; HippoEventListenerRegistry.get().register(this); } @Override public void shutdown() { HippoEventListenerRegistry.get().unregister(this); } @Subscribe public void handleEvent(final HippoWorkflowEvent event) { if (event.success() && PUBLICATION_INTERACTION.equals(event.interaction())) { postPublish(event); } } private void postPublish(final HippoWorkflowEvent workflowEvent) { String title = null; try { final HippoNode handle = (HippoNode) session.getNodeByIdentifier(workflowEvent.subjectId()); final Node published = getPublishedVariant(handle); if (published != null) { title = JcrUtils.getStringProperty(published, TITLE_PROPERTY, handle.getDisplayName()); } else { log.warn("Unable to find the published document variant."); title = handle.getDisplayName(); } } catch (ItemNotFoundException e) { log.warn("Unable to find the document handle for the published document."); } catch (RepositoryException e) { log.error("Unexpected exception during JCR read operations.", e); } System.out.println(workflowEvent.user() + " published " + title); } private static Node getPublishedVariant(Node handle) throws RepositoryException { for (Node variant : new NodeIterable(handle.getNodes(handle.getName()))) { final String state = JcrUtils.getStringProperty(variant, HippoStdNodeType.HIPPOSTD_STATE, null); if (HippoStdNodeType.PUBLISHED.equals(state)) { return variant; } } return null; } }
Step 4: Register the Repository Component
Register the repository-managed component using the Console at /hippo:configuration/hippo:modules:
/hippo:configuration/hippo:modules: /postpublication: jcr:primaryType: hipposys:module hipposys:className: org.example.PublicationPostProcessingModule
Verification
- Perform a publication workflow action in the CMS.
- Confirm that the message
[User] published [document title]appears in the output.