Showing posts with label huamn task. Show all posts
Showing posts with label huamn task. Show all posts

2013/06/11

Clustering in jBPM v6


Clustering in jBPM v5 was not an easy task, there where several known issues that had to be resolved on client (project that was implementing solution with jBPM) side, to name few:

  • session management - when to load/dispose knowledge session
  • timer management - required to keep knowledge session active to fire timers
This is not the case any more in version 6 where several improvements made their place in code base, for example new module that is responsible for complete session management was introduced - jbpm runtime manager. More on runtime manager in next post, this one focuses on how clustered solution might look like. First of all lets start with all the important pieces jbpm environment consists of:


  1. asset repository - VFS based repository backed with GIT - this is where all the assets are stored during authoring phase
  2. jbpm server that includes JBoss AS7 with deployed jbpm console (bpm focused web application) of kie-wb (fully features web application that combines BPM and BRM worlds)
  3. data base - backend where all the state date is kept (process instances, ksessions, history log, etc)

Repository clustering

Asset repository is GIT backed virtual file system (VFS) that keeps all the assets (process definitions, rules, data model, forms, etc) is reliable and efficient way. Anyone who used to work with GIT understands perfectly how good it is for source management and what else assets are if not source code?
So if that is file system it resides on the same machine as the server that uses it, that enforces it to be kept in sync between all servers of a cluster. For that jbpm makes use of two well know open source projects:

Zookeeper is responsible for gluing all parts together where Helix is cluster management component that registers all cluster details (cluster itself, nodes, resources).

So this two components are utilized by the runtime environment on which jbpm v6 is based on:
  • kie-commons - provides VFS implementation and clustering 
  • uber fire framework - provides backbone of the web applications

So let's take a look at what we need to do to setup cluster of our VFS:

Get the software

  • download Apache Zookeeper (note that 3.3.4 and 3.3.5 are the only versions that were currently tested so make sure you get the correct version)
  • download Apache Helix  (note that version that was tested was 0.6.1)

Install and configure

  • unzip Apache Zookeeper into desired location - ( from now one we refer to it as zookeeper_home)
  • go to zookeeper_home/conf and make a copy of zoo_sample.conf to zoo.conf
  • edit zoo.conf and adjust settings if needed, these two are important in most of the cases:
# the directory where the snapshot is stored.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181

  •  unzip Apache helix to into desired location (from now one we refer to it as helix_home)

Setup cluster

Now we have all the software available locally so next step is to configure the cluster itself. We start with start of the Zookeeper server that will be master of the configuration of the cluster:
  • go to zookeeper_home/bin
  • execute following command to start zookeeper server:
sudo ./zkServer.sh start
  • zookeeper server should be started, if the server fails to start make sure that the data directory defined in zoo.conf file exists and is accessible
  • all zookeeper activities can be viewed zookeeper_home/bin/zookeeper.out
To do so, Apache Helix provides utility scripts that can be found in helix_home/bin.

  • go to helix_home/bin
  • create cluster
./helix-admin.sh --zkSvr localhost:2181 --addCluster jbpm-cluster
  • add nodes to the cluster 
node 1
./helix-admin.sh --zkSvr localhost:2181 --addNode jbpm-cluster nodeOne:12345
node2
    ./helix-admin.sh --zkSvr localhost:2181 --addNode jbpm-cluster nodeTwo:12346
add as many nodes as you will have cluster members of jBPM server (in most cases number of application servers in the cluster)
NOTE: nodeOne:12345 is the unique identifier of the node, that will be referenced later on when configuring application severs, although it looks like host and port number it is use to identify uniquely logical node.
  • add resources to the cluster
./helix-admin.sh --zkSvr localhost:2181 
           --addResource jbpm-cluster vfs-repo 1 LeaderStandby AUTO_REBALANCE
  • rebalance cluster to initialize it
./helix-admin.sh --zkSvr localhost:2181 --rebalance jbpm-cluster vfs-repo 2

  • start the Helix controller to manage the cluster
