You are on page 1of 92

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

jBPM Developers Guide

1. Introduction 1.1. Target audience 1.2. 1.3. 1.4. 1.5. Overview Sources and WIKI Maven repository Library dependencies

2. Incubation 2.1. timer 2.1.1. 2.1.2. 2.1.3. 2.1.4. 2.1.5. Duedate expressions Business calendar Timer transition Timer event Timer business time

2.1.6. Timer repeat 2.2. group activity 2.2.1. group simple 2.2.2. group timer 2.2.3. group multiple entries 2.2.4. group concurrency 2.2.5. group secret 2.3. Multiplicative split with foreach 2.4. java activity 2.5. assign 2.6. Rules deployer 2.7. rules-decision activity 2.8. rules activity 2.9. jms activity 2.9.1. Mock JMS provider for easy testing 2.9.2. Text messages 2.9.3. Object messages 2.9.4. Map messages 2.10. History session chain 2.11. Creating identity groups 2.12. Task forms 2.12.1. Usage 2.12.2. Form format 2.13. Instance Migration 2.13.1. Simple Migration 2.13.2. Ending Running Instances 2.13.3. Version Ranges 2.13.4. Activity Mappings 2.13.5. Migration Handlers 2.14. User object caching 2.15. Transactions 2.15.1. Standalone transactions 2.15.2. JTA transactions 2.15.3. User transactions 3. BPMN 2.0 3.1. What is BPMN 2.0? 3.2. History and goal 3.3. JPDL vs BPMN 2.0 3.4. Bpmn 2.0 execution

1 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

3.5. 3.6. 3.7. 3.8.

Configuration Examples Process root element Basic constructs 3.8.1. Events 3.8.2. 3.8.3. 3.8.4. 3.8.5. 3.8.6. 3.8.7. Event: None start event Event: None end event Event: Terminate end event Sequence Flow Gateways Gateway: Exclusive Gateway

3.8.8. Gateway: Parallel Gateway 3.8.9. Gateway: Inclusive Gateway 3.8.10. Tasks 3.8.11. Task: User Task 3.8.12. Task: Java Service Task 3.8.13. Task: Script Task 3.8.14. Task: Manual task 3.8.15. Task: Java Receive task 3.9. Advanced constructs 3.9.1. Embedded sub-process 3.9.2. Timer start event 3.9.3. Intermediate events 3.9.4. Intermediate catch event: Timer 3.10. Complete example (including console task forms) 4. Migration from jBPM 3 4.1. Goals of jBPM 4 4.2. Known limitations 4.3. Process conversion tool 4.3.1. Overview 4.3.2. Arguments 4.3.3. Usage examples 4.3.4. Advanced 4.4. Translations and changes 5. The Process Virtual Machine 6. Architecture 6.1. APIs 6.2. Activity API 6.3. 6.4. 6.5. 6.6. 6.7. Event listener API Client API Environment Commands Services

7. Implementing basic activities 7.1. ActivityBehaviour 7.2. ActivityBehaviour example 7.3. ExternalActivityBehaviour 7.4. 7.5. 7.6. 7.7. ExternalActivity example Basic process execution Events Event propagation

8. Process anatomy 9. Advanced graph execution 9.1. Loops 9.2. 9.3. 9.4. 9.5. 9.6. 9.7. Implicit proceed behaviour Functional activities Execution and threads Process concurrency Exception handlers Process modifications

9.8. Locking and execution state 10. Configuration 10.1. Configuration basics 10.2. Customizing the business calendar 10.3. Customizing the identity component

2 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

11. Persistence 12. JobExecutor 12.1. Overview 12.2. Configuration 13. Advanced Mail Support 13.1. Producers 13.1.1. Default Producer 13.2. Templates 13.3. Servers 13.3.1. Multiple Servers 13.4. Custom Mail Producers 13.4.1. Extending the default mail producer 14. Software logging 14.1. Configuration 14.2. Categories 14.3. JDK logging 14.4. Debugging persistence 15. History 16. JBoss Integration 16.1. Packaging process archives 16.2. Deploying processes archives to a JBoss instance 16.3. Process deployments and versioning 16.4. ProcessEngine and J2EE/JEE programming models 17. Spring Integration 17.1. Overview 17.2. Configuration 17.3. Usage 17.4. Testing 18. Signavio web modeler 18.1. Introduction 18.2. Installation 18.3. Configuration

Chapter 1. Introduction
1.1. 1.2. 1.3. 1.4. 1.5. Target audience Overview Sources and WIKI Maven repository Library dependencies

1.1. Target audience


This developers guide is intended for experienced developers that want to get the full flexibility out of jBPM. The features described in this developers guide are currently not supported. Use at your own risk.

1.2. Overview
Chapter 2, Incubation explains the features that are intended to move to the userguide eventually and become part of the supported offering. Do note that incubation features are not yet considered stable (ie. there could be major syntax or implementation changes in next versions). Chapter 3, BPMN 2.0 shows how the BPMN 2.0 process language can be used with jBPM. Chapter 5, The Process Virtual Machine through Chapter 9, Advanced graph execution explain the core of jBPM, the process virtual machine (PVM) and how activity and event listener can be build for it. Chapter 10, Configuration through Chapter 18, Signavio web modeler explain advanced usage of the jBPM framework.

1.3. Sources and WIKI

3 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The source code for jBPM can be found in our SVN repository: https://anonsvn.jboss.org/repos/jbpm/jbpm4/ A description of how to build the sources is available in the wiki: http://www.jboss.org/community/docs/DOC-12867 The jBPM WIKI is located here: http://www.jboss.org/community/docs/DOC-11184

1.4. Maven repository


You can use jBPM with the libraries that ship in the distribution. The jbpm.jar in the distribution contains the classes of many jBPM modules: jbpm-api, jbpm-log, jbpm-test-base, jbpm-pvm, jbpm-jpdl and jbpm-enterprise. So the single jbpm.jar in the distribution does not allow to make a compile time distinction between the API classes and the implementation classes. If you prefer to build your project with only a dependency on jBPM's API, then our repository can be used directly. It is located here: http://repository.jboss.com/maven2/org/jbpm/jbpm4/

1.5. Library dependencies


If you want to install/deploy jBPM into your own application, this is still as easy as it was before: just put the right libs in your application classpath. We didn't yet clean up the dependency description in the maven pom files. So we can't yet give the exact minimal set of libraries from the lib directory that you need to include in your application (See Jira issue JBPM-2556 and vote for it if you want to let us know that this issue has priority for you). The versions of the libraries that are in the lib directory are the ones that we tested with. So we recommend you to use those very versions of the libs. To help you on your way, here's the current maven dependency list for jPDL: [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] -----------------------------------------------------------------------Building jBPM 4 - jPDL task-segment: [dependency:tree] -----------------------------------------------------------------------[dependency:tree] org.jbpm.jbpm4:jbpm-jpdl:jar:4.0 +- org.jbpm.jbpm4:jbpm-pvm:jar:4.0:compile | +- org.jbpm.jbpm4:jbpm-api:jar:4.0:compile | | \- jboss:jboss-j2ee:jar:4.2.2.GA:compile | +- org.jbpm.jbpm4:jbpm-log:jar:4.0:compile | +- org.jbpm.jbpm4:jbpm-test-base:jar:4.0:compile | | \- org.hibernate:hibernate-core:jar:3.3.1.GA:compile | | +- antlr:antlr:jar:2.7.6:compile | | \- commons-collections:commons-collections:jar:3.1:compile | +- org.apache.ant:ant:jar:1.7.0:compile | | \- org.apache.ant:ant-launcher:jar:1.7.0:compile | +- log4j:log4j:jar:1.2.14:compile | +- juel:juel:jar:2.1.0:compile | +- juel:juel-impl:jar:2.1.0:compile | +- juel:juel-engine:jar:2.1.0:compile | +- org.slf4j:slf4j-api:jar:1.5.2:compile | +- org.slf4j:slf4j-jdk14:jar:1.5.2:compile | +- org.jboss.identity.idm:idm-core:jar:1.0.0.Beta1:compile | | +- org.jboss.identity.idm:idm-common:jar:1.0.0.Beta1:compile | | +- org.jboss.identity.idm:idm-api:jar:1.0.0.Beta1:compile | | +- org.jboss.identity.idm:idm-spi:jar:1.0.0.Beta1:compile | | \- com.sun.xml.bind:jaxb-impl:jar:2.1.8:compile | | \- javax.xml.bind:jaxb-api:jar:2.1:compile | | \- javax.xml.stream:stax-api:jar:1.0-2:compile | +- org.jboss.identity.idm:idm-hibernate:jar:1.0.0.Beta1:compile | | +- javassist:javassist:jar:3.4.GA:compile | | +- org.hibernate:hibernate-cglib-repack:jar:2.1_3:compile | | \- org.slf4j:slf4j-log4j12:jar:1.5.2:compile | +- org.hibernate:hibernate-entitymanager:jar:3.4.0.GA:compile | | +- org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile | | +- org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile | | +- org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile | | +- dom4j:dom4j:jar:1.6.1:compile | | | \- xml-apis:xml-apis:jar:1.0.b2:compile | | \- javax.transaction:jta:jar:1.1:compile | +- org.livetribe:livetribe-jsr223:jar:2.0.5:compile | \- javax.mail:mail:jar:1.4.1:compile | \- javax.activation:activation:jar:1.1:compile +- junit:junit:jar:3.8.1:compile \- hsqldb:hsqldb:jar:1.8.0.7:test ------------------------------------------------------------------------

4 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The jboss idm dependencies in sections org.jboss.identity.idm:* can be ignored, including the org.hibernate:hibernate-entitymanager This list should already get you started to select a small subset of libs instead of including all the libs from the ${jbpm.home}/lib directory.

Chapter 2. Incubation
2.1. timer 2.1.1. 2.1.2. 2.1.3. 2.1.4. Duedate expressions Business calendar Timer transition Timer event

2.1.5. Timer business time 2.1.6. Timer repeat 2.2. group activity 2.2.1. group simple 2.2.2. group timer 2.2.3. group multiple entries 2.2.4. group concurrency 2.2.5. group secret 2.3. Multiplicative split with foreach 2.4. java activity 2.5. assign 2.6. Rules deployer 2.7. rules-decision activity 2.8. rules activity 2.9. jms activity 2.9.1. Mock JMS provider for easy testing 2.9.2. Text messages 2.9.3. Object messages 2.9.4. Map messages 2.10. History session chain 2.11. Creating identity groups 2.12. Task forms 2.12.1. Usage 2.12.2. Form format 2.13. Instance Migration 2.13.1. Simple Migration 2.13.2. Ending Running Instances 2.13.3. Version Ranges 2.13.4. Activity Mappings 2.13.5. Migration Handlers 2.14. User object caching 2.15. Transactions 2.15.1. Standalone transactions 2.15.2. JTA transactions 2.15.3. User transactions This section documents some of the more advanced activities and features of jPDL that are still in incubation. These features and activities are not supported yet, but they are available for you to try and use. There are no stability guarantees on these activities and features; use them at your own risk.

2.1. timer
Important
Timers will be changed before they are moved to the user guide. See JBPM-2329.

A timer can be specified in the transition element in wait state activities such as states, tasks, sub-processes and groups. When such a timer fires, that transition is taken.

5 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

A timer can also be specified in custom events in wait state activities such as states, tasks, sub-processes and groups. The timer element should then be the first element in the on element representing the event. In that case the event fires upon the duedate of the timer. Timers are created when the activity is entered. The timer can fire when the execution remains in the activity until the duedate. When the execution leaves the activity, the timer is cancelled. Table 2.1. timer attributes: Attribute duedate Type duedate expression duedate expression Default Required? required Description Specifies when the timer needs to fire. For example: 20 minutes or 3 business days or #{proc_var} + 1 week When a timer fires, this attribute specifies when the timer optional needs to fire again. For example: 20 minutes or 3 business days

repeat

2.1.1. Duedate expressions


A duedate expression has the following syntax: [<Base Date> {+|-}] quantity [business] {second | seconds | minute | minutes | hour | hours | day | days | week | weeks | month | months | year | years} Where Base Date is specified as EL and where quantity is a positive integer. And adding the optional indication business means that only business hours should be taken into account for this duration. Without the indication business, the duration will be interpreted as an absolute time period. How to configure business hours is explained in Section 2.1.2, Business calendar Note: 'business' is not supported when subtracting from a base date!

2.1.1.1. Base date


The base date can be specified in any JAVA Expression Language expression that resolves to a JAVA Date or Calendar object. Referencing variables of other object types, even a String in a date format like '2036-02-12', will throw a JbpmException NOTE: This baseDate is supported on the duedate and repeat attributes of all places where timers can be used, but also on the reminder of a task

2.1.1.2. Examples
The following examples of the usage are all possible <timer name="daysBeforeHoliday" duedate="5 business days">...</timer> <timer name="pensionDate" duedate="#{dateOfBirth} + 65 years" >...</timer> <timer name="pensionReminder" duedate="#{dateOfPension} - 1 year" >...</timer> <timer name="fireWorks" duedate="#{chineseNewYear} repeat="1 year" >...</timer> <reminder name="hitBoss" duedate="#{payRaiseDay} + 3 days" repeat="1 week" /> <reminder name="hitBoss" duedate="#{payRaiseDay} + 3 days" repeat="#{iritationFactor}" />

Remember, the following example, a subtraction in combination with 'business', is not supported and will throw an exception, as will resulting due dates that will be in the past <reminder name="toGoOrNotToGo" duedate="#{goLive} - 3 business days"/>

2.1.2. Business calendar


The default configuration will contain a reference to the file jbpm.business.calendar.xml. That contains a

6 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

configuration of business hours in the following format: <?xml version="1.0" encoding="UTF-8"?> <jbpm-configuration xmlns="http://jbpm.org/xsd/cfg"> <process-engine-context> <business-calendar> <monday hours="9:00-12:00 and 12:30-17:00"/> <tuesday hours="9:00-12:00 and 12:30-17:00"/> <wednesday hours="9:00-12:00 and 12:30-17:00"/> <thursday hours="9:00-12:00 and 12:30-17:00"/> <friday hours="9:00-12:00 and 12:30-17:00"/> <holiday period="01/07/2008 - 31/08/2008"/> </business-calendar> </process-engine-context> </jbpm-configuration> If the default business calendar implementation is sufficient for you, you can simply adjust the timings in the xml configuration as shown above. If the default implementation doesn't cover your use cases, you can easily write your own implementation by implementing the org.jbpm.pvm.internal.cal.BusinessCalendar interface. For example: public class CustomBusinessCalendar implements BusinessCalendar { public Date add(Date date, String duration) { if ("my next birthday".equals(duration)) { GregorianCalendar gregorianCalendar = new GregorianCalendar(); gregorianCalendar.set(Calendar.MONTH, Calendar.JULY); gregorianCalendar.set(Calendar.DAY_OF_MONTH, 21); return gregorianCalendar.getTime(); } return null; } }

To configure the jBPM engine to use this custom business calendar, just add the following line to your jbpm.cfg.xml: <process-engine-context> <object class="org.jbpm.test.custombusinesscalendarimpl.CustomBusinessCalendar" /> </process-engine-context>

Take a look at the org.jbpm.test.custombusinesscalendarimpl.CustomBusinessCalendarImplTest for more information.

2.1.3. Timer transition


The example org.jbpm.examples.timer.transition.TimerTransitionTest shows how to put a timer on a transition.

Figure 2.1. The timer transition example process

7 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="TimerTransition" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="guardedWait" /> </start> <state name="guardedWait"> <transition name="go on" to="next step" /> <transition name="timeout" to="escalation"> <timer duedate="10 minutes" /> </transition> </state> <state name="next step" /> <state name="escalation" /> </process> When an process instance for this process is started, it arrives immediately in the guardedWait state. At that time, a timer is created that will fire after 10 minutes. Execution processInstance = executionService .startProcessInstanceByKey("TimerTransition"); With the following query, we can query for the timers related to the newly created processInstance. We know that there should be exactly one such timer. Job job = managementService.createJobQuery() .timers() .processInstanceId(processInstance.getId()) .uniqueResult();

In a unit test, we won't use the JobExecutor to execute the timer. Instead, we execute timers directly in the thread of the unit test. That way it is easy to simulate one scenario though an execution. So as the next step, we assume that the timer will fire. We simulate this by executing the timer programmatically: managementService.executeJob(job.getDbid()); After that the process instance will have taken the timeout transition and moved to the escalation state. processInstance = executionService.findExecutionById(processInstance.getId()); assertEquals("escalation", processInstance.getActivityName()); The second scenario in TimerTransitionTest shows that the timer is cancelled in case the signal go on is given before the timer fires. In that case the execution ends up in the next step.

2.1.4. Timer event


Example TimerEventTest shows how to put a timer on a custom event.

Figure 2.2. The timer event example process

8 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="TimerEvent" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="guardedWait" /> </start> <state name="guardedWait" > <on event="timeout"> <timer duedate="10 minutes"/> <event-listener class="org.jbpm.examples.timer.event.Escalate" /> </on> <transition name="go on" to="next step" /> </state> <state name="next step" /> </process> In this case, if the execution is not signalled within 10 minutes after the activity is started, the event timeout is fired and the event listener org.jbpm.examples.timer.event.Escalate will be notified. Again, if the guardedWait activity is ended within 10 minutes, then the timer is cancelled and the Escalate event listener will not be notified.

2.1.5. Timer business time


Example TimerBusinessTimeTest shows how business time works.

Figure 2.3. The timer businesstime example process

<process name="TimerBusinessTime" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="guardedWait" /> </start> <state name="guardedWait" > <transition name="go on" to="next step" /> <transition name="timeout" to="escalation" > <timer duedate="9 business hours" /> </transition> </state> <state name="next step" /> <state name="escalation" /> </process> Suppose that a new TimerBusinessTime process instance is started at 11:30am on a tuesday. The default configured business calendar specifies working hours between 9:00-12:00 and 12:30-17:00. So 9 business hours later results in an actual duedate for the timer of wednesday 13:00 (1pm). Since we do not know when the TimerBusinessTimeTest will be ran, we only assert in the test that the actual duedate of the scheduled timer at least 24 hours ahead.

2.1.6. Timer repeat


Example TimerRepeatTest shows how to put a timer with a repeat. The attribute repeat on a timer will cause the timer to be rescheduled automatically after it is executed.

9 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 2.4. The timer repeat example process

<process name="TimerRepeat" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="guardedWait" /> </start> <state name="guardedWait"> <on event="timeout"> <timer duedate="20 minutes" repeat="10 seconds" /> <event-listener class="org.jbpm.examples.timer.repeat.Escalate" /> </on> <transition name="go on" to="next step"/> </state> <state name="next step"/> </process> When a new process is started, a timer is created and the duedate will be 20 minutes ahead. When the timer fires, a new timer will be created with a duedate of 10 seconds ahead. When that timer fires, a new timer will be created again 10 seconds ahead. And so on. New timers will be created each time the timer fires until the guardedWait state activity is ended with a signal. When the guardedWait state activity is ended, the existing timer will be cancelled.

2.2. group activity


Groups a set of activities in a process together. Contained groups must be nested hierarchically. A group corresponds to a BPMN expanded sub process. Table 2.2. group elements: Element any activity transition Multiplicity 0..* 0..* Description Contained activities. Outgoing transitions for the group activity.

2.2.1. group simple


This example scenario shows the basic operations of a group.

Figure 2.5. The simple group example process

10 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="GroupSimple" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="evaluate document" /> </start> <group name="evaluate document"> <start> <transition to="distribute document" /> </start> <state name="distribute document"> <transition to="collect feedback" /> </state> <state name="collect feedback"> <transition name="approved" to="done" /> <transition name="rejected" to="update document" /> </state> <state name="update document"> <transition to="distribute document" /> </state> <end name="done" /> <transition to="publish document" /> </group> <state name="publish document" /> </process> The next code snippet shows a test scenario that rejects a document when it comes in the collect feedback first time round. Then it goes through update document, distribute document and back to collect feedback. The second time, it will be approved. All activities involved are wait states. ProcessInstance processInstance = executionService .startProcessInstanceByKey("GroupSimple"); String pid = processInstance.getId(); assertEquals("distribute document", processInstance.getActivityName()); processInstance = executionService.signalExecutionById(pid); assertEquals("collect feedback", processInstance.getActivityName()); processInstance = executionService.signalExecutionById(pid, "rejected"); assertEquals("update document", processInstance.getActivityName()); processInstance = executionService.signalExecutionById(pid); assertEquals("distribute document", processInstance.getActivityName()); processInstance = executionService.signalExecutionById(pid); assertEquals("collect feedback", processInstance.getActivityName()); processInstance = executionService.signalExecutionById(pid, "approved"); assertEquals("publish document", processInstance.getActivityName());

2.2.2. group timer

Figure 2.6. The group timer example process

11 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="GroupTimer" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="evaluate document" /> </start> <group name="evaluate document"> <start> <transition to="approve" /> </start> <state name="approve"> <transition to="done" /> </state> <end name="done" /> <transition to="publish document" /> <transition name="timeout" to="escalate"> <timer duedate="2 business hours" /> </transition> </group> <state name="escalate" /> <state name="publish document" /> </process> The next code snippet shows a test scenario in which the timer will fire before the group activity evaluate document completes. ProcessInstance processInstance = executionService .startProcessInstanceByKey("GroupTimer"); Execution approveExecution = processInstance .findActiveExecutionIn("approve"); assertNotNull(approveExecution); List<Job> jobs = managementService .createJobQuery() .processInstanceId(processInstance.getId()) .list(); assertEquals(1, jobs.size()); Timer timer = (Timer) jobs.get(0); managementService.executeJob(timer.getDbid()); processInstance = executionService .findProcessInstanceById(processInstance.getId()); assertNotNull(processInstance.findActiveExecutionIn("escalate") );

