How to implement a custom workflow?
Basic custom workflow
A custom workflow consists of at least:
- An interface that extends org.hippoecm.repository.api.Workflow.
- An implementation of that interface, possibly extending org.hippoecm.repository.ext.WorkflowImpl.
- An entry in one or more workflow categories. Normally as a YAML file. Here you configure in which situations your workflow is allowed within the context of that category. This is based on the node type of the node to perform workflow on and the role of the user wanting to do that.
- CND file to define the extra properties for the documents, along with its YAML namespace definition.
GUI plugin
To be able to invoke the workflow from the CMS user interface, it's necessary to create a menu plugin. We'll assume that a suitable plugin has been created under the name FeaturedWorkflowPlugin.
Example custom workflow
A custom workflow module consists of the following files, which will be described below:
. |____pom.xml |____src | |____main | | |____java | | | |____com | | | | |____mycompany | | | | | |____FeaturedWorkflow.java | | | | | |____FeaturedWorkflowImpl.java | | |____resources | | | |____hcm-config | | | | |____categories.yaml | | | | |____configuration.yaml | | | | |____featured.cnd | | | | |____namespace.yaml | | | |____hcm-module.yaml
Custom workflow interface
src/main/java/com/mycompany/FeaturedWorkflow.java
package com.mycompany; import ... public interface FeaturedWorkflow extends Workflow { void feature() throws WorkflowException, RepositoryException, MappingException, RemoteException; }
The FeaturedWorkflow consists of a single workflow action, called 'feature'.
Note that the interface extends org.hippoecm.repository.api.Workflow; this is required of all workflows.
Custom workflow implementation
src/main/java/com/mycompany/FeaturedWorkflowImpl.java
package com.mycompany; import ...; public class FeaturedWorkflowImpl extends WorkflowImpl implements FeaturedWorkflow { public FeaturedWorkflowImpl() throws RemoteException { } public void feature() throws WorkflowException, MappingException, RepositoryException { getNode().setProperty("featured:isFeatured", true); } }
The implementation of the workflow is named 'FeaturedWorkflowImpl. As required, it implements the FeaturedWorkflow interface and extends WorkflowImpl, the standard implementation of the Workflow interface. The single workflow action 'feature' is implemented to do very little: just set a boolean named flag to be true. It could mean that the document that this action is performed on is considered important. There is no workflow action in this custom workflow to set the flag on false.
The boolean flag is not a property of a document so this would not change the state of the document this workflow action is performed on.
CND file
The properties used for persisting have to exist, which is defined by a CND. You could set a property that already exists in the document type of the document. Then you would not have to write a separate CND for it. But you have to be sure that other uses of the property will not interfere with your use of that property. Your custom workflow will be self-contained if you define a separate namespace containing a mixin node type.
src/main/resources/hcm-config/featured.cnd
<jcr='http://www.jcp.org/jcr/1.0'> <nt='http://www.jcp.org/jcr/nt/1.0'> <mix='http://www.jcp.org/jcr/mix/1.0'> <hippo='http://www.onehippo.org/jcr/hippo/nt/2.0'> <featured='http://www.mycompany.com/featured/nt/1.0'> [featured:featured] mixin - featured:isFeatured (Boolean) = 'false' mandatory autocreated
In the CND above the namespace http://www.mycompany.com/featured/nt/1.0 has prefix featured. In this namespace, abbreviated as featured, a mixin node type is defined with local name featured. The full name of the mixin node type is therefore featured:featured.
In the mixin node type featured:featured a property is defined, with local name isFeatured. Its full name is therefore featured:isFeatured. This property is of type Boolean and has default value false. It is mandatory and autocreated so that it is always available when needed. This property will be a property of every document that has this mixin type. This is defined in the document type of the document.
Use the following YAML definition to bootstrap the CND file to the repository:
src/main/resources/hcm-config/namespace.yaml
definitions: namespace: featured: uri: http://www.mycompany.com/featured/nt/1.0 cnd: featured.cnd
Workflow manager configuration
src/main/resources/hcm-config/configuration.yaml
definitions: config: /hippo:configuration/hippo:workflows/featured: jcr:primaryType: hipposys:workflowcategory /featured: jcr:primaryType: frontend:workflow hipposys:classname: com.mycompany.FeaturedWorkflowImpl hipposys:display: Featured workflow hipposys:nodetype: featured:featured hipposys:privileges: ['hippo:editor'] /hipposys:types: jcr:primaryType: hipposys:types /frontend:renderer: jcr:primaryType: frontend:plugin plugin.class: com.mycompany.FeaturedWorkflowPlugin
Above you see a YAML definition for a hipposys:workflowcategory named featured. This defines a context of situations (see the introduction). When this file is imported, that workflow category is created, if it did not yet exist. If the workflow category node already exists the children from this file are added to it. In the file above there is one child node named featured. The type frontend:workflow indicates that the workflow also has a CMS component, i.e. the menu button.
If the node to change is of the given node type and the user of the given role, then an instance of the given class is returned by the workflow manager.
The node type is specified with the property hipposys:nodetype. You should specify a node type such that each workflow action (method) of the given workflow (class) is applicable on each node of that type. In the example the node type is set to the mixin node type that holds the boolean property featured:isFeatured ,which was used in the workflow action feature(). If another workflow action would be added to the workflow and it would use a new property in the same mixin node type, everything is still fine. But if the new property would be in a new mixin node type, none of the two mixin node types could be used as value of the hipposys:nodetype property above. You would have to create an extra mixin node type that extends both.
The role of the allowed users is specified in the hipposys:privileges property. The workflow class to return an instance of is specified in the hipposys:classname property.
In the hipposys:display property you specify how the work flow would be named when displayed. In the plugin.class property of the frontend:renderer child node you specify which plugin to use for buttons for the workflow in the CMS UI. Instead of the type frontend:plugin, it is also possible to use the type frontend:plugincluster for the sub-node. This allows multiple plugins to be used for the same workflow.
To enable the workflow the CMS UI, it is necessary to add the workflow category name to the list of categories used in the editor. The following YAML definition achieves this:
src/main/resources/hcm-config/featured.yaml
definitions: config: /hippo:configuration/hippo:frontend/cms/cms-preview/workflowPlugin: workflow.categories: operation: add type: string value: [featured]
The featured workflow category will show up as a new workflow menu in the document viewer. Localization of the menu label is done as in the following YAML example:
src/main/resources/hcm-config/translations.yaml
definitions: config: /hippo:configuration/hippo:translations/hippo:workflows/en: featured: Featured Workflow /hippo:configuration/hippo:translations/hippo:workflows/nl: featured: Aanbevolen