./run-helix-controller.sh --zkSvr localhost:2181 
                        --cluster jbpm-cluster 2>&1 > /tmp/controller.log &
Values given above are just examples and can be changed according to the needs:
cluster name: jbpm-cluster
node name: nodeOne:12345, nodeTwo:12346
resource name: vfs-repo
zkSvr value must match Zookeeper server that is used.

Prepare data base 


Before we start with application server configuration data base needs to be prepared, for this example we use PostgreSQL data base. jBPM server will create all required tables itself by default so there is no big work required for this but some simple tasks must be done before starting the server configuration.

Create data base user and data base

First of all PostgreSQL data base needs to be installed, next user needs to be created on the data base that will own the jbpm schema, in this example we use:
user name: jbpm
password: jbpm

Once the user is ready, data base can be created, and again for the example jbpm is chosen for the data base name.

NOTE: this information (username, password, data base name) will be used later on in application server configuration.

Create Quartz tables

Lastly Quartz related tables must be created, to do so best is to utilize the data base scripts provided with Quartz distribution, jbpm uses Quartz 1.8.5. DB scripts are usually located under QUARTZ_HOME/docs/dbTables.

Create quartz definition file 

Quartz configuration that will be used by the jbpm server needs to accomodate the needs of the environment, as this guide is about to show the basic setup obviously it will not cover all the needs but will allow for further improvements.

Here is a sample configuration used in this setup:
#============================================================================
# Configure Main Scheduler Properties  
#============================================================================

org.quartz.scheduler.instanceName = jBPMClusteredScheduler
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool  
#============================================================================

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================

org.quartz.jobStore.misfireThreshold = 60000

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.dataSource=managedDS
org.quartz.jobStore.nonManagedTXDataSource=notManagedDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval = 20000

#============================================================================
# Configure Datasources  
#============================================================================
org.quartz.dataSource.managedDS.jndiURL=jboss/datasources/psjbpmDS
org.quartz.dataSource.notManagedDS.jndiURL=jboss/datasources/quartzNotManagedDS


Configure JBoss AS 7 domain


1. Create JDBC driver module - for this example PostgreSQL
a) go to JBOSS_HOME/modules directory (on EAP JBOSS_HOME/modules/system/layers/base)
b) create module folder org/postgresql/main
c) copy postgresql driver jar into the module folder (org/postgresql/main) as postgresql-jdbc.jar          name
d) create module.xml file inside module folder (org/postgresql/main) with following content:
         <module xmlns="urn:jboss:module:1.0" name="org.postgresql">
         <resources>
           <resource-root path="postgresql-jdbc.jar"/>
         </resources>

             <dependencies>
      <module name="javax.api"/>
      <module name="javax.transaction.api"/>
         </dependencies>
</module>

2. Configure data sources for jbpm server
a) go to JBOSS_HOME/domain/configuration
b) edit domain.xml file
for simplicity sake we use default domain configuration which uses profile "full" that defines two 
        server nodes as part of main-server-group
c) locate the profile "full" inside the domain.xml file and add new data sources
main data source used by jbpm
   <datasource jndi-name="java:jboss/datasources/psjbpmDS" 
                pool-name="postgresDS" enabled="true" use-java-context="true">
        <connection-url>jdbc:postgresql://localhost:5432/jbpm</connection-url>
        <driver>postgres</driver>
        <security>
            <user-name>jbpm</user-name>
                <password>jbpm</password>
        </security>
   </datasource>
        
        additional data source for quartz (non managed pool)
        <datasource jta="false" jndi-name="java:jboss/datasources/quartzNotManagedDS"   
           pool-name="quartzNotManagedDS" enabled="true" use-java-context="true">
      <connection-url>jdbc:postgresql://localhost:5432/jbpm</connection-url>
        <driver>postgres</driver>
        <security>
         <user-name>jbpm</user-name>
                <password>jbpm</password>
        </security>
    </datasource>
defined the driver used for the data sources
<driver name="postgres" module="org.postgresql">
      <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
    </driver>
        