2.2.3. group multiple entries


This shows how a group can have multiple exclusive entry points. Analogue to multiple entry points, a group can also have multiple exit points.

Figure 2.7. The group multiple entries example process

12 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="GroupMultipleEntries" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="choose strategy" /> </start> <decision name="choose strategy" expr="#{time}"> <transition name="plenty" to="play" /> <transition name="running out" to="plan" /> </decision> <group name="evaluate project"> <start name="play"> <transition to="distribute document" /> </start> <state name="distribute document" /> <start name="plan"> <transition to="make planning" /> </start> <state name="make planning" /> </group> </process> The following scenario will be when there is plenty of time: Map<String, Object> variables = new HashMap<String, Object>(); variables.put("time", "plenty"); ProcessInstance pi = executionService .startProcessInstanceByKey("GroupMultipleEntries", variables); assertNotNull(pi.findActiveExecutionIn("distribute document")); The following scenario will be when there is time is running out: Map<String, Object> variables = new HashMap<String, Object>(); variables.put("time", "running out"); ProcessInstance pi = executionService .startProcessInstanceByKey("GroupMultipleEntries", variables); assertNotNull(pi.findActiveExecutionIn("make planning"));

2.2.4. group concurrency


This scenario shows how a group can be used to create concurrent paths of execution. When an execution arrives in a group, each activity that doesn't have incoming transitions is started. So the first activities don't have to be start activities. The group takes the default transition out when all contained work is done.

Figure 2.8. The group concurrency example process

13 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="GroupConcurrency" xmlns="http://jbpm.org/4.4/jpdl"> <start> <transition to="evaluate project" /> </start> <group name="evaluate project"> <start> <transition to="distribute document" /> </start> <state name="distribute document"> <transition to="collect feedback" /> </state> <state name="collect feedback"> <transition to="document finished" /> </state> <end name="document finished" /> <start> <transition to="make planning" /> </start> <state name="make planning"> <transition to="estimate budget" /> </state> <state name="estimate budget"> <transition to="planning finished" /> </state> <end name="planning finished" /> <transition to="public project announcement" /> </group> <state name="public project announcement" /> </process> The following scenario will show a scenario in which all wait state acitivities are signalled in some random order till all work is done: ProcessInstance pi = executionService .startProcessInstanceByKey("GroupConcurrency"); String documentExecutionId = pi .findActiveExecutionIn("distribute document").getId(); String planningExecutionId = pi .findActiveExecutionIn("make planning").getId(); pi = executionService.signalExecutionById(documentExecutionId); assertNotNull(pi.findActiveExecutionIn("collect feedback")); assertNotNull(pi.findActiveExecutionIn("make planning")); pi = executionService.signalExecutionById(planningExecutionId); assertNotNull(pi.findActiveExecutionIn("collect feedback")); assertNotNull(pi.findActiveExecutionIn("estimate budget")); pi = executionService.signalExecutionById(planningExecutionId); assertNotNull(pi.findActiveExecutionIn("collect feedback")); pi = executionService.signalExecutionById(documentExecutionId); assertNotNull(pi.findActiveExecutionIn("public project announcement"));

2.2.5. group secret


Groups also support that you create transitions over group boundaries. So it's possible to have a tranition from an activity outside the group directly to an activity inside the group without modelling a start activity on the border of the group. Similarly with transitions from activities inside the group to activities outside the group. But shhhhhhhhh! Don't tell anyone cause this is not BPMN compliant.

2.3. Multiplicative split with foreach


Activity foreach allows multiple paths of execution to be started over a single branch of the process. Its attributes are described in the table below.

14 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Table 2.3. foreach attributes: Attribute Type expression or text Default Required? Description The collection to be iterated. Each item in the collection spawns in required a new concurrent execution leaving over the default transition. in supports collections of any kind, arrays and comma separated strings. The variable where the current item of the collection is stored. var text required This variable is set in the concurrent execution and is visible only to that execution.

In the example that follows, there is a need to collect reports from different departments. The same task is to be performed by different groups. This situation is easily modeled with foreach. Process variable departments provides the group names, whereas quota indicates how many tasks must be completed before execution leaves the join activity. <process name="ForEach" xmlns="http://jbpm.org/4.4/jpdl"> <start g="28,61,48,48" name="start1"> <transition to="foreach1"/> </start> <foreach var="department" in="#{departments}" g="111,60,48,48" name="foreach1"> <transition to="Collect reports"/> </foreach> <task candidate-groups="#{department}" g="201,58,92,52" name="Collect reports"> <transition to="join1"/> </task> <join g="343,59,48,48" multiplicity="#{quorum}" name="join1"> <transition to="end1"/> </join> <end g="433,60,48,48" name="end1"/> </process>

Important
When using foreach, the corresponding join must have the multiplicity attribute set. Without it, join continues execution based on its incoming transitions. In the preceding example, join has a single incoming transition. If multiplicity is not specified, the first execution that reaches the join activity will cause the parent execution to leave the join.

Here is how to initialize the iterative process variables. Map<String, Object> variables = new HashMap<String, Object>(); variables.put("departments", new String[] { "sales-dept", "hr-dept", "finance-dept" }); variables.put("quorum", 3); ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEach", variables);

2.4. java activity


The purpose of the java activity in general is to invoke a Java method as explained in the User Guide. This section in the Developer Guide is specifically about how to use the java activity to invoke a method of an ejb session bean. Exactly for this purpose it is possible to use the ejb-jndi-name attribute. As its name indicates the attribute specifies the jndi name of the ejb of which the method needs to be invoked. Consider the following ejb:

15 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

package org.jbpm.test.enterprise.stateless.bean; import javax.ejb.Stateless; @Stateless public class CalculatorBean implements CalculatorRemote, CalculatorLocal { public Integer add(Integer x, Integer y) { return x + y; } public Integer subtract(Integer x, Integer y) { return x - y; } } and the following process definition:

Figure 2.9. The ejb method invocation example process

<process name="EJB"> <start> <transition to="calculate" /> </start> <java name="calculate" ejb-jndi-name="CalculatorBean/local" method="add" var="answer"> <arg><int value="25"/></arg> <arg><int value="38"/></arg> <transition to="wait" /> </java> <state name="wait" /> </process> As you can expect, the execution of this node will invoke the add method of the ejb that is known under the jndi name CalculatorBean/local. The result will be stored in the variable answer. This is illustrated in the following test snippet. public void testEjbInvocation() throws Exception { String executionId = executionService .startProcessInstanceByKey("EJB") .getProcessInstance() .getId(); assertEquals(63, executionService.getVariable(executionId, "answer")); }

2.5. assign
The assign activity retrieves a value and assigns it to a target location. Table 2.4. assign attributes: Attribute from-var from-expr lang Type string expression string default expression language defined in ??? Default Required? one of from-var, from-expr, from is required Description variable that provides the source value expression that resolves the source value language in which from-expr is written

optional

16 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Attribute to-var to-expr

Type string expression

Default

Required? one of to-var, to-expr is required

Description variable that provides the target location expression that resolves the target location

Table 2.5. assign elements: Element from Multiplicity 0..1 Description descriptor that constructs the source value

Every form of from can be combined with any form of to. The listing below simply assigns a variable to another. <assign name='copy' from-var='person' to-var='clone'> <transition to='wait' /> </assign> The next example shows an expression value being assigned to a variable. <assign name='resolve' from-expr='#{person.name}' to-var='name'> <transition to='wait' /> </assign> Our last example presents a value constructed by a descriptor being assigned to the expression location. <assign name='resolve' to-expr='#{person.address.street}'> <from><string value='gasthuisstraat' /></from> <transition to='wait' /> </assign>

2.6. Rules deployer


The rules deployer is a convenience integration between jBPM and Drools. It creates a KnowledgeBase based on all .drl files that are included in a business archive deployment. That KnowledgeBase is then stored in the repository cache. So one KnowledgeBase is maintained in memory the process-engine-context. Activities like the rules decision leverage this KnowledgeBase.

2.7. rules-decision activity


A rules-decision is an automatic activity that will select a single outgoing transition based on the evaluation of rules. Rules for a rules decision are to be deployed as part of the business archive. Those rules can use all process variables as globals in rule definitions. The rule-decision activity will use a stateless knowledge session on the knowledgebase. The execution arriving in the rules-decision is executed on the stateless drools knowledge session. Let's look at the next example how that works in practice. We'll start with the RulesDecision process

Figure 2.10. The rules decision example process

17 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="RulesDecision"> <start> <transition to="isImportant" /> </start> <rules-decision name="isImportant"> <transition name="dunno" to="analyseManually" /> <transition name="important" to="processWithPriority" /> <transition name="irrelevant" to="processWhenResourcesAvailable" /> </rules-decision> <state name="analyseManually" /> <state name="processWithPriority" /> <state name="processWhenResourcesAvailable" /> </process> The following isImportant.drl is included in the business archive deployment. global java.lang.Integer amount; global java.lang.String product; global org.jbpm.jpdl.internal.rules.Outcome outcome; rule "LessThen3IsIrrelevant" when eval(amount < 3) then outcome.set("irrelevant"); end rule "MoreThen24IsImportant" when eval(amount > 24) then outcome.set("important"); end rule "TwelveTempranillosIsImportant" when eval(product == "Tempranillo") eval(amount > 12) then outcome.set("important"); end First you see that amount and product are defined as globals. Those will resolve by the rules-decision to the process variables with those respective names. outcome is a special global variable that is used to indicate the transition to take in the consequence. Also, if no outcome is specified by the rules, the default transition will be taken. So let's start a new process instance and set 2 variables product and amount with respective values shoe and 32: Map<String, Object> variables = new HashMap<String, Object>(); variables.put("amount", 32); variables.put("product", "shoe"); ProcessInstance processInstance = executionService.startProcessInstanceByKey("RulesDecision", variables); After starting the process instance method returns, the process instance will have arrived in the activity processWithPriority In similar style, a new RulesDecision process instance with 2 missiles will go to activity processWhenResourcesAvailable A RulesDecision process instance with 15 shoes will go to activity analyseManually And a RulesDecision process instance with 13 Tempranillos will go to activity analyseManually

2.8. rules activity


A rules is an automatic activity that will create a stateful knowledge session, feed a number of facts in it and fire all rules. The idea is that the rules will update or create process variables that will be used later in the process. Facts can

18 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

be specified as sub elements of the rules activity. Table 2.6. rules elements: Element fact Multiplicity 0..* Description A fact that will be fed into the stateful rule session.

Table 2.7. fact attributes: Attribute var expr Type variable name expression Default Required? either var or expr is required either var or expr is required Description the variable name for which the value should be inserted as a fact. the expression for which the resulting value should be inserted as a fact.

If a rules activity has one outgoing transition, then that one is taken automatically. But multiple outgoing transitions can be specified with conditions on them, just like with the decision activity when using the conditions. For example:

Figure 2.11. The rules example process

<process name="Rules"> <start> <transition to="evaluateStatus"/> </start> <rules name="evaluateStatus"> <fact var="room" /> <transition to="checkForFires"/> </rules> <decision name="checkForFires"> <transition to="getFireExtinguisher"> <condition expr="#{room.onFire}" /> </transition> <transition to="goToPub"/> </decision> <state name="getFireExtinguisher"/> <state name="goToPub"/> </process> The process first checks with rules if the room is on fire. The Room class looks like this: public class Room implements Serializable { int temperature = 21; boolean smoke = false; boolean isOnFire = false; public Room(int temperature, boolean smoke) { this.temperature = temperature; this.smoke = smoke; } ...getters and setters... }

19 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Following rules are deployed in the same business archive: rule "CheckRoomOnFire" when room : org.jbpm.examples.rules.Room( temperature > 30, smoke == true ) then room.setOnFire( true ); end So when a new Rules process instance is started like this: Map<String, Object> variables = new HashMap<String, Object>(); variables.put("room", new Room(350, true)); ProcessInstance processInstance = executionService.startProcessInstanceByKey("Rules", variables); Then the process will end up in the activity getFireExtinguisher And when the process is started with a Room(21, false), it will end up in the activity goToPub

2.9. jms activity


Disclaimer: this activity is not yet stable. Two aspects will be revisisted in following releases: Binding the non-xa use of JMS to the standard transaction We're still figuring out why in JBoss the java:JmsXA connection factory doesn't implement XAConnectionFactory. And that we have to use the non-XA JMS API's for sending and retrieving messages. That is why we've put transacted="false" in our enterprise QA run processes (used for docs here). And that is why we use method jmsConsumeMessageFromQueue("java:JmsXA", "queue/jbpm-test-queue", 1000, false, Session.AUTO_ACKNOWLEDGE); in our test cases that run on JBoss (also used in docs here) The jms activity provides users with convenience for sending JMS messages. At this moment the sending of three different types of JMS messages is possible: text, object and map. Specifying message properties is not yet supported. Table 2.8. jms attributes: Attribute connectionfactory destination transacted Type jndi name jndi name boolean: {true, false} acknowledge { auto | client | dups-ok } auto optional true Default Required? required required optional Description the JNDI name of the jms connection factory. the JNDI name of the jms queue or topic. Specifies if JMS message send should happen transactional. @see QueueConnection.createQueueSession(boolean transactional, int acknowledgeMode) Specifies the acknowledge mode @see QueueConnection.createQueueSession(boolean transactional, int acknowledgeMode)

There are 3 types of JMS messages that you can send to to the destination: text, object and map. The connection-factory and destination attributes are mandatory and respectively contain the names of the connection factory and destination (queue or topic) that will be used to lookup the corresponding objects in JNDI. The lookup is done like this: InitialContext initialContext = new InitialContext(); Destination destination = (Destination) initialContext.lookup(destinationName); Object connectionFactory = initialContext.lookup(connectionFactoryName); The jms activity will use the JMS queue apis if the destination is an instanceof Queue. Analogue for topics. The jms activity will use the XA JMS apis if the connectionFactory is an instanceof XAConnectionFactory. Analogue for plain ConnectionFactory's. So if you're running inside an appserver, then the new InitialContext() will see the queue's and topics configured in the appserver. When your're using the JMS mocking in standalone test mode, then the queues and topics that you created with

20 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

JbpmTestCase.jmsCreateQueue and JbpmTestCase.jmsCreateTopic will be available. When you're running as a remote application client, then you have to specify the jndi environment with system properties. Table 2.9. jms elements: Element text object map Multiplicity 0..1 0..1 0..1 Description A string of text that will be used as payload for the JMS message. A serializable object that will be used as payload for the JMS message. A map of which the key-value entries will be used as payload for the JMS message.

Exactly one of the elements text, object or map is mandatory. The presence of this element will determine the kind of message that will be sent to the queue obtained in the lookup mentioned above. This message will be a TextMessage, ObjectMessage or MapMessage respectively. In the following subsections the different types of supported messages will be explained. The used process is in the three cases similar. The graphical representation of the process is shown below.

2.9.1. Mock JMS provider for easy testing


