Creating business workflows

  Written by The Jahia Team
   Estimated reading time:
7.0 7.1 7.3 7.2

Jahia works with a business process engine to manage its workflows. The business process engine is mainly used for publication operations, which usually require user validation and interaction with external systems. However, you can use the process engine for other operations related to Jahia or for a purely business-oriented workflow.

Jahia is bundled and configured with the jBPM process engine.

Workflow declaration

Workflow processes must be deployed into the process engine and declared in Jahia to be used by site administrators and end-users. See Using jBPM for information about how to create and deploy process with the jBPM process engine.

Once the workflow is available in the process engine, you must register it with the workflow service. You can do so by creating a spring bean in the module. This bean has to declare multiple properties:

  • definition
    The key of the process definition as declared in jBPM.
  • type
    The type of workflow, such as publish, unpublish, or another name. Each workflow must be associated with a workflow type. Only one workflow per type can be associated to a node. For example, if multiple publication workflows exist, one must be chosen at a specific level.
  • forms
    A mapping of task names to task data node types. If a node type is associated with a task, a task data node is created under the task and is available for modification by the user completing the task. The task data can be filled with task input parameters, and its values can also be mapped with output parameters to the process variables. A form based on that node type displays to the user when they complete the task in My Dashboard in Edit mode. In the My tasks components, the task data node displays with a taskData view of this type.
  • permissions
    An optional mapping between workflow actions and Jahia permissions. The map contains the workflow action as the key and the permission full path as the value. A user must be part of a role with the permission to execute the workflow action (see Roles). Note that you can base the permission name on a custom variable that has been set previously in the workflow context. For example, in the translationWorkflow, the  jcr:modifyProperties_default_$translateTo permission is replaced by jcr:modifyProperties_default_en if the translateTo variable has been set to en. If no permission is defined for a task, a specific permission is automatically created.
  • canBeUsedForDefault
    Specifies if the workflow definition is available by default on all nodes without having to setup a workflow rule.
  • defaultPriority
    Specifies that if multiple workflows have canBeUsedForDefault, the workflow with the highest priority applies.
    <bean class="">
        <property name="type" value="unpublish"/>
        <property name="definition" value="1-step-unpublication"/>
        <property name="forms">
                <entry key="start" value="jnt:simpleWorkflow"/>
                <entry key="unpublish" value="jnt:simpleWorkflow"/>

Using a workflow

You can start and execute workflows on a node. Workflows are always tied to a node, such as a page, user, or any simple node. Workflow rules (which workflow can be started) and roles (who can execute the tasks) are set on these nodes or on parent nodes and are inherited on all sub nodes.

Workflow rules

Workflow rules define which workflow can be started on which node. You set this in the Workflow tab in the edit engine.

For every workflow type listed on the left, a drop-down menu allows you to select (or deselect) a workflow. You must clear the Same workflow as parent checkbox to select a new workflow.

Once saved, the workflow is available to the users who have the permission to start it.


A workflow is about interactions between users. Some users can start a workflow which requires action by other users. Jahia permissions and roles allows you to define possible actions for every user and group in the system.

When you declare a workflow, you define a mapping between workflow actions and Jahia permissions. To be able to start a workflow or assign and execute a task, a user must have the matching permission through a role. If no specific mapping is specified, a permission is automatically created for every task in /permissions/workflow-tasks/. See Workflow declaration for information on how to declare a workflow and a custom permission mapping.

Workflow permissions, like other permissions, are assigned to roles in Administration>Roles and permissions.

Users and groups are assigned to roles in the Edit Roles tab in the edit engine.

Starting and executing a workflow

Once a workflow rule has been set, a user who has rights to start a workflow on a node accesses it in the Workflow>Start workflow menu.

A workflow typically creates tasks that are assigned to users who have a role matching the required permissions. A user who has waiting tasks can execute them by opening his dashboard in Workflow>Workflow Dashboard.