3. Configure security domain 
     a) go to JBOSS_HOME/domain/configuration
     b) edit domain.xml file
for simplicity sake we use default domain configuration which uses profile "full" that defines two
        server nodes as part of main-server-group
      
     c) locate the profile "full" inside the domain.xml file and add new security domain to define security 
         domain for jbpm-console (or kie-wb) - this is just a copy of the "other" security domain defined 
         there by default
    
<security-domain name="jbpm-console-ng" cache-type="default"> <authentication>
            <login-module code="Remoting" flag="optional">
               <module-option name="password-stacking" value="useFirstPass"/>
            </login-module>
            <login-module code="RealmDirect" flag="required">
                  <module-option name="password-stacking" value="useFirstPass"/>
            </login-module>
        </authentication>
    </security-domain>  
        
for kie-wb application, simply replace jbpm-console-ng with kie-ide as name of the security domain.  
        
4. Configure server nodes

    a) go to JBOSS_HOME/domain/configuration
    b) edit host.xml file
    c) locate servers that belongs to "main-server-group" in host.xml file and add following system  
        properties:
    


property nameproperty valuecomments
org.uberfire.nio.git.dir/home/jbpm/node[N]/repolocation where the VFS asset repository will be stored for the node[N]
org.quartz.properties/jbpm/quartz-definition.propertiesabsolute file path to the quartz definition properties
jboss.node.namenodeOneunique node name within cluster (nodeOne, nodeTwo, etc)
org.uberfire.cluster.idjbpm-clustername of the helix cluster
org.uberfire.cluster.zklocalhost:2181location of the zookeeper server
org.uberfire.cluster.local.idnodeOne_12345unique id of the helix cluster node, note that ':' is replaced with '_'
org.uberfire.cluster.vfs.lockvfs-reponame of the resource defined on helix cluster
org.uberfire.nio.git.daemon.port9418port used by the GIT repo to accept client connections, must be unique for each cluster member
org.uberfire.nio.git.ssh.port8001port used by the GIT repo to accept client connections (over ssh), must be unique for each cluster member
org.uberfire.nio.git.daemon.hostlocalhosthost used by the GIT repo to accept client connections, in case cluster members run on different machines this property must be set to actual host name instead of localhost otherwise synchronization won't work
org.uberfire.nio.git.ssh.hostlocalhosthost used by the GIT repo to accept client connections (over ssh), in case cluster members run on different machines this property must be set to actual host name instead of localhost otherwise synchronization won't work
org.uberfire.metadata.index.dir/home/jbpm/node[N]/indexlocation where index for search will be created (maintained by Apache Lucene)
org.uberfire.cluster.autostartfalsedelays VFS clustering until the application is fully initialized to avoid conficts when all cluster members create local clones
    
examples for the two nodes:
    
  •     nodeOne
<system-properties>
  <property name="org.uberfire.nio.git.dir" value="/tmp/jbpm/nodeone" 
                                       boot-time="false"/>
  <property name="org.quartz.properties" 
      value="/tmp/jbpm/quartz/quartz-db-postgres.properties" boot-time="false"/>
  <property name="jboss.node.name" value="nodeOne" boot-time="false"/>
  <property name="org.uberfire.cluster.id" value="jbpm-cluster" 
                                           boot-time="false"/>
    <property name="org.uberfire.cluster.zk" value="localhost:2181" 
                                           boot-time="false"/>
  <property name="org.uberfire.cluster.local.id" value="nodeOne_12345" 
                                                 boot-time="false"/>
  <property name="org.uberfire.cluster.vfs.lock" value="vfs-repo" 
                                                 boot-time="false"/>
  <property name="org.uberfire.nio.git.daemon.port" value="9418" boot-time="false"/>
  <property name="org.uberfire.metadata.index.dir" value="/tmp/jbpm/nodeone" boot-time="false"/>
  <property name="org.uberfire.cluster.autostart" value="false" boot-time="false"/>
</system-properties>
    
  •     nodeTwo