Apart from configuring a real JMS and making sure it is available in JNDI, a jms activity can also be tested with a mock JMS provider. That might be easier to perform scenario testing of your process. Following test helper methods are based solely on plain JMS apis and hence they work in a standalone environment as well as in an appserver environment: JbpmTestCase.jmsConsumeMessageFromQueue(String connectionFactoryJndiName, String queueJndiName) with defaults 1000, true, Session.AUTO_ACKNOWLEDGE for parameters timeout, transacted and acknowledgeMode respectively JbpmTestCase.jmsConsumeMessageFromQueue(String connectionFactoryJndiName, String queueJndiName, long timeout, boolean transacted, int acknowledgeMode) JbpmTestCase.jmsConsumeMessageFromQueueXA(String connectionFactoryJndiName, String queueJndiName, long timeout) JbpmTestCase.jmsAssertQueueEmpty(String connectionFactoryJndiName, String queueJndiName, long timeout, boolean transacted, int acknowledgeMode) JbpmTestCase.jmsAssertQueueEmptyXA(String connectionFactoryJndiName, String queueJndiName, long timeout) JbpmTestCase.jmsStartTopicListener(String connectionFactoryJndiName, String topicJndiName, boolean transacted, int acknowledgeMode) JbpmTestCase.jmsStartTopicListenerXA(String connectionFactoryJndiName, String topicJndiName) JmsTopicListener.getNextMesssage(long timeout) JmsTopicListener.stop() For example, after the process execution has executed the jms activity, messages can be asserted like this: MapMessage mapMessage = (MapMessage) jmsConsumeMessageFromQueue("java:/JmsXA", "queue/ProductQueue"); assertEquals("shampoo", mapMessage.getString("product")); The following jms helper methods are based on mockrunner and hence they only work in a standalone environment: (we're collaborating with mockrunner people to have these methods also work in an appserver environment) void jmsCreateQueue(String connectionFactoryJndiName, String queueJndiName) void jmsRemoveQueue(String connectionFactoryJndiName, String queueJndiName) void jmsCreateTopic(String connectionFactoryJndiName, String topicJndiName) void jmsRemoveTopic(String connectionFactoryJndiName, String topicJndiName)

21 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

For example, a queue can be created and removed in the setup and tearDown methods of a test like this: protected void setUp() throws Exception { super.setUp(); jmsCreateQueue("java:/JmsXA", "queue/ProductQueue"); } protected void tearDown() throws Exception { jmsRemoveQueue("java:/JmsXA", "queue/ProductQueue"); super.tearDown(); }

2.9.2. Text messages


The first possibility of sending JMS messages is to use text as its payload. In this case a JMS TextMessage will be created and sent to the specified destination. Consider the following process definition: <process name="JmsQueueText"> <start> <transition to="send message"/> </start> <jms name="send message" connection-factory="java:JmsXA" destination="queue/jbpm-test-queue" transacted="false"> <text>This is the body</text> <transition to="wait"/> </jms> <state name="wait"/> </process> As you may expect and as is shown in the following test case starting this process will cause the JMS node to send a message to the queue with the name "queue/jbpm-test-queue". The factory used to create a connection to connect to this queue is named "java:JmsXA". The payload of the message is the text string "This is the body". executionService.startProcessInstanceByKey("JmsQueueText"); TextMessage textMessage = (TextMessage) jmsConsumeMessageFromQueue("java:JmsXA", "queue/jbpm-test-queue", 1000, false, Session.AUTO_ACKNOWLEDGE); assertEquals("This is the body", textMessage.getText()); The relevant code is shown above in boldface. The rest of the method is boilerplate code needed to setup a message consumer. We will omit this code in the subsequent examples.

2.9.3. Object messages


The second possibility is to use a serializable object as the payload of the message. In this case a JMS ObjectMessage will be created and sent to the specified destination. Consider the following process definition: <process name="JmsQueueObject"> <start> <transition to="send message"/> </start> <jms name="send message" connection-factory="java:JmsXA" destination="queue/jbpm-test-queue" transacted="false"> <object expr="${object}"/> <transition to="wait"/> </jms> <state name="wait"/> </process> As in the previous case a message will be sent to the queue with the name "queue/jbpm-test-queue". Also again a factory used to create a connection to connect to this queue is named "java:JmsXA". But in this case the payload of the message is the serializable object that is obtained by evaluating the expression specified by the expr attribute.

22 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

This is illustrated in the test case below. Map<String, Object> variables = new HashMap<String, Object>(); variables.put("object", "this is the object"); executionService.startProcessInstanceByKey("JmsQueueObject", variables); ObjectMessage objectMessage = (ObjectMessage) jmsConsumeMessageFromQueue("java:JmsXA", "queue/jbpm-test-queue", 1000, false, Session.AUTO_ACKNOWLEDGE); assertEquals("this is the object", objectMessage.getObject());

2.9.4. Map messages


In this third possibility the payload is constituted by the key-value entries of a map. This time a JMS MapMessage will be created and sent to the specified destination. Consider the following process definition: <process name="JmsQueueMap"> <start> <transition to="send message"/> </start> <jms name="send message" connection-factory="java:JmsXA" destination="queue/jbpm-test-queue" transacted="false"> <map> <entry> <key><string value="x"/></key> <value><string value="foo"/></value> </entry> </map> <transition to="wait"/> </jms> <state name="wait"/> </process> Again a message will be sent to the queue with the name "queue/jbpm-test-queue" and the factory used to create a connection to connect to this queue is named "java:JmsXA". In this case the payload of the message are the specified key-value pairs of the map. It is illustrated in the test case below. executionService.startProcessInstanceByKey("JmsQueueMap"); MapMessage mapMessage = (MapMessage) jmsConsumeMessageFromQueue("java:JmsXA", "queue/jbpm-test-queue", 1000, false, Session.AUTO_ACKNOWLEDGE); assertTrue(mapMessage.itemExists("x")); assertEquals("foo", mapMessage.getObject("x"));

2.10. History session chain


The history session, which can be added to the transaction-context in the jBPM configuration will add a default history event listener to the process engine. This default history session will write the information in the history events to the history tables in the database. The history session chain construct allows to define custom history event listeners. These custom history sessions will be called when a history event is fired. Multiple custom implementations are possible as follows: <transaction-context> <history-sessions> <object class="org.jbpm.test.historysessionchain.MyProcessStartListener" /> <object class="org.jbpm.test.historysessionchain.MyProcessEndListener" /> </history-sessions> </transaction-context>

The custom history sessions must be on the classpath when the jBPM configuration is parsed and they must implement the HistorySession interface.

23 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

public class MyProcessStartListener implements HistorySession { public void process(HistoryEvent historyEvent) { if (historyEvent instanceof ProcessInstanceCreate) { ... } } }

If you want to add the default history session implementation to your configuration, add the following line to the transaction-context section: <history-sessions> <object class="org.jbpm.pvm.internal.history.HistorySessionImpl" /> </history-sessions>

If you are using the jbpm.default.cfg.xml import in your configuration, this default history session implementation is already configured as above.

2.11. Creating identity groups


The identity service methods to create groups are based on component generated ID's. public class IdentityService { /** create a group new group * @return the generated id for this group. */ String createGroup(String groupName); /** create a group new group * @return the generated id for this group. */ String createGroup(String groupName, String groupType); /** create a group new group * @return the generated id for this group. */ String createGroup(String groupName, String groupType, String parentGroupId); ... } In the next release we might switch to user provided ID's for these 3 methods.

2.12. Task forms


Human interaction happens nowadays most of the times through web interfaces using some kind of form to capture input of the user. Using jBPM task forms, a process designer can attach such input forms to a task activity or a start activity. When using the jBPM console, the forms will automatically be displayed for user input when a process instance is started or when a task is completed. An example process (VacationRequest) is shipped with the default examples of the distribution demo.

2.12.1. Usage
Task form references can be put on start and task activities: <start form="org/jbpm/examples/taskform/request_vacation.ftl" name="start"> <transition to="verify_request"/> </start> <task candidate-users="mike,peter" form="org/jbpm/examples/taskform/verify_request.ftl" name="verify_request"> <transition name="reject" to="vacation_rejected"/> <transition name="accept" to="vacation_accepted"/> </task>

2.12.2. Form format


Task forms are plain text files containing arbitray content. However, when using the jBPM console, HTML pages containing a form element are required. The default form plugin of the console leverages the freemarker templating

24 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

library. It builds on the following constraints: Templates need to be suffixed *.ftl and be included with the deployment: deployment.addResourceFromClasspath("org/jbpm/examples/taskform/verify_request.ftl"); The action of the form must be "${form.action}" HTML forms need to provide the correct enctype: "multipart/form-data" Form field names become process variables names and vice versa A reserved field name is available for signaling execution upon task completion: "outcome" <html> <body> <form action="${form.action}" method="POST" enctype="multipart/form-data"> <h3>Your employee, ${employee_name} would like to go on vacation</h3> Number of days: ${number_of_days}<br/> <hr> In case you reject, please provide a reason:<br/> <input type="textarea" name="reason"/><br/> <#list outcome.values as transition> <input type="submit" name="outcome" value="${transition}"> </#list> </form> </body> </html>

In this example, the process variables employee_name and number_of_days is displayed on the screen using a variable reference expression. The value of the input field reason will be stored as a process variable. The jBPM console will render the taskforms automatically:

2.13. Instance Migration


By default the behaviour of jBPM upon redeployment is to start new process instances with the newly deployed version. Also, it is possible to start new process instances using a specified older version if needed. The existing running process instances always keep running following the definition that they were started in. But what when a customer or some piece of legislation mandates that this behaviour is not enough? We could e.g. think of a situation where process instances do not make sense anymore when a new definition is deployed. In this case these instances should be ended. In another situation it might be needed that all (or even some particular) instances are migrated and moved to the newly deployed definition. jBPM contains a tool that exactly supports these use cases. Before delving into the details of the instance migration tool, we have to warn the reader. Though we did a reasonable attempt at trying to understand the different use cases, there are certainly a number of situations that are not yet covered. For now we have concentrated on the limited case where the nodes that are involved in the migration are states. The goal is to expand this support to other nodes (e.g. human tasks) in the future. We welcome any feedback

25 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

around these use cases very eagerly. For all the examples that follow, we will start from the same original process definition: <process name="foobar"> <start> <transition to="a"/> </start> <state name="a"> <transition to="b"> </state> <state name="b"> <transition to="c"/> </state> <state name="c"> <transition to="end"/> </state> <end name="end"/> </process>

2.13.1. Simple Migration


The first obvious use case that we wanted to cover is where a new version of a process is deployed for which one of the following statements is true: the structure of the process is completely the same and all the nodes have the same name only new nodes have been added but all the nodes from the previous definition still exist This use case might be useful if for instance event handler names change between versions, if new processing has to be inserted or if new paths of execution have to be added. Consider the following modification of the above process definition to indicate that running instances have to be migrated: <process name="foobar"> <start> <transition to="a"/> </start> <state name="a"> <transition to="b"> </state> <state name="b"> <transition to="c"/> </state> <state name="c"> <transition to="end"/> </state> <end name="end"/> <migrate-instances/> </process>

When this second process is deployed the running instances of the previous version - and only of the previous version - will be migrated to the new version. We"ll explain later what to do if you want more than only the instances of the previous version to be migrated. Assume that when deploying the second version there would be one process instance in the state "a" and one process instance in the state "b". The following snippet in a unit test would be valid: ProcessDefinition pd1 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi1 = startAndSignal(pd1, "a"); ProcessInstance pi2 = startAndSignal(pd1, "b"); ProcessDefinition pd2 = deployProcessDefinition("foobar", versionWithSimpleMigration); pi1 = executionService.findProcessInstanceById(pi1.getId()); pi2 = executionService.findProcessInstanceById(pi2.getId()); assertEquals(pd2.getId(), pi1.getProcessDefinitionId()); assertEquals(pd2.getId(), pi2.getProcessDefinitionId()); assertEquals(pi1, pi1.findActiveExecutionIn("a")); assertEquals(pi2, pi2.findActiveExecutionIn("b"));

2.13.2. Ending Running Instances


The second use case is when the instances of the previous process definition have to be ended. The way to indicate this would be to add the action attribute to the migrate-instances tag with the value of "end".

26 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="foobar"> ... <migrate-instances action="end"/> </process>

If we take the situation from above with one process in state "a" and another in state "b" the two processes would be ended as can be seen in the following snippet: ProcessDefinition pd1 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi1 = startAndSignal(pd1, "a"); ProcessInstance pi2 = startAndSignal(pd1, "b"); ProcessDefinition pd2 = deployProcessDefinition("foobar", versionWithSimpleAbortion); pi1 = executionService.findProcessInstanceById(pi1.getId()); pi2 = executionService.findProcessInstanceById(pi2.getId()); assertNull(pi1); assertNull(pi2);

2.13.3. Version Ranges


So we've showed you how instances of the previously deployed version - and only that one - could be either migrated or ended. But what to do when you want to perform these actions on process instances of other already deployed versions. This can be done by making use of the versions attribute of the migrate-instances tag. This attribute lets you specify a range of versions that need to be migrated (or ended). Consider the following process definition: <process name="foobar"> <start> <transition to="a"/> </start> <state name="a"> <transition to="b"> </state> <state name="b"> <transition to="c"/> </state> <state name="c"> <transition to="end"/> </state> <end name="end"/> <migrate-instances versions="2..3"/> </process>

Imagine a situation where we would deploy the original process definition 4 times in a row and for each deployment start a process instance that waits in state "a". Then we deploy the above version of the process definition with instance migration. The result will be that instance 2 and instance 3 will be migrated while instance 1 and instance 4 will keep running following their original definition. This is shown in the snippet below: ProcessDefinition pd1 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi1 = startAndSignal(pd1, "a"); ProcessDefinition pd2 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi2 = startAndSignal(pd2, "a"); ProcessDefinition pd3 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi3 = startAndSignal(pd3, "a"); ProcessDefinition pd4 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi4 = startAndSignal(pd4, "a"); ProcessDefinition pd5 = deployProcessDefinition("foobar", versionWithAbsoluteVersionRange); pi1 = executionService.findProcessInstanceById(pi1.getId()); pi2 = executionService.findProcessInstanceById(pi2.getId()); pi3 = executionService.findProcessInstanceById(pi3.getId()); pi4 = executionService.findProcessInstanceById(pi4.getId()); assertEquals(pd1.getId(), pi1.getProcessDefinitionId()); assertEquals(pd5.getId(), pi2.getProcessDefinitionId()); assertEquals(pd5.getId(), pi3.getProcessDefinitionId()); assertEquals(pd4.getId(), pi4.getProcessDefinitionId());

A number of variants exist for the versions attribute. The example above uses an absolute version range. It is also possible to use an expression of the form x-n to indicate a version number relative to the last deployed version. So if you want to only migrate instances from the last two versions you could use the following expression for the versions attribute:

27 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process name="foobar"> ... <migrate-instances versions="x-2..x"/> </process>

You can also mix and match the absolute and the relative specifications. E.g. if you would like to migrate all the instances of all the versions to the newly deployed version you can use the following: <process name="foobar"> ... <migrate-instances versions="1..x"/> </process>

And for this last example you can also use the "*" wildcard notation: <process name="foobar"> ... <migrate-instances versions="*"/> </process>

2.13.4. Activity Mappings


In some cases users will want to map nodes from the previously deployed process definition to nodes of the newly deployed process definition. This could be the case when in the newly deployed process definition some nodes are deleted or have been replaced by nodes with a different name. To support this use case it is possible to specify so-called activity-mapping elements. These elements have two attributes: the activity name in the old process definition and the activity name in the new process definition. Consider the following process definition: <process name="foobar"> <start> <transition to="a"/> </start> <state name="a"> <transition to="b"> </state> <state name="b"> <transition to="c"/> </state> <state name="c"> <transition to="d"/> </state> <state name="d"> <transition to="end"/> </state> <end name="end"/> <migrate-instances> <activity-mapping old-name="b" new-name="a"/> <activity-mapping old-name="c" new-name="d"/> </migrate-instances> </process>

Deploying this process will put all the instances of the previously deployed process that are waiting in the state "b" into the state "a" of the newly deployed process. Likewise all instances of the previously deployed process definition that are waiting in state "c" will be placed in the state "d". The following piece of code illustrates this:

28 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

ProcessDefinition pd1 = deployProcessDefinition("foobar", originalVersion); ProcessInstance pi1 = startAndSignal(pd1, "a"); ProcessInstance pi2 = startAndSignal(pd1, "b"); ProcessInstance pi3 = startAndSignal(pd1, "c"); ProcessDefinition pd2 = deployProcessDefinition("foobar", versionWithCorrectMappings); pi1 = executionService.findProcessInstanceById(pi1.getId()); pi2 = executionService.findProcessInstanceById(pi2.getId()); pi3 = executionService.findProcessInstanceById(pi3.getId()); assertEquals(pd2.getId(), pi1.getProcessDefinitionId()); assertEquals(pd2.getId(), pi2.getProcessDefinitionId()); assertEquals(pd2.getId(), pi3.getProcessDefinitionId()); assertEquals(pi1, pi1.findActiveExecutionIn("a")); assertEquals(pi2, pi2.findActiveExecutionIn("a")); assertEquals(pi3, pi3.findActiveExecutionIn("d")); pi1 = executionService.signalExecutionById(pi1.getId()); pi2 = executionService.signalExecutionById(pi2.getId()); pi2 = executionService.signalExecutionById(pi2.getId()); pi3 = executionService.signalExecutionById(pi3.getId()); assertEquals(pi1, pi1.findActiveExecutionIn("b")); assertEquals(pi2, pi2.findActiveExecutionIn("c")); assertTrue(pi3.isEnded());

2.13.5. Migration Handlers


We already mentioned that there are a lot of use cases that we probably didn't think of or for which there was not enough time to build support. Exactly for this reason we provide the concept of a migration handler. This is a user defined piece of code that implements the interface "org.jbpm.pvm.internal.migration.MigrationHandler": public interface MigrationHandler { void migrateInstance( ProcessDefinition newProcessDefinition, ProcessInstance processInstance, MigrationDescriptor migrationDescriptor); }

This migration handler can be specified in the process definition xml and will be executed for each process instance that has to be migrated. Experienced users can use this to do all kinds of bookkeeping they need to do when migrating (or ending) process instances. To perform this bookkeeping, it gets of course a handle to the process instance that needs to be migrated, but also to the new process definition and to a so called migration descriptor that contains among others the migration mapping. Take e.g. the following example: <process name="foobar"> ... <migrate-instances> <migration-handler class="org.jbpm.test.migration.TestHandler"/> </migrate-instances> </process>

In this case the specified migration handler will be executed for each process instance that needs to be migrated AFTER the default migration has been done. If the attribute action is set to "end" the migration handler will be called BEFORE the process instance is ended. If more than one migration handler is specified, they will be executed one after another.

2.14. User object caching


As indicated in section "User code" in the Users guide, instantiated user objects are by default cached as part of the process definition. So the single user object will be used to serve all requests. So you have to make sure that when your user code is used, that it doesn't change the member fields of the user object. In that case it will be safe for your user object to be used by all threads/requests. This is also called stateless user objects. In case you do have a need for stateful user objects, you can specify parameter cache="disabled" on the definition of the user code. In that case a new user object will be instatiated for every usage.

2.15. Transactions

29 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

2.15.1. Standalone transactions


TODO

2.15.2. JTA transactions


TODO

2.15.3. User transactions


In your project you might have user domain objects like e.g. an Order or Claim object in your project mapped with hibernate. This section explains how to combine updates to user domain objects with jBPM operations in a single transaction. Here's an example of a user command: public class MyUserCommand implements Command<Void> { public Void execute(Environment environment) throws Exception { // your user domain objects // an example jBPM operation ExecutionService executionService = environment.get(ExecutionService.class); executionService.signalExecutionById(executionId); return null; } } Then such commands can be executed by the ProcessEngine: processEngine.execute(new MyUserCommand());

Chapter 3. BPMN 2.0


3.1. What is BPMN 2.0? 3.2. 3.3. 3.4. 3.5. 3.6. 3.7. History and goal JPDL vs BPMN 2.0 Bpmn 2.0 execution Configuration Examples Process root element constructs Events Event: None start event Event: None end event Event: Terminate end event

3.8. Basic 3.8.1. 3.8.2. 3.8.3. 3.8.4.

3.8.5. Sequence Flow 3.8.6. Gateways 3.8.7. Gateway: Exclusive Gateway 3.8.8. Gateway: Parallel Gateway 3.8.9. Gateway: Inclusive Gateway 3.8.10. Tasks 3.8.11. Task: User Task 3.8.12. Task: Java Service Task 3.8.13. Task: Script Task 3.8.14. Task: Manual task 3.8.15. Task: Java Receive task 3.9. Advanced constructs 3.9.1. Embedded sub-process 3.9.2. Timer start event 3.9.3. Intermediate events 3.9.4. Intermediate catch event: Timer 3.10. Complete example (including console task forms)

30 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

3.1. What is BPMN 2.0?


The Business Process Modeling Notation (BPMN) is a standard for the graphical notation of business process models. The standard is maitained by the Object Management Group (OMG). Basically, the BPMN specification defines how a task must look like, which constructs can be connected to each other, etc. in a meaning that cannot be misinterpreted. Earlier versions of the standard (<= version 1.2) are limited to the modeling only, aiming at a common understanding between all stakeholders involved in documenting, discussing and implementing business processes. The BPMN standard has proven itself, as many modeling tools on the market today use the symbols and constructs specified in the BPMN standard. In fact, the current JPDL designer also uses BPMN symbols. Version 2.0 of the BPMN specification, which is currently in finalization phase and is scheduled to be finished soon, allows to add precise technical details to the shapes and symbols available in BPMN and at the same time specify what the execution semantics of BPMN 'elements' are. By using an XML language to specify the executable semantics of a business process, the BPMN specification has evolved into a language for business processes that can be executed on any BPMN2 compliant process engine - while still having the powerful graphical notation.

3.2. History and goal


The jBPM BPMN2 implementation was started in close collaboration with the community in augustus 2009 after releasing jBPM 4.0. Later, it was decided that the first release (ie documented/QA'd) to incorporate parts of the BPMN2 spec would be jBPM 4.3. The goal of this effort is to build a native BPMN2 runtime engine (or better said implementing 'BPMN2 exectuable') leveraging the Process Virtual Machine (PVM). Do note that the primary focus of this release is native executability, not the graphical notation - but we recognize its importance for further releases. Users who are already familiar with jBPM will find that the configuration mechanism remains unchanged the API is the same or very similar to the existing one testing BPMN2 process still can be done with regular Java testing frameworks the database schema remains unchanged So in general, our main goal is to keep everything that was good about jBPM, and enhance it with a standards based process language.

3.3. JPDL vs BPMN 2.0


One of the first questions that might, rightfully, come to mind is why BPMN2 is being implemented while there is jPDL. Both are languages have as goal to define executable business processes. From a high-level technical point of view, both languages are equivalent. The main distinction is that BPMN2 is as vendor-neutral as you can have with standards, while JPDL has always been tied to jBPM (although some might argue that a vendor lock-in for an open-source process language such as JPDL is less a lock-in than with closed-source products). Within jBPM, both language implementations are built on top of the jBPM Process Virtual Machine (PVM). This means that both languages share a common foundation (persistence, transactions, configuration, but also basic process constructs, etc.). As a result, optimizations to the core of jBPM often benefits both languages. Leveraging the PVM, the BPMN2 implementation is built upon a foundation that has already proven itself in the past and has a large end-user community. When evaluating the languages and comparing them which each other however, following points must be taken into consideration: BPMN2 is based on a standard accepted by the BPM industry. BPMN2 is implementation-unaware. The downside of this is that integrating with Java technology will always be easier with JPDL. So, from a Java developer's perspective JPDL is simpler and feels more natural (some of the 'layers' of BPEL/WSDL are in BPMN as well). A focus of JPDL is XML readability. BPMN2 processes will still be readable to a certain level, but tooling or a more detailed knowledge of the spec will definitely be required to achieve the same level of productivity. Java developers who are super-fast in JPDL since they know the JPDL language by heart, will find the use of tools sometimes bothersome and the language itself overly complicated.

31 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

BPMN2 contains a large set of constructs described in the specification. However, the "binding" of interfaces to code is left open in the spec (comparable with XPDL), even if WDSL is often considered the default. This means that a process portability can be lost when porting the process to an engine that doesn't support the same binding mechanism. Calling Java classes for example is already going to be such a jBPM specific binding. It is natural to the political level of BPMN2 specification process to go rather slow. JPDL on the other hand will be able to incorporate changes faster, integrate with new technologies when they are released and evolve generally at a quicker pace compared to BPMN2. Of course, since both are built on top of the same PVM, it is only logical that additions to JPDL can be ported to BPMN2 as an extension without much hassle.

3.4. Bpmn 2.0 execution


The BPMN2 specification defines a very rich language for modeling and executing business processes. However, this also means that it is quite hard to get an overview of what's possible with BPMN2. To simplify this situation, we've decided to categorize the BPMN2 constructs into three 'levels'. The separation itself is primarily based on the book 'BPMN method and Style' by Bruce Silver (http://www.bpmnstyle.com/), the training material of Dr. Jim Arlow (http://www.slideshare.net/jimarlow/introductiontobpmn005), 'How much BPMN do you need' (http://www.bpmresearch.com/2008/03/03/how-much-bpmn-do-you-need/), and also our own experience. We define three categories of BPMN2 constructs: Basic: constructs in this category are straight-forward and easy to grasp. Constructs in this category can be used to model simple business processes. Advanced: contains more powerful or expressive constructs, but this comes with higher modeling and execution semantics learning curve. The majority of business processes are implementable with constructs from this and the previous category. Complex: constructs in this category are used in specific and/or rare cases, or their semantics are difficult to understand.

3.5. Configuration
Enabling BPMN 2.0 in your application is extremely simple: just add the following line to the jbpm.cfg.xml file. <import resource="jbpm.bpmn.cfg.xml" />

This import will enable BPMN 2.0 process deployment by installing a BPMN 2.0 deployer in the Process Engine. Do note that a Process Engine can cope with both JPDL and BPMN 2.0 processes. This means that in your application, some processes can be JPDL and others can be BPMN 2.0. Process definitions are distinguished by the process engine based on the extension of the definition file. For BPMN 2.0, use the *.bpmn.xml extension (where JPDL is having the *.jpdl.xml extension).

3.6. Examples
The examples that are shipped with the distribution also contain examples for every construct that is discussed in the following sections. Look for example BPMN 2.0 processes and test cases in the org.jbpm.examples.bpmn.* package . See the userguide, chapter 2 (Installation), for a walktough on how to import the examples. Look for the section 'Importing the Examples'.

3.7. Process root element


The root of an BPMN 2.0 XML process is the definitions elements. As the name states, the subelements will contain the actual definitions of the business process(es). Every process child will be able to have an id (required) and name (optional). An empty business process in BPMN 2.0 looks as follows. Also note that it is handy to have the BPMN2.xsd on the classpath, to enable XML completion.

32 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<definitions id="myProcesses" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schema.omg.org/spec/BPMN/2.0 BPMN20.xsd" xmlns="http://schema.omg.org/spec/BPMN/2.0" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://jbpm.org/example/bpmn2"> <process id="My business processs" name="myBusinessProcess"> ... </process> <definitions>

If a name is defined for the process element, it is be used as key for that process (ie. starting a process can be done by calling executionService.startProcessInstanceByKey("myBusinessProcess"). If no name is defined, the id will be used as key. So having only an id defined, will allow to start a process instance using that id. So basically, name and key are of equivalent in usage, for example to search process definitions. Note that for a key the same rules apply as with JPDL: whitespace and non alpha-numeric characters are replaced by an underscore.

3.8. Basic constructs


3.8.1. Events
Together with activitites and gateways, events are used in practically every business process. Events allow process modelers to describe business processes in a very natural way, such as 'This process starts when I receive a customer order', 'If the task is not finished in 2 days, terminate the process' or 'When I receive a cancel e-mail when the process is running, handle the e-mail using this sub-process'. Notice that typical businesses always work in a very event-driven way. People are not hard-coded sequential creatures, but they tend to react on things that happen in their environment (ie. events). In the BPMN specification, a great number of event types are described, to cover the range of possible things that might occur in context of a business.

3.8.2. Event: None start event


A start event indicates the start of process (or a subprocess). Graphically, it is visualized as a circle with (possibly) a small icon inside. The icon specifies the actual type of event that will trigger the process instance creation. The 'none start event' is drawn as a circle without an icon inside, which means that the trigger is unknown or unspecified. The start activity of JPDL basically has the same semantics. Process instances whose process definition has a 'none start event' are created using the typical API calls on the executionService. A none start event is defined as follows. An id is required, a name is optional. <startEvent id="start" name="myStart" />

3.8.3. Event: None end event


An end event indicates the end of an execution path in a process instance. Graphically, it is visualized as a circle with a thick border with (possibly) a small icon inside. The icon specifies the type of signal that is thrown when the end is reached. The 'none end event' is drawn as a circle with thick border with no icon inside, which means that no signal is thrown when the execution reaches the event. The end activity in JPDL has the same semantics as the none end event. A none end event is defined as follows. An id is required, a name is optional. <endEvent id="end" name="myEnd" />

The following example shows a process with only a none start and end event:

33 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The corresponding executable XML for this process looks like this (omitting the definitions root element for clarity) <process id="noneStartEndEvent" name="BPMN2 Example none start and end event"> <startEvent id="start" /> <sequenceFlow id="flow1" name="fromStartToEnd" sourceRef="start" targetRef="end" /> <endEvent id="end" name="End" /> </process>

A process instances can now be created by calling the startProcessInstanceXXX operations. ProcessInstance processInstance = executionService.startProcessInstanceByKey("noneStartEndEvent");

3.8.4. Event: Terminate end event


The difference between a 'terminate' and a 'none' end event lies in the fact how a path of execution is treated (or a 'token' in BPMN 2.0 terminology). The 'terminate' end event will end the complete process instance, whereas the 'none' end event will only end the current path of execution. They both don't throw anything when the end event is reached. A terminate end event is defined as follows. An id is required, a name is optional. <endEvent id="terminateEnd" name="myTerminateEnd"> <terminateEventDefinition/> </endEvent>

A terminate end event is depicted as an end event (circle with thick border), with a full circle as icon inside. In the following example, completing the 'task1' will end the process instance, while completing the 'task2' will only end the path of execution which enters the end event, leaving the task1 open.

See the examples shipped with the jBPM distribution for the unit test and XML counterpart of this business process.

3.8.5. Sequence Flow


A sequence flow is the connection between events, activities and gateways shown as a solid line with an arrow in a BPMN diagram (JPDL equivalent is the transition). Each sequence flow has exactly one source and exactly one target reference, that contains the id of an activity, event or gateway.

34 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<sequenceFlow id="myFlow" name="My Flow" sourceRef="sourceId" targetRef="targetId" />

An important difference with JPDL is the behaviour of multiple outgoing sequence flows. In JPDL, only one transition is selected as outgoing transition, unless the activity is a fork (or a custom activity with fork behaviour). However, in BPMN, the standard behaviour of multiple outgoing sequence flow is to split the incoming token ('execution' in jBPM terminology) into a collection of tokens, one for each outgoing sequence flow. In the following situation, after completing the first task, there will be three tasks activated instead of one.

To avoid that a certain sequence flow is taken, one has to add a condition to the sequence flow. At runtime, only when the condition evaluates to true, that sequence flow will be taken. To put a condition on a sequence flow, add a conditionExpression element to the sequence flow. Conditions are to be put between ${}. <sequenceFlow id=....> <conditionExpression xsi:type="tFormalExpression">${amount >= 500}</conditionExpression> </sequenceFlow>

Note that is currently is necessary to add the xsi:type="tFormalExpression" to the conditionExpression. A conditional sequence flow is visualized as a mini diamond shape at the beginning of the sequence flow. Keep in mind that conditions always can be defined on sequence flow, but some constructs will not interprete them (eg. parallel gateway). Activities (such as the user task) and gateways (such as the exclusive gateway) can have a default sequence flow. This default sequence flow is taken only when all the other outgoing sequence flow from an activity or gateway have a condition that evaluate to false. A default sequence flow is graphically visualized as a sequence flow with a 'slash marker'.

The default sequence flow is specified by filling in the 'default' attribute of the activity or gateway. Also note that an expression on a default sequence flow is ignored.

3.8.6. Gateways
A gateway in BPMN is used to control the flow through the process. More specifically, when a token (the BPMN 2.0 conceptual notion of an execution) arrives in a gateway, it can be merged or split depending on the gateway type. Gateways are depicted as a diamond shape, with an icon inside specifying the type (exclusive, inclusive, etc.). On every gateway type, the attribute gatewayDirection can be set. following values are possible:

35 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

unspecificed (default): the gateway may have multiple incoming and multiple sequence flow. mixed: the gateway must have multiple incoming and multiple outgoing sequence flow. converging: the gateway must have multiple incoming sequence flow, but can have only one outgoing sequence flow. diverging: the gateway must have only one incoming sequence flow and multiple outgoing sequence flow. Take for example the following example: a parallel gateway that has as gatewayDirection 'converging', will have a join behaviour. <parallelGateway id="myJoin" name="My synchronizing join" gatewayDirection="converging" />

Note: the 'gatewayDirection' attribute is optional according to the specification. This means that we cannot rely on this attribute at runtime to know which type of behaviour a certain gateway has (for example for a parallel gateway if we have joining of forking behaviour). However, the 'gatewayDirection' attribute is used at parsing time as a constraint check for the incoming/outgoing sequence flow. So using this attribute will lower the chance on errors when referencing sequence flow, but is not required.

3.8.7. Gateway: Exclusive Gateway


An exclusive gateway represents an exclusive decision in the process. Exactly one outgoing sequence flow will be taken, depending on the conditions defined on the sequence flow. The corresponding JPDL construct with the same semantics is the decision activity. The full technical name of the exclusive gateway is the 'exclusive data-based gateway', but it is also often called the XOR Gateway. The XOR gateway is depicted as a diamond with a 'X' icon inside. An empty diamond without a gateway also signifies an exclusive gateway. The following diagram shows the usage of an exclusive gateway: depending on the value of the amount variable, one of the three outgoing sequence flow out of the exclusive gateway is chosen.

The corresponding executable XML of this process looks as follows. Note that the conditions are defined on the sequence flow. The exclusive gateway will select the single sequence flow for which its condition evaluates to true. If multiple conditions evaluate to true, the first one encountered will be taken (a log message will indicate this situation).

36 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process id="exclusiveGateway" name="BPMN2 Example exclusive gateway"> <startEvent id="start" /> <sequenceFlow id="flow1" name="fromStartToExclusiveGateway" sourceRef="start" targetRef="decideBasedOnAmountGateway" /> <exclusiveGateway id="decideBasedOnAmountGateway" name="decideBasedOnAmount" /> <sequenceFlow id="flow2" name="fromGatewayToEndNotEnough" sourceRef="decideBasedOnAmountGateway" targetRef="endNotEnough"> <conditionExpression xsi:type="tFormalExpression"> ${amount < 100} </conditionExpression> </sequenceFlow> <sequenceFlow id="flow3" name="fromGatewayToEnEnough" sourceRef="decideBasedOnAmountGateway" targetRef="endEnough"> <conditionExpression xsi:type="tFormalExpression"> ${amount <= 500 && amount >= 100} </conditionExpression> </sequenceFlow> <sequenceFlow id="flow4" name="fromGatewayToMoreThanEnough" sourceRef="decideBasedOnAmountGateway" targetRef="endMoreThanEnough"> <conditionExpression xsi:type="tFormalExpression"> ${amount > 500} </conditionExpression> </sequenceFlow> <endEvent id="endNotEnough" name="not enough" /> <endEvent id="endEnough" name="enough" /> <endEvent id="endMoreThanEnough" name="more than enough" /> </process>

This process needs a variable such that the expression can be evaluated at runtime. Variables can be provided when starting the process instance (similar to JPDL): Map<String, Object> vars = new HashMap<String, Object>(); vars.put("amount", amount); ProcessInstance processInstance = executionService.startProcessInstanceByKey("exclusiveGateway", vars);

The exclusive gateway requires that all outgoing sequence flow have conditions defined on them. An exception to this rule is the default sequence flow. Use the default attribute to reference an existing id of a sequence flow. This sequence flow will be taken when the conditions on the other outgoing sequence flow all evaluate to false. <exclusiveGateway id="decision" name="decideBasedOnAmountAndBankType" default="myFlow"/> <sequenceFlow id="myFlow" name="fromGatewayToStandard" sourceRef="decision" targetRef="standard"> </sequenceFlow>

An exclusive gateway can have both convering and diverging functionality. The logic is easy to grasp: for every execution that arrives at the gateway, one outgoing sequence flow is selected to continue the flow. The following diagram is completely legal in BPMN 2.0 (omitting names and conditions for clarity).

37 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

3.8.8. Gateway: Parallel Gateway


A parallel gateway is used to split or synchronize the respectively incoming or outgoing sequence flow. A parallel gateway with one incoming sequence flow and more than one outgoing sequence flow is called a 'parallel split or an 'AND-split'. All outgoing sequence flow are going to be taken in parallel. Note: as defined by the specification, conditions on the outgoing sequence flow are ignored. A parallel gateway with multiple incoming sequence flow and one outgoing sequence flow is called a 'parallel join' or an AND-join. All incoming sequence flow need to arrive in this parallel joing before the outgoing sequence flow is taken. A parallel gateway is defined as follows: <parallelGateway id="myParallelGateway" name="My Parallel Gateway" />

Note that the 'gatewayDirection' attribute can be used to catch modeling errors at parsing time (see above). The following diagram shows how a parallel gateway can be used. After process start, both the 'prepare shipment' and 'bill customer' user tasks will be active. The parallel gateway is depicted as a diamond shape with a plus icon inside, both for the splitting and joining behaviour.

The XML counterpart of this diagram looks as follows:

38 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process id="parallelGateway" name="BPMN2 example parallel gatewar"> <startEvent id="Start" /> <sequenceFlow id="flow1" name="fromStartToSplit" sourceRef="Start" targetRef="parallelGatewaySplit" /> <parallelGateway id="parallelGatewaySplit" name="Split" gatewayDirection="diverging"/> <sequenceFlow id="flow2a" name="Leg 1" sourceRef="parallelGatewaySplit" targetRef="prepareShipment" /> <userTask id="prepareShipment" name="Prepare shipment" implementation="other" /> <sequenceFlow id="flow2b" name="fromPrepareShipmentToJoin" sourceRef="prepareShipment" targetRef="parallelGatewayJoin" /> <sequenceFlow id="flow3a" name="Leg 2" sourceRef="parallelGatewaySplit" targetRef="billCustomer" /> <userTask id="billCustomer" name="Bill customer" implementation="other" /> <sequenceFlow id="flow3b" name="fromLeg2ToJoin" sourceRef="billCustomer" targetRef="parallelGatewayJoin" /> <parallelGateway id="parallelGatewayJoin" name="Join" gatewayDirection="converging"/> <sequenceFlow id="flow4" sourceRef="parallelGatewayJoin" targetRef="End"> </sequenceFlow> <endEvent id="End" name="End" /> </process>

A parallel gateway (as is the case for any gateway) can have both splitting and merging behaviour. The following diagram is completely legal BPMN 2.0. After process start, both task A and B will be active. When both A en B are completed, tasks C,D and E will be active.

3.8.9. Gateway: Inclusive Gateway

39 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

An inclusive gateway - also called an OR-gateway - is used to 'conditionally' split or merge sequence flow. It basically behaves as a parallel gateway, but it also takes in account conditions on the outgoing sequence flow (split behaviour) and calculates if there are executions left that could reach the gateway (merge behaviour). The inclusive gateway is depicted as a typical gateway shape with a circle inside (referring to 'OR' semantics). Unlike the exclusive gateway, all condition expressions are evaluated (diverging or 'split' behaviour). For every expression that evaluates to true, a new child execution is created. Sequence flow without a condition will always be taken (ie. a child execution will always be created in that case). A converging inclusive gateway ('merge' behaviour) has a somewhat more difficult execution logic. When an execution (Token in BPMN 2.0 terminology) arrives at the merging inclusive gateway, the following is checked (quoting the specification literally): For each empty incoming sequence flow, there is no Token in the graph anywhere upstream of this sequence flow, i.e., there is no directed path (formed by Sequence Flow) from a Token to this sequence flow unless a) the path visits the inclusive gateway or b) the path visits a node that has a directed path to a non-empty incoming sequence flow of the inclusive gateway. "

In more simple words: when an execution arrives at the gateway, all active execution are checked if they can reach the inclusive gateway, by only taking in account the sequence flow (note: conditions are not evaluated!). When the inclusive gateway is used, it is usally used in a pair of splitting/merging inclusive gateways. In those cases, the execution behaviour is easy enough to grasph by just looking at the model. Of course, it is not hard to imagine situations where the executions are split and merged in complex combinations using a variety of constructs including the inclusive gateway. In those cases, it could very well be that the actual execution behaviour might not be what the modelers' expects. So be careful when using the inclusive gateway and keep in mind that it is often the best practice to use inclusive gateways just in pairs. The following diagram shows how the inclusive gateway can be used. (example taken from "BPMN method and style" by Bruce Silver)

We can distinguish following cases: Cash more than 10000 and not a foreign bank: Only the "Large deposit" task will be active. Cash more than 10000 and a foreign bank: Both the "Large deposit" and "Foreign deposit" task will be active. Cash lower than 10000 and a foreign bank: Only the "Foreign deposit" task will be active. Cash lower than 10000 and not a foreign bank: In this case, both expressions evaluate to false. The default sequence flow will now be chosen. In this example, this means that the "Standard deposit" task is active. No matter how many tasks are active after going through the inclusive gateway, the converging inclusive gateway on the right will wait until all outgoing sequence flow of the inclusive gateway on the left have reached the merging gateway (sometimes only one, sometimes two). Take a look at org.jbpm.examples.bpmn.gateway.inclusive.InclusiveGatewayTest to see how this example reflects in a unit test.

40 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The XML version of the example above looks as follows: <process id="inclusiveGateway" name="BPMN2 Example inclusive gateway"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="inclusiveGatewaySplit" /> <inclusiveGateway id="inclusiveGatewaySplit" default="flow3"/> <sequenceFlow id="flow2" sourceRef="inclusiveGatewaySplit" targetRef="largeDeposit"> <conditionExpression xsi:type="tFormalExpression">${cash > 10000}</conditionExpression> </sequenceFlow> <sequenceFlow id="flow3" sourceRef="inclusiveGatewaySplit" targetRef="standardDeposit" /> <sequenceFlow id="flow4" sourceRef="inclusiveGatewaySplit" targetRef="foreignDeposit"> <conditionExpression xsi:type="tFormalExpression">${bank == 'foreign'}</conditionExpression> </sequenceFlow> <userTask id="largeDeposit" name="Large deposit" /> <sequenceFlow id="flow5" sourceRef="largeDeposit" targetRef="inclusiveGatewayMerge" /> <userTask id="standardDeposit" name="Standard deposit" /> <sequenceFlow id="flow6" sourceRef="standardDeposit" targetRef="inclusiveGatewayMerge" /> <userTask id="foreignDeposit" name="Foreign deposit" /> <sequenceFlow id="flow7" sourceRef="foreignDeposit" targetRef="inclusiveGatewayMerge" /> <inclusiveGateway id="inclusiveGatewayMerge" /> <sequenceFlow id="flow8" sourceRef="inclusiveGatewayMerge" targetRef="theEnd" /> <endEvent id="theEnd" /> </process>

As with any gateway type, the inclusive gateway type can have both merging and splitting behaviour. In that case, the inclusive gateway will first wait until all executions have arrived, before splitting again for every sequence flow that has a condition that evauluates to true (or doesn't have a condition).

3.8.10. Tasks
A task represents work that needs to be done by an external entity, such as a human actor or an automated service. It's important to note that the BPMN semantics of a 'task' differ from the JPDL semantics. In JPDL, the concept 'task' is always used in the context of a human actor doing some type of work. When the process engine encounters a task in JPDL, it will create a task in some human actor's task list and it will behave as a wait state. In BPMN 2.0 however, there are several task types, some indicating a wait state (eg. the User Task and some indicating an automatic activity (eg. the Service Task). So take good care not to confuse the meaning of the task concept when switching languages. Tasks are depicted by a rounded rectangle, typically containing a text inside. The type of the task (user task, service task, script task, etc.) is shown as a little icon on the left top corner of the rectangle. Depending on the task type, the engine will execute different functionality.

3.8.11. Task: User Task

41 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

A User task is the typical 'human task' that is found in practically every workflow or BPM software out there. When process execution reaches such a user task, a new human task is created in task list for a given user. The main difference with a manual task (which also signifies work for a human actor) is that the task is known to the process engine. The engine can track the completion, assignee, time, etc which is not the case for a manual task. A user task is depicted as a rounded rectangle with a small user icon in the top left corner.

A user task is defined as follows in the BPMN 2.0 XML: <userTask id="myTask" name="My task" />

According to the specification, multiple implementations are possible (Webservice, WS-humantask, etc.), as stated by using the implementation attribute. Currently, only the standard jBPM task mechanism is available, so there is no point (yet) in defining the 'implementation' attribute. The BPMN 2.0 specification contains quite a few ways of assigning user tasks to user(s), group(s), role(s), etc. The current BPMN 2.0 jBPM implementation allows to assign tasks using a resourceAssignmentExpression, combined with the humanPerformer or PotentialOwner construct. It is to be expected that this area will evolve future releases. A potentialOwner is used when you want to make a certain user, group, role, etc. a candidate for a certain task. Take the following example. Here the candidate group for the task 'My task' will be the 'management' group. Also note that a resource must be defined outside the process, such that the task assignment can reference the resource. In fact, any activity can reference one or more resource elements. Currently, only defining this resource is enough (since it is a required attribute by the spec), but this will be enhanced in a later release (eg. resources can have runtime parameters). <resource id="manager" name="manager" /> <process ...> ... <userTask id="myTask" name="My task"> <potentialOwner resourceRef="manager" jbpm:type="group"> <resourceAssignmentExpression> <formalExpression>management</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask>

Note that we are using a specific extension here (jbpm:type="group"), to define this is a group assignment. If this attribute is removed, the group semantics will be used as default (which would be ok in this example). Now suppose that Peter and Mary are a member of the management group (here using the default identity service): identityService.createGroup("management"); identityService.createUser("peter", "Peter", "Pan"); identityService.createMembership("peter", "management"); identityService.createUser("mary", "Mary", "Littlelamb"); identityService.createMembership("mary", "management");

Then both peter and mary can look in their task list for this task (code snippet from the example unit test):

42 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

// Peter and Mary are both part of management, so they both should see the task List<Task> tasks = taskService.findGroupTasks("peter"); assertEquals(1, tasks.size()); tasks = taskService.findGroupTasks("mary"); assertEquals(1, tasks.size()); // Mary claims the task Task task = tasks.get(0); taskService.takeTask(task.getId(), "mary"); assertNull(taskService.createTaskQuery().candidate("peter").uniqueResult()); taskService.completeTask(task.getId()); assertProcessInstanceEnded(processInstance);

When the assignment should be done to a candidate user, just use the jbpm:type="user" attribute. <userTask id="myTask" name="My User task"> <potentialOwner resourceRef="employee" jbpm:type="user"> <resourceAssignmentExpression> <formalExpression>peter</formalExpression> </resourceAssignmentExpression> </potentialOwner> </userTask>

In this example, peter will be able to find the task since he's a candidate user for the task. List<Task> tasks = taskService.createTaskQuery().candidate("peter").list();

A human performer is used when you want to assign a task directly to a certain user, group, role, etc. The way to do this looks very much like that of the potential owner. <resource id="employee" name="employee" /> <process ...> ... <userTask id="myTask" name="My User task"> <humanPerformer resourceRef="employee"> <resourceAssignmentExpression> <formalExpression>mary</formalExpression> </resourceAssignmentExpression> </humanPerformer> </userTask>

In this example, the task will be directly assigned to Mary. She can now find the task in her task list: List<Task> tasks = taskService.findPersonalTasks("mary");

Since the task assignment is done through the use of a formalExpression, it's also possible to define expressions that are evaluated at runtime. The expressions itself need to be put inside a ${}, as usual in jBPM. For example, if a process variable 'user' is defined, then it can be used inside an expression. More complex expressions are of course possible. <userTask id="myTask" name="My User task"> <humanPerformer resourceRef="employee"> <resourceAssignmentExpression> <formalExpression>${user}</formalExpression> </resourceAssignmentExpression> </humanPerformer> </userTask>

Note that it is not needed to use the 'jbpm:type' on a humanPerformer element, since only direct user assignments can be done. If a task needs to be assigned to a role or group, use the potentialOwner with a group type (when you assign a task to a group, all members of that group will always be candidate users for that group - hence the usage of potentialOwner).

3.8.12. Task: Java Service Task

43 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

A Service Task is an automatic activity that calls some sort of service, such as a web service, Java service, etc. Currently, only Java service invocations are supported by the jBPM engine, but Web service invocations are planned for a future release.

Defining a service task requires quite a few lines of XML (the BPEL influence is certainly visible here). Of course, in the near future, we expect that tooling will simplify this area a lot. A service task is defined as follows: <serviceTask id="MyServiceTask" name="My service task" implementation="Other" operationRef="myOperation" />

The service task has a required id and an optional name. The implementation attribute is used to indicate what the type of the invoked service is. Possible values are WebService, Other or Unspecified. Since we've only implemented the Java invocation, only the Other choice will do something useful for the moment. The service task will invoke a certain operation that is referenced by the operationRef attribute using the id of an operation. Such an operation is part of an interface as shown below. Every operation has at least one input message and at most one output message. <interface id="myInterface" name="org.jbpm.MyJavaServicek"> <operation id="myOperation2" name="myMethod"> <inMessageRef>inputMessage</inMessageRef> <outMessageRef>outputMessage</outMessageRef> </bpmn:operation> </interface>

For a Java service, the name of the interface is used to specificy the fully qualified classname of the Java class. The name of the operation is then used to specify the name of the method that must be called. The input/output message that represent the parameters/return value of the Java method are defined as follows: <message id="inputMessage" name="input message" structureRef="myItemDefinition1" />

Several elements in BPMN are so-called 'item-aware', including this message construct. This means that they are involved in storing or reading items during process execution. The data structure to hold these elements is specified using a reference to an ItemDefinition. In this context, the message specifies its data structure by referencing an Itemdefinition in the structureRef attribute.

<itemDefinition id="myItemDefinition1" > <jbpm:arg> <jbpm:object expr="#{var1}" /> </jbpm:arg> </itemDefinition> <itemDefinition id="myItemDefinition2"> <jbpm:var name="returnVar" /> </itemDefinition>

Do note that this is not fully standard BPMN 2.0 as by the specification (hence the 'jbpm' prefix). In fact, according to the specification, the ItemDefinition shouldn't contain more than a data structure definition. The actual mapping between input paramaters, with a ceratin data structure, is done in the ioSpecification section of the serviceTask. However, the current jBPM BPMN 2.0 implementation hasn't implemented that construct yet. So, this means that the current usage as described above, will probably change in the near future. Important note: Interfaces, ItemDefinitions and messages are defined outside a <process>. See the example ServiceTaskTest for a concrete process and unit test.

44 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

3.8.13. Task: Script Task


A script task is a an automatic activity upon which the process engine will execute a script when the task is reached. The script task is used as follows: <scriptTask id="scriptTask" name="Script Task" scriptLanguage="bsh"> <script><![CDATA[ for(int i=0; i < input.length; i++){ System.out.println(input[i] + " x 2 = " + (input[i]*2)); }]]> </script> </scriptTask>

The script task, besides the required id and the optional name, allows for specifying a scriptLanguage and a script. Since we're using JSR-223 ('Scripting for the Java platform'), changing the script language involves changing the scriptLanguage attribute to the JSR-223 compliant name adding the ScriptEngine implementation of the JSR specification to the classpath The XML above is visualized as follows (adding a none start and end event).

As shown in the example, process variables can be used inside the scripts. We can now start a process instance for this example process, while also supplying some random input variables: Map<String, Object> variables = new HashMap<String, Object>(); Integer[] values = { 11, 23, 56, 980, 67543, 8762524 }; variables.put("input", values); executionService.startProcessInstanceBykey("scriptTaskExample", variables);

In the output console, we can now see the script being executed: 11 x 2 = 22 23 x 2 = 46 56 x 2 = 112 980 x 2 = 1960 67543 x 2 = 135086 8762524 x 2 = 17525048

3.8.14. Task: Manual task

A manual task is a task that is performed by an external actor, but without the aid of a BPM system or a service that is invoked. In the real world, examples are plenty: the installation of telephone system, sending of a letter using regular mail, calling a customer by phone, etc. <manualTask id="myManualTask" name="Call customer" />

The purpose of the manual task is more documentation/modeling-wise, as it has no meaning for execution on a

45 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

process engine. As such, the process engine will simply pass through a manual task when it encounters one.

3.8.15. Task: Java Receive task


A receive task is a task that waits for the arrival of an external message. Besides the obvious use case involving webservices, the specification is liberal in what to do in other environments. The web service use case is not yet implemented, but the receive task can already be used in a Java environment. The receive task is depicted as a rounded rectangle (= task shape) with a little enveloppe in the left top corner.

In a Java environment, the receive task without any other attribute filled in besides an id and (optionally) a name, behaves as a wait state. To introduce a wait state in your business process, just add the following line: <receiveTask id="receiveTask" name="wait" />

Process execution will wait in such a receive task. The process can then be continued using the familiar jBPM signal methods. Note that this will probably change in the future, since a 'signal' has a completely different meaning in BPMN 2.0. Execution execution = processInstance.findActiveExecutionIn("receiveTask"); executionService.signalExecutionById(execution.getId());

3.9. Advanced constructs


3.9.1. Embedded sub-process
Subprocesses are in the first place a way of making a process "hierarchical", meaning that a modeller can create several 'levels' of detail. The top level view then explains the high-level way of doing things, while the lowest level focusses on the nitty gritty details. Take for example the following diagram. In this model, only the high level steps are shown. The actual implementation of the "Check credit" step is hidden behind a collapsed subprocess, which may be the perfect level of detail to discuss business processes with end-users.

The second major use case for sub-processes is that the sub-process "container" acts as a scope for events. When an event is fired from within the sub-process, the catch events on the boundary of the sub-process will be the first to receive this event. A sub-process that is defined within a top-level process is called an embeddable sub-process. All process data that is available in the parent process is also available in the sub-process. The following diagram shows the expanded version of the model above.

46 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The XML counterpart of this model looks as follows:$ <process id="embeddedSubprocess"> <startEvent id="theStart" /> <sequenceFlow id="flow1" sourceRef="theStart" targetRef="receiveOrder" /> <receiveTask name="Receive order" id="receiveOrder" /> <sequenceFlow id="flow2" sourceRef="receiveOrder" targetRef="checkCreditSubProcess" /> <subProcess id="checkCreditSubProcess" name="Credit check"> ... </subProcess> <sequenceFlow id="flow9" sourceRef="checkCreditSubProcess" targetRef="theEnd" /> <endEvent id="theEnd" /> </process>

Note that inside the sub-process, events, activities, tasks are defined as if it were a top-level process (hence the three "..." within the XML example above. Sub-processes are only allowed to have a none start event. Conceptually an embedded sub-process works as follows: when an execution arrives at the subprocess, a child execution is created. The child execution can then later create other (sub-)child executions, for example when a parallel gateway is used whithin the sub-process. The sub-process however, is only completed when no executions are active anymore within the subprocess. In that case, the parent execution is taken for further continuation of the process. For example, in the following diagram, the "Third task" will only be reached after both the "First task" and the "Second task" are completed. Completing one of the tasks in the sub-process, will not trigger the continuation of the sub-process, since one execution is still active within the sub-process.

47 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Sub-processes can have multiple start events. In that case, multiple parallel paths will exist within the sub-process. The rules for sub-process completion are unchanged: the sub-process will only be left when all the executions of the parallel paths are ended.

Nested sub-processes are also possible. This way, the process can be divided into several levels of detail. There is no limitation on the levels of nesting.

Implementation note: According to the BPMN 2 specification, an activity without ougoing sequence flow implicitly ends the current execution. However currently, it is necessary for a correct functioning to specifically use an end event within the sub-process to end a certain path. This will be enhanced in the future to be specification-compliant.

3.9.2. Timer start event


A timer start event is used to indicate that a process should be started when a given time condition is met. This could be a specific point in time (eg. October 10th, 2010 at 5am), but also and more typically a recurring time (eg. every Friday at midnight). A timer start event is visualized as a circle with the clock icon inside.

48 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Using a Timer Start event is done by adding a timerEventDefinition element below the startEvent element: <startEvent name="Every Monday morning" id="myStart"> <timerEventDefinition/> </startEvent>

Following time definitions are possible: timeDate: specifies a fixed date when a process instance must be created. The default format of the date specification is "dd/MM/yyyy hh:mm:ss". This can engine-wide be changed by setting the jbpm.duedatetime.format property in the configuration. <startEvent id="myStartEvent" > <timerEventDefinition> <timeDate>10/10/2099 00:00:00</timeDate> </timerEventDefinition> </startEvent>

Note that using a fixed duedate makes the process only useable for a single time. After the process instance is created, the timer start event will never fire again. timeCycle: specifies the recurring time when a new process instance will be created. Two types are possible Duration expression: quantity [business] {second | seconds | minute | minutes | hour | hours | day | days | week | weeks | month | months | year | years}

This is completely similar to a timer duration definition in JPDL. Note that the BPMN2 start timer event also understands "business time". This allows for example to define a "business day" as an interval from 9am to 5pm. This way, the time from 5pm to 9am will not be taken in account when the time on which the event will fire is calculated. Please refer to the JPDL userguide for more details on how this business calendar can be customized. The following example shows a timer start event that will start a new process instance every five hours. <startEvent id="myStartEvent" > <timerEventDefinition> <timeCycle>5 hours</timeCycle> </timerEventDefinition> </startEvent>

Cron expression: altough duration expressions cover already a great deal of recurring time definitions, sometimes they are not easy to use. When for example a process instance should be started every Friday night 23pm, cron expressions allow a more natural way of defining such repeating occurrences. The following example shows a timer start event that will start a new process instance every Friday at 23pm. <startEvent id="myStartEvent" > <timerEventDefinition> <timeCycle>0 0 23 ? * FRI</timeCycle> </timerEventDefinition> </startEvent>

The timer start event implementation in jBPM also has following features: Process definitions that have a timer start event, can be started as if it also were a none start event. This means that calling for example executionService.startProcessInstanceByKey(key) just works. The timer start event is internally implemented as a scheduled job. This means that a job executor has to be configured for the timer start event to work. The advantage of this implementation is that the timer start event firing is transactional (eg. if a service tasks right after the timer start event fails, the transaction will be rolled back and the timer start event will be retried later) and able to cope with a server crash (ie. the when the server comes back up, the timer start event will be picked up by the job executor just as if nothing has happened). When a new version of a process definition with a timer start event is deployed, the old timer start event job is removed from the system. This means that only the latest version of the process definition will be used to create a new process instances.

49 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

3.9.3. Intermediate events


An intermediate event is used to model something that happens during a process (ie. after the process has started and before it is ended). Intermediate events are visualized as a circle with a double border, with an icon indicating the event type within the circle. There are several intermediate event types, such as a timer event, signal event, escalation event, etc. Intermediate events can be either throwing or catching: Throwing: when an execution arrives in the event, it immediately fires a certain trigger (a signal, an error, etc.). Throwing events can be graphically recognized by the icon that is filled in with black. Catching: when an execution arrives in the event, it will wait for a certain trigger to happen (an error, a timer, etc.). Catching events can be graphically recognized by the icon that is not filled with black (ie. white inside).

3.9.4. Intermediate catch event: Timer


An intermediate timer event is used to represent a delay in the process. Straightfoward use cases are for example polling of data, executing heavy logic only at night when nobody is working, etc. Note that an intermediate timer only can be used as a catch event (throwing a timer event makes no sense). The following diagram shows how the intermediate timer event is visualized.

Defining an intermediate timer event is done in XML as follows: <intermediateCatchEvent id="myTimer" name="Wait for an hour"> <timerEventDefinition> <timeCycle>1 hour</timeCycle> </timerEventDefinition> </intermediateCatchEvent>

There are two ways to specify the delay, using either a timeCycle or a timeDate. In the example above, a timeCycle is used. Following delay definitions are possible (similar to those for a Timer Start Event). timeDate: specifies a fixed date when the timer will fire and the process continues. The default format of the date specification is "dd/MM/yyyy hh:mm:ss". This can engine-wide be changed by setting the jbpm.duedatetime.format property in the configuration. <intermediateCatchEvent id="myTimer" > <timerEventDefinition> <timeDate>10/10/2099 00:00:00</timeDate> </timerEventDefinition> </intermediateCatchEvent>

timeCycle: specifies a delay duration relative to the time when the execution enters the timer event. Two types are possible Duration expression: quantity [business] {second | seconds | minute | minutes | hour | hours | day | days | week | weeks | month | months | year | years}

This is completely similar to a timer duration definition in JPDL. Note that the BPMN2 intermediate timer event also understands "business time". This allows for example to define a "business day" as an interval from 9am to 5pm. Timers that are started at 4pm with a duration of 2 hours, will fire at 10am the next business day. Please refer to the JPDL userguide for more details on how this business calendar can be customized.

50 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<intermediateCatchEvent id="intermediateTimer" > <timerEventDefinition> <timeCycle>5 hours</timeCycle> </timerEventDefinition> </intermediateCatchEvent>

Cron expression: altough duration expressions cover already a great deal of delay definitions, sometimes they are not easy to use. When for example the process should be delayed until Friday night 23pm such that the processes can be executed in the weekend, duration expressions are hard to use (you need something like "#{calculated_value} seconds", where you need to calculate the value first). Cron expressions allow to define delays in a way many people know (since cron expressions are used to define scheduled task on Unix machines). Note that a cron expression typically is used to define repetion. In this context however, the first point in time where the cron expression is satisfied is used to set the due date of the timer event (so no repetition). The following example shows how an intermediate timer event can be specified to continue the process the next friday night at 23pm. <intermediateCatchEvent id="intermediateTimer" > <timerEventDefinition> <timeCycle>0 0 23 ? * FRI</timeCycle> </timerEventDefinition> </intermediateCatchEvent>

3.10. Complete example (including console task forms)


Prerequisites: to run the example, we assume that a working jBPM console has been installed on your JBoss server. If not, please run the 'demo.setup.jboss' install script first. The business process we're implementing looks as follows:

You might recognize this example, since weve also implemented it in JPDL as an example in our distribution. The business process is simple: an employee can start a new process and make a request for a certain amount of vacation days. After the request task has been completed, the manager will find a verification task in its tasklist. The Manager can now decide to accept or reject this request. Depending on the outcome (thats the little rhombus on the outgoing sequence flow - it means there is a conditional expression on the sequence flow), a rejection message is send or the process ends. Do note that in fact we've used a shortcut here: instead of putting expressions on the outgoing sequence flow of the 'verify request' task, we've could have used an exclusive gateway after the user task to control the flow through the process. Also note that since we haven't implemented swimlanes yet (probably the next release), it's difficult to actually see who does what in the business process. The XML version of this process looks as follows:

51 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<process id="vacationRequestProcess" name="BPMN2 Example process using task forms"> <startEvent id="start" /> <sequenceFlow id="flow1" name="fromStartToRequestVacation" sourceRef="start" targetRef="requestVacation" /> <userTask id="requestVacation" name="Request Vacation" implementation="other"> <potentialOwner resourceRef="user" jbpm:type="group"> <resourceAssignmentExpression> <formalExpression>user</formalExpression> </resourceAssignmentExpression> </potentialOwner> <rendering id="requestForm"> <jbpm:form>org/jbpm/examples/bpmn/usertask/taskform/request_vacation.ftl</jbpm:form> </rendering> </userTask> <sequenceFlow id="flow2" name="fromRequestVacationToVerifyRequest" sourceRef="requestVacation" targetRef="verifyRequest" /> <userTask id="verifyRequest" name="Verify Request" implementation="other"> <potentialOwner resourceRef="user" jbpm:type="group"> <resourceAssignmentExpression> <formalExpression>manager</formalExpression> </resourceAssignmentExpression> </potentialOwner> <rendering id="verifyForm"> <jbpm:form>org/jbpm/examples/bpmn/usertask/taskform/verify_request.ftl</jbpm:form> </rendering> </userTask> <sequenceFlow id="flow3" name="fromVerifyRequestToEnd" sourceRef="verifyRequest" targetRef="theEnd"> <conditionExpression xsi:type="tFormalExpression"> ${verificationResult == 'OK'} </conditionExpression> </sequenceFlow> <sequenceFlow id="flow4" name="fromVerifyRequestToSendRejectionMessage" sourceRef="verifyRequest" targetRef="sendRejectionMessage"> <conditionExpression xsi:type="tFormalExpression"> ${verificationResult == 'Not OK'} </conditionExpression> </sequenceFlow> <scriptTask id="sendRejectionMessage" name="Send rejection Message" scriptLanguage="bsh"> <script> <![CDATA[System.out.println("Vacation request refused!");]]> </script> </scriptTask> <sequenceFlow id="flow5" name="fromSendRejectionMessageToEnd" sourceRef="sendRejectionMessage" targetRef="theEnd" /> <endEvent id="theEnd" name="End" /> </process>

Note: this example is already installed when you've used the demo setup. Also note that we're using a Script Task here, to quickly write something as output instead of sending a real message (the diagram is showing a Service Task). Also note that we've taken some shortcuts here regarding task assignment (will be fixed in the next release). The constructs used in this implementation are all covered in the previous section. Also note that we're using the taskform functionality here, which is a custom jBPM extension for the rendering element of a User task.

52 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<userTask id="verifyRequest" name="Verify Request" implementation="other"> <potentialOwner resourceRef="user" jbpm:type="group"> <resourceAssignmentExpression> <formalExpression>user</formalExpression> </resourceAssignmentExpression> </potentialOwner> <rendering id="verifyForm"> <jbpm:form>org/jbpm/examples/bpmn/usertask/taskform/verify_request.ftl</jbpm:form> </rendering> </userTask>

The mechanism regarding task forms for BPMN 2.0 is complete equivalent to that of JPDL. The form itself is a Freemarker template file that needs to be incorporated in the deployment. For example, the 'verify_request.ftl' form looks like as follows. <html> <body> <form action="${form.action}" method="POST" enctype="multipart/form-data"> <h3>Your employee, ${employee_name} would like to go on vacation</h3> Number of days: ${number_of_days}<br/> <hr> In case you reject, please provide a reason:<br/> <input type="textarea" name="reason"/><br/> <input type="submit" name="verificationResult" value="OK"> <input type="submit" name="verificationResult" value="Not OK"> </form> </body> </html>

Note that process variables can be accessed using the ${my_process_variable} construct. Also note that named input controls (eg. input field, submit button) can be used to define new process variables. For example, the text input of the following field will be stored as the process variable 'reason' <input type="textarea" name="reason"/>

Note that there are two submit buttons (which makes sense if you look at the 'OK' and 'Not OK' sequence flows going out the 'request vacation' task. By pressing one of these buttons, the process variable 'verificationResult' will be stored. It can then be used to evaluate the outgoing sequence flow: <sequenceFlow id="flow3" name="fromVerifyRequestToEnd" sourceRef="verifyRequest" targetRef="theEnd"> <conditionExpression xsi:type="tFormalExpression"> ${verificationResult == 'OK'} </conditionExpression> </sequenceFlow>

The process can now be deployed. You can use the ant deploy task for this (see examples), or you can point your jBPM configuration to the database of the console. To deploy your process programmatically, you need to add the task forms to your deployment: NewDeployment deployment = repositoryService.createDeployment(); deployment.addResourceFromClasspath("org/jbpm/examples/bpmn/usertask/taskform/vacationrequest.bpmn.xml"); deployment.addResourceFromClasspath("org/jbpm/examples/bpmn/usertask/taskform/request_vacation.ftl"); deployment.addResourceFromClasspath("org/jbpm/examples/bpmn/usertask/taskform/verify_request.ftl"); deployment.deploy();

You can now embed (or run on a standalone server) this business process, by using the familiar jBPM API operations. For example, process instances can now be started using the key (ie. the process id for BPMN 2.0): ProcessInstance pi = executionService.startProcessInstanceByKey("vacationRequestProcess");

Or tasks list can be retrieved:

53 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Task requestTasktask = taskService.createTaskQuery().candidate("peter").uniqueResult();

When deploying to the jBPM console database, you should see our new business process popping up.

After you start a new process, a new task should be available in the employee's tasklist. When clicking on 'view', the task form will be displayed, requesting to fill in some variables for further use in the process.

After task completion, the manager will find a new verification task in his task list. He can now accept or reject the vacation request, based on the input of the employee.

54 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Since the database schema remains unchanged when we added BPMN 2.0 on top of the jBPM PVM, all existing reports can be applied to our new BPMN 2.0 processes.

Chapter 4. Migration from jBPM 3


4.1. Goals of jBPM 4 4.2. Known limitations 4.3. Process conversion tool 4.3.1. Overview 4.3.2. Arguments 4.3.3. Usage examples

55 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

4.3.4. Advanced 4.4. Translations and changes

4.1. Goals of jBPM 4


In building jBPM 4, we have pursued 2 major goals: Improve supportability: In jBPM 3 we relied only on community feedback for improving stability and portability. In jBPM 4 we have added a clear indication of which environments and configurations that we support. Those environments will be backed with continuous integration in the JBoss QA Labs. The build now supports all these environments and configurations so that it is easier for us to reproduce and investigate problems if they pop up. This coverage will also guarantee longer lifespan of jBPM 4. Lowering the treshold and increasing adoption to the next level: In jBPM 4 we created a clear differentiation between the common, basic usage on the one hand and the advanced usage on the other hand. So it will be easier to get started and harder (but still possible) to leverage the bleeding edge stuff on which developers can burn their fingers.

4.2. Known limitations


As part of creating a clear separation between basic and advanced usage, the API has been completely revisited. Basic usage is covered with the public API. The same API is available in all the supported environments. Package names in jBPM 4 are strictly separated from package names in jBPM 3. Instead of providing a full DB migration, we opted for a strategy to allow for jBPM 3 and jBPM 4 instances to run concurrently next to each other. The table prefix is changed from JBPM_ to JBPM4_. There is no migration tool to convert jBPM 3 runtime database contents to jBPM 4. We're not sure if we'll be able to build such a tool in one of the next version. One of the main reasons is that any QA for a data migration of the DB contents would be impossible for the project team to achieve. Furthermore, there are some features that are not yet available on jBPM 4. They are ordered from likely to unlikely to get implemented in jBPM 4. User provided transasctional resources such as JDBC connections or hibernate connections Exception handlers Transient variables Identity expression to calculate the assignee of a task Task form variable-to-parameter conversions

4.3. Process conversion tool


In many cases, a lot of work has been put in the design of JPDL3 process definitions. To avoid a complete manual translation of these processes to the JPDL4 format, the jBPM distribution contains a subdirectory called migration, which contains a command-line tool for converting JPDL3 process definition files to JPDL process XML files. Translated processes might not be executable any more. The jBPM 4 features might still be missing or the translation itself might not yet be implemented. But the tedious work of reformatting will be handled by the tool. It will also indicate the parts that it can't translate. The tool itself uses only dom4j to do the translation between the two formats and should be easy extensible (the source code is also in the same directory). The design of the tool is deliberately kept very simple (ie most of the logic can be found in the Jpdl3Converter class). Note that this tool is experimental and tested only a small set of JPDL3 process files.

4.3.1. Overview
The jPDL Conversion tool takes a jpdl3 process file as input, and converts it to a jpdl4 process file. Syntax: java org.jbpm.jpdl.internal.convert.JpdlConverterTool -v -o <outputfile> <processfile>

56 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

4.3.2. Arguments
-v (verbose): The tool will print the detail messages while converting the process file. When this argument is used, it will also print the error stacktrace if exceptions are thrown. -o (output) Specifies the output file name. By default, the tool will generate a file name ending in 'converted.jpdl.xml' using as a base file name the name derived from the input process file. The output-filename can be an absolute file name path or a relative file name path.

4.3.3. Usage examples


java -jar jpdl-migration-XX.jar simple.jpdl.xml java -jar jpdl-migration-XX.jar -v simple.jpdl.xml java -jar jpdl-migration-XX.jar -o /home/scott/simple.converted.xml simple.jpdl.xml

4.3.4. Advanced
The conversion tool can easily be integrated with regular Java code (or with Maven or Ant). The following code example shows how to call the internal api to convert the process file: URL url = new URL("simple.jpdl"); Jpdl3Converter jpdlConverter = new Jpdl3Converter(url); Document jpdl4Doc = jpdlConverter.readAndConvert(); for (Problem problem : jpdlConverter.problems) { //do something to handle the problem } Writer fileWriter = new FileWriter(outputFile); OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter( fileWriter, format ); writer.write(jpdl4Doc); writer.close();

4.4. Translations and changes


This section gives an indication of the most important renamings and changes that were applied in jBPM4 Table 4.1. General name changes jBPM 3 Node

jBPM 4 Activity

Remarks

Token

Execution

The root execution is now the same object as the process instance. (In jBPM 3, the ProcessInstance had a pointer to the root token). Also, unlike in jBPM 3, executions in jBPM 4 might get inactivated, create a child execution and let the child execution continue, even when logically this represents only one single path of execution. This happens in scope activities (or composite activities) that have timers or variables declared.

Action

Event listener

Table 4.2. jPDL XML changes jBPM 3 process-definition event type="..." action node process-state super-state jBPM 4 process on event="..." event-listener custom sub-process group (still in incubation)

57 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Table 4.3. Default changes jBPM 3 by default, propagated events trigger actions in outer process elements jBPM 4 by default, propagated events do not invoke event-listeners in outer elements, but only in the element on which the event listener is subscribed.

Chapter 5. The Process Virtual Machine


To accomodate multiple process languages and activity pluggability, jBPM is based on the Process Virtual Machine. In essence, the Process Virtual Machine is a framework specifying executable graphs. A process definition represents an execution flow and has a structure that be represented graphically as a diagram. The Process Virtual Machine separates the structure from a process definition from the activity behaviours. The Process Virtual Machine takes the execution of a process from one activity to the next and delegates the behaviour of the activities to pluggable Java classes. There is an API (ActivityBehaviour) that serves as the interface between the Process Virtual Machine and the activity behaviour code. Languages like jPDL are merely a set of ActivityBehaviour implementations and a parser.

Figure 5.1. Example process definition

Typically, process definitions are static. A process definition is composed of activities and transitions. The runtime behaviour of a activity is encapsulated in a so called Activity and it's decoupled from the process graph structure.

Figure 5.2. Process structure class diagram

The Process Virtual Machine doesn't contain any such activity implementations. It only provides the execution environment and an activity API to write ActivityBehaviour implementations as Java components. Activities can also be wait states. This means that the activity control flow goes outside the process system. For example a human task or invoking an service asynchronously. While the execution is waiting, the runtime state of that execution can be persisted in a DB. Many executions can be started for one process definition. An execution is a pointer that keeps track of the current

58 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

activity.

Figure 5.3. Example execution

To represent concurrent paths of execution, there is a hierarchical parent-child relation between so that one process instance can cope with concurrent paths of execution.

Figure 5.4. Execution class diagram

Chapter 6. Architecture
6.1. APIs 6.2. Activity API 6.3. Event listener API 6.4. 6.5. 6.6. 6.7. Client API Environment Commands Services

6.1. APIs
The Process Virtual Machine has 4 integrated API's that together offer a complete coverage of working with processes in the different execution modes. Each of the APIs has a specific purpose that fits within the following overall architecture.

59 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 6.1. The 4 API's of the Process Virtual Machine

The services interfaces should be used from application code that wants to interact with the Process Virtual Machine which runs in transactional persistent mode, backed by a database. This is the most typical way how users interact with the PVM as a workflow engine. To execute processes without persistence, the client API can be used to work with process and execution objects directly. The client API expose the methods of the core model objects. The activity API is used to implement the runtime behaviour of activities. So a activity type is in fact a component with at the core an implementation of the ActivityBehaviour interface. ActivityBehaviour implementations can control the flow of execution. The event listener API serves to write pieces of Java code that should be executed upon process events. It's very similar to the activity API with that exception that event listeners are not able to control the flow of execution.

6.2. Activity API


The activity API allows to implement the runtime activity behaviour in Java. public interface ActivityBehaviour extends Serializable { void execute(ActivityExecution execution) throws Exception; } An activity is the behaviour of the activity to which it is associated. The provided execution is the execution that arrives in the activity. The interface ActivityExecution exposes special methods to control the execution flow. public interface ActivityExecution extends OpenExecution { void waitForSignal(); void take(String transitionName); void execute(String activityName); ... }

6.3. Event listener API


The event listener API allows for listeners to be developed in Java code and that are invoked on specific process events like entering a activity or leaving a activity. It is very similar to the activity API, but the difference is that the propagation of the execution flow cannot be controlled. E.g. when an execution is taking a transition, a listener to that event can be notified, but since the transition is already being taking, the execution flow cannot be changed by the event listeners. public interface EventListener extends Serializable { void notify(EventListenerExecution execution) throws Exception; }

6.4. Client API


The client API is the interface that exposes the methods for managing executions on the plain process definition and execution objects directly.

60 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

At a minimal, the client API and the activity API are needed to create some a process definition with activities and execute it.

6.5. Environment
In the persistent execution mode, the first purpose of the environment is to enable processes to be executed in different transactional environments like standard Java, enterprise Java, SEAM and Spring. The PVM code itself will only use transactional resources through self-defined interfaces. For example, the PVM itself has interfaces for some methods on the hibernate session, a async messaging session and a timer session. The environment allows to configure the actual implementations, lazy initialization of the services on a request-basis and caching the service objects for the duration of the transaction. An environment factory is static and one environment factory can serve all the threads in an application. EnvironmentFactory environmentFactory = new PvmEnvironmentFactory("environment.cfg.xml"); Environment blocks can surround persistent process operations like this: Environment environment = environmentFactory.openEnvironment(); try { ... inside the environment block... } finally { environment.close(); } The PVM itself will fetch all it's transactional resources and configurations from the environment. It's recommended that Activity implementations do the same. The org.jbpm.pvm.internal.cfg.JbpmConfiguration acts as Configuration, ProcessEngine and EnvironmentFactory.

6.6. Commands
Commands encapsulate operations that are to be executed within an environment block. The main purpose for commands is to capture the logic of public interface Command<T> extends Serializable { T execute(Environment environment) throws Exception; }

6.7. Services
There are three main services: RepositoryService, ExecutionService and ManagementService. In general, services are session facades that expose methods for persistent usage of the PVM. The next fragments show the essential methods as example to illustrate those services. The RepositoryService manages the repository of process definitions. public interface RepositoryService { Deployment createDeployment(); ProcessDefinitionQuery createProcessDefinitionQuery(); ... } The ExecutionService manages the runtime executions.

61 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

public interface ExecutionService { ProcessInstance startProcessInstanceById(String processDefinitionId); ProcessInstance signalExecutionById(String executionId); ... } The ManagementService groups all management operations that are needed to keep the system up and running. public interface ManagementService { JobQuery createJobQuery(); void executeJob(long jobDbid); ... } The implementation of all these methods is encapsulated in Commands. And the three services all delegate the execution of the commands to a CommandService: public interface CommandService { <T> T execute(Command<T> command); } The CommandService is configured in the environment. A chain of CommandServices can act as interceptors around a command. This is the core mechanism on how persistence and transactional support can be offered in a variety of environments. The default configuration file jbpm.default.cfg.xml includes following section that configures the services <jbpm-configuration> <process-engine> <repository-service /> <repository-cache /> <execution-service /> <history-service /> <management-service /> <identity-service /> <task-service /> And the file jbpm.tx.hibernate.cfg.xml contains the following command service configuration: <jbpm-configuration> <process-engine-context> <command-service> <retry-interceptor /> <environment-interceptor /> <standard-transaction-interceptor /> </command-service> </process-engine-context> ... The services like e.g. repository-service, execution-service and management-service will look up the configured command-service by type. The command-service tag corresponds to the default command service that essentially does nothing else then just execute the command providing it the current environment. The configured command-service results into the following a chain of three interceptors followed by the default command executor.

62 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 6.2. The CommandService interceptors

The retry interceptor is the first in the chain and that one that will be exposed as the CommandService.class from the environment. So the retry interceptor will be given to the respective services repository-service, execution-service and management-service. The retry-interceptor will catch hibernate StaleObjectExceptions (indicating optimistic locking failures) and retry to execute the command. The environment-interceptor will put an environment block around the execution of the command. The standard-transaction-interceptor will initialize a StandardTransaction. The hibernate session/transaction will be enlisted as a resource with this standard transaction. Different configurations of this interceptor stack will also enable to delegate execution to a local ejb command service so that an container managed transaction is started. delegate to a remote ejb command service so that the command actually gets executed on a different JVM. package the command as an asynchronous message so that the command gets executed asynchronously in a different transaction.

Chapter 7. Implementing basic activities


7.1. ActivityBehaviour 7.2. ActivityBehaviour example 7.3. 7.4. 7.5. 7.6. 7.7. ExternalActivityBehaviour ExternalActivity example Basic process execution Events Event propagation

This chapter explains the basics of process definitions, the features offered by the Process Virtual Machine and how activity implementations can be build. At the same time the client API is shown to execute processes with those activity implementations.

7.1. ActivityBehaviour
The PVM library doesn't have a fixed set of process constructs. Instead, runtime behaviour of a activity is delegated to an ActivityBehaviour. In other words, ActivityBehaviour is an interface to implement the runtime behaviour of process constructs in plain Java. public interface ActivityBehaviour extends Serializable { void execute(ActivityExecution execution) throws Exception; } When an activity behaviour is called, it is in full control of the further propagation of the execution. In other words, an activity behaviour can decide what the execution should do next. For example, it can take a transition with execution.take(Transition) or go into a wait state with execution.waitForSignal(). In case the activity behaviour does not invoke any of the above execution propagation methods, the execution will proceed in a default way.

7.2. ActivityBehaviour example

63 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

We'll start with a very original hello world example. A Display activity will print a message to the console: public class Display implements ActivityBehaviour { String message; public Display(String message) { this.message = message; } public void execute(ActivityExecution execution) { System.out.println(message); } } Let' build our first process definition with this activity:

Figure 7.1. Display example process

TODO add ProcessBuilder example code Now we can execute this process as follows: Execution execution = processDefinition.startExecution(); The invocation of startExecution will print hello world to the console: hello world One thing already worth noticing is that activities can be configured with properties. In the Display example, you can see that the message property is configured differently in the two usages. With configuration properties it becomes possible to write reusable activities. They can then be configured differently each time they are used in a process. That is an essential part of how process languages can be build on top of the Process Virtual Machine. The other part that needs explanation is that this activity implementation does not contain any instructions for the propagation of the execution. When a new process instance is started, the execution is positioned in the initial activity and that activity is executed. The method Display.execute makes use of what is called implicit propagation of execution. Concretely this means that the activity itself does not invoke any of the methods on the execution to propagate it. In that case implicit propagation kicks in. Implicit propagation will take the first transition if there is one. If not, it will end the execution. This explains why both activities a and b are executed and that the execution stops after activity b is executed. More details about the implicit proceed behaviour can be found in Section 9.2, Implicit proceed behaviour

7.3. ExternalActivityBehaviour
External activities are activities for which the responsibility for proceeding the execution is transferred externally, meaning outside the process system. This means that for the system that is executing the process, it's a wait state. The execution will wait until an external trigger is given. For dealing with external triggers, ExternalActivityBehaviour adds one method to the ActivityBehaviour: public interface ExternalActivity extends Activity { void signal(Execution execution, String signal, Map<String, Object> parameters) throws Exception; } Just like with plain activities, when an execution arrives in a activity, the execute-method of the external activity

64 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

behaviour is invoked. In external activities, the execute method typically does something to transfer the responsibility to another system and then enters a wait state by invoking execution.waitForSignal(). For example in the execute method, responsibility could be transferred to a person by creating a task entry in a task management system and then wait until the person completes the task. In case a activity behaves as a wait state, then the execution will wait in that activity until the execution's signal method is invoked. The execution will delegate that signal to the ExternalActivityBehaviour object associated to the current activity. So the Activity's signal-method is invoked when the execution receives an external trigger during the wait state. With the signal method, responsibility is transferred back to the process execution. For example, when a person completes a task, the task management system calls the signal method on the execution. A signal can optionally have a signal name and a map of parameters. Most common way on how activity behaviours interprete the signal and parameters is that the signal relates to the outgoing transition that needs to be taken and that the parameters are set as variables on the execution. But those are just examples, it is up to the activity to use the signal and the parameters as it pleases.

7.4. ExternalActivity example


Here's a first example of a simple wait state implementation: public class WaitState implements ExternalActivity { public void execute(ActivityExecution execution) { execution.waitForSignal(); } public void signal(ActivityExecution execution, String signalName, Map<String, Object> parameters) { execution.take(signalName); } } The execute-method calls execution.waitForSignal(). The invocation of execution.waitForSignal() will bring the process execution into a wait state until an external trigger is given. signal-method takes the transition with the signal parameter as the transition name. So when an execution receives an external trigger, the signal name is interpreted as the name of an outgoing transition and the execution will be propagated over that transition. Here's the same simple process that has a transition from a to b. This time, the behaviour of the two activities will be WaitState's.

Figure 7.2. The external activity example process

ClientProcessDefinition processDefinition = ProcessFactory.build() .activity("a").initial().behaviour(new WaitState()) .transition().to("b") .activity("b").behaviour(new WaitState()) .done(); Let's start a new process instance for this process definition: ClientExecution execution = processDefinition.startProcessInstance(); Starting this process will execute the WaitState activity in activity a. WaitState.execute will invoke ActivityExecution.waitForSignal. So when the processDefinition.startProcessInstance() returns, the execution will still be positioned in activity a. assertEquals("a", execution.getActivityName());

65 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Then we provide the external trigger by calling the signal method. execution.signal(); The execution.signal() will delegate to the activity of the current activity. So in this case that is the WaitState activity in activity a. The WaitState.signal will invoke the ActivityExecution.take(String transitionName). Since we didn't supply a signalName, the first transition with name null will be taken. The only transition we specified out of activity a didn't get a name so that one will be taken. And that transition points to activity b. When the execution arrives in activity b, the WaitState in activity b is executed. Similar as we saw above, the execution will wait in activity b and this time the signal method will return, leaving the execution positioned in activity b. assertEquals("b", execution.getActivityName());

7.5. Basic process execution


In this next example, we'll combine automatic activities and wait states. This example builds upon the loan approval process with the WaitState and Display activities that we've just created. Graphically, the loan process looks like this:

Figure 7.3. The loan process

Building process graphs in Java code can be tedious because you have to keep track of all the references in local variables. To resolve that, the Process Virtual Machine comes with a ProcessFactory. The ProcessFactory is a kind of domain specific language (DSL) that is embedded in Java and eases the construction of process graphs. This pattern is also known as a fluent interface. ClientProcessDefinition processDefinition = ProcessFactory.build("loan") .activity("submit loan request").initial().behaviour(new Display("loan request submitted")) .transition().to("evaluate") .activity("evaluate").behaviour(new WaitState()) .transition("approve").to("wire money") .transition("reject").to("end") .activity("wire money").behaviour(new Display("wire the money")) .transition().to("archive") .activity("archive").behaviour(new WaitState()) .transition().to("end") .activity("end").behaviour(new WaitState()) .done(); For more details about the ProcessFactory, see the api docs. An alternative for the ProcessFactory would be to create an XML language and an XML parser for expressing processes. The XML parser can then instantiate the classes of package org.jbpm.pvm.internal.model directly. That approach is typically taken by process languages. The initial activity submit loan request and the activity wire the money are automatic activities. In this example, the Display implementation of activity wire the money uses the Java API's to just print a message to the console. But the witty reader can imagine an alternative Activity implementation that uses the Java API of a payment processing library to make a real automatic payment. A new execution for the process above can be started like this

66 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

ClientExecution execution = processDefinition.startProcessInstance(); When the startExecution-method returns, the activity submit loan request will be executed and the execution will be positioned in the activity evaluate.

Figure 7.4. Execution positioned in the 'evaluate' activity

Now, the execution is at an interesting point. There are two transitions out of the state evaluate. One transition is called approve and one transition is called reject. As we explained above, the WaitState implementation will take the transition that corresponds to the signal that is given. Let's feed in the 'approve' signal like this: execution.signal("approve"); The approve signal will cause the execution to take the approve transition and it will arrive in the activity wire money. In activity wire money, the message will be printed to the console. Since, the Display activity didn't invoke the execution.waitForSignal(), nor any of the other execution propagation methods, the implicit proceed behaviour will just make the execution continue over the outgoing transition to activity archive, which is again a WaitState.

Figure 7.5. Execution positioned in 'archive' activity

So only when the archive wait state is reached, the signal("approve") returns. Another signal like this: execution.signal("approve"); will bring the execution eventually in the end state.

67 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 7.6. Execution positioned in the 'end' activity

7.6. Events
Events are points in the process definition to which a list of EventListeners can be subscribed. public interface EventListener extends Serializable { void notify(EventListenerExecution execution) throws Exception; } The motivation for events is to allow for developers to add programming logic to a process without changing the process diagram. This is a very valuable instrument in facilitating the collaboration between business analysts and developers. Business analysts are responsible for expressing the requirements. When they use a process graph to document those requirements, developers can take this diagram and make it executable. Events can be a very handy to insert technical details into a process (like e.g. some database insert) in which the business analyst is not interested. Most common events are fired by the execution automatically: TODO: explain events in userguide Events are identified by the combination of a process element and an event name. Users and process languages can also fire events programmatically with the fire method on the Execution: public interface Execution extends Serializable { ... void fire(String eventName, ProcessElement eventSource); ... } A list of EventListeners can be associated to an event. But event listeners can not influence the control flow of the execution since they are merely listeners to an execution which is already in progress. This is different from activities that serve as the behaviour for activities. Activity behaviour activities are responsible for propagating the execution. We'll create a PrintLn event listener which is very similar to the Display activity from above. public class PrintLn implements EventListener { String message; public PrintLn(String message) { this.message = message; } public void notify(EventListenerExecution execution) throws Exception { System.out.println("message"); } } Several PrintLn listeners will be subscribed to events in the process.

68 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 7.7. The PrintLn listener process

ClientProcessDefinition processDefinition = ProcessFactory.build() .activity("a").initial().behaviour(new AutomaticActivity()) .event("end") .listener(new PrintLn("leaving a")) .listener(new PrintLn("second message while leaving a")) .transition().to("b") .listener(new PrintLn("taking transition")) .activity("b").behaviour(new WaitState()) .event("start") .listener(new PrintLn("entering b")) .done(); The first event shows how to register multiple listeners to the same event. They will be notified in the order as they are specified. Then, on the transition, there is only one type of event. So in that case, the event type must not be specified and the listeners can be added directly on the transition. A listeners will be called each time an execution fires the event to which the listener is subscribed. The execution will be provided in the activity interface as a parameter and can be used by listeners except for the methods that control the propagation of execution.

7.7. Event propagation


Events are by default propagated to enclosing process elements. The motivation is to allow for listeners on process definitions or composite activities that get executed for all events that occur within that process element. For example this feature allows to register an event listener on a process definition or a composite activity on end events. Such action will be executed if that activity is left. And if that event listener is registered on a composite activity, it will also be executed for all activities that are left within that composite activity. To show this clearly, we'll create a DisplaySource event listener that will print the message leaving and the source of the event to the console. public class DisplaySource implements EventListener { public void execute(EventListenerExecution execution) { System.out.println("leaving "+execution.getEventSource()); } } Note that the purpose of event listeners is not to be visible, that's why the event listener itself should not be displayed in the diagram. A DisplaySource event listener will be added as a listener to the event end on the composite activity. The next process shows how the DisplaySource event listener is registered as a listener to to the 'end' event on the composite activity:

Figure 7.8. A process with an invisible event listener on a end event on a composite activity.

TODO update code snippet Next we'll start an execution. ClientExecution execution = processDefinition.startProcessInstance();

69 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

After starting a new execution, the execution will be in activity a as that is the initial activity. No activities have been left so no message is logged. Next a signal will be given to the execution, causing it to take the transition from a to b. execution.signal(); When the signal method returns, the execution will have taken the transition and the end event will be fired on activity a. That event will be propagated to the composite activity and to the process definition. Since our DisplaySource event listener is placed on the composite activity, it will receive the event and print the following message on the console: leaving activity(a) Another execution.signal(); will take the transition from b to c. That will fire two activity-leave events. One on activity b and one on activity composite. So the following lines will be appended to the console output: leaving activity(b) leaving activity(composite) Event propagation is build on the hierarchical composition structure of the process definition. The top level element is always the process definition. The process definition contains a list of activities. Each activity can be a leaf activity or it can be a composite activity, which means that it contains a list of nested activities. Nested activities can be used for e.g. super states or composite activities in nested process languages like BPEL. So the even model also works similarly for composite activities as it did for the process definition above. Suppose that 'Phase one' models a super state as in state machines. Then event propagation allows to subscribe to all events within that super state. The idea is that the hierarchical composition corresponds to diagram representation. If an element 'e' is drawn inside another element 'p', then p is the parent of e. A process definition has a set of top level activities. Every activity can have a set of nested activities. The parent of a transition is considered as the first common parent for it's source and destination. If an event listener is not interested in propagated events, propagation can be disabled with propagationDisabled() while building the process with the ProcessFactory. The next process is the same process as above except that propagated events will be disabled on the event listener. The graph diagram remains the same.

Figure 7.9. A process with an event listener to 'end' events with propagation disabled.

Building the process with the process factory: TODO update code snippet So when the first signal is given for this process, again the end event will be fired on activity a, but now the event listener on the composite activity will not be executed cause propagated events have been disabled. Disabling propagation is a property on the individual event listener and doesn't influence the other listeners. The event will always be fired and propagated over the whole parent hierarchy. ClientExecution execution = processDefinition.startProcessInstance(); The first signal will take the process from a to b. No messages will be printed to the console. execution.signal(); Next, the second signal will take the transition from b to c. execution.signal()

70 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Again two end events are fired just like above on activities b and composite respectively. The first event is the end event on activity b. That will be propagated to the composite activity. So the event listener will not be executed for this event cause it has propagation disabled. But the event listener will be executed for the end event on the composite activity. That is not propagated, but fired directly on the composite activity. So the event listener will now be executed only once for the composite activity as shown in the following console output: leaving activity(composite)

Chapter 8. Process anatomy


Above we already touched briefly on the two main process constructs: Activities, transitions and activity composition. This chapter explores in full all the possibilities of the process definition structures. There are basically two forms of process languages: graph based and composite process languages. First of all, the process supports both. Even graph based execution and activity composition can be used in combination to implement something like UML super states. Furthermore, automatic functional activities can be implemented so that they can be used with transitions as well as with activity composition.

Figure 8.1. UML class diagram of the logical process structure

By separating the structure of a process from the behaviour of the activities, any process model can be formed in the PVM. It's up to the activity implementations to use this structure. Activities can also impose restrictions on the diagram structures they can support. Typically activities that control process concurrency will impose restrictions on the process model structures that they can support. Next we'll show a series of example diagram structures that can be formed with the PVM process model.

Figure 8.2. Any two activities can be connected with a transition.

Figure 8.3. A self transition.

Composite activity is a list of nested activities. Figure 8.4. Composite activity is a list of nested activities.

71 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 8.5. Transition to a activity inside a composite.

Figure 8.6. Transition from a activity inside a composite to a activity outside the composite.

Figure 8.7. Transition of composite activities are inherited. The activity inside can take the transition of the composite activity.

Figure 8.8. Transition from a activity to an outer composite.

Figure 8.9. Transition from a composite activity to an inner composed activity.

72 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 8.10. An initial activity inside a composite activity.

Chapter 9. Advanced graph execution


9.1. 9.2. 9.3. 9.4. 9.5. Loops Implicit proceed behaviour Functional activities Execution and threads Process concurrency

9.6. Exception handlers 9.7. Process modifications 9.8. Locking and execution state

9.1. Loops
Activities can implement loops based on transitions or on activity composition. Loops can contain wait states. To support high numbers of automatic loop executions, the Process Virtual Machine tranformed the propagation of execution from tail recursion to a while loop.

9.2. Implicit proceed behaviour


An ActivityBehaviour can explicitely propagate the execution with following methods: waitForSignal() take(Transition) end(*) execute(Activity) createExecution(*) As a side note, some of these methods are not exposed in the interfaces, but only in the implementation. Those methods are still in 'incubation'. So if you want to use those, you can use them at your own risk by casting the ActivityExecution interface to the implementation class ExecutionImpl. When ActivityBehaviour implementations used for activity behviour don't call any of the following execution propagation methods, then, after the activity is executed, the execution will apply the implicit proceed behaviour. The implicit proceed behaviour is defined as follows: If the current activity has a default outgoing transition, take it. If the current activity has a parent activity, move back to the parent activity. Otherwise, end this execution. Process languages can overwrite the implicit proceed behaviour by overriding the proceed method in ExecutionImpl.

9.3. Functional activities


ActivityBehaviours that also can be used as event listeners are called functional activities. Examples of automatic activities are sending an email, doing a database update, generating a pdf, calculating an average, etc. All of these are automatic activities that do not change the execution flow. Here's how such activities can be implemented: public class FunctionalActivity implements ActivityBehaviour, EventListener { public void execute(ActivityExecution execution) { perform(execution); } public void notify(EventListenerExecution execution) { perform(execution); } void perform(OpenExecution execution) { ...do functional work... } }

73 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

The perform method takes an OpenExecution, which is the supertype of both ActivityExecution and EventListenerExecution. OpenExecution does not allow any of the specific purpose methods, but still the current state and the process definition can be inspected as well as the variables, which contain the context information for the process execution. None of these methods actually invoke execution propagation methods. So after the perform method is completed, the execution will proceed in the default way.

9.4. Execution and threads


This section explains how the Process Virtual Machine boroughs the thread from the client to bring an execution from one wait state to another. When a client invokes a method (like e.g. the signal method) on an execution, by default, the Process Virtual Machine will use that thread to progress the execution until it reached a wait state. Once the next wait state has been reached, the method returns and the client gets the thread back. This is the default way for the Process Virtual Machine to operate. Two more levels of asynchonous execution complement this default behaviour: Asynchronous continuations and in the future we'll also provide a way to invoke service methods asynchronously. TODO: update the example that is now commented The benefits of using this paradigm is that the same process definition can be executed in client execution mode (in-memory without persistence) as well as in persistent execution mode, depending on the application and on the environment. When executing a process in persistent mode, this is how you typically want to bind that process execution to transactions of the database:

Figure 9.1. Transactions over time in persistent execution mode.

In most situations, the computational work that needs to be done as part of the process after an external trigger (the red pieces) is pretty minimal. Typically transactions combining the process execution and processing the request from the UI takes typically less then a second. Whereas the wait state in business processes typically can span for hours, days or even years. The clue is to clearly distinct when a wait state starts so that only the computational work done before the start of that wait state should be included in the transaction. Think of it this way: "When an approval arrives, what are all the automated processing that needs to be done before the process system needs to wait for another external trigger?" Unless pdf's need to be generated or mass emails need to be send, the amount of time that this takes is usually neglectable. That is why in the default persistent execution mode, the process work is executed in the thread of the client. This reasoning even holds in case of concurrent paths of execution. When a single path of execution splits into concurrent paths of execution, the process overhead of calculating that is neglectable. So that is why it makes sense for a fork or split activity implementation that targets persistent execution mode to spawn the concurrent paths sequentially in the same thread. Basically it's all just computational work as part of the same transaction. This can only be done because the fork/split knows that each concurrent path of execution will return whenever a wait state is encountered. Since this is a difficult concept to grasp, I'll explain it again with other words. Look at it from the overhead that is produced by the process execution itself in persistent execution mode. If in a transaction, an execution is given an external trigger and that causes the execution to split into multiple concurrent paths of execution. Then the process overhead of calculating this is neglectable. Also the overhead of the generated SQL is neglectable. And since all the work done in the concurrent branches must be done inside that single transaction, there is typically no point in having

74 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

fork/split implementations spawn the concurrent paths of execution in multiple threads. To make executable processes, developers need to know exactly what the automatic activities are, what the wait states are and which threads will be allocated to the process execution. For business analysts that draw the analysis process, things are a bit simpler. For the activities they draw, they usually know whether it's a human or a system that is responsible. But they typically don't not how this translates to threads and transactions. So for the developer, the first job is to analyse what needs to be executed within the thread of control of the process and what is outside. Looking for the external triggers can be a good start to find the wait states in a process, just like verbs and nouns can be the rule of thumb in building UML class diagrams.

9.5. Process concurrency


To model process concurrency, there is a parent-child tree structure on the execution. The idea is that the main path of execution is the root of that tree. The main path of execution is also called the process instance. It is the execution that is created when starting or creating a new process instance for a given process definition. Now, because the main path of execution is the same object as the process instance, this keeps the usage simple in case of simple processes without concurrency.

Figure 9.2. UML class diagram of the basic execution structure

To establish multiple concurrent paths of execution, activity implementations like a fork or split can create child executions with method ActivityExecution.createExecution. Activity implementations like join or merge can stop these concurrent paths of execution by calling method stop on the concurrent execution. Only leaf executions can be active. Non-leave executions should be inactive. This tree structure of executions doesn't enforce a particular type of concurrency or join behaviour. It's up to the forks or and-splits and to the joins or and-merges to use the execution tree structure in any way they want to define the wanted concurrency behaviour. Here you see an example of concurrent executions.

Figure 9.3. Concurrent paths of execution

There is a billing and a shipping path of execution. In this case, the flat bar activities represent activities that fork and join. The execution shows a three executions. The main path of execution is inactive (represented as gray) and the billing and shipping paths of execution are active and point to the activity bill and ship respectively. It's up to the activity behaviour implementations how they want to use this execution structure. Suppose that multiple tasks have to be completed before the execution is to proceed. The activity behaviour can spawn a series of child executions for this. Or alternatively, the task component could support task groups that are associated to one single execution. In that case, the task component becomes responsible for synchronizing the tasks, thereby moving this responsibility outside the scope of the execution tree structure.

75 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

9.6. Exception handlers


In all the code that is associated to a process like Activitys, EventListeners and Conditions, it's possible to associate exception handlers. This can be thought of as including try-catch blocks in the method implementations of those implementations. But in order to build more reusable building blocks for both the delegation classes and the exception handling logic, exception handlers are added to the core process model. An exception handler can be associated to any process element. When an exception occurs in a delegation class, a matching exception handler will be searched for. If such an exception handler is found, it will get a chance to handle the exception. If an exception handler completes without problems, then the exception is considered handled and the execution resumes right after the delegation code that was called. For example, a transition has three actions and the second action throws an exception that is handled by an exception handler, then Writing automatic activities that are exception handler aware is easy. The default is to proceed anyway. No method needs to be called on the execution. So if an automatic activity throws an exception that is handled by an exception handler, the execution will just proceed after that activity. It becomes a big more difficult for control flow activities. They might have to include try-finally blocks to invoke the proper methods on the execution before an exception handler gets a chance to handle the exception. For example, if an activity is a wait state and an exception occurs, then there is a risk that the thread jumps over the invocation of execution.waitForSignal(), causing the execution to proceed after the activity. TODO: exceptionhandler.isRethrowMasked TODO: transactional exception handlers TODO: we never catch errors

9.7. Process modifications


TODO: process modifications

9.8. Locking and execution state


The state of an execution is either active or locked. An active execution is either executing or waiting for an external trigger. If an execution is not in STATE_ACTIVE, then it is locked. A locked execution is read only and cannot receive any external triggers. When a new execution is created, it is in STATE_ACTIVE. To change the state to a locked state, use lock(String). Some STATE_* constants are provided that represent the most commonly used locked states. But the state '...' in the picture indicates that any string can be provided as the state in the lock method.

Figure 9.4. States of an execution

If an execution is locked, methods that change the execution will throw a PvmException and the message will reference the actual locking state. Firing events, updating variables, updating priority and adding comments are not considered to change an execution. Also creation and removal of child executions are unchecked, which means that those methods can be invoked by external API clients and activity behaviour methods, even while the execution is in a locked state.

76 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Make sure that comparisons between getState() and the STATE_* constants are done with .equals and not with '==' because if executions are loaded from persistent storage, a new string is created instead of the constants. An execution implementation will be locked: When it is ended When it is suspended During asynchronous continuations Furthermore, locking can be used by Activity implementations to make executions read only during wait states hen responsibility for the execution is transferred to an external entity such as: A human task A service invocation A wait state that ends when a scanner detects that a file appears In these situations the strategy is that the external entity should get full control over the execution because it wants to control what is allowed and what not. To get that control, they lock the execution so that all interactions have to go through the external entity. One of the main reasons to create external entities is that they can live on after the execution has already proceeded. For example, in case of a service invocation, a timer could cause the execution to take the timeout transition. When the response arrives after the timeout, the service invocation entity should make sure it doesn't signal the execution. So the service invocation can be seen as a activity instance (aka activity instance) and is unique for every execution of the activity. External entities themselves are responsible for managing the execution lock. If the timers and client applications are consequent in addressing the external entities instead of the execution directly, then locking is in theory unnecessary. It's up to the activity behaviour implementations whether they want to take the overhead of locking and unlocking.

Chapter 10. Configuration


10.1. Configuration basics 10.2. Customizing the business calendar 10.3. Customizing the identity component

10.1. Configuration basics


The userguide explains how to install jBPM into the most common runtime environments. That is the most simple and convenient way to get started with jBPM. Please use those instructions. These docs provide some background information for developers that want to understand more about the way how configurations are handled. Use at your own risk :-) The jbpm.jar contains a number of default configuration files that can be imported by the user configuration file. This way, it's easy to include or exclude features for users. And also the configuration details are kept in the implementation so users that only import those configuration files will not be affected when we release changes in those configuration files. Configuration files that can be imported by the user's jbpm.cfg.xml: jbpm.businesscalendar.cfg.xml jbpm.default.cfg.xml jbpm.identity.cfg.xml jbpm.jbossremote.cfg.xml jbpm.jobexecutor.cfg.xml jbpm.tx.hibernate.cfg.xml jbpm.tx.jta.cfg.xml jbpm.default.cfg.xml: Contains the default configurations like the services, the hibernate configuration (configured from resource jbpm.hibernate.cfg.xml), hibernate session factory, business calendar and so on. A typical configuration for standard java would look like this:

77 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<?xml version="1.0" encoding="UTF-8"?> <jbpm-configuration> <import <import <import <import <import <import resource="jbpm.default.cfg.xml" /> resource="jbpm.businesscalendar.cfg.xml" /> resource="jbpm.tx.hibernate.cfg.xml" /> resource="jbpm.jpdl.cfg.xml" /> resource="jbpm.identity.cfg.xml" /> resource="jbpm.jobexecutor.cfg.xml" />

</jbpm-configuration> When you want to change the configuration, first consider to change an import with one of the other provided importable configuration files. For example, in a JTA environment, replace the import of jbpm.tx.hibernate.cfg.xml with jbpm.tx.jta.cfg.xml The second way to define a more customized configuration is to specify configuration items directly into the jbpm.cfg.xml. For an example, see Section 10.3, Customizing the identity component below. The more you customize, the more likely you are doing things we didn't anticipate. The jbpm.jar contains also following hibernate mapping configuration files: jbpm.execution.hbm.xml jbpm.history.hbm.xml jbpm.identity.hbm.xml jbpm.repository.hbm.xml jbpm.task.hbm.xml These all map the java domain model objects to a relational database. Other various configuration files that are included in jbpm.jar: jbpm.task.lifecycle.xml jbpm.variable.types.xml jbpm.wire.bindings.xml jbpm.jpdl.activities.xml jbpm.jpdl.eventlisteners.xml Normally it is not necessary to dive into the parsing itself. It's most a matter of figuring out how to specify the configuration that you want :-) But just in case: To get started on the parsing for the configuration files, see class org.jbpm.pvm.internal.env.JbpmConfigurationParser resource modules/pvm/src/main/resources/jbpm.wire.bindings.xml package modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/binding

10.2. Customizing the business calendar


To provide a custom implementation for the business calendar, specify a custom business calendar implementation like this in the jbpm.cfg.xml <jbpm-configuration> <import resource="jbpm.default.cfg.xml" /> ... <process-engine-context> <object class="org.jbpm.test.custombusinesscalendarimpl.CustomBusinessCalendar" /> </process-engine-context> </jbpm-configuration> Here's an example implementation

78 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

public class CustomBusinessCalendar implements BusinessCalendar { public Date add(Date date, String duration) { if ("my next birthday".equals(duration)) { GregorianCalendar gregorianCalendar = new GregorianCalendar(); gregorianCalendar.set(Calendar.MONTH, Calendar.JULY); gregorianCalendar.set(Calendar.DAY_OF_MONTH, 21); return gregorianCalendar.getTime(); } return null; } }

10.3. Customizing the identity component


There are 2 identity components that we support out of the box: jBPM's built-in identity component: ships with the jBPM project distro JBoss IDM: ships in the JBoss product platforms The jboss/build.xml installation scripts can be used to install jBPM in JBoss using the JBoss IDM component. There is some property in that build file to overwrite the default built-in identity component with the value for the JBoss IDM component. If you want to plug in your own identity component, remove the following line in the jbpm.cfg.xml: <import resource="jbpm.identity.cfg.xml" /> And in the same file, add following section <transaction-context> <object class="your.package.YourIdentitySessionImpl" /> </transaction-context> YourIdentitySessionImpl should implement org.jbpm.pvm.internal.identity.spi.IdentitySession Making this identity pluggable is not our first target, but it was taken into the design. Let us know how it goes.

Chapter 11. Persistence


Currently jBPM's persistence is based on hibernate. But in the future we might switch to JPA. That is why we recommend to stick with the API as much as possible as the API will hide you from those changes. Here's the jBPM database schema in an ER diagram. Thanks to MySQL Workbench>.

79 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 11.1. The jBPM repository and runtime schema ER diagram

80 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 11.2. The jBPM history schema ER diagram

Figure 11.3. The jBPM identity schema ER diagram

Chapter 12. JobExecutor


12.1. Overview 12.2. Configuration For jPDL features like asynchronous continuations and timers, jBPM relies on transactional asynchronous messaging and timers. Those are not available on the standard Java platform. Therefore, jBPM includes the JobExecutor component, which executes asynchronous messages and timers in any (potentially clustered) environment.

12.1. Overview
By default, when calling a jBPM service operation (eg. TaskService, ExecutionService, etc.), the jBPM logic is executed on the same thread as where the call came from. In most cases, this is sufficient since most steps in a process don't take much time. This means that signalling a process instance from one wait state to another, passing by several other steps in the business process, can be done in one transaction. However, in some occasions business processes can be made more efficient by introducing asynchronous continuations. By marking an activity as asynchronous, the jBPM engine will take care that the logic encapsulated in the activity isn't executed on the thread of the caller, but on a separate dedicated thread. The same mechanism is used for timers and asynchronous mailing (which means mails will be sent later, in a separate thread). The following picture shows which components come into play when using this mechanism.

81 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Figure 12.1. JobExecutor components overview

When using timers or asynchronous continuations in a business process, the jBPM engine will store a 'job' into the database (a job contains mainly a duedate and continuation logic). Do note that this mechanism is pluggable, which means that in the future other destinations could be used (JMS, JCR, etc). Now the JobExecutor comes in to play, which is in fact a manager for several subcomponents: A shared BlockingQueue, which is used to temporary store job identifiers of jobs which are executable (e.g. due date is passed). Every JobExecutor has one DispatcherThread. This thread will query the database for 'acquirable jobs' (e.g. timers which due date is passed), using a dedicated command through the CommandService. Since the dispatcher uses the CommandService, the command is automatically made transactional and wrapped by the configured interceptors. As long as jobs are available the dispatcher will put job identifiers on the shared queue, until the queue is either full (the thread will automatically be blocked by the JVM until a slot is free) or until no new jobs can be found in the database. If the latter case, the dispatcher will wait for a configured time (ie the 'idle time'). The JobExecutor also maintains a pool of job executor threads. The number of executor threads can be configured and influences the size of the shared queue used to transfer and hold submitted jobs. Each executor thread will take a job from the queue. The shared queue blocks the executor threads until a job is queued. The new job will be acquired by exactly one waiting executor thread. After taking a job from the queue, the job is transactionally executed using a dedicated command through the CommandService. Therefore, the job will be executed completely on the executor thread instead of the caller thread. In consequence, the order in which the jobs are executed is unknown since there are multiple competing executor threads. However, it is certain that only one job will be done per transaction, except for exclusive jobs. In this case, all exclusive jobs are sequentially executed.

12.2. Configuration
Enabling the jobExecutor is very easy by adding the following line to the jbpm.cfg.xml file (using default settings): <import resource="jbpm.jobexecutor.cfg.xml" />

Additional attributes can be set to fine-tune the JobExecutor: threads: defines the number of JobexecutorThreads (default 3 threads) idle: number of milliseconds the dispatcher component waits after no new jobs were found in the database (default 5 seconds) idle-max: each time an exception occurs, the idle period will be doubled until the 'idle-max' is reached (back-off mechanism used to avoid a constant load on a failing database) lock-millis: Number of milliseconds that a job will be locked after being acquired by the dispatcher. This prevents starvation in case one of more JobExecutorThreads would die (eg when used in a cluster).

<process-engine-context> <job-executor threads="4" idle="15000" idle-max="60000" lock-millis="3600000" /> </process-engine-context>

Chapter 13. Advanced Mail Support

82 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

13.1. Producers 13.1.1. Default Producer 13.2. Templates 13.3. Servers 13.3.1. Multiple Servers 13.4. Custom Mail Producers 13.4.1. Extending the default mail producer jBPM 4 takes advantage of the JavaMail API to make high-level email services available to business process authors.

13.1. Producers
Mail producers are responsible for creating email messages within jBPM. Producers implement the org.jbpm.pvm.internal.email.spi.MailProducer interface. A default producer is available out of the box to address typical email needs.

13.1.1. Default Producer


The default mail producer is capable of creating email messages with text, HTML and attachments from a template. Templates can be provided inline or in the process-engine-context section of the jBPM configuration. Templates may contain expressions which are evaluated through the script manager. The following listing presents a mail activity with an inline template. <mail name="rectify" language="juel"> <from addresses='winston@minitrue' /> <to addresses='julia@minitrue, obrien@miniluv'/> <cc users='bigbrother'/> <bcc groups='thinkpol, innerparty'/> <subject>Part ${part} Chapter ${chapter}</subject> <text>times ${date} reporting bb dayorder doubleplusungood refs ${unpersons} rewrite fullwise upsub antefiling</text> <html><table><tr><td>times</td><td>${date}</td> <td>reporting bb dayorder doubleplusungood refs ${unpersons} rewrite fullwise upsub antefiling</td> </tr></table></html> <attachments> <attachment url='http://www.george-orwell.org/1984/3.html'/> <attachment resource='org/example/pic.jpg'/> <attachment file='${user.home}/.face'/> </attachments> </mail> (1) (2) (3) (4) (5) (6)

(7)

1. Expressions within the template are written in the scripting language indicated here. If not specified, the default expression language will be assumed. 2. List of message senders. Senders are either identified directly by their email addresses or appointed by means of the identity model. 3. Lists of message recipients, categorized as follows: To (primary), CC (carbon copy) and BCC (blind carbon copy). Like senders, recipients are directly identified by their email addresses or appointed by means of the identity model. 4. Character data contained in element subject are used as the message subject. 5. Character data contained in element text are used as the plain text content of the message. 6. Nodes contained in element html are used as the HTML content of the message. 7. Attachments can be specified as absolute URLs, classpath resources, local files or expressions. Note that every section of the template is amenable to expression evaluation. For complex emails or custom generation of attachments, see: custom mail producers.

13.2. Templates
Mail templates are available to externalize commonly used messages from process definitions. Templates are placed in the process-engine-context section of your configuration file. All elements available to inline templates, as described in the previous section are available to external templates. Consider the fragment below.

83 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<jbpm-configuration> <process-engine-context> <mail-template name="rectify-template"> <!-- same elements as inline template --> </mail-template> </process-engine-context> </jbpm-configuration> Each template must have an unique name. Mail activities may reference the template through the template attribute, as follows. <mail name="rectify" template="rectify-template />

13.3. Servers
Mail servers are declared in the configuration file. The mail-server element describes an SMTP mail server capable of sending email messages. Because jBPM uses JavaMail to send mail, all properties supported by JavaMail are also exposed to jBPM. Within the session-properties child element, the SMTP properties must be provided as shown in the example below. See the JavaMail documentation for details on the supported properties. <jbpm-configuration> <transaction-context> <mail-session> <mail-server> <session-properties> <property name="mail.smtp.host" value="localhost" /> <property name="mail.smtp.port" value="2525" /> <property name="mail.from" value="noreply@jbpm.org" /> </session-properties> </mail-server> </mail-session> </transaction-context> </jbpm-configuration> If the "From" attribute is not present in an outgoing message, the value of the mail.from property will be used instead.

13.3.1. Multiple Servers


Multiple SMTP server support has been added to jBPM 4 to accommodate a wider variety of organizational server structures. For example, this is useful for companies that have both internal and external SMTP servers. To setup multiple SMTP mail servers, declare multiple mail servers within the configuration file, as described below. The tag address-filter exists to define which domains are serviced by each mail server. The address filter consists of regular expressions that determine whether an address will be processed by a given server. See the Pattern API for more information about the allowable regular expressions.

84 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

<jbpm-configuration> <transaction-context> <mail-session> <mail-server> <address-filter> <include>.+@example.com</include> </address-filter> <session-properties> <property name="mail.smtp.host" value="internal.smtp.example.com" /> <property name="mail.from" value="noreply@example.com" /> </session-properties> </mail-server> <mail-server> <address-filter> <exclude>.+@example.com</exclude> </address-filter> <session-properties> <property name="mail.smtp.host" value="external.smtp.example.com" /> <property name="mail.from" value="noreply@example.com" /> </session-properties> </mail-server> </mail-session> </transaction-context> </jbpm-configuration> Address filters follow the logic below to accept an address. Address is accepted if it is included and not excluded. Absence of includes implies the address is included. Absence of excludes implies the address is not excluded.

13.4. Custom Mail Producers


jBPM 4 allows the creation of custom mail producers to address the specific requirements of an organization. To do so, create a class that implements the org.jbpm.pvm.internal.email.spi.MailProducer interface. Method produce takes an Execution and returns a collection of Messages to be sent through the MailSession.

13.4.1. Extending the default mail producer


The underpinning of customized mail production is the ability to instantiate a class that implements the MailProducer interface. In the simplest scenario, the class will extend the default mail producer and make a small addition such as adding more recipients. The following process snippet shows a mail activity with a custom mail producer. <mail name='send mail' class='org.example.AuditMailProducer'> <property name='template'> <object method='getTemplate'> <factory><ref type='org.jbpm.pvm.internal.email.impl.MailTemplateRegistry'/></factory> <arg><string value='rectify-template'/></arg> </object> </property> <property name='auditGroup'><string value='thinkpol'/></property> <transition to='end' /> </mail> The Java code for the AuditMailProducer comes next.

85 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

public class AuditMailProducer extends MailProducerImpl { private String auditGroup; public String getAuditGroup() { return auditGroup; } public void setAuditGroup(String auditGroup) { this.auditGroup = auditGroup; } @Override protected void fillRecipients(Execution execution, Message email) throws MessagingException { // add recipients from template super.fillRecipients(execution, email); // load audit group from database EnvironmentImpl environment = EnvironmentImpl.getCurrent(); IdentitySession identitySession = environment.get(IdentitySession.class); Group group = identitySession.findGroupById(auditGroup); // send a blind carbon copy of every message to the audit group AddressResolver addressResolver = environment.get(AddressResolver.class); email.addRecipients(RecipientType.BCC, addressResolver.resolveAddresses(group)); } } MailProducerImpl exposes a template property. To access a mail template, the mail producer descriptor references the MailTemplateRegistry object and invokes its getTemplate method. This method takes one string parameter, the name of the desired template. AuditMailProducer adds an extra property, the identifier of the group that will receive blind carbon copies of the outgoing emails. The audit mail producer overrides the default fillRecipients implementation to add the extra BCC recipients.

Chapter 14. Software logging


14.1. Configuration 14.2. Categories 14.3. JDK logging 14.4. Debugging persistence

14.1. Configuration
PVM can use JDK logging (java.util.logging) or log4j. When the first message is logged, PVM logging will make the selection with following procedure: 1. If a logging.properties resource is found on the classpath (using the context classloader), then JDK logging will be used and that file will be used to initialize the JDK logging. 2. If log4j is found on the classpath, then log4j will be used. The check for log4j will be done by checking availability of class org.apache.log4j.LogManager with the context classloader. 3. If none of the above, JDK logging will be used.

14.2. Categories
The PVM classes use their class name as the category for the logger. To have a basic understanding of what the PVM classes are doing, turning on the debug level is great. Level trace might be spitting out too much for that purpose.

14.3. JDK logging


In JDK logging, debug maps to fine and trace maps to finest. Level finer is not used. org.jbpm.pvm.internal.log.LogFormatter is part of the pvm library and it can create a nice one-line output for log messages. It also has a neat feature that creates a unique indentation per thread. To configure it, this is a typical logging.properties

86 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = FINEST java.util.logging.ConsoleHandler.formatter = org.jbpm.pvm.internal.log.LogFormatter # For example, set the com.xyz.foo logger to only log SEVERE messages: # com.xyz.foo.level = SEVERE .level = SEVERE org.jbpm.level=FINE org.jbpm.tx.level=FINE org.jbpm.pvm.internal.wire.level=FINE

14.4. Debugging persistence


When testing the persistence, following logging configurations can be valuable. Category org.hibernate.SQL shows the SQL statement that is executed and category org.hibernate.type shows the values of the parameters that are set in the queries. org.hibernate.SQL.level=FINEST org.hibernate.type.level=FINEST And in case you get a failed batch as a cause in a hibernate exception, you might want to set the batch size to 0 like this in the hibernate properties: hibernate.jdbc.batch_size = 0 Also in the hibernate properties, the following properties allow for detailed logs of the SQL that hibernate spits out: hibernate.show_sql = true hibernate.format_sql = true hibernate.use_sql_comments = true

Chapter 15. History


History information is the information that will be maintained in the database for querying purposes. This information is kept in the database after the process or task has ended. But it is always up to date with the runtime information. History information is updated inside of the runtime transaction. We maintain history information on 4 entities: process instance, activity instance task and variable. Each entity has a list of details associated to it. Preferably use the history queries to access this information through the API. HistoryEvents are fired during process execution and dispatched to the configured HistorySession. (see HistoryEvent.fire) All the HistoryEvents are delegated to a HistorySession. The default HistorySessionImpl will invoke the process() method on the history events themselves. The HistoryEvents are temporary events. In the process method, they build up the information in the history model. There is a HistoryProcessInstance and there is a whole class hierarchy starting with HistoryActivityInstance. In the HistoryEvent.process methods, the history events create model entities or merge information into the history entities. For instance, a ProcessInstanceCreate history event will create a HistoryProcessInstance entity/record. And the ProcessInstanceEnd will set the endTime property in the existing HistoryProcessInstance entity/record. Similar pattern for the activities. But for automatic activities, there is an optimisation so that only 1 event is created and all the information is stored in one single insert (as all this happens inside 1 transaction).

Chapter 16. JBoss Integration


16.1. 16.2. 16.3. 16.4. Packaging process archives Deploying processes archives to a JBoss instance Process deployments and versioning ProcessEngine and J2EE/JEE programming models

jBPM provides integration with JBoss 4.2.x and JBoss 5.0.0.GA. As part of the installation, the ProcessEngine and a deployer for jBPM archives will be installed as a JBoss service. After a successful installation you should see that the ProcessEngine has been started and bound to JNDI:

87 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

[...] 14:12:09,301 INFO 14:12:09,301 INFO 14:12:09,301 INFO

[JBPMService] jBPM 4 - Integration JBoss 4 [JBPMService] 4.0.0.Beta1 [JBPMService] ProcessEngine bound to: java:/ProcessEngine

16.1. Packaging process archives


When jBPM is deployed on a JBoss instance, process deployments are treated like any other deployment artifact (i.e. *.war, *.ear) and processed by the JBPMDeployer. In order to deploy a process archive simply create a *.jpdl archive (zip file) that contains the process definition (*.jpdl.xml) and all required resources to execute the process (i.e. classes, property files): Bonanova:Desktop hbraun$ jar -tf OrderProcess.jpdl META-INF/MANIFEST.MF OrderProcess.jpdl.xml org/mycompany/order/*.class

16.2. Deploying processes archives to a JBoss instance


In order to deploy a process archive simply copy it to $JBOSS_HOME/server/<config>/deploy: (1) cp OrderProcess.jpdl $JBOSS_HOME/server/default/deploy (2) less $JBOSS_HOME/server/default/log [...] 2009-04-08 14:12:21,947 INFO [org.jbpm.integration.jboss4.JBPMDeployer] Deploy file:/Users/hbraun/dev/prj/jboss/tags/JBoss_4_2_2_GA /build/output/jboss-4.2.2.GA/server/default/deploy/OrderProcess.jpdl

In order to remove a process simply remove the process archive from the deploy directory.

16.3. Process deployments and versioning


TBD: A prelimenary explanation cn be found here

16.4. ProcessEngine and J2EE/JEE programming models


As described above the ProcessEngine will be installed as JBoss service and bound to JNDI. This means that any EE component (i.e. servlet, ejb) can access it doing a JNDI lookup: private ProcessEngine processEngine; [...] try { InitialContext ctx = new InitialContext(); this.processEngine = (ProcessEngine)ctx.lookup("java:/ProcessEngine"); } catch (Exception e) { throw new RuntimeException("Failed to lookup process engine"); }

Once you obtained an instance of the ProcessEngine you can invoke on it as described in chapter services

88 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

UserTransaction tx = (UserTransaction)ctx.lookup("UserTransaction"); Environment env = ((EnvironmentFactory)processEngine).openEnvironment(); try { ExecutionService execService = (ExecutionService) this.processEngine.get(ExecutionService.class); // begin transaction tx.begin(); // invoke on process engine executionService.signalExecutionById("ICL.82436"); // commit transaction tx.commit(); } catch (Exception e) { if(tx!=null) { try { tx.rollback(); } catch (SystemException e1) {} } throw new RuntimeException("...", e); } finally { env.close(); }

(1)

(1) Wrapping the call in a UserTransaction is not necessary if the invocation comes a CMT component, i.e. an EJB.

Chapter 17. Spring Integration


17.1. Overview 17.2. Configuration 17.3. Usage 17.4. Testing The embeddability of the jBPM engine in different environments has always been one of its core strengths, but often extra libraries to do the integration were required. Since jBPM4 however, it is now possible to natively integrate jBPM with Spring. This section will explain which steps are required for such an integration. The Spring integration has started out as a community effort by Andries Inz. Do note that Spring integration currently is in 'incubation', before it is moved to the user guide.

17.1. Overview
The default jBPM behaviour is to open a transaction for each operation that is called on the service API. In a typical Spring setup, applications are accessed from the web tier and enter a transactional boundary by invoking operations on service beans. These service beans will then access the jBPM services. All these operations run typically in a single transaction (ie one transaction per request from the browser), which invalidates the standard jBPM transaction handling approach. Instead of starting and committing a transaction for every service operation, the existing transaction should be used (or a new one started if none exists).

17.2. Configuration
The easiest way to integrate Spring with jBPM is to import the jbpm.tx.spring.cfg.xml in your jbpm.cfg.xml file: <import resource="jbpm.tx.spring.cfg.xml" />

89 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

This configuration uses the single transaction manager which is defined in the Spring configuration. Start from the content of this file if you need to tweak the jBPM-Spring integration configuration. If you start from an existing configuration, replace the standard-transaction-interceptor with the spring-transactioninterceptor. The hibernate session needs the attribute current=true, depending if you are using the 'current Session' strategy in Spring. Also, the <transaction/> must be removed from the transaction-context if you want the transactions to be handled by Spring only. This forces jBPM to search for the current session, which will then be provided by Spring. <process-engine-context> <command-service> <spring-transaction-interceptor /> ... </command-service> ... </process-engine-context> <transaction-context> ... <hibernate-session current="true"/> </transaction-context>

The spring-transaction-interceptor will look by default for a PlatformTransactionManager implementation by doing a search by type on the defined beans. In the case of multiple transaction managers, it is possible to specifically define the name of the transaction manager that must be used by the interceptor: <spring-transaction-interceptor transaction-manager="myTransactionManager" />

The Spring integration provides a special context, which is added to the set of contexts where the jBPM engine will look for beans. Using this SpringContext, it is now possible to retrieve beans from the Spring Application Context. The jBPM process engine can be configured in a Spring applicationContext.xml as follows: <bean id="springHelper" class="org.jbpm.pvm.internal.processengine.SpringHelper"> <property name="jbpmCfg" value="org/jbpm/spring/jbpm.cfg.xml"></property> </bean> <bean id="processEngine" factory-bean="springHelper" factory-method="createProcessEngine" />

Note that the jbpmCfg property for the SpringHelper is optional. If a default jbpm.cfg.xml exists on the classpath (ie not in some package), this line can be removed. The jBPM services can also be defined in the Spring applicationContext, as following: <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" /> <bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />

17.3. Usage
The previous section already showed how the jBPM services can be made accessible for other Spring services. The other use case is calling Spring beans from within a process. This can be done by using an expression which resolves to the name of a Spring bean. <java name="echo" expr="#{echoService}" method="sayHello" > <transition name="to accept" to="join1"/> </java>

The scripting engine will look into all contexts from the bean named echoService. If you configured the ScriptManager as above, Spring will be the last context to search for. You can also add a Spring bean to the Spring Application context (eg IdentitySessionImpl with id identitySession) and use it in the jBPM config (eg by adding <env class="identitySession" />)

17.4. Testing
Use the AbstractTransactionalJbpmTestCase to test a process in isolation (ie without impact on the database). This class extends from the AbstractTransactionalDataSourceSpringContextTests class, which means that testing a process comes down to exactly the same approach as testing a DAO.

90 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

Chapter 18. Signavio web modeler


18.1. Introduction 18.2. Installation 18.3. Configuration

18.1. Introduction
Since version 4.1, jBPM ships with a completely open-source web-based BPMN modeling tool called 'Signavio'. This Signavio web modeler is the result of a close collaboration between the JBoss jBPM team, the company also named 'Signavio' and the Hasso Plattner Instut (HPI) in Germany. Signavio is based on the web-based modeling tool Oryx, which was developed in open-source by HPI. Both HPI and Signavio have comitted themselves to continue investing in Oryx and Signavio. More information about the initiative can be found here.

Using the Signavio web-based BPMN modeler, it is possible to let business analyst model the business processes through their browser. The file format which is used to store the BPMN processes is actually jPDL. This means that the resulting processes can directly be imported into the Eclipse GPD and vice-versa. The process files will be stored on the hard disk, in $jbpm_home/signavio-repository if you've used the default installation scripts. NOTE: The web-based BPMN modeling tool which ships with jBPM is 100% open-source (MIT-licence). The company Signavio also offers commercial versions of the same modeling tool, enhanced with additional features. Do note that new features, beneficial for the jBPM project, always will be comitted in the open-source repository of the modeling tool.

18.2. Installation
There are several ways of installing Signavio into your web container: Use the demo.setup.jboss/tomcat scripts in $jbpm_home/install Use the install.signavio.into.jboss/tomcat scripts in $jbpm_home/install Copy the $jbpm_home/install/src/signavio/jbpmeditor.war to your web container

18.3. Configuration
Most of the Signavio configuration parameters can be changed in the web.xml file, which you can find in jbpmeditor.war/WEB-INF/. The only parameters which is of real importance is the fileSystemRootDirectory parameter. The value of this parameter must point to an existing folder on your hard disk and indicates where the processes must be stored:

91 de 92

27/03/11 21:39

jBPM Developers Guide

http://docs.jboss.com/jbpm/v4/devguide/html_singl...

</context-param> <context-param> <description>Filesystem directory that is used to store models</description> <param-name>fileSystemRootDirectory</param-name><param-value>/home/jbarrez/dev/temp/jbpm-4.4-SNAPSHOT/signavio </context-param>

If you use the installation scripts provided in $jbpm_home/install, this parameter is automatically set to $jbpm_home/signavio-repository during installation.

92 de 92

27/03/11 21:39

You might also like