A user can also check and execute their tasks in the My tasks section on the start page.

Using jBPM 6

For more information about jBPM, see .

jBPM configuration

The jBPM provider configuration file is the following:


This file contains references to other services, the path used by jBPM to get the process definitions, and the location of the jBPM config file.

The JBPMModuleProcessLoader bean, which is loaded in the context of every module, defines where the system looks for the process definition files. This bean is defined in:


Declaring a workflow in jBPM

As you can see in the jBPM configuration file, Jahia uses a wildcard classpath lookup to search for the BPMN workflow process definition files. This means that you can simply put your module in the proper package (by default under org.jahia.modules) in a file with the .bpmn2 extension and it will be picked up when Jahia starts. To be available in Jahia, the process must also be declared in a configuration file. For more information see Workflow declaration.

jBPM forms

jBPM allows you to associate a form with a task. In Jahia, this form is defined by a simple node type. This node type creates the form and the data is stored like a standard JCR node in the process engine. Forms are associated to tasks by a mapping in the workflow registration. For more information, see Workflow declaration.

Here the "request" task uses the "jnt:translationRequest" as a form.

     <bpmn2:userTask id="UserTask_2" name="request">

The jnt:translationRequest type is defined in a CND file with:

[jnt:translationRequest] > mix:title
- request (string, richtext)
- translateTo (string, choicelist[siteLocales])

The mapping is done during the workflow registration.

<bean name="translationWorkflow" class="">
    <property name="forms">
            <entry key="start" value="jnt:translationRequest"/>
            <entry key="request" value="jnt:translationRequest"/>

The execution of this task displays a form in all the engine automatically that the user needs to complete. Data entered in this form can later be used in other work items.

To use and render your form in HTML pages using tasks modules, you need to define a view of that form. To be used by the tasks module, the view be named taskData. Here's an example from the workflowRemotePublicationForm.taskData.jsp file :

<%@ taglib prefix="template" uri="" %>
<%@ taglib prefix="c" uri="" %>
<%@ taglib prefix="jcr" uri="" %>
<%@ taglib prefix="fmt" uri="" %>
    <c:url value='${url.base}${currentNode.path}' var="url"/>
    <form id="taskDataForm_${currentNode.parent.identifier}" method="post" action="${url}">
        <input type="hidden" name="jcrMethodToCall" value="put"/>
            <jcr:propertyInitializers node="${currentNode}" name="remotePublicationToExecute" var="values"/>
            <fmt:message key="jnt_workflowRemotePublicationForm.remotePublicationToExecute"/> :
            <select name="remotePublicationToExecute">
                <c:forEach items="${values}" var="value">
                    <option value="${value.value.string}">${value.displayName}</option>

Assigning jBPM tasks

jBPM needs to know how to assign new tasks to users when the task is created. Depending on the roles assigned to the node, the task is not assigned to the same users and groups. Jahia automatically assigns the task to the users or groups who have the correct permissions when the task is created. Subsequent changes to the roles are not visible for existing tasks.

Using jBPM customs work items handlers

At one point of the process, the process may need to interact with Jahia services. For example, a publication workflow needs to publish some nodes after a validation. There are multiple ways to do this with jBPM, but the simplest way is to create custom handlers. A few handlers are provided with Jahia to lock or unlock nodes and publish or unpublish nodes. They are located in*.

Defining your WorkItem handler

Handlers must be registered in your module spring file with a name, which is used in the BPMN files in the drools:taskName property of a task. For example, the following handler can be defined:

    <bean id="unlockWH" parent="abstractWH" class="">
        <property name="name" value="Unlock node"/>

And the handler is used in a process by the following task:

    <bpmn2:task id="Task_16" drools:taskName="Unlock node" name="Unlock the node">

Sharing data between tasks

You can share variables between tasks using Input/Output variables. On Eclipse, when editing a task, just switch to I/O Parameters and define your Input and Output variables. For example, if your task requires workspace and nodeIds as inputs and needs to define a valid boolean as output, you should have the following configuration:


In the .bpmn2 file, it is represented as:

<bpmn2:task id="Task_3" name="Call a custom workitem handler" drools:taskName="Custom work item handler">
  <bpmn2:ioSpecification id="InputOutputSpecification_5">
    <bpmn2:dataInput id="DataInput_3" itemSubjectRef="ItemDefinition_9" name="workspace"/>
    <bpmn2:dataInput id="DataInput_4" itemSubjectRef="ItemDefinition_278" isCollection="true" name="nodeIds"/>
    <bpmn2:dataOutput id="DataOutput_1" itemSubjectRef="ItemDefinition_603" name="valid"/>
    <bpmn2:inputSet id="InputSet_5" name="Input Set 5">
    <bpmn2:outputSet id="OutputSet_5" name="Output Set 5">
  <bpmn2:dataInputAssociation id="DataInputAssociation_3">
  <bpmn2:dataInputAssociation id="DataInputAssociation_4">
  <bpmn2:dataOutputAssociation id="DataOutputAssociation_1">

Using the WorkItem input variable, you can retrieve input data or set output data in your WorkItemHandler:

public void executeWorkItem(WorkItem workItem, WorkItemManager workItemManager) {
   // Retrieving input data
   List<String> nodeIds = (List<String>) workItem.getParameter("nodeIds");
   String workspace = (String) workItem.getParameter("workspace");

   ... Your code here ...

   Boolean result = false;

   // Setting output data
   workItem.getResults().put("valid", result);
   workItemManager.completeWorkItem(workItem.getId(), null);

Internationalizing workflow labels

You can create an optional resource bundle file along with the bpmn file to internationalize the name and labels of the process. The resource bundle must be named with the key of the jBPM process. For example, if the process has the "translation-workflow" key, the file must be named This file can include resources for process name, actions, and action outcomes. You can also specify a key for completed tasks by adding ".completed" to the task key.

Sending mail with jBPM

You can send mail using the Send mail task handler provided by Jahia. You can define a task as shown in the following example :

   <bpmn2:task id="Task_13" drools:taskName="Send mail" name="Send Mail">

This task requires the following input variables to send mail:

  • user
    The user initiating the workflow
  • currentUser
    The user who executed the last task
  • templateKey
    The name of the mail template to use
  • workflow
    The workflow definition
  • nodeIds
    The list of nodes on which the workflow has been started
  • locale
    The locale on which the workflow has been started
  • workspace
    The workspace on which the workflow has been started

The templateKey input defines which template to use to send mail. Mail templates are found, like workflows, in a path specified in the JBPMModuleProcessLoader bean. By default, all resources in the org.jahia.modules package with the .mail extension are taken. The following example, start-publication-template.mail, defines mail that is sent when a publication workflow starts.

to: #if ($userNotificationEmail) $userNotificationEmail #end
to-users: assignableFor(review)
subject: Publication request by ${PrincipalViewHelper.getFullName($currentUser)} for $site.getDisplayableName()
text: Hello,

A publication workflow with one validation step has been started on ${date.format("short","short",$submissionDate,$locale)} by ${currentUser.getName()}, on the following items :
#foreach( $node in $nodes )
    #if( $velocityCount <= 10)
    - #if( $node.getDisplayableName().length() > 100) ${node.getDisplayableName().substring(0, 100)}... #{else} $node.getDisplayableName() #end

html: Hello,
    ${PrincipalViewHelper.getFullName($currentUser)} has requested the publication of $publicationCount item(s) for $site.getDisplayableName() ($site.getServerName()) on

#set( $fileCheck = "/$site.getSiteKey()/files/" )
#set( $contentCheck = "/$site.getSiteKey()/contents/" )
#set( $replace = "/sites/$site.getSiteKey()")
        <li>Language: $locale</li>
        <li>Publication title: $workflowTitle</li>
            Publication items:
                #foreach( $entry in $publications.entrySet() )
                    #if( $entry.value.size() > 0 )
                                #foreach( $nodeInfo in $entry.value )
                                    #set( $node = $nodeInfo.get("node") )
                                ##Determine the "open in" link (Open in Edit Mode OR Open in Content Media Manager)
                                    #if ( $site.getSiteKey() == "systemsite" || $node.getPath().indexOf($fileCheck) != -1 || $node.getPath().indexOf($contentCheck) != -1 )
                                        #define( $openIn )
                                        ##Determine which route will be used
                                            #if ( $node.getPath().indexOf($fileCheck) != -1 )
                                                #set( $prefix = "$cmmPrefix/browse-files")
                                                #set( $prefix = "$cmmPrefix/browse")
                                         We need to use the folder path when opening CMM. Check if this node is a folder,
                                         otherwise get the parent node which will be a folder.
                                            #if( $node.isNodeType("nt:folder") )
                                                #set( $contentNodePath = "$prefix$node.getPath().replace($replace, '')" )
                                                #set( $contentNodePath = "$prefix$node.getParent().getPath().replace($replace, '')" )
                                            <a href="$contentNodePath">Open in Content and Media Manager</a>
                                        #define( $openIn )
                                            #set( $displayablePath = $nodeInfo.get("displayablePath") )
                                            #define( $previewLink ) - <a href="${previewPrefix}${displayablePath}.html">Preview</a> #end
                                            <a href="${editPrefix}${displayablePath}.html">Open in Edit Mode</a>
                                        ${nodeInfo.get("displayableName")} (${nodeInfo.get("type")}) ${openIn} #if( $previewLink ) $previewLink #end
                #if ($publicationCount > 10) <li>...</li> #end
##Display any comments that are apart of this workflow
#if ( $comments )
        #foreach( $comment in $comments )
                $comment.get("userName") on ${date.format("default", "default", $comment.get("time"), $locale)}

The template contains both text and HTML versions of the mail and uses velocity language to get dynamic information. You can use another script language (as defined by the JSR 223) by using the key language in the template file. The following variables are bound when executing the script: bundle, user, currentUser, date, submissionDate, locale, workspace, and nodes.

You can also declare one template per locale by suffixing the template name by language code. For example, is used when the workflow locale is French.


This example shows how to implement a new workflow from scratch. Most of the implementation is performed using Eclipse IDE and BPMN Modeler (an Eclipse plugin). The example workflow can be found directly on Github: The example uses Eclipse version 4.6.0 and the BPMN Modeler version 1.3.0 Eclipse plugin.

In the example, you build the following process:

  • Workflow starts
  • Lock the node
  • Evaluate the content using a Java class which can accept or reject the publication:
    • Accept
      The node is published
    • Reject
      No publication and the node is unlocked
  • End of the workflow

Initializing the workflow

Using Eclipse, open the module in which you want to define a new workflow.

In the folder /src/main/resources, create a new package related to your module, for example, org/jahia/modules/newCustomWorkflows.

In this new folder, create a new file using the Eclipse wizard "Generic BPMN 2.0 Diagram":

Select the Process type.

Enter a name and ensure the extension is .bpmn2.

In the Default Process tab, change the name so it matches the file's name, for example, new-custom-workflow.

Then change the Target Namespace to: and switch values for Type Language and Expression Language as follows:

Declaring data types and variables

You need to declare the variables needed for your workflow. This is done on the Data Items>Variable list for Process. In this case, define the following variables:

Name Data Type
nodeId java.lang.String
nodeIds java.util.List
workspace java.lang.String
locale java.util.Locale
user java.lang.String
currentUser java.lang.String
valid java.lang.Boolean

You should have something like the following:

Diagram of the process

Using the BPMN graphic editor (right-click on your .bpmn2 file, "Open with"/"Bpmn2 diagram editor"), you should see the following diagram:

All the tools needed for this diagram are available on the palette :

  • Connectors/Sequence Flow
    Tool to link elements together
  • Tasks/Task
    Tool to display a task
  • Gateways/Exclusive Gateway
    Represents two possible paths excluding each other

Example for the sequence flow:


Configuring input and output variables

For each task, you need to define what input and output variables are needed by the task. For example, the "Lock node" task will not define output variables, but in order to work, it needs as input the "workspace" and "nodeIds"  (=list of nodes on which the publication has been called) variables.

To define such variables, click on the task, and go into the tab "I/O Parameters".

You should define the following parameters for your tasks:

Locking the node

Custom work item handler

Publish node

Unlock node

Configuring the gateways

The first gateway must be a Diverging gateway. There have two possible conditions to define to automatically publish the content or reject the publication, depending on the output of our custom WorkItem Handler.

The second gateway should be a converging one. Nothing has to be configured there. If you specified the correct sequence flow the gateway should already be converging:

Creating a custom WorkItemHandler

Next you define a custom task which will be able to analyze the content trying to be published in order to automatically accept or reject it, based on business rules (possibly a call to a WebService). To do so, you need to define a Java class extending AbstractWorkItemHandler and implementing WorkItemHandler.

Create the following Java package: org.jahia.modules.newCustomWorkflows

In this package, create the CustomWorkItemHandler class as following :

package org.jahia.modules.newCustomWorkflows;

import java.util.List;

import org.kie.api.runtime.process.WorkItem;
import org.kie.api.runtime.process.WorkItemHandler;
import org.kie.api.runtime.process.WorkItemManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CustomWorkItemHandler extends AbstractWorkItemHandler implements WorkItemHandler {

 private transient static Logger logger = LoggerFactory.getLogger(CustomWorkItemHandler.class);
 public void abortWorkItem(WorkItem workItem, WorkItemManager workItemManager) {
  logger.debug("CustomWorkItemHandler has been canceled");

 public void executeWorkItem(WorkItem workItem, WorkItemManager workItemManager) {
  logger.debug("CustomWorkItemHandler has been called");

  // Retrieving input data
  List nodeIds = (List) workItem.getParameter("nodeIds");
  String workspace = (String) workItem.getParameter("workspace");
  Boolean result = false;
   * Write business code here and eventually modify the result
   * (call to webservices, checking data trying to be published, ...)
  result = true;

  // Setting output data
  workItem.getResults().put("valid", result);
  workItemManager.completeWorkItem(workItem.getId(), null);


You then need to declare the Spring bean related to your class. Edit your module Spring configuration file: src/main/resources/META-INF/spring/nameOfYourModule.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""
    <bean id="customWH" parent="abstractWH" class="org.jahia.modules.newCustomWorkflows.CustomWorkItemHandler">
        <property name="name" value="Custom work item handler"/>

Configuring tasks

The following section requires manually edit the .bpmn2 file. Be aware that any further modifications of this file using the BPMN Eclipse Modeler plugin could result in a rollback of your modifications.

Before configuring the task you set in your diagram, you need to specify some configurations related to Drools and to the schema location you are about to use.

Edit the <bpmn2:definitions...> element and add the two following attributes, if they are not already configured properly:

xmlns:drools="" xsi:schemaLocation=" drools.xsd BPMN20.xsd bpsim.xsd"

Edit the <bpmn2:process...> element and add the two following attributes, if they are not already configured properly:

drools:version="1" drools:packageName="org.jahia.modules.newCustomWorkflows"

Then for each <bpmn2:task...> element you should add the attribute "drools:taskName" with one of the following case sensitive value:

Task name drools:taskName value
Lock the node Lock node
Unlock the node Unlock node
Call a custom workitem handler Custom work item handler
Publish node Publish node

As you can see, the value to fill for your custom task corresponds to the value you specified for its name when declaring it as a bean. 

Depending on the version of the BPMN Modeler you are using, you may have to also redefine the id attribute of your properties elements.
For each <bpmn2:property...> element, replace the value of the id element with the value of the name element. Also replace the previous use of these ID values with the new value
For example, the following code:

<bpmn2:property id="Property_6" itemSubjectRef="ItemDefinition_9" name="user"/>


<bpmn2:property id="user" itemSubjectRef="ItemDefinition_9" name="user"/>

And the following code:

      <bpmn2:dataInputAssociation id="DataInputAssociation_7">


      <bpmn2:dataInputAssociation id="DataInputAssociation_7">

Declaring your workflow in Jahia

Workflow processes must be deployed into the process engine and declared in Jahia in order to be available to users. Once the workflow is available in the process engine, it has to be registered to the workflow service. This registration is done by declaring a Spring bean in the module's Spring configuration file. For your custom workflow, you need to add the following bean:

<bean name="new-custom-workflow" class="">
    <property name="type" value="publish"/>
    <property name="definition" value="new-custom-workflow"/>
    <property name="forms">
            <entry key="start" value="jnt:simpleWorkflow"/>
            <entry key="review" value="jnt:simpleWorkflow"/>
    <property name="permissions" >
            <entry key="start" value="publication-start"/>
            <entry key="review" value="publication-review"/>

Regular workflow errors

This section describes common errors raised during the development of a custom workflow.

Prefix drools not bound

Error stacktrace

ERROR [ExtensibleXmlParser] - (null: 18, 78): The prefix "drools" for attribute "drools:taskName" associated with an element type "bpmn2:task" is not bound.
org.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 78; The prefix "drools" for attribute "drools:taskName" associated with an element type "bpmn2:task" is not bound.


You are using drools attributes but you have not specified an XML Schema Instance defining them. You must perform the two following steps:

In your <bpmn2:process...> element, add the attributes drools:version with value 1 and drools:packageName with your BPMN2 package as value. For example:

<bpmn2:process id="new-custom-workflow" name="new-custom-workflow" isExecutable="false" drools:version="1" drools:packageName="org.jahia.modules.newCustomWorkflows">

In your <bpmn2:definitions...> element, ensure you have the following attributes and values, and otherwise, add them:

xsi:schemaLocation=" drools.xsd BPMN20.xsd bpsim.xsd"

Could not find variable scope

Error stacktrace

ERROR [scheduler_Worker-1] org.jbpm.workflow.instance.node.WorkItemNodeInstance: Could not find variable scope for variable Property_3
ERROR [scheduler_Worker-1] org.jbpm.workflow.instance.node.WorkItemNodeInstance: when trying to execute Work Item Lock node


You likely used the BPMN Modeler Eclipse plugin to create your input/output task's variables. The variables IDs have been auto-populated. For each <bpmn2:property...> element, replace the auto-calculated value of the id element (for example, "Property_6") with the value of the name element you specified (for example, "user").

For example, the following code:

<bpmn2:property id="Property_6" itemSubjectRef="ItemDefinition_9" name="user"/>

Should become:

<bpmn2:property id="user" itemSubjectRef="ItemDefinition_9" name="user"/>

For each use of this property, you also must replace the use of the previous ID specified by the new ID. For example, the following code:

      <bpmn2:dataInputAssociation id="DataInputAssociation_7">

Should become:

      <bpmn2:dataInputAssociation id="DataInputAssociation_7">

Workflow mail notification

Jahia provides some keywords that you can use to define which people you want to send mail to.

<mail name="done">
   <from users="jahiaSettingsProperty"/>
   <to users="currentWorkflowStarter"/>
   <cc users="previousTaskAssignable"/>
   <subject>Your request for translation has been accepted</subject>
   <text>Your request for translation has been accepted</text>
   <transition to="end"/>

jahiaSettingsProperty returns the mail_from property defined in or the administration center.

currentWorkflowStarter refers to the person who started the workflow.

previousTaskAssignable or nextTaskAssignable refers to the people that can participate in the previous task or the next task in your process flow.