Workflow & jBPM

Table of Contents

15.1. Workflow in Nuxeo 5.1
15.1.1. Deploying process definitions
15.2. Workflow from Nuxeo 5.2: the jBPM Service
15.2.1. Introduction
15.2.2. jBPM service configuration
15.2.3. Document management
15.2.4. Default processes
15.2.5. Nuxeo jBPM How-to

15.1. Workflow in Nuxeo 5.1

15.1.1. Deploying process definitions

A workflow definition is designed for a given workflow engine backend and not for the Nuxeo workflow service itself. Nuxeo workflow doesn't specify a new process definition language. Thus it has no Nuxeo specificities speaking of format or process definition language. For instance, if you use jBPM as a backend with Nuxeo 5 then the workflow definition should be a standard jpdl file that you may have designed using your favorite editor or still if you are using Shark as a backend then the workflow definition will be a standard WFMC process definition.

Once your workflow definition has been designed and is ready you can deploy it in Nuxeo workflow. Of course, the target workflow engine backend plugin should be deployed and registered against the workflow service.

15.1.1.1. Using extension points

The Nuxeo workflow service provides a dedicated extension point for workflow definition deployment. The extension point is called definition.

In this case, the workflow definition will be deployed at application server deployment time (For now, this is the case when the application server is starting up since hot deployment is not yet possible using Nuxeo Runtime at the time of writing this document).It means this way of deploying workflow definition is not suitable for all cases. See the next subsections for other ways of deploying workflow definitions.

Below is an example of a jPDL workflow definition contribution for the jBPM backend. This XML fragment would be defined in a contribution registered as a component in a bundle:

<?xml version="1.0"?>

<component name="com.company.workflow.sample.contributions">

  <extension target="org.nuxeo.ecm.platform.workflow.service.WorkflowService"
             point="definition">
    <definition>
      <engineName>jbpm</engineName>
      <mimetype>text/xml</mimetype>
      <definitionPath>workflows/process_definition.xml</definitionPath>
    </definition>
  </extension>

</component>    
  • engineName: name specified for the target backend at workflow service registration time (see workflow service backend extension point)

  • mimetype: mimetype of the workflow definition. This is especially interesting in case of the format is binary. (serialization issue at deployment time)

  • definitionPath: bundle relative path of the workklow definition to deploy.

In this situation here is how would look the tree:

com.company.workflow /
  META-INF /
    workflows /
      process_definition.xml
      MANIFEST.MF
  OSGI-INF /
    workflow-definitions-contrib.xml

15.2. Workflow from Nuxeo 5.2: the jBPM Service

15.2.1. Introduction

Nuxeo jBPM Service is a task and work flow management service based on jBPM. One can use this service without knowledge of jBPM, but for any advance use a good knowledge is necessary, please refer to jBPM documentation .

The service provides:

15.2.2. jBPM service configuration

15.2.2.1. Event and Notification

jBPM can be used for different use cases. The default Nuxeo contributions uses it as a simple workflow management on a single document. You could use it for complex BPM, SOA orchestration or pageflow management. All those different uses make it impossible to send meaningful event at the service level.

So we let the responsability of sending event to the user of the jBPM service. It is the responsability of the user of the service to send event .

For example, the default workflow will send a workflowStart event when the user presses the 'Start Workflow' button. (However, the jBPM process has already started and 2 tasks have already been completed at this stage). The default workflow also sends event (workflowTaskAssign) when a task is assigned to a pooled actors (This is not considered a task assignment for jBPM) and send a mail to each pooled actor.

If you use jBPM for workflow management on documents, we recommend that you use the event named in JbpmEventNames. You can check the default workflow, the TaskNotificationHandler or the JbpmActionsBean for code that sends event.

15.2.2.2. configurationPath and activeConfiguration extension points

Nuxeo configures jBPM in 2 steps . First, it creates named configurations using configurationPath extension point, such as:

<extension
    target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
    point="configurationPath">
  <configuration name="prod" path="config/jbpm.cfg.xml" />
</extension>

Finally, it gives the configuration to use:

<component
    name="org.nuxeo.ecm.platform.jbpm.core.ActiveConfiguration">
  <extension target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
    point="activeConfiguration">
    <configuration name="prod" />
  </extension>
</component>

If you want to use a different configuration you just need to overwrite the org.nuxeo.ecm.platform.jbpm.core.ActiveConfiguration component.

The default configuration uses a transactional persistent service. It also adds to the default hibernate configuration a nuxeo.hibernate.queries.hbm.xml file with nuxeo's specific queries.

Production settings

The default hibernate configuration, referenced in jbpm.cfg.xml, is not for production. For production, you should comment out the 'hibernate.hbm2ddl' property. You also should ask your DBA to finalize your database schema for your target database (Derby should not be used in production).

15.2.2.3. processDefinition extension point

To contribute a new process definition, contribute to the processDefinition extension point by giving the definition path relative to the root of the package and the name of the deployer.

The default contribution is:

<extension target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
    point="processDefinition">
  <processDefinition path="process/parallel-review.xml" deployer="ifChanged" />
  <processDefinition path="process/validation-review.xml" deployer="ifChanged" />
</extension>

15.2.2.4. deployer extension point

jBPM needs to keep all process definition versions in persistent storage, so a process may finish with the same definition it started with. When Nuxeo starts, the jBPM service needs to know if a process definition is to be deployed as a new version. The Deployer is responsible for process definition deployment, you choose how processes are deployed by choosing a Deployer.

The service comes with 3 Deployers:

ifChanged

This deployer deploys the process definition only if it wasn't deployed. To check it, it removes comments and whitespace from the process definition and compute the md5. If the previous definition had a different md5, then it is deployed.

never

This deployer never deploys a process definition.

always

This deployer always deploys a process definition.

You can contribute to new Deployer by contributing to the deployer extension-point. The contributed class needs to implement the ProcessDefinitionDeployer interface. It can also extend the AbstractProcessDefinitionDeployer that provides some helpers method.

The default contribution is:

<extension target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
    point="deployer">
  <deployer name="always"
    class="org.nuxeo.ecm.platform.jbpm.core.deployer.AlwaysDeployer" />
  <deployer name="never"
    class="org.nuxeo.ecm.platform.jbpm.core.deployer.NeverDeployer" />
  <deployer name="ifChanged"
    class="org.nuxeo.ecm.platform.jbpm.core.deployer.IfChangedDeployer" />
</extension>

15.2.2.5. securityPolicy extension point

The security extension point allows to contribute a security policy to a process definition. This security policy is used in the document related methods of the JbpmService.

The default contribution is:

<extension target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
  point="securityPolicy">

  <securityPolicy
    class="org.nuxeo.ecm.platform.jbpm.core.service.DefaultJbpmSecurityPolicy"
    for="review_parallel" />
  <securityPolicy
    class="org.nuxeo.ecm.platform.jbpm.core.service.DefaultJbpmSecurityPolicy"
    for="review_approbation" />

</extension>

This class follows the JbpmSecurityPolicy interface, and is used to define who is allowed to edit the process (administrator or initiator). Other permissions (who is allowed to add some reviewers for instance) is left out to the interface.

15.2.2.6. typeFilter extension point

The typeFilter extension point allows to bind process definition to a type of document. This is used in the default 'Workflow' tab to show what choices to offer to the user.

The default contribution is:

<extension target="org.nuxeo.ecm.platform.jbpm.core.JbpmService"
  point="typeFilter">
  <type name="Note">
    <processDefinition>review_parallel</processDefinition>
    <processDefinition>review_approbation</processDefinition>
  </type>
  <type name="File">
    <processDefinition>review_parallel</processDefinition>
    <processDefinition>review_approbation</processDefinition>
  </type>
</extension>

15.2.3. Document management

The jBPM service provides a set of methods to interact with a single document. We use a simple convention to attach a document to a process instance. 2 variables are added to the process instance:

documentId

The id of the document.

documentRepositoryName

The name of the document's repository.

The VariableName enum on the JbpmService names the different variables.

The abstract class AbstractJbpmHandlerHelper implements ActionHandler, AssignmentHandler, DecisionHandler and TaskControllerHandler. It provides useful methods when dealing with document and repository.

15.2.4. Default processes

15.2.4.1. The parallel review workflow

Description

Start state

When the process is started, 3 variables are added to the process: the document id and the repository name variable, the transition to follow( endLifecycleTransition variable). A start state task is also created to capture the initiator actor id. It is retrievable afterward as the 'initiator' swimlane.

Choose participants node

A task is created for the initiator. At the end of this task a 'participants' variable is added to the process. It is a list with one item per participant.

Set up rights

This is an action node. The process sets up the rights on the document so all participants can read it.

for each participant node

It uses an action node defined in the Nuxeo jBPM service. It creates a child token for each item of the list given as parameter in the process definition. In this case, a child token is created for each participant. On each child token, a variable named participant will hold the participant.

validate node

A task for the participant. If it is rejected, adds a variable named 'rejected' to the process. (The process is therefore considered rejected if only one participant rejects it)

join

A normal jBPM join. Waits for all participants to finish their tasks before resuming.

do follow transition

A decision node that checks if there is a 'rejected' variable. If there is, go to end. Otherwise go to follow transition node.

follow transition

The attached document follows the named transition

15.2.4.2. The validation review workflow

Description

start state

Same as for the parallel review process.

choose participants

Same as for the parallel review process.

Condition on participants

Check if there is an item in the participants list. If there isn't, then go to follow transition. Otherwise go to set up rights. Remove the first item of 'participants' list and put it in the participant variable. In any case, remember the previous participant in the previousActorId variable (the initiator if no previous participant).

Setup rights

Makes the document readable to the participants

validate node

Create a task for participant. If she validates, then go to condition on participants otherwise to validate after reject node.

validate after reject node

Create a task for previousActorId user. She has to validate the node.

follow transition

The document follows the transition set in the transition variable.

15.2.5. Nuxeo jBPM How-to

15.2.5.1. How to optimize jBPM service ?

The jBPM service methods on documents use the jBPM API. To find task related to a document it iterates over all the tasks and checks its variables.

If you have a lot of tasks, such a behavior can be too costly. We recommend in such a case to create a hibernate query and to call this query from your own jbpmOperation object. The module nuxeo-platform-jbpm-core comes with a nuxeo.hibernate.queries.hbm.xml that you can use. If you create your own query file, you need to add it in the hibernate configuration file.

If you need to query on property of the attached document, you can optimize the query by directly using the repository (this is valid only when using the sql backend). You need to create a class to map to the schema you want to query and add the hibernate annotation, you'll then be able to create a hbm query using the schema. You need to keep in mind that hibernate or the repository could be caching data, using such queries should be used carefully.

15.2.5.2. How to use jBPM as a task management service ?

The jBPM service can also be used as a simple task management service. The publication service uses it that way. It creates a task when someone needs to validates a publishing request. There is no process instance attached to it (but still a document attached to the task).

The code to create a task is:

TaskInstance ti = new TaskInstance();
ti.setPooledActors(new String[]{"some", "actors"});
Map<String, Serializable> variables = new HashMap<String, Serializable>();
variables.put(JbpmService.VariableName.documentId.name(), document.getId());
variables.put(JbpmService.VariableName.documentRepositoryName.name(), document.getRepositoryName());
ti.setVariables(variables);
ti.setName("my task");
ti.setCreate(new Date());
jbpmService().saveTaskInstances(Collections.singletonList(ti));

15.2.5.3. How to clean the database ?

jBPM keeps all tasks, processes and definitions in the database. If you don't need to keep an history of the processes, you have two ways to delete unwanted data.

You can use the event service to call the deleteProcess on all finished process periodically (Note: the default process in Nuxeo finishes only when all tasks are finished).

You can run a SQL procedure at the database level to remove the ended process and attached tasks.

15.2.5.4. How to test a process ?

Testing a process is done in two steps. The first step is to test the process definition itself. The second is to test the use of the process definition by the jbpm service and your other methods.

To test a process definition, you can extend the AbstractProcessDefinitionTest and implement the getProcessDefinitionResource() methods. It should return the path of the process definition. You can then use the jbpmContext variable to interact with the process definition. You might have trouble if one of your action requests some of Nuxeo services. If your handlers extend the AbstractJbpmHandlerHelper, you can surround the logic inside a if(nuxeoHasStarted()){....}. This way no nuxeo services will be called inside unit test without services.

If you want to test a process definition and its interaction with nuxeo service, you can have a look at JbpmServiceTest. It creates a repository, deploys the user manager service and the sql directory.