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.

Figure 1 : Interfaces of a WFMS
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).
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.
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.
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.
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).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE process-definition PUBLIC
"-//jBpm/jBpm Mapping DTD 2.0//EN"
"http://jbpm.org/dtd/processdefinition-2.0.dtd">
<process-definition name="pay raise process">
...
<!-- START-STATE -->
<start-state name="request a payraise" ...>
<transition to="evaluating"/>
</start-state>
<!-- NODES -->
<state name="evaluating">
...
<transition name="approve" to="fork"/>
<transition name="disapprove" to="done"/>
</state>
<fork name="fork">
<transition to="updating erp asynchronously" />
<transition to="treating collegues on cake and pie" />
</fork>
<state name="updating erp asynchronously">
...
<transition to="join" />
</state>
<state name="treating collegues on cake and pie">
...
<transition to="join" />
</state>
<join name="join">
<transition to="done" />
</join>
<!-- END-STATE -->
<end-state name="done" />
</process-definition>
|
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
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.
// create a process archive input stream
String resource = "payraise/processdefinition.xml";
InputStream is = PayRaiseTest
.class
.getClassLoader()
.getResourceAsStream(resource);
ArchiveBuilder ab = new ArchiveBuilder(is);
JarInputStream jis = ab.getJarInputStream();
// deploy the process
DefinitionService ds = JbpmServiceFactory
.getInstance()
.openDefinitionService();
ds.deployProcessArchive(jis);
ds.close();
|
After packing and deploying this process to the jBpm database, the next code example shows how to start a process instance.
ExecutionService executionService =
JbpmServiceFactory.getInstance().openExecutionService("AlbertEinstein");
executionService.startProcessInstance( "payraise" );
executionService.close();
|
// get an execution service for user Carl Gauss (cg)
ExecutionService executionService = JbpmServiceFactory.getInstance().openExecutionService("cg");
// get the task list for Carl Gauss (cg)
Collection tasks = executionService.getTaskList("cg");
executionService.close();
|
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.
ExecutionService executionService =
JbpmServiceFactory.getInstance().openExecutionService("CarlGauss");
Collection tasks = executionService.getTaskList("CarlGauss");
Token token = (Token) tasks.iterator().next();
executionService.endOfState( token.getId(), "approve" );
executionService.close();
|
Next important aspect of jBpm is including actions in a process definition. An action is a piece of java-code that must be executed upon some event in the process. Suppose for example you want to send a message in a bottle when a the example process is started. Then you'll write first the code that sends the message in a bottle as an ActionHandler...
public class ExampleActionHandler implements ActionHandler {
public void execute(ExecutionContext executionContext) {
System.out.println( "message in a bottle" );
}
}
|
Then we can create an action on the transition that leaves the start-state like this...
...
<start-state name="start">
<transition to="only state">
<action><delegation class="org.jbpm.example.ExampleActionHandler" /></action>
</transition>
</start-state>
...
|
Basically, there are 3 event-types on which actions can be placed : taking a transition, entering a node and leaving a node.
The variables are persisted in a text field in the database. So when trying to set a variable, jBpm has to know how to convert the object to text. For the following types, jBpm knows how to do this automatic :
If you want to store other java types as variables, you have to specify a custom serializer in the processdefinition.xml like this :
... <type java-type="org.jbpm.impl.YourCustomJavaType"> <delegation class="org.jbpm.impl.YourCustomSerializer" /> </type> ... |
To avoid that jBpm has to discover automatically the serializer to use, you can specify the variables inside of the type like this :
... <type java-type="org.jbpm.impl.YourCustomJavaType"> <delegation class="org.jbpm.impl.YourCustomSerializer" /> <variable name="your-custom-var-name"> <variable name="your-second-custom-var-name"> </type> ... |
The last option is to declare a transient variable. Transient variables can be accessed by ActionHandlers, but they will not be stored into the database. Here's how to declare transient variables :
... <type> <transient /> <variable name="your-transient-var-name"> <variable name="your-second-transient-var-name"> </type> ... |