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:

PropertyDescription
subjectIdUUID of the content item involved in the event. For documents, this is the document handle.
subjectPathRepository path of the content item.
interactionThe user interaction that triggered the event. A single interaction can generate multiple workflow actions (see action). Each action results in a separate event.
actionThe workflow action that triggered the event. Actions are part of an interaction.
userThe user who initiated the interaction.
documentTypeThe document type of the content item.
successIndicates 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 cms module 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 initialize method.
  • Unregister the listener in the shutdown method.

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.
Share Feedback
Page: /build/workflows/workflow-events
Section: Build
Category *