<system-properties>
    <property name="org.uberfire.nio.git.dir" value="/tmp/jbpm/nodetwo" 
                                         boot-time="false"/>
    <property name="org.quartz.properties" 
       value="/tmp/jbpm/quartz/quartz-db-postgres.properties" boot-time="false"/>
    <property name="jboss.node.name" value="nodeTwo" boot-time="false"/>
    <property name="org.uberfire.cluster.id" value="jbpm-cluster" 
                                             boot-time="false"/>
    <property name="org.uberfire.cluster.zk" value="localhost:2181" 
                                             boot-time="false"/>
    <property name="org.uberfire.cluster.local.id" value="nodeTwo_12346" 
                                                   boot-time="false"/>
    <property name="org.uberfire.cluster.vfs.lock" value="vfs-repo" 
                                                   boot-time="false"/>
    <property name="org.uberfire.nio.git.daemon.port" value="9419" boot-time="false"/>
    <property name="org.uberfire.metadata.index.dir" value="/tmp/jbpm/nodetwo" boot-
     time="false"/>
    <property name="org.uberfire.cluster.autostart" value="false" boot-time="false"/>
</system-properties>

NOTE: since this example runs on single node host properties for ssh and git daemons are omitted.

Since repository synchronization is done between git servers make sure that GIT daemons are active (and properly configured - host name and port) on every cluster member.
5. Create user(s) and assign it to proper roles on application server

Add application users
In previous step security domain has been created so jbpm console (or kie-wb) users could be authenticated while logging on. Now it's time to add some users to be able to logon to the application once it's deployed. To do so:
 a) go to JBOSS_HOME/bin
 b) execute ./add-user.sh script and follow the instructions on the screen
  - use Application realm not management
  - when asked for roles, make sure you assign at least:
  for jbpm-console: jbpm-console-user
  for kie-wb: kie-user
 
add as many users you need, same goes for roles, listed above are required to be authorized to use the web application. 

Add management (of application server) user
To be able to manage the application server as domain, we need to add administrator user, it's similar to what was defined for adding application users but the realm needs to be management
 a) go to JBOSS_HOME/bin
 b) execute ./add-user.sh script and follow the instructions on the screen
  - use Management realm not application

Application server should be now ready to be used, so let's start the domain:

JBOSS_HOME/bin/domain.sh

