JBPM is a workflow management system (WFMS). The next image shows the
interfaces between jBpm and all actors involved in the form of a use
case diagram.
Since the term workflow mangament system has a complete different meaning
to different people, I will explain the core responsabilities of a workflow management system in
four layers. A more detailed description of the 4 layers can be found in the article
The State of Workflow.
jBpm takes
process archives as input.
A process archive is a formal description of a business
process. After a process archive is deployed, jBpm can manage the executions of this process.
'Managing the executions' means
keeping track of the state of a process (State layer),
storing information associated with a process execution (Context layer), integrating
custom programming logic like e.g. sending emails, interacting with an ERP, ...
(Programming logic layer) and optionally
allow users to complete tasks by submitting
forms (User interfaces layer).
Main responsibility
The main responsibility of a WFMS is to maintain the state of process executions. The
state model of jBpm is based on a graph with nodes and transitions. Nodes and transitions
are the main ingredients of a process definition. A state is an example of a node.
Runtime interaction
The 2 most important interactions with jBpm are : starting one instance (=one execution) of
a process definition and signalling the end of a state. As a result of both these interactions
jBpm will calculate the next state of the process instance.
Actions
The state graph, provides the structure of the process. Actions are pieces of programming
logic that can be executed upon events in the process. There are three types of events :
entering a node, leaving a node and taking a transition. While jBpm is calculating the
next state, a number of these events will fire.
Process archives
The main file in a process archive is processdefinition.xml
. That file
contains the formal description of the process. The act of parsing the processdefinition.xml
and storing it in the database is called deploying a process. All other files
in a process archive are stored as attachments with the process definition (either
in the database or as files on the filesystem).
Example
Create a process archive
We have modelled the following process for requesting a pay raise...
The payraise process
This process is expressed as xml like this:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE process-definition PUBLIC
3 "-//jBpm/jBpm Mapping DTD 2.0//EN"
4 "http://jbpm.org/dtd/processdefinition-2.0.dtd">
5
6 <process-definition name="pay raise process">
7
8 <!-- START-STATE -->
9 <start-state name="request a payraise" >
10 <transition to="evaluating"/>
11 </start-state>
12
13 <!-- NODES -->
14 <state name="evaluating">
15
16 <transition name="approve" to="fork"/>
17 <transition name="disapprove" to="done"/>
18 </state>
19
20 <fork name="fork">
21 <transition to="updating erp asynchronously" />
22 <transition to="treating collegues on cake and pie" />
23 </fork>
24
25 <state name="updating erp asynchronously">
26
27 <transition to="join" />
28 </state>
29
30 <state name="treating collegues on cake and pie">
31
32 <transition to="join" />
33 </state>
34
35 <join name="join">
36 <transition to="done" />
37 </join>
38
39 <!-- END-STATE -->
40 <end-state name="done" />
41
42 </process-definition>
snippet of the processdefinition.xml
Deploy process archive
jBpm store its process definitions in the database. So deploying
a process into jbpm actually means parsing the processdefinition.xml
and store it in the jbpm database. This can be done in one of 2 ways:
- the jbpm ant-tasks
par
and deploypar
.
par
lets you create a process archive from a set of
files. deploypar
deploys a process archive to the
database. The deploypar takes a jbpm.properties file as an
attribute. That file specifies the jbpm configurations including
the database to which the process archive has to be deployed. For
more information about the properties, see
configuration.
- programmatically like this:
1 // create a process archive input stream
2 String resource = "payraise/processdefinition.xml";
3 InputStream is = PayRaiseTest
4 .class
5 .getClassLoader()
6 .getResourceAsStream(resource);
7 ArchiveBuilder ab = new ArchiveBuilder(is);
8 JarInputStream jis = ab.getJarInputStream();
9
10 // deploy the process
11 DefinitionService ds = JbpmServiceFactory
12 .getInstance()
13 .openDefinitionService();
14 ds.deployProcessArchive(jis);
15 ds.close();
code to deploy a process archive
Note that also this code uses the jbpm.properties for its configuration, including
the database to which the process archive is deployed.
Note that the jbpm default configurations points to an hypersonic in-memory database.
That is ideal for testing. But this is of little use when using the ant task
to deploy your process. In that case, your database will live in the runtime
memory of the ant-task so you'll not be able to access it after the ant-task has
completed.
Start process instance
After packing and deploying this process to the jBpm database,
the next code example shows how to start a process instance.
1 ExecutionService executionService =
2 JbpmServiceFactory.getInstance().openExecutionService("AlbertEinstein");
3 executionService.startProcessInstance( "payraise" );
4 executionService.close();
code to start a process instance
Getting a task list
A token is a pointer to a state. In jbpm, every token can point to one actor, thereby
creating a relation between a state and an actor. The idea behind this state-actor relation
in a token. is the following : when workflow engine enters a state, that means that the
workflow engine will be waiting for some external trigger. If the process definition is
equipped with a calculation that determines *who* it is waiting for, this calculation
is executed when the token enters the state. So the task list will be a collection
of tokens that refer to a given actor. Actors in jBpm are
always referenced by their id : actorId (java.lang.String).
1 // get an execution service for user Carl Gauss (cg)
2 ExecutionService executionService = JbpmServiceFactory.getInstance().openExecutionService("cg");
3 // get the task list for Carl Gauss (cg)
4 Collection tasks = executionService.getTaskList("cg");
5 executionService.close();
code to get a tasklist
Signal the end of a state
When the process instances was started, jBpm calculated that
the next state is 'evaluating' and that user CarlGauss is responsible
for this task. This resulted in the token of the process being assigned to
'CarlGauss'. The next snippet asks jBpm all the tokens that are
waiting for CarlGauss. In this example we assume that the first task
is the one we started above. When CarlGauss has made his decision, he
informs jBpm by means of the endOfState method call. Note that in this
example we explicitly provide the name of the leaving transition to indicate
the choice made by the user.
1 ExecutionService executionService =
2 JbpmServiceFactory.getInstance().openExecutionService("CarlGauss");
3 Collection tasks = executionService.getTaskList("CarlGauss");
4 Token token = (Token) tasks.iterator().next();
5 executionService.endOfState( token.getId(), "approve" );
6 executionService.close();
code to signal an end of state