Workflow Events - BloomReach Experience - Open Source CMS

This article covers a Hippo CMS version 10. There's an updated version available that covers our most recent release.

12-05-2015

Workflow Events

There are many cases where you want additional steps to be taken whenever a certain action occurs to a document. For instance whenever a document gets published you may want an e-mail to be sent. But for this you should not have to re-implement the existing workflow. The ideal for these types of 'orthogonal concerns' is to keep the existing workflow unchanged and just 'tag along' and also execute another action. One way to achieve this is to create a repository component that subscribes to events posted on the hippo event bus. The event handler inspects the event to determine if it is of the relevant type and invokes the appropriate post-action.

Example

package org.onehippo.repository.example;

import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.hippoecm.repository.api.HippoNode;
import org.hippoecm.repository.util.NodeIterable;
import org.onehippo.cms7.services.HippoServiceRegistry;
import org.onehippo.cms7.services.eventbus.HippoEventBus;
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;

import static org.hippoecm.repository.HippoStdNodeType.HIPPOSTD_STATE;
import static org.hippoecm.repository.HippoStdNodeType.PUBLISHED;
import static org.hippoecm.repository.util.JcrUtils.getStringProperty;


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 = "gettingstarted:title";

    private Session session;

    @Override
    public void initialize(final Session session) throws RepositoryException {
        this.session = session;
        HippoServiceRegistry.registerService(this, HippoEventBus.class);
    }

    @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 = getStringProperty(published, TITLE_PROPERTY, handle.getLocalizedName());
            } else {
                log.warn("Something's wrong because I can't find the document variant that was just published");
                title = handle.getLocalizedName();
            }
        } catch (ItemNotFoundException e) {
            log.warn("Something's wrong because I can't find the handle of the document that was just published");
        } catch (RepositoryException e) {
            log.error("Something's very wrong: unexpected exception while doing simple 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 = getStringProperty(variant, HIPPOSTD_STATE, null);
            if (PUBLISHED.equals(state)) {
                return variant;
            }
        }
        return null;
    }

    @Override
    public void shutdown() {
        HippoServiceRegistry.unregisterService(this, HippoEventBus.class);
    }

}

Notice that we only subscribed to HippoWorkflowEvents, not to HippoEvents in general. This was done simply by using the HippoWorkflowEvent class as an argument to the subscribed method. The workflow manager posts HippoWorkflowEvents to the event bus whenever a workflow operation occurred.

Notice also that it is necessary to check whether the operation succeeded, because an event will also be raised for unsuccessful workflow operations.

Finally notice that the subject of the workflow actions we are interested in is a hippo:handle node. The DocumentWorkflow that was introduced in CMS 7.9 no longer operates on the document variant but on the handle, hence we could retrieve the handle of the document that was published by using the subjectId field of the workflow event, and needed to iterate through its children to find the published document variant.

In order for the repository to initialize our component, we must register it at  /hippo:configuration/hippo:modules:

<?xml version="1.0" encoding="UTF-8"?>
<sv:node sv:name="postpublication" xmlns:sv="http://www.jcp.org/jcr/sv/1.0">
  <sv:property sv:name="jcr:primaryType" sv:type="Name">
    <sv:value>hipposys:module</sv:value>
  </sv:property>
  <sv:property sv:name="hipposys:className" sv:type="String">
    <sv:value>org.onehippo.repository.example.PublicationPostProcessingModule</sv:value>
  </sv:property>
</sv:node>

HippoWorkflowEvent Properties

A HippoWorkflowEvent object provides some useful information about itself through the following methods:

subjectId The UUID of the content item that is the subject of the event. In case of a document, the subject is the handle of the document.
subjectPath The repository path at which the content item that is the subject of the event is stored.
interaction

The user interaction that caused the event. A single interaction can cause multiple workflow actions (see action). Each action will cause an event, hence there can be multiple events for the same interaction.

action The workflow action that caused the event. An action is part of an interaction (see interaction).
user The user that initiated the interaction.
documentType The document type of the subject of the interaction.
success Whether the interaction was successful.

For more information see org.onehippo.repository.events.HippoWorkflowEvent the API documentation and the Hippo Event Log documentation.

Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?