after few seconds (it's still empty servers) you should be able to access both server nodes on following locations:
administration console: http://localhost:9990/console

the port offset is configurable in host.xml for given server.


Deploy application - jBPM console (or kie-wb)

Now it's time to prepare and deploy application, either jbpm-console or kie-wb. As by default both application comes with predefined persistence that uses ExampleDS from AS7 and H2 data base there is a need to alter this configuration to use PostgreSQL data base instead.

Required changes in persistence.xml

  • change jta-data-source name to match one defined on application server
             java:jboss/datasources/psjbpmDS
  • change hibernate dialect to be postgresql 
             org.hibernate.dialect.PostgreSQLDialect

Application build from source

If the application is built from source then you need to edit persistence.xml file that is located under:
jbpm-console-ng/jbpm-console-ng-distribution-wars/src/main/jbossas7/WEB-INF/classes/META-INF/
next rebuild the jbpm-distribution-wars module to prepare deployable package - once that is named: 
jbpm-console-ng-jboss-as7.0.war

Deployable package downloaded

In case you have deployable package downloaded (which is already a war file) you need to extract it change the persistence.xml located under:
WEB-INF/classes/META-INF
once the file is edited and contains correct values to work properly with PostgreSQL data base application needs to be repackaged:
NOTE: before repackaging make use that previous war is not in the same directory otherwise it will be packaged into new war too.

jar -cfm jbpm-console-ng.war META-INF/MANIFEST.MF *

IMPORTANT: make sure that you include the same manifest file that was in original war file as it contains valuable entires.


To deploy application logon as management user into administration console of the domain and add new deployments using Runtime view of console. Once the deployment is added to the domain, assign it to the right server group - in this example we used main-server-group it will be default enable this deployment on all servers within that group - meaning deploy it on the servers. This will take a while and after successful deployment you should be able to access jbpm-console (or kie-wb) on following locations:


the context root (jbpm-console-ng) depends on the name of the war file that was deployed so if the filename will be jbpm-console-ng-jboss7.war then the context root will be jbpm-console-ng-jboss7. Same rule apply to kie-wb deployment.

And that's it - you should have fully operational jbpm cluster environment!!!

Obviously in normal scenarios you would like to hide the complexity of different urls to the application from end users (like putting in front of them a load balancer) but I explicitly left that out of this example to show proper behavior of independent cluster nodes.

Next post will go into details on how different components play smoothly in cluster, to name few:
  • failover - in case cluster node goes down
  • timer management - how does timer fire in cluster environment
  • session management - auto reactivation of session on demand
  • etc
As we are still in development mode, please share your thoughts on what would you like to see in cluster support for jBPM, your input is most appreciated!

Update:
There was a change in naming of system properties since the article was written so for those that configured it already for 6.0.0.Final there will be a need to adjust name of following system properties:

  • org.kie.nio.git.dir -> org.uberfire.nio.git.dir
  • org.kie.nio.git.daemon.port -> org.uberfire.nio.git.daemon.port
  • org.kie.kieora.index.dir -> org.uberfire.metadata.index.dir
  • org.uberfire.cluster.autostart - new parameter
Table above already contains proper values for 6.0.0.Final

2012/10/05

jBPM5 Developer Guide book is on its way!!!

For those that keep an eye on jBPM user forum it won't be any surprise as it was already announced and sometime ago even request for comments was posted. So, I would like to emphasise once again - a brand new book for developers about jBPM5 and Drools by Mauricio Salatino a.k.a. Salaboy is coming.



I had a pleasure to slightly help with this book by reviewing it. I admit this is an excellent reading for those that are new to jBPM5 (and Drools) world as well as to those that are already familiar with it and are planning to put it into mission critical systems. Mauricio provides not only guidelines about the engine but goes beyond that by elaborating about different approaches on how to best utilize these frameworks.

It is much more than title would suggest, it is not only about jBPM5 (but main focus is on the business processes) but it covers topics like:
  • BPMN2 specification
  • Human tasks and WS-HT specification
  • Rule engine (Drools Expert)
  • Complex Event Processing (Drools Fusion)
  • Tooling (jBPM Web Designer, eclipse modeller, etc)
  • Centrailzed repository (Drools Guvnor)
Book is equipped with number of real life examples including source code that allows reader to follow all the content put in every chapter.

In conclusion, this is a book that everyone who wants to use jBPM5 to its full extend should get. I definitely recommend it for  everyone who is interested in jBPM and Drools projects as it provides excellent introduction and much more than that.

Book is scheduled to be available in December 2012 so stay tuned.

Credits
Special thanks go to Maurico Salatino and Esteban Aliverti for this great book. Looking forward to the next one :)

2012/07/31

Service Task with web service implementation

Invocation of web services as part of business process is common and most likely because of that default implementation of Service Task in BPMN2 specification is web service. Recently (5.4) jBPM5 has gotten support for such activity.

jBPM5 web service support is based on Apache CXF dynamic client. It provides dedicated Service Task handler (that implements WorkItemHandler interface).

org.jbpm.process.workitem.bpmn2.ServiceTaskHandler

Worth noting is that this handler is capable of invoking both web service end points and simple Java based services as with previous ServiceTask handler (org.jbpm.bpmn2.handler.SendTaskHandler) based on the implementation attribute of service task node

web service implementation
 <bpmn2:serviceTask id="ServiceTask_1" name="Service Task" implementation="##WebService" operationRef="_2_ServiceOperation"> </bpmn2:serviceTask>

java implementation
<bpmn2:serviceTask id="_2" name="Hello" operationRef="_2_ServiceOperation" implementation="Other" >
</bpmn2:serviceTask>

ServiceTaskHandler can invoke web service operations in three modes:
  • synchronous (sends request and waits for response before continuing)
  • asynchronous (sends request and uses callback to get response)
  • one way (sends request and does not wait for any response)
This configuration is done on service node level as parameter (data input) so it allows to have different configuration for service nodes and to be handled by the same service task handler.

Let's try to go through this implementation with example. We are going to build a process that will get weather forecast for given zip codes in US. So process will look like this:

This process will:
  • ask for couple of zip codes on the first human task (task is assigned to john)
  • next transform result of the user task to a collection that will be used as input for multi instance service task
  • then based on the input collection process will create several instances of service task to query the weather forecast service
  • once all service task instances are completed it will log result to the console
  • and create another human task to show the weather forecast for selected zip codes (task is assigned to john)
When process instance is started it will prompt the user to select in what mode service task instances should be executed: async or sync. With this particular example changing the mode from async to sync will not make big difference as the service we use is rather fast but with services that takes some time to respond difference will be noticeable.

But how does it know it is web service and even more important what web service it is? This is configured as part of process definition using few dedicated constructs:

1. first of all we need to tell the engine where is our WSDL so it can be read and operations from it can be invoked - this is done with BPMN2 import:
 <import importType="http://schemas.xmlsoap.org/wsdl/" location="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL" namespace="http://ws.cdyne.com/WeatherWS/"/>

2. next message, interface and operations must be defined:
<itemDefinition id="_2-2-4_InMessageType" />
<message id="_2-2-4_InMessage" itemRef="_2-2-4_InMessageType" />

<interface id="_2-2-4_ServiceInterface" name="" implementationRef="Weather">
 
  <operation id="_2-2-4_ServiceOperation"   
       implementationRef="GetCityWeatherByZIP" name="hello">
      <inMessageRef>_2-2-4_InMessage</inMessageRef>
  </operation>
</interface>

Important: make sure that implementationRef for both interface and operations point to valid service and operation in WSDL.

3. Next use defined operation in your service task and set implementation as web service (or don't specify that attribute at all so default will be taken):
<serviceTask id="_2" name="Service Task" operationRef="_2-2-4_ServiceOperation" implementation="##WebService" >
........
</serviceTask>

NOTE: Unfortunately tooling does not support this yet so the bpmn2 file needs to be edited by hand. Soon tooling will provide this as well.

Yet another important thing here is that if you plan to use request or response object of the service in your process as variables make sure that all of them implement java.io.Serializable interface so they can be properly persisted. One way to do this (used in the example) is to provide additional configuration to tell JAXB to add Serializable while generating classes from WSDL and generate classes as part of the build:

Complete source code can be found here. It comes with test cases that uses this example as well as local service that can be used to illustrate difference between sync and async modes.

This example can be executed on jbpm-console when build from master, as it already has this service task handler configured. Here is a short guide on how to do it:
1. clone jbpm master and build it with mvn clean install -DskipTests -Dfull (alternatively download latest build from build server)
2. clone jbpm-examples and build jbpm-ws-example project with mvn clean install
3. copy result of build in point 2 (jbpm-ws-sample-1.0-SNAPSHOT.jar) into jbpm-installer/dependencies
4. copy WeatherWSServiceProcess.bpmn2 into jbpm-installer/sample/evaluation/src/main/resource
5. copy all archives from jbpm-distribution into jbpm-installer/lib
6. use jbpm-installer to install jbpm into jboss AS7 - ant install.demo.noeclipse
7. start demo server - ant start.demo.noeclipse

then go to jbpm-console and run the process with name WeatherWSServiceProcess.

Have fun!

2012/06/01

Self managable user tasks - notification and reassignment

As a continuation of the first post, let's try to make use of LDAP configuration to make actors aware of the tasks awaiting their attention.
Human task service is capable of reacting on certain events such as task was not started or task was not completed in time. Currently there are two options a process designer can choose from:
  • remind the user about the task
  • reassign the task to another actor/group
Depending on the needs either one of them or both can be configured on a user task activity, moreover designers are not limited to single instances of those events, for instance user task can be modelled as follows:
  1. as soon as task is created send notification to the actor assigned to it
  2. if there is no action within a day, send a reminder to the actor
  3. if there is no action within two days, reassign the task to another actor
  4. if the task is not completed within a week send notification to a manager
This is illustrated on following screen cast, starting at designing a process with user task, configuring deadlines (reassignment and notifications), building and running the process.

1. first let's design the process and define deadlines


2. now it is time to build the package and execute process


Task service supports four types of events:
  • reassign if not started
  • reassign if not completed
  • notify if not started
  • notify if not completed
To give some flexibility, expression that reference process and task variables are supported, for instance when modelling notification, users and/or groups can point to a process variables to get a list of users/groups that should be notified. In addition, notification subject and body can reference both process and task variables and provides additional variables that could be useful when referring to a task:
  • processInstanceId
  • processSessionId
  • workItemId
  • taskId
  • owners
 and all task variables are available as Map in
  • doc
Process variables are accessed with #{variable} and task variables are accessed with ${variable}, simple notification could look like this:

Hello,

A task with id ${taskId} was assigned to you. You can access it in your personal <a href="http://localhost:8080/jbpm-console/app.html#errai_ToolSet_Tasks;Group_Tasks.3">inbox</a>.

Regards
jBPM

Although HTML notifications are supported it is recommended to make use of process variables and some services to provide email templates instead of putting them inline within process definition, the bpmn2 file. Both subject and body of the notification can be declared as process variable.

but how to configure it?

Note: This guide assumes that human task service is deployed as web application, if that is not the case please refer to online documentation.

There are two elements that needs to be provided to make human task capable of performing deadline actions:
  1. configure user info component that delivers information required by notification mechanism
  2. configure email service
And of course declare deadline requirements on the user task in your process.

Previous post showed how to configure LDAP user info component to utilize external service as user information provider (Quick recap - it simple requires to put the right class name in web.xml init param section - user.info.class and LDAP configuration property file). As this is rather common to use LDAP in such cases there is a way to add custom implementations as well so you are not limited to that.

Configuring email service is done by providing drools.email.conf property file that contains smtp configuration and place it inside META-INF directory of jbpm-human-task-war/WEB-INF/classes.

from = sender-email-address (required)
replyTo = reply-to-email-address (optional)
host = smtp-host-name (required)
port = smtp-port-number (required)
defaultLanguage = en-UK
user=username-if-authentication-enabled
password=password-if-authentication-enabled

NOTE: there could be a need of prefixing file name with additional drools. to be found properly due to bug. So file name should be drools.drools.email.conf; this will be fixed in 5.4.

With this, many uses cases can be covered as shown in the example but most likely not all, so if there are any scenarios you find yourself in and think it might be useful to others please let us know about it:)

2012/05/14

jBPM 5.3 brings LDAP into the picture

jBPM engine itself does not require to have knowledge about users and groups but to build more complete platform based on it sooner or later users and their memberships will be needed. Prior to version 5.3, jBPM relied on basic (and demo only) setup based on some property files. With 5.3 you can make use of integration that allow to employ existing LDAP server.

So, let's start digging into it :)

User and group information are relevant to two components:
  • jbpm console
  • human task server
jbpm console need to know about users and their roles to properly authenticate and grant them with correct access in the console.
Human task server has bit more to do with users and groups. First of all it requires it when assigning task to entities (either user or group). Next, in case notification mechanism is configured it requires to fetch more information about the entity (such as email address, etc.)

Bit of heads up is always welcome, but how this can be configured and used? Firstly, we need to have a LDAP server that could be used as user repository. If you have already one this step can be omitted.

Install and configure LDAP server


Install and configure LDAP server of your choice, I personally use OpenLDAP that can be downloaded and used freely for evaluation purpose. Regardless of your choice most likely the best guide on installation and configuration is to be found on the server home page.

Note: make sure that when configuring your LDAP server inetOrgPerson schema is included otherwise import of example ldif will fail.

Once the server is up and running it's time to load it with some information that will be used later on by jBPM. Following is a sample setup of users and groups that matches the one used in previous versions of jBPM5 (Example ldif file expect that there is already domain configured (dc=jbpm,dc=org)):

Sample LDIF file

Rest of the post assumes that LDAP server is installed on the same machine as application server that hosts jbpm (but it is not limited to that).

Configure JBoss AS7 security domain to use LDAP


Next step is to configure application server that host jbpm console to authenticate users using LDAP instead of the default property file based security domain. In fact there are no changes needed to jbpm console itself but only to JBoss AS7 configuration.
To use LDAP, jbpm-console security domain inside standalone.xml file should be replaced with:
 <security-domain name="jbpm-console">
      <authentication>
         <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required">
             <module-option name="baseCtxDN" value="ou=People,dc=jbpm,dc=org"/>
             <module-option name="baseFilter" value="(uid={0})"/>
             <module-option name="rolesCtxDN" value="ou=Roles,dc=jbpm,dc=org"/>
             <module-option name="roleFilter" value="(member=uid={0},ou=People,dc=jbpm,dc=org)"/>
             <module-option name="roleAttributeID" value="cn"/>
             <module-option name="allowEmptyPasswords" value="true"/>
         </login-module>
     </authentication>
 </security-domain>
This is pure JBoss configuration so in case of more advanced setup is required please visit JBoss AS7 documentation.

Note that from jBPM 5.3 jbpm console is capable of using any security domain that JBoss AS supports with just configuring it properly on application server so it is not limited to LDAP.

Configure Human task server to use LDAP


Finally it is time to look into the details of human task server configuration to make it use of LDAP as user repository. Those that are following jBPM development are already familiar with UserGroupCallback interface that is responsible for providing user and group/role information to the task server. So naturally LDAP integration is done through implementation of that interface.
Similar to configuring application server, ldap callback needs to be configured (with property file for instance). Here is a sample file that corresponds to the configuration used throughout the post:

ldap.user.ctx=ou\=People,dc\=jbpm,dc\=org
ldap.role.ctx=ou\=Roles,dc\=jbpm,dc\=org
ldap.user.roles.ctx=ou\=Roles,dc\=jbpm,dc\=org
ldap.user.filter=(uid\={0})
ldap.role.filter=(cn\={0})
ldap.user.roles.filter=(member\={0})

As from 5.3 by default human task server is deployed as web application on Jboss AS7. With this, user can simply adjust configuration of the human task server by editing its web.xml file. And this is how LDAP callback is registered.

<init-param>
     <param-name>user.group.callback.class</param-name>
     <param-value>org.jbpm.task.service.LDAPUserGroupCallbackImpl</param-value>
</init-param>

Next put the jbpm.usergroup.callback.properties on the root of the classpath inside jbpm-human-task.war web application and your LDAP callback will be ready to rock!

In addition, when using deadlines on your tasks together with notification, there is one more step to configure so user information (for instance email address) could be retrieved from LDAP server. UserInfo interface is dedicated to providing this sort of information to the deadline handler and thus it's implementation needs to registered as well.
Similar as user group callback was registered it can be done via web.xml of human task web application:

<init-param>
     <param-name>user.info.class</param-name>
     <param-value>org.jbpm.task.service.LDAPUserInfoImpl</param-value>
</init-param>

It requires to be configured as well and it could be done via property file that should be named jbpm.user.info.properties and be placed on root of the class path.
As it shares most of the properties with callback configuration, in many cases users could use single file that contains all required values and instruct both implementation where to find this file with system properties:

-Djbpm.user.info.properties=classpath-location-and-file-name
-Djbpm.usergroup.callback.properties=classpath-location-and-file-name

With all that jBPM will now utilize your LDAP server for users and groups information whenever it needs them.

P.S.
This post is more of introduction to the LDAP integration rather than complete and comprehensive guide as it touches on high level all the components involved. More detailed information about configuring particular pieces can be found in jBPM documentation for 5.3 release.

Any comments are more than welcome.