JBoss.orgCommunity Documentation

jBPM jPDL User Guide

A guide to developing with and using jBPM 3

Abstract

This is the User Guide for jBPM 3. jBPM is a flexible Business Process Management (BPM) Suite that bridges the gap between non-technical business users and developers by offering both BPM and workflow features.


1. Introduction
1.1. Overview
1.2. The jPDL suite
1.3. The jPDL graphical process designer
1.4. The jBPM console web application
1.5. The jBPM core library
1.6. The JBoss jBPM identity component
1.7. The JBoss jBPM Job Executor
2. Getting started
2.1. Downloading and installing jBPM
2.2. The JBoss jBPM cummunity page
3. Tutorial
3.1. Hello World example
3.2. Database example
3.3. Context example: process variables
3.4. Task assignment example
3.5. Custom action example
4. Deployment
4.1. jBPM libraries
4.2. Java runtime environment
4.3. Third party libraries
4.4. Deployment in JBoss
4.4.1. The jbpm directory
4.4.2. The enterprise bundle
4.4.3. Configuring the logs in the suite server
4.4.4. Debugging a process in the suite
5. Configuration
5.1. Customizing factories
5.2. Configuration properties
5.3. Other configuration files
5.3.1. Hibernate cfg xml file
5.3.2. Hibernate queries configuration file
5.3.3. Node types configuration file
5.3.4. Action types configuration file
5.3.5. Business calendar configuration file
5.3.6. Variable mapping configuration file
5.3.7. Converter configuration file
5.3.8. Default modules configuration file
5.3.9. Process archive parsers configuration file
5.4. Logging of optimistic concurrency exceptions
5.5. Configuring the job executor
5.6. Object factory
6. Persistence
6.1. The persistence API
6.1.1. Relation to the configuration framework
6.1.2. Convenience methods on JbpmContext
6.1.3. Managed transactions
6.1.4. Injecting the hibernate session
6.1.5. Injecting resources programmatically
6.1.6. Advanced API usage
6.2. Configuring the persistence service
6.2.1. The DbPersistenceServiceFactory
6.2.2. The hibernate session factory
6.2.3. Configuring a c3po connection pool
6.2.4. Configuring a ehcache cache provider
6.3. Hibernate transactions
6.4. JTA transactions
6.5. Customizing queries
6.6. Database compatibility
6.6.1. Isolation level of the JDBC connection
6.6.2. Changing the jBPM DB
6.6.3. The jBPM database schema
6.7. Combining your hibernate classes
6.8. Customizing the jBPM hibernate mapping files
6.9. Second level cache
7. The jBPM Database
7.1. Switching the Database Backend
7.1.1. Isolation level
7.1.2. Installing the PostgreSQL Database Manager
7.1.3. Installing the MySQL Database Manager
7.1.4. Creating the JBoss jBPM Database with your new PostgreSQL or MySQL
7.1.5. Last Steps
7.1.6. Update the JBoss jBPM Server Configuration
7.2. Database upgrades
7.3. Starting hsqldb manager on JBoss
8. Java EE Application Server Facilities
8.1. Enterprise Beans
8.2. jBPM Enterprise Configuration
8.3. Hibernate Enterprise Configuration
8.4. Client Components
9. Process Modelling
9.1. Overview
9.2. Process graph
9.3. Nodes
9.3.1. Node responsibilities
9.3.2. Nodetype task-node
9.3.3. Nodetype state
9.3.4. Nodetype decision
9.3.5. Nodetype fork
9.3.6. Nodetype join
9.3.7. Nodetype node
9.4. Transitions
9.5. Actions
9.5.1. Action configuration
9.5.2. Action references
9.5.3. Events
9.5.4. Event propagation
9.5.5. Script
9.5.6. Custom events
9.6. Superstates
9.6.1. Superstate transitions
9.6.2. Superstate events
9.6.3. Hierarchical names
9.7. Exception handling
9.8. Process composition
9.9. Custom node behaviour
9.10. Graph execution
9.11. Transaction demarcation
10. Context
10.1. Accessing variables
10.2. Variable lifetime
10.3. Variable persistence
10.4. Variables scopes
10.4.1. Variables overloading
10.4.2. Variables overriding
10.4.3. Task instance variable scope
10.5. Transient variables
10.6. Customizing variable persistence
11. Task management
11.1. Tasks
11.2. Task instances
11.2.1. Task instance lifecycle
11.2.2. Task instances and graph execution
11.3. Assignment
11.3.1. Assignment interfaces
11.3.2. The assignment data model
11.3.3. The personal task list
11.3.4. The group task list
11.4. Task instance variables
11.5. Task controllers
11.6. Swimlanes
11.7. Swimlane in start task
11.8. Task events
11.9. Task timers
11.10. Customizing task instances
11.11. The identity component
11.11.1. The identity model
11.11.2. Assignment expressions
11.11.3. Removing the identity component
12. Scheduler
12.1. Timers
12.2. Scheduler deployment
13. Asynchronous continuations
13.1. The concept
13.2. An example
13.3. The job executor
13.4. jBPM's built-in asynchronous messaging
14. Business calendar
14.1. Duedate
14.1.1. Duration
14.1.2. Base date
14.1.3. Examples
14.2. Calendar configuration
15. Email support
15.1. Mail in jPDL
15.1.1. Mail action
15.1.2. Mail node
15.1.3. Task assign mails
15.1.4. Task reminder mails
15.2. Expressions in mails
15.3. Specifying mail recipients
15.3.1. Multiple recipients
15.3.2. Sending Mails to a BCC recipient
15.3.3. Sending Mails to a CC recipient
15.3.4. Address resolving
15.4. Mail templates
15.5. Mail server configuration
15.6. From address configuration
15.7. Customizing mail support
16. Logging
16.1. Creation of logs
16.2. Log configurations
16.3. Log retrieval
16.4. Database warehousing
17. jBPM Process Definition Language (JPDL)
17.1. The process archive
17.1.1. Deploying a process archive
17.1.2. Process versioning
17.1.3. Changing deployed process definitions
17.1.4. Migrating process instances
17.2. Delegation
17.2.1. The jBPM class loader
17.2.2. The process class loader
17.2.3. Configuration of delegations
17.3. Expressions
17.4. jPDL xml schema
17.4.1. Validation
17.4.2. process-definition
17.4.3. node
17.4.4. common node elements
17.4.5. start-state
17.4.6. end-state
17.4.7. state
17.4.8. task-node
17.4.9. process-state
17.4.10. super-state
17.4.11. fork
17.4.12. join
17.4.13. decision
17.4.14. event
17.4.15. transition
17.4.16. action
17.4.17. script
17.4.18. expression
17.4.19. variable
17.4.20. handler
17.4.21. timer
17.4.22. create-timer
17.4.23. cancel-timer
17.4.24. task
17.4.25. swimlane
17.4.26. assignment
17.4.27. controller
17.4.28. sub-process
17.4.29. condition
17.4.30. exception-handler
18. Security
18.1. Todos
18.2. Authentication
18.3. Authorization
19. TDD for workflow
19.1. Introducing TDD for workflow
19.2. XML sources
19.2.1. Parsing a process archive
19.2.2. Parsing an xml file
19.2.3. Parsing an xml String
19.3. Testing sub processes
20. Pluggable architecture
A. GNU Lesser General Public License version 3
B. Revision History

JBoss jBPM is a flexible, extensible framework for process languages. jPDL is one process language that is build on top of that common framework. It is an intuitive process language to express business processes graphically in terms of tasks, wait states for asynchronous communication, timers, automated actions,... To bind these operations together, jPDL has the most powerful and extensible control flow mechanism.

jPDL has minimal dependencies and can be used as easy as using a java library. But it can also be used in environments where extreme throughput is crucial by deploying it on a J2EE clustered application server.

jPDL can be configured with any database and it can be deployed on any application server.

The suite is a download that contains all the jBPM components bundled in one easy download. The download includes:

config

configuration files for a standard java environment

db

SQL scripts for DB creation and compatibility information

designer

the eclipse plugin to author jPDL processes and installation scripts (this is not part of the plain jpdl download) See also Section 1.3, “The jPDL graphical process designer”.

doc

userguide and javadocs

examples

These are examples.

lib

libraries on which jbpm depends. For more information on this see Section 4.3, “Third party libraries”

server

a preconfigured jboss that contains jbpm inside the console web application (this is not part of the plain jpdl download)

src

the jbpm and identity component java sources

The preconfigured JBoss application server has the following components installed :

The web console

packaged as a web archive. That console can be used by process participants as well as jBPM administrators.

job executor

enacts timers and asynchronous messages. There is a servlet context listener in the console web app that launches the job executor, which spawns a thread pool for monitoring and executing timers and asynchronous messages.

jBPM database

an in-process hypersonic database that contains the jBPM tables.

example process

is already deployed into the jBPM database.

Identity component

libraries are part of the console web application. The tables of the identity component are available in the database (those are the tables that start with JBPM_ID_)

This chapter takes you through the first steps of getting JBoss jBPM and provides the initial pointers to get up and running in no time.

To get the latest release jBPM 3 version, go to the jBPM jPDL 3 package on Sourceforge.net and download the latest installer.

The jBPM installer creates a runtime installation and it can also download and install the eclipse designer and a jboss server. You can use jBPM also without application server, but all of these components are preconfigured to interoperate out-of-the-box to get you started with jBPM quickly. To launch the installer, open a command line and go to the directory where you downloaded it. Then type:

java -jar jbpm-installer-{version}.jar

Step through the instructions. Any supported version of JBoss and the exact version of eclipse can optionally be downloaded by the installer.

When installing jBPM into JBoss, this will create a jBPM directory into a server configuration's deploy directory. All jBPM files are centralized inside this deploy/jbpm directory. No other files of your JBoss installation will be touched.

You can use your own eclipse (if it is version 3.4+) or you can use the eclipse that the installer downloaded. To install the graphical process designer in eclipse, just use the eclipse update mechanism (Help --> Software Updates --> ...) and point it to the file designer/jbpm-jpdl-designer-site.zip.

The jBPM Community Page provides all the details about where to find forums, wiki, issue tracker, downloads, mailing lists and the source repositories.

This tutorial will show you basic process constructs in jpdl and the usage of the API for managing the runtime executions.

The format of this tutorial is explaining a set of examples. The examples focus on a particular topic and contain extensive comments. The examples can also be fond in the jBPM download package in the directory src/java.examples.

The best way to learn is to create a project and experiment by creating variations on the examples given.

To get started first, download and install jBPM. Section 2.1, “Downloading and installing jBPM”

jBPM includes a graphical designer tool for authoring the XML that is shown in the examples. You can find download instructions for the graphical designer in the Downloadables Overview section.. You don't need the graphical designer tool to complete this tutorial.

A process definition is a directed graph, made up of nodes and transitions. The hello world process has 3 nodes. To see how the pieces fit together, we're going to start with a simple process without the use of the designer tool. The following picture shows the graphical representation of the hello world process:


public void testHelloWorldProcess() {
  // This method shows a process definition and one execution
  // of the process definition.  The process definition has 
  // 3 nodes: an unnamed start-state, a state 's' and an 
  // end-state named 'end'.
  // The next line parses a piece of xml text into a
  // ProcessDefinition.  A ProcessDefinition is the formal 
  // description of a process represented as a java object.
  ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
    "<process-definition>" +
    "  <start-state>" +
    "    <transition to='s' />" +
    "  </start-state>" +
    "  <state name='s'>" +
    "    <transition to='end' />" +
    "  </state>" +
    "  <end-state name='end' />" +
    "</process-definition>"
  );
  
  // The next line creates one execution of the process definition.
  // After construction, the process execution has one main path
  // of execution (=the root token) that is positioned in the
  // start-state.
  ProcessInstance processInstance = 
      new ProcessInstance(processDefinition);
  
  // After construction, the process execution has one main path
  // of execution (=the root token).
  Token token = processInstance.getRootToken();
  
  // Also after construction, the main path of execution is positioned
  // in the start-state of the process definition.
  assertSame(processDefinition.getStartState(), token.getNode());
  
  // Let's start the process execution, leaving the start-state 
  // over its default transition.
  token.signal();
  // The signal method will block until the process execution 
  // enters a wait state.

  // The process execution will have entered the first wait state
  // in state 's'. So the main path of execution is now 
  // positioned in state 's'
  assertSame(processDefinition.getNode("s"), token.getNode());

  // Let's send another signal.  This will resume execution by 
  // leaving the state 's' over its default transition.
  token.signal();
  // Now the signal method returned because the process instance 
  // has arrived in the end-state.
  
  assertSame(processDefinition.getNode("end"), token.getNode());
}

One of the basic features of jBPM is the ability to persist executions of processes in the database when they are in a wait state. The next example will show you how to store a process instance in the jBPM database. The example also suggests a context in which this might occur. Separate methods are created for different pieces of user code. E.g. an piece of user code in a webapplication starts a process and persists the execution in the database. Later, a message driven bean loads the process instance from the database and resumes its execution.

More about the jBPM persistence can be found in Chapter 6, Persistence.

public class HelloWorldDbTest extends TestCase {

  static JbpmConfiguration jbpmConfiguration = null; 

  static {
    // An example configuration file such as this can be found in 
    // 'src/config.files'.  Typically the configuration information is in the 
    // resource file 'jbpm.cfg.xml', but here we pass in the configuration 
    // information as an XML string.
    
    // First we create a JbpmConfiguration statically.  One JbpmConfiguration
    // can be used for all threads in the system, that is why we can safely 
    // make it static.

    jbpmConfiguration = JbpmConfiguration.parseXmlString(
      "<jbpm-configuration>" +
      
      // A jbpm-context mechanism separates the jbpm core 
      // engine from the services that jbpm uses from 
      // the environment.  
      
      "  <jbpm-context>" +
      "    <service name='persistence' " +
      "             factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />" + 
      "  </jbpm-context>" +
      
      // Also all the resource files that are used by jbpm are 
      // referenced from the jbpm.cfg.xml
      
      "  <string name='resource.hibernate.cfg.xml' " +
      "          value='hibernate.cfg.xml' />" +
      "  <string name='resource.business.calendar' " +
      "          value='org/jbpm/calendar/jbpm.business.calendar.properties' />" +
      "  <string name='resource.default.modules' " +
      "          value='org/jbpm/graph/def/jbpm.default.modules.properties' />" +
      "  <string name='resource.converter' " +
      "          value='org/jbpm/db/hibernate/jbpm.converter.properties' />" +
      "  <string name='resource.action.types' " +
      "          value='org/jbpm/graph/action/action.types.xml' />" +
      "  <string name='resource.node.types' " +
      "          value='org/jbpm/graph/node/node.types.xml' />" +
      "  <string name='resource.varmapping' " +
      "          value='org/jbpm/context/exe/jbpm.varmapping.xml' />" +
      "</jbpm-configuration>"
    );
  }
  
  public void setUp() {
    jbpmConfiguration.createSchema();
  }
  
  public void tearDown() {
    jbpmConfiguration.dropSchema();
  }

  public void testSimplePersistence() {
    // Between the 3 method calls below, all data is passed via the 
    // database.  Here, in this unit test, these 3 methods are executed
    // right after each other because we want to test a complete process
    // scenario.  But in reality, these methods represent different 
    // requests to a server.
    
    // Since we start with a clean, empty in-memory database, we have to 
    // deploy the process first.  In reality, this is done once by the 
    // process developer.
    deployProcessDefinition();

    // Suppose we want to start a process instance (=process execution)
    // when a user submits a form in a web application...
    processInstanceIsCreatedWhenUserSubmitsWebappForm();

    // Then, later, upon the arrival of an asynchronous message the 
    // execution must continue.
    theProcessInstanceContinuesWhenAnAsyncMessageIsReceived();
  }

  public void deployProcessDefinition() {
    // This test shows a process definition and one execution 
    // of the process definition.  The process definition has 
    // 3 nodes: an unnamed start-state, a state 's' and an 
    // end-state named 'end'.
    ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
      "<process-definition name='hello world'>" +
      "  <start-state name='start'>" +
      "    <transition to='s' />" +
      "  </start-state>" +
      "  <state name='s'>" +
      "    <transition to='end' />" +
      "  </state>" +
      "  <end-state name='end' />" +
      "</process-definition>"
    );

    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {
      // Deploy the process definition in the database 
      jbpmContext.deployProcessDefinition(processDefinition);

    } finally {
      // Tear down the pojo persistence context.
      // This includes flush the SQL for inserting the process definition  
      // to the database.
      jbpmContext.close();
    }
  }

  public void processInstanceIsCreatedWhenUserSubmitsWebappForm() {
    // The code in this method could be inside a struts-action 
    // or a JSF managed bean. 

    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {

      GraphSession graphSession = jbpmContext.getGraphSession();
      
      ProcessDefinition processDefinition = 
          graphSession.findLatestProcessDefinition("hello world");
    
      // With the processDefinition that we retrieved from the database, we 
      // can create an execution of the process definition just like in the 
      // hello world example (which was without persistence).
      ProcessInstance processInstance = 
          new ProcessInstance(processDefinition);
      
      Token token = processInstance.getRootToken(); 
      assertEquals("start", token.getNode().getName());
      // Let's start the process execution
      token.signal();
      // Now the process is in the state 's'.
      assertEquals("s", token.getNode().getName());
      
      // Now the processInstance is saved in the database.  So the 
      // current state of the execution of the process is stored in the 
      // database.  
      jbpmContext.save(processInstance);
      // The method below will get the process instance back out 
      // of the database and resume execution by providing another 
      // external signal.

    } finally {
      // Tear down the pojo persistence context.
      jbpmContext.close();
    }
  }

  public void theProcessInstanceContinuesWhenAnAsyncMessageIsReceived() {
    // The code in this method could be the content of a message driven bean.

    // Lookup the pojo persistence context-builder that is configured above
    JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
    try {

      GraphSession graphSession = jbpmContext.getGraphSession();
      // First, we need to get the process instance back out of the database.
      // There are several options to know what process instance we are dealing 
      // with here.  The easiest in this simple test case is just to look for 
      // the full list of process instances.  That should give us only one 
      // result.  So let's look up the process definition.
      
      ProcessDefinition processDefinition = 
          graphSession.findLatestProcessDefinition("hello world");

      // Now, we search for all process instances of this process definition.
      List processInstances = 
          graphSession.findProcessInstances(processDefinition.getId());
      
      // Because we know that in the context of this unit test, there is 
      // only one execution.  In real life, the processInstanceId can be 
      // extracted from the content of the message that arrived or from 
      // the user making a choice.
      ProcessInstance processInstance = 
          (ProcessInstance) processInstances.get(0);
      
      // Now we can continue the execution.  Note that the processInstance
      // delegates signals to the main path of execution (=the root token).
      processInstance.signal();

      // After this signal, we know the process execution should have 
      // arrived in the end-state.
      assertTrue(processInstance.hasEnded());
      
      // Now we can update the state of the execution in the database
      jbpmContext.save(processInstance);

    } finally {
      // Tear down the pojo persistence context.
      jbpmContext.close();
    }
  }
}

The process variables contain the context information during process executions. The process variables are similar to a java.util.Map that maps variable names to values, which are java objects. The process variables are persisted as a part of the process instance. To keep things simple, in this example we only show the API to work with variables, without persistence.

More information about variables can be found in Chapter 10, Context

// This example also starts from the hello world process.
// This time even without modification.
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
  "<process-definition>" +
  "  <start-state>" +
  "    <transition to='s' />" +
  "  </start-state>" +
  "  <state name='s'>" +
  "    <transition to='end' />" +
  "  </state>" +
  "  <end-state name='end' />" +
  "</process-definition>"
);

ProcessInstance processInstance =
  new ProcessInstance(processDefinition);

// Fetch the context instance from the process instance 
// for working with the process variables.
ContextInstance contextInstance = 
  processInstance.getContextInstance();

// Before the process has left the start-state, 
// we are going to set some process variables in the 
// context of the process instance.
contextInstance.setVariable("amount", new Integer(500));
contextInstance.setVariable("reason", "i met my deadline");

// From now on, these variables are associated with the 
// process instance.  The process variables are now accessible 
// by user code via the API shown here, but also in the actions 
// and node implementations.  The process variables are also  
// stored into the database as a part of the process instance.

processInstance.signal();

// The variables are accessible via the contextInstance. 

assertEquals(new Integer(500), 
             contextInstance.getVariable("amount"));
assertEquals("i met my deadline", 
             contextInstance.getVariable("reason"));

In the next example we'll show how you can assign a task to a user. Because of the separation between the jBPM workflow engine and the organisational model, an expression language for calculating actors would always be too limited. Therefore, you have to specify an implementation of AssignmentHandler for including the calculation of actors for tasks.

public void testTaskAssignment() {
  // The process shown below is based on the hello world process.
  // The state node is replaced by a task-node.  The task-node 
  // is a node in JPDL that represents a wait state and generates 
  // task(s) to be completed before the process can continue to 
  // execute.  
  ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
    "<process-definition name='the baby process'>" +
    "  <start-state>" +
    "    <transition name='baby cries' to='t' />" +
    "  </start-state>" +
    "  <task-node name='t'>" +
    "    <task name='change nappy'>" +
    "      <assignment class='org.jbpm.tutorial.taskmgmt.NappyAssignmentHandler' />" +
    "    </task>" +
    "    <transition to='end' />" +
    "  </task-node>" +
    "  <end-state name='end' />" +
    "</process-definition>"
  );
  
  // Create an execution of the process definition.
  ProcessInstance processInstance = 
      new ProcessInstance(processDefinition);
  Token token = processInstance.getRootToken();
  
  // Let's start the process execution, leaving the start-state 
  // over its default transition.
  token.signal();
  // The signal method will block until the process execution 
  // enters a wait state.   In this case, that is the task-node.
  assertSame(processDefinition.getNode("t"), token.getNode());

  // When execution arrived in the task-node, a task 'change nappy'
  // was created and the NappyAssignmentHandler was called to determine
  // to whom the task should be assigned.  The NappyAssignmentHandler 
  // returned 'papa'.

  // In a real environment, the tasks would be fetched from the
  // database with the methods in the org.jbpm.db.TaskMgmtSession.
  // Since we don't want to include the persistence complexity in 
  // this example, we just take the first task-instance of this 
  // process instance (we know there is only one in this test
  // scenario).
  TaskInstance taskInstance = (TaskInstance)  
      processInstance
        .getTaskMgmtInstance()
        .getTaskInstances()
        .iterator().next();

  // Now, we check if the taskInstance was actually assigned to 'papa'.
  assertEquals("papa", taskInstance.getActorId() );
  
  // Now we suppose that 'papa' has done his duties and mark the task 
  // as done. 
  taskInstance.end();
  // Since this was the last (only) task to do, the completion of this
  // task triggered the continuation of the process instance execution.
  
  assertSame(processDefinition.getNode("end"), token.getNode());
}

Actions are a mechanism to bind your custom java code into a jBPM process. Actions can be associated with its own nodes (if they are relevant in the graphical representation of the process). Or actions can be placed on events like e.g. taking a transition, leaving a node or entering a node. In that case, the actions are not part of the graphical representation, but they are executed when execution fires the events in a runtime process execution.

We'll start with a look at the action implementation that we are going to use in our example : MyActionHandler. This action handler implementation does not do really spectacular things... it just sets the boolean variable isExecuted to true. The variable isExecuted is static so it can be accessed from within the action handler as well as from the action to verify it's value.

More information about actions can be found in Section 9.5, “Actions”

// MyActionHandler represents a class that could execute 
// some user code during the execution of a jBPM process.
public class MyActionHandler implements ActionHandler {

  // Before each test (in the setUp), the isExecuted member 
  // will be set to false.
  public static boolean isExecuted = false;  

  // The action will set the isExecuted to true so the 
  // unit test will be able to show when the action
  // is being executed.
  public void execute(ExecutionContext executionContext) {
    isExecuted = true;
  }
}

As mentioned before, before each test, we'll set the static field MyActionHandler.isExecuted to false;

  // Each test will start with setting the static isExecuted 
  // member of MyActionHandler to false.
  public void setUp() {
    MyActionHandler.isExecuted = false;
  }

We'll start with an action on a transition.

public void testTransitionAction() {
    // The next process is a variant of the hello world process.
    // We have added an action on the transition from state 's' 
    // to the end-state.  The purpose of this test is to show 
    // how easy it is to integrate java code in a jBPM process.
    ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
      "<process-definition>" +
      "  <start-state>" +
      "    <transition to='s' />" +
      "  </start-state>" +
      "  <state name='s'>" +
      "    <transition to='end'>" +
      "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +
      "    </transition>" +
      "  </state>" +
      "  <end-state name='end' />" +
      "</process-definition>"
    );
    
    // Let's start a new execution for the process definition.
    ProcessInstance processInstance = 
      new ProcessInstance(processDefinition);
    
    // The next signal will cause the execution to leave the start 
    // state and enter the state 's'
    processInstance.signal();

    // Here we show that MyActionHandler was not yet executed. 
    assertFalse(MyActionHandler.isExecuted);
    // ... and that the main path of execution is positioned in 
    // the state 's'
    assertSame(processDefinition.getNode("s"), 
               processInstance.getRootToken().getNode());
    
    // The next signal will trigger the execution of the root 
    // token.  The token will take the transition with the
    // action and the action will be executed during the  
    // call to the signal method.
    processInstance.signal();
    
    // Here we can see that MyActionHandler was executed during 
    // the call to the signal method.
    assertTrue(MyActionHandler.isExecuted);
  }

The next example shows the same action, but now the actions are placed on the enter-node and leave-node events respectively. Note that a node has more than one event type in contrast to a transition, which has only one event. Therefore actions placed on a node should be put in an event element.

ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(
  "<process-definition>" +
  "  <start-state>" +
  "    <transition to='s' />" +
  "  </start-state>" +
  "  <state name='s'>" +
  "    <event type='node-enter'>" +
  "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +
  "    </event>" +
  "    <event type='node-leave'>" +
  "      <action class='org.jbpm.tutorial.action.MyActionHandler' />" +
  "    </event>" +
  "    <transition to='end'/>" +
  "  </state>" +
  "  <end-state name='end' />" +
  "</process-definition>"
);

ProcessInstance processInstance = 
  new ProcessInstance(processDefinition);

assertFalse(MyActionHandler.isExecuted);
// The next signal will cause the execution to leave the start 
// state and enter the state 's'.  So the state 's' is entered 
// and hence the action is executed. 
processInstance.signal();
assertTrue(MyActionHandler.isExecuted);

// Let's reset the MyActionHandler.isExecuted  
MyActionHandler.isExecuted = false;

// The next signal will trigger execution to leave the  
// state 's'.  So the action will be executed again. 
processInstance.signal();
// Voila.  
assertTrue(MyActionHandler.isExecuted);

jPDL is an embeddable BPM engine, which means that you can take the jPDL libraries and embed it into your own Java project, rather then installing a separate product and integrate with it. One of the key aspects that make this possible is minimizing the dependencies. This chapter discusses the jbpm libraries and their dependencies.

All the libraries on which jPDL might have a dependency, are located in the lib directory. The actual version of those libraries might depend on the JBoss server that you've selected in the installer.

In a minimal deployment, you can create and run processes with jBPM by putting only the commons-logging and dom4j library in your classpath. Beware that persisting processes to a database is not supported. The dom4j library can be removed if you don't use the process xml parsing, but instead build your object graph programatically.


A typical deployment for jBPM will include persistent storage of process definitions and process executions. In that case, jBPM does not have any dependencies outside hibernate and its dependent libraries.

Of course, hibernate's required libraries depend on the environment and what features you use. For details refer to the hibernate documentation. The next table gives an indication for a plain standalone POJO development environment.


The beanshell library is optional. If you don't include it, you won't be able to use the beanshell integration in the jBPM process language and you'll get a log message saying that jbpm couldn't load the Script class and hence, the script element won't be available.


The installer deploys jBPM into JBoss. This section walks you through the deployed components.

First of all, in case you're just starting to develop a new process, it is much easier to use plain JUnit tests and run the process in memory like explained in Chapter 3, Tutorial.

But if you want to run the process in the console and debug it there here are the 2 steps that you need to do:

1) in jboss-{version}/server/bin/run.bat, somewhere at the end, there is a line like this:

rem set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y %JAVA_OPTS%

For backup reasons, just start by making a copy of that line, then remove the first 'rem' and change suspend=y to suspend=n. Then you get something like

rem set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y %JAVA_OPTS%
set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n %JAVA_OPTS%

2) In your IDE debug by connecting to a remote Java application on localhost on port 8787. Then you can start adding break points and run through the processes with the console until the breakpoint is hit.

For more info about configuring logging of optimistic locking failures, see Section 5.4, “Logging of optimistic concurrency exceptions”

The simplest way to configure jBPM is by putting the jbpm.cfg.xml configuration file in the root of the classpath. If that file is not found as a resource, the default minimal configuration will be used that is included in the jbpm library (org/jbpm/default.jbpm.cfg.xml). If a jbpm configuration file is provided, the values configured will be used as defaults. So you only need to specify the parts that are different from the default configuration file.

The jBPM configuration is represented by the java class org.jbpm.JbpmConfiguration. Most easy way to get a hold of the JbpmConfiguration is to make use of the singleton instance method JbpmConfiguration.getInstance().

If you want to load a configuration from another source, you can use the JbpmConfiguration.parseXxxx methods.

static JbpmConfinguration jbpmConfiguration = JbpmConfinguration.parseResource("my.jbpm.cfg.xml");

The JbpmConfiguration is threadsafe and hence can be kept in a static member. All threads can use the JbpmConfiguration as a factory for JbpmContext objects. A JbpmContext typically represents one transaction. The JbpmContext makes services available inside of a context block. A context block looks like this:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  // This is what we call a context block.
  // Here you can perform workflow operations

} finally {
  jbpmContext.close();
}

The JbpmContext makes a set of services and the configuration available to jBPM. These services are configured in the jbpm.cfg.xml configuration file and make it possible for jBPM to run in any Java environment and use whatever services are available in that environment.

Here's the default configuration for the JbpmContext:

<jbpm-configuration>
  
  <jbpm-context>
    <service name="authentication" factory="org.jbpm.security.authentication.DefaultAuthenticationServiceFactory" />
    <service name="logging" factory="org.jbpm.logging.db.DbLoggingServiceFactory" />
    <service name="message" factory="org.jbpm.msg.db.DbMessageServiceFactory" />
    <service name="persistence" factory="org.jbpm.persistence.db.DbPersistenceServiceFactory" />
    <service name="scheduler" factory="org.jbpm.scheduler.db.DbSchedulerServiceFactory" />
    <service name="tx" factory="org.jbpm.tx.TxServiceFactory" />
  </jbpm-context>

  <!-- database persistence configuration  -->
  <string name="resource.hibernate.cfg.xml" value="hibernate.cfg.xml" />
  <!-- additional database persistence properties
  <string name="resource.hibernate.properties" value="hibernate.properties" />
  --> 

  <!-- entries pointing to default configuration resources in jbpm-jpdl.jar -->
  <string name="resource.business.calendar" value="org/jbpm/calendar/jbpm.business.calendar.properties" />
  <string name="resource.default.modules" value="org/jbpm/graph/def/jbpm.default.modules.properties" />
  <string name="resource.converter" value="org/jbpm/db/hibernate/jbpm.converter.properties" />
  <string name="resource.action.types" value="org/jbpm/graph/action/action.types.xml" />
  <string name="resource.node.types" value="org/jbpm/graph/node/node.types.xml" />
  <string name="resource.parsers" value="org/jbpm/jpdl/par/jbpm.parsers.xml" />
  <string name="resource.varmapping" value="org/jbpm/context/exe/jbpm.varmapping.xml" />
  <string name="resource.mail.templates" value="jbpm.mail.templates.xml" />

  <!-- alternate delegation class loader
  <string name="jbpm.class.loader" value="context" />
  -->
  <bean name="process.class.loader.factory" class="org.jbpm.instantiation.SharedProcessClassLoaderFactory" singleton="true" />
  <bean name="jbpm.task.instance.factory" class="org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl" singleton="true" />

  <!-- make sure the block size matches the length in ByteArray.hbm.xml -->
  <int name="jbpm.byte.block.size" value="1024" singleton="true" />

  <bean name="jbpm.expression.evaluator" class="org.jbpm.jpdl.el.impl.ExpressionEvaluatorImpl" singleton="true" />
  <bean name="jbpm.variable.resolver" class="org.jbpm.jpdl.el.impl.JbpmVariableResolver" singleton="true" />
  <!-- custom function mapper
  <bean name="jbpm.function.mapper" class="org.example.FunctionMapperImpl" />
  -->
  <!-- user code interceptor
  <bean name="jbpm.user.code.interceptor" class="org.example.UserCodeInterceptorImpl" />
  -->

  <!-- mail settings -->
  <string name="jbpm.mail.smtp.host" value="localhost" />
  <string name="jbpm.mail.from.address" value="jbpm@noreply" />
  <bean name="jbpm.mail.address.resolver" class="org.jbpm.identity.mail.IdentityAddressResolver" singleton="true" />
  
  <bean name="jbpm.job.executor" class="org.jbpm.job.executor.JobExecutor">
    <property name="jbpmConfiguration"><ref bean="jbpmConfiguration" /></property>
    <property name="name"><string value="JbpmJobExecutor" /></property>
    <property name="nbrOfThreads"><int value="1" /></property>
    <property name="retries"><int value="3" /></property>
    <property name="idleInterval"><int value="5000" /></property>
    <property name="maxIdleInterval"><int value="3600000" /><!-- 1 hour --></property>
    <property name="maxLockTime"><int value="600000" /><!-- 10 minutes --></property>
    <property name="lockMonitorInterval"><int value="60000" /><!-- 1 minute --></property>
    <property name="lockBufferTime"><int value="5000" /><!-- 5 seconds --></property>
  </bean>

</jbpm-configuration>

In this configuration file you can see 3 parts:

  • The first part configures the jbpm context with a set of service implementations. The possible configuration options are covered in the chapters that cover the specific service implementations.

  • The second part are all mappings of references to configuration resources. These resource references can be updated if you want to customize one of these configuration files. Typically, you make a copy the default configuration which is in the jbpm-3.x.jar and put it somewhere on the classpath. Then you update the reference in this file and jbpm will use your customized version of that configuration file.

  • The third part are some miscellaneous configurations used in jbpm. These configuration options are described in the chapters that cover the specific topic.

The default configured set of services is targeted at a simple webapp environment and minimal dependencies. The persistence service will obtain a jdbc connection and all the other services will use the same connection to perform their services. So all of your workflow operations are centralized into 1 transaction on a JDBC connection without the need for a transaction manager.

JbpmContext contains convenience methods for most of the common process operations:

  public void deployProcessDefinition(ProcessDefinition processDefinition) {...}
  public List getTaskList() {...}
  public List getTaskList(String actorId) {...}
  public List getGroupTaskList(List actorIds) {...}
  public TaskInstance loadTaskInstance(long taskInstanceId) {...}
  public TaskInstance loadTaskInstanceForUpdate(long taskInstanceId) {...}
  public Token loadToken(long tokenId) {...}
  public Token loadTokenForUpdate(long tokenId) {...}
  public ProcessInstance loadProcessInstance(long processInstanceId) {...}
  public ProcessInstance loadProcessInstanceForUpdate(long processInstanceId) {...}
  public ProcessInstance newProcessInstance(String processDefinitionName) {...}
  public void save(ProcessInstance processInstance) {...}
  public void save(Token token) {...}
  public void save(TaskInstance taskInstance) {...}
  public void setRollbackOnly() {...}

Note that the XxxForUpdate methods will register the loaded object for auto-save so that you don't have to call one of the save methods explicitly.

It's possible to specify multiple jbpm-contexts, but then you have to make sure that each jbpm-context is given a unique name attribute. Named contexts can be retrieved with JbpmConfiguration.createContext(String name);

A service element specifies the name of a service and the service factory for that service. The service will only be created in case it's asked for with JbpmContext.getServices().getService(String name).

The factories can also be specified as an element instead of an attribute. That might be necessary to inject some configuration information in the factory objects. The component responsible for parsing the XML, creating and wiring the objects is called the object factory.

Here's a short description of all the configuration files that are customizable in jBPM.

The object factory can create objects according to a beans-like xml configuration file. The configuration file specifies how objects should be created, configured and wired together to form a complete object graph. The object factory can inject the configurations and other beans into a bean.

In its simplest form, the object factory is able to create basic types and java beans from such a configuration:

<beans>
  <bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance"/>
  <string name="greeting">hello world</string>
  <int name="answer">42</int>
  <boolean name="javaisold">true</boolean>
  <float name="percentage">10.2</float>
  <double name="salary">100000000.32</double>
  <char name="java">j</char>
  <null name="dusttodust" />
</beans>

---------------------------------------------------------

ObjectFactory of = ObjectFactory.parseXmlFromAbove();
assertEquals(TaskInstance.class, of.getNewObject("task").getClass());
assertEquals("hello world", of.getNewObject("greeting"));
assertEquals(new Integer(42), of.getNewObject("answer"));
assertEquals(Boolean.TRUE, of.getNewObject("javaisold"));
assertEquals(new Float(10.2), of.getNewObject("percentage"));
assertEquals(new Double(100000000.32), of.getNewObject("salary"));
assertEquals(new Character('j'), of.getNewObject("java"));
assertNull(of.getNewObject("dusttodust"));

Also you can configure lists:

<beans>
  <list name="numbers">
    <string>one</string>
    <string>two</string>
    <string>three</string>
  </list>
</beans>

and maps

<beans>
  <map name="numbers">
    <entry><key><int>1</int></key><value><string>one</string></value></entry>
    <entry><key><int>2</int></key><value><string>two</string></value></entry>
    <entry><key><int>3</int></key><value><string>three</string></value></entry>
  </map>
</beans>

Beans can be configured with direct field injection and via property setters.

<beans>
  <bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
    <field name="name"><string>do dishes</string></field>
    <property name="actorId"><string>theotherguy</string></property>
  </bean>
</beans>

Beans can be referenced. The referenced object doesn't have to be a bean, it can be a string, integer or any other object.

<beans>
  <bean name="a" class="org.jbpm.A" />
  <ref name="b" bean="a" />
</beans>

Beans can be constructed with any constructor

<beans>
  <bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
    <constructor>
      <parameter class="java.lang.String">
        <string>do dishes</string>
      </parameter>
      <parameter class="java.lang.String">
        <string>theotherguy</string>
      </parameter>
    </constructor>
  </bean>
</beans>

... or with a factory method on a bean ...

<beans>
  <bean name="taskFactory" 
         class="org.jbpm.UnexistingTaskInstanceFactory" 
         singleton="true"/>

  <bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
    <constructor factory="taskFactory" method="createTask" >
      <parameter class="java.lang.String">
        <string>do dishes</string>
      </parameter>
      <parameter class="java.lang.String">
        <string>theotherguy</string>
      </parameter>
    </constructor>
  </bean>
</beans>

... or with a static factory method on a class ...

<beans>
  <bean name="task" class="org.jbpm.taskmgmt.exe.TaskInstance" >
    <constructor factory-class="org.jbpm.UnexistingTaskInstanceFactory" method="createTask" >
      <parameter class="java.lang.String">
        <string>do dishes</string>
      </parameter>
      <parameter class="java.lang.String">
        <string>theotherguy</string>
      </parameter>
    </constructor>
  </bean>
</beans>

Each named object can be marked as singleton with the attribute singleton="true". That means that a given object factory will always return the same object for each request. Note that singletons are not shared between different object factories.

The singleton feature causes the differentiation between the methods getObject and getNewObject. Typical users of the object factory will use the getNewObject. This means that first the object factory's object cache is cleared before the new object graph is constructed. During construction of the object graph, the non-singleton objects are stored in the object factory's object cache to allow for shared references to one object. The singleton object cache is different from the plain object cache. The singleton cache is never cleared, while the plain object cache is cleared at the start of every getNewObject method.

In most scenarios, jBPM is used to maintain execution of processes that span a long time. In this context, "a long time" means spanning several transactions. The main purpose of persistence is to store process executions during wait states. So think of the process executions as state machines. In one transaction, we want to move the process execution state machine from one state to the next.

A process definition can be represented in 3 different forms : as xml, as java objects and as records in the jBPM database. Executional (=runtime) information and logging information can be represented in 2 forms : as java objects and as records in the jBPM database.


For more information about the xml representation of process definitions and process archives, see JPDL.

The persistence API is an integrated with the configuration framework (Chapter 5, Configuration) by exposing some convenience persistence methods on the JbpmContext. Persistence API operations can therefore be called inside a jBPM context block like this:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {

  // Invoke persistence operations here

} finally {
  jbpmContext.close();
}

In the following sections, the configuration is assumed to include a persistence service as shown below.

<jbpm-configuration>

  <jbpm-context>
    <service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />
    ...
  </jbpm-context>
  ...
</jbpm-configuration>

The three most common persistence operations are:

First deploying a process definition. Typically, this will be done directly from the graphical process designer or from the deployprocess ant task. But here you can see how this is done programmatically:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  ProcessDefinition processDefinition = ...;
  jbpmContext.deployProcessDefinition(processDefinition);
} finally {
  jbpmContext.close();
}

For the creation of a new process execution, we need to specify of which process definition this execution will be an instance. The most common way to specify this is to refer to the name of the process and let jBPM find the latest version of that process in the database:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  String processName = ...;
  ProcessInstance processInstance = 
      jbpmContext.newProcessInstance(processName);
} finally {
  jbpmContext.close();
}

For continuing a process execution, we need to fetch the process instance, the token or the taskInstance from the database, invoke some methods on the POJO jBPM objects and afterwards save the updates made to the processInstance into the database again.

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long processInstanceId = ...;
  ProcessInstance processInstance = 
      jbpmContext.loadProcessInstance(processInstanceId);
  processInstance.signal();
  jbpmContext.save(processInstance);
} finally {
  jbpmContext.close();
}

Note that if you use the xxxForUpdate methods in the JbpmContext, an explicit invocation of the jbpmContext.save is not necessary any more because it will then occur automatically during the close of the jbpmContext. E.g. suppose we want to inform jBPM about a taskInstance that has been completed. Note that task instance completion can trigger execution to continue so the processInstance related to the taskInstance must be saved. The most convenient way to do this is to use the loadTaskInstanceForUpdate method:

JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
try {
  long taskInstanceId = ...;
  TaskInstance taskInstance = 
      jbpmContext.loadTaskInstanceForUpdate(taskInstanceId);
  taskInstance.end();
} finally {
  jbpmContext.close();
}

Just as background information, the next part is an explanation of how jBPM manages the persistence through Hibernate.

The JbpmConfiguration maintains a list of ServiceFactory instances. The service factories are configured in jbpm.cfg.xml and instantiated as needed. The DbPersistenceServiceFactory manages a Hibernate SessionFactory. The session factory is built on demand as well, since not every operation in DbPersistenceServiceFactory requires it.


During the invocation of jbpmConfiguration.createJbpmContext(), only the JbpmContext is created. No further persistence related initializations are done at that time. The JbpmContext maintains a sequence of Service instances, created as needed. The DbPersistenceService wraps a Hibernate session which is opened when the first persistence operation is performed.

The DbPersistenceServiceFactory itself has 3 more configuration properties: isTransactionEnabled, sessionFactoryJndiName and dataSourceJndiName. To specify any of these properties in the jbpm.cfg.xml, you need to specify the service factory as a bean in the factory element like this:

IMPORTANT: don't mix the short and long notation for configuring the factories. See also Section 5.1, “Customizing factories”. If the factory is just a new instance of a class, you can use the factory attribute to refer to the factory class name. But if properties in a factory must be configured, the long notation must be used and factory and bean must be combined as nested elements. Like this:

  <jbpm-context>
    <service name="persistence">
      <factory>
        <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
          <field name="isTransactionEnabled"><false /></field>
          <field name="sessionFactoryJndiName">
            <string value="java:/myHibSessFactJndiName" />
          </field>
          <field name="dataSourceJndiName">
            <string value="java:/myDataSourceJndiName" />
          </field>
        </bean>
      </factory>
    </service>
    ...
  </jbpm-context>
isTransactionEnabled

by default, jBPM will begin a hibernate transaction when the session is fetched the first time and if the jbpmContext is closed, the hibernate transaction will be ended. The transaction is then committed or rolled back depending on wether jbpmContext.setRollbackOnly was called. The isRollbackOnly property is maintained in the TxService. To disable transactions and prohibit jBPM from managing transactions with hibernate, configure the isTransactionEnabled property to false as in the example above. This property only controls the behaviour of the jbpmContext, you can still call the DbPersistenceService.beginTransaction() directly with the API, which ignores the isTransactionEnabled setting. For more info about transactions, see Section 6.3, “Hibernate transactions”.

sessionFactoryJndiName

by default, this is null, meaning that the session factory is not fetched from JNDI. If set and a session factory is needed to create a hibernate session, the session factory will be fetched from jndi using the provided JNDI name.

dataSourceJndiName

by default, this is null and creation of JDBC connections will be delegated to hibernate. By specifying a datasource, jBPM will fetch a JDBC connection from the datasource and provide that to hibernate while opening a new session. For user provided JDBC connections, see Section 6.1.5, “Injecting resources programmatically”.

If you want to configure jBPM with JBossCache, have a look at the jBPM configuration wiki page

For more information about configuring a cache provider in hibernate, take a look at the hibernate documentation, section 'Second level cache'

The hibernate.cfg.xml that ships with jBPM includes the following line:

<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

This is done to get people up and running as fast as possible without having to worrie about classpaths. Note that hibernate contains a warning that states not to use the HashtableCacheProvider in production.

To use ehcache instead of the HashtableCacheProvider, simply remove that line and put ehcache.jar on the classpath. Note that you might have to search for the right ehcache library version that is compatible with your environmment. Previous incompatibilities between a jboss version and a perticular ehcache version were the reason to change the default to HashtableCacheProvider.

The most common scenario for managed transactions is when using jBPM in a JEE application server like JBoss. The most common scenario to bind your transactions to JTA is the following:

  <jbpm-context>
    <service name="persistence">
      <factory>
        <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
          <field name="isTransactionEnabled"><false /></field>
          <field name="isCurrentSessionEnabled"><true /></field>
          <field name="sessionFactoryJndiName">
            <string value="java:/myHibSessFactJndiName" />
          </field>
        </bean>
      </factory>
    </service>
    ...
  </jbpm-context>

Then you should specify in your hibernate session factory to use a datasource and bind hibernate to the transaction manager. Make sure that you bind the datasource to an XA datasource in case you're using more then 1 resource. For more information about binding hibernate to your transaction manager, please, refer to paragraph 'Transaction strategy configuration' in the hibernate documentation.

<hibernate-configuration>
  <session-factory>

    <!-- hibernate dialect -->
    <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>

    <!-- DataSource properties (begin) -->
    <property name="hibernate.connection.datasource">java:/JbpmDS</property>

    <!-- JTA transaction properties (begin) -->
    <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
    <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
    <property name="jta.UserTransaction">java:comp/UserTransaction</property>

    ...
  </session-factory>
</hibernate-configuration>

Then make sure that you have configured hibernate to use an XA datasource.

These configurations allow for the enterprise beans to use CMT and still allow the web console to use BMT. That is why the property 'jta.UserTransaction' is also specified.

jBPM runs on any database that is supported by hibernate.

The example configuration files in jBPM (src/config.files) specify the use of the hypersonic in-memory database. That database is ideal during development and for testing. The hypersonic in-memory database keeps all its data in memory and doesn't store it on disk.

The database and config directories in the distribution contain scripts and Hibernate configuration files to help you get started on your choice database.

While jBPM is capable of generating DDL scripts for any database supported by Hibernate, the resulting schemas are not always optimized. You might want to have your DBA review the DDL that is generated to optimize the column types and use of indexes.

In development you might be interested in the following hibernate configuration: If you set hibernate configuration property hibernate.hbm2ddl.auto to create-drop in the Hibernate configuration file, the database schema will be automatically created the first time the application accesses the database. When the application closes down, the schema will be dropped.

jBPM provides an API for creating and droping the database schema through the org.jbpm.JbpmConfiguration methods createSchema and dropSchema. Be aware that there is no constraint on invoking these methods other than the privileges of the configured database user.

The aforementioned APIs constitute a facade to the broader functionality offered by class org.jbpm.db.JbpmSchema:

  • Create, drop, update and clean (drop-create) the database schema

  • Generate SQL scripts for the above operations

  • List the mapped tables and query the existing tables in the database

Switching the JBoss jBPM database backend is reasonably straightforward. We will step through this process using PostgreSQL and MySQL as an example. The process is identical for all other supported databases. For a number of these supported databases, a number of JDBC drivers, Hibernate configuration files and Ant build files to generate the database creation scripts are present in the jBPM distribution in the DB subproject. If you cannot find these files for the database you wish to use, you should first make sure if Hibernate supports your database. If this is the case you can have a look at files for one of the databases present in the DB project and mimic this using your own database.

For this document, we will use the jBPM jPDL installer. Download and install as described in Section 2.1, “Downloading and installing jBPM”. We will assume that this installation was done to a location on your machine named ${jbpm-jpdl-home}. You will find the DB subproject of jBPM in the ${jbpm-jpdl-home}/db.

After installing the database of your choice, you will have to run the database creation scripts to create the jBPM tables. Note that in the hsqldb inside jboss this is done automatically during installation.

To install PostgreSQL or any other database you may be using, we refer to the installation manual of these products. For Windows PostgreSQL installation is pretty straightforward. The installer creates a dedicated Windows user and allows to define the database administrator. PostgreSQL comes with an administration tool called pgAdmin III that we will use to create the jBPM database. A screenshot of this tool right after creating the JbpmDB database with it is shown in the figure below.


After the installation of the database, we can use the pgAdmin III Query tool to look at the contents of the database.

Before we do, we have to define a database connection in pgAdmin to our newly created database. We will use this tool further in this document to make sure the creation scripts and process deployment are working as expected. For an example of creating the connection in pgAdmin we refer to the following figure. As you will see, there are no tables present yet in this database. We will create them in the following section.


Another thing worth mentioning is the Database URL above : 'jdbc:postgresql://localhost:5432/JbpmDB'. If you created the JbpmDB database with another name, or if PostgreSQL is not running on the localhost machine or on another port, you'll have to adapt your Database URL accordingly.

In order to get the proper database scripts for your database, you should look int the directory ${jbpm-jpdl-home}/db. Using your database admin console, navigate to the database and then open and execute the create script we just referenced. Below are screen shots doing this for PostgreSQL and MySQL under their respective admin consoles

Before we can really use our newly created database with the JBoss jBPM default web app we will have to do some updates to the JBoss jBPM configuration. The location of the jbpm server configuration is ${jboss-home}/server/default/deploy/jbpm.

First we create a new datasource in JBoss that binds to our database. In the default installation, this is the done in the file jbpm-hsqldb-ds.xml. That hypersonic database configuration file can be removed and should be replaced by the a file that ends with -ds.xml like e.g. jbpm-postgres-ds.xml

<?xml version="1.0" encoding="UTF-8"?>

<datasources>
  <local-tx-datasource>
    <jndi-name>JbpmDS</jndi-name>
    <connection-url>jdbc:postgresql://localhost:5432/JbpmDB</connection-url>
    <driver-class>org.postgresql.Driver</driver-class>
    <user-name>user</user-name>
    <password>password</password>
    <metadata>
      <type-mapping>PostgreSQL 8.1</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

For MySQL, the datasource definition would look as follows:

<datasources>
  <local-tx-datasource>
    <jndi-name>JbpmDS</jndi-name>
    <connection-url>jdbc:mysql://localhost:3306/jbpmdb</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>root</password>
    <metadata>
      <type-mapping>MySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>

Of course it is possible that you have to change some of the values in this file to accommodate for your particular situation. You then simply save this file in the ${jboss-home}/server/default/deploy/jbpm folder. Congratulations, you just created a new DataSource for your JBoss jBPM server. Well, almost... To make things really work you will have to copy the correct JDBC driver to the ${jboss.home}/server/default/lib folder. The file is named postgresql-8.1-*.jdbc3.jar and it can be found in the jdbc subdirectory of your PostgreSQL installation folder.

For MySQL, copy the jdbc driver installed from the MySQL ConnectorJ package. The version you need to use is currently the MySQL Connector/J 3.1 available from http://www.mysql.com/products/connector/j/

The last thing we have to do to make everything run is to update the hibernate configuration file hibernate.cfg.xml. That file is located in directory ${jboss.home}/server/default/deploy/jbpm-service.sar. Replace the section containing the jdbc connection properties. This section should look like shown in the listing below. There are two changes in this file : the hibernate.connection.datasource property should point to the JbpmDS datasource we created as the first step in this section and the hibernate.dialect property should match the PostgreSQL or MySQL dialect.

Below is a sample of the 2 changes required, comment out the version of the dialect you don't need depending on the database you are using. You can get a list of supported database Dialect types from here http://www.hibernate.org/hib_docs/v3/reference/en/html/session-configuration.html#configuration-optional-dialects

<hibernate-configuration>
  <session-factory>

    <!-- jdbc connection properties -->
    <!-- comment out the dialect not needed! -->
    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.datasource">java:/JbpmDS</property>
        
    <!-- other hibernate properties 
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    -->
    
    <!-- ############################################ -->
    <!-- # mapping files with external dependencies # -->
    <!-- ############################################ -->

    ...

  </session-factory>
</hibernate-configuration>

Now we are ready to fire up the server, and look if the web app works. You will not be able to start any processes yet, as there are no processes deployed yet. To do this we refer to the document on process definition deployment.

The present chapter describes the facilities offered by jBPM to leverage the Java EE infrastructure.

CommandServiceBean is a stateless session bean that executes jBPM commands by calling it's execute method within a separate jBPM context. The environment entries and resources available for customization are summarized in the table below.


CommandListenerBean is a message-driven bean that listens on the CommandQueue for command messages. This bean delegates command execution to the CommandServiceBean.

The body of the message must be a Java object that implements the org.jbpm.Command interface. The message properties, if any, are ignored. If the message does not match the expected format, it is forwarded to the DeadLetterQueue. No further processing is done on the message. If the destination reference is absent, the message is rejected.

In case the received message specifies a replyTo destination, the result of the command execution is wrapped into an object message and sent there. The command connection factory environment reference indicates the resource manager that supplies JMS connections.

Conversely, JobListenerBean is a message-driven bean that listens on the JbpmJobQueue for job messages to support asynchronous continuations.

The message must have a property called jobId of type long which references a pending Job in the database. The message body, if any, is ignored.

This bean extends the CommandListenerBean and inherits its environment entries and resource references available for customization.


The TimerEntityBean interacts with the EJB timer service to schedule jBPM timers. Upon expiration, execution of the timer is actually delegated to the command service bean.

The timer entity bean requires access to the jBPM data source for reading timer data. The EJB deployment descriptor does not provide a way to define how an entity bean maps to a database. This is left off to the container provider. In JBoss AS, the jbosscmp-jdbc.xml descriptor defines the data source JNDI name and the relational mapping data (table and column names, among others). Note that the JBoss CMP descriptor uses a global JNDI name (java:JbpmDS), as opposed to a resource manager reference (java:comp/env/jdbc/JbpmDataSource).

Earlier versions of jBPM used a stateless session bean called TimerServiceBean to interact with the EJB timer service. The session approach had to be abandoned because there is an unavoidable bottleneck at the cancelation methods. Because session beans have no identity, the timer service is forced to iterate through all the timers for finding the ones it has to cancel. The bean is still around for backwards compatibility. It works under the same environment as the TimerEntityBean, so migration is easy.


jbpm.cfg.xml includes the following configuration items:

<jbpm-context>
  <service name="persistence"
           factory="org.jbpm.persistence.jta.JtaDbPersistenceServiceFactory" />
  <service name="message"
           factory="org.jbpm.msg.jms.JmsMessageServiceFactory" />
  <service name="scheduler"
           factory="org.jbpm.scheduler.ejbtimer.EntitySchedulerServiceFactory" />
</jbpm-context>

JtaDbPersistenceServiceFactory enables jBPM to participate in JTA transactions. If an existing transaction is underway, the JTA persistence service clings to it; otherwise it starts a new transaction. The jBPM enterprise beans are configured to delegate transaction management to the container. However, if you create a JbpmContext in an environment where no transaction is active (say, in a web application), one will be started automatically. The JTA persistence service factory has the configurable fields described below.

isCurrentSessionEnabled

if true, jBPM will use the "current" Hibernate session associated with the ongoing JTA transaction. This is the default setting. See the Hibernate guide, section 2.5 Contextual sessions for a description of the behavior. You can take advantage of the contextual session mechanism to use the same session used by jBPM in other parts of your application through a call to SessionFactory.getCurrentSession(). On the other hand, you might want to supply your own Hibernate session to jBPM. To do so, set isCurrentSessionEnabled to false and inject the session via the JbpmContext.setSession(session) method. This will also ensure that jBPM uses the same Hibernate session as other parts of your application. Note, the Hibernate session can be injected into a stateless session bean via a persistence context, for example.

isTransactionEnabled

a true value for this field means jBPM will begin a transaction through Hibernate's transaction API (section 11.2. Database transaction demarcation of the Hibernate manual shows the API) upon JbpmConfiguration.createJbpmContext(), commit the transaction and close the Hibernate session upon JbpmContext.close(). This is NOT the desired behaviour when jBPM is deployed as an ear, hence isTransactionEnabled is set to false by default.

JmsMessageServiceFactory leverages the reliable communication infrastructure exposed through JMS interfaces to deliver asynchronous continuation messages to the JobListenerBean. The JMS message service factory exposes the following configurable fields.

connectionFactoryJndiName

the JNDI name of the JMS connection factory. Defaults to java:comp/env/jms/JbpmConnectionFactory.

destinationJndiName

the JNDI name of the JMS destination where job messages are sent. Must match the destination where JobListenerBean receives messages. Defaults to java:comp/env/jms/JobQueue.

isCommitEnabled

tells whether the message service should create a transacted session and either commit or rollback on close. Messages produced by the JMS message service are never meant to be received before the database transaction commits. The J2EE tutorial states "when you create a session in an enterprise bean, the container ignores the arguments you specify, because it manages all transactional properties for enterprise beans". Unfortunately the tutorial fails to indicate that said behavior is not prescriptive. JBoss ignores the transacted argument if the connection factory supports XA, since the overall JTA transaction controls the session. Otherwise, transacted produces a locally transacted session. In Weblogic, JMS transacted sessions are agnostic to JTA transactions even if the connection factory is XA enabled. With isCommitEnabled set to false (the default), the message service creates a nontransacted, auto-acknowledging session. Such a session works with containers that either disregard the creation arguments or do not bind transacted sessions to JTA. Conversely, setting isCommitEnabled to true causes the message service to create a transacted session and commit or rollback according to the TxService.isRollbackOnly method.

EntitySchedulerServiceFactory builds on the transactional notification service for timed events provided by the EJB container to schedule business process timers. The EJB scheduler service factory has the configurable field described below.

timerEntityHomeJndiName

the name of the TimerEntityBean's local home interface in the JNDI initial context. Defaults to java:comp/env/ejb/TimerEntityBean.

hibernate.cfg.xml includes the following configuration items that may be modified to support other databases or application servers.

<!-- sql dialect -->
<property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>

<property name="hibernate.cache.provider_class">
  org.hibernate.cache.HashtableCacheProvider
</property>

<!-- DataSource properties (begin) -->
<property name="hibernate.connection.datasource">java:comp/env/jdbc/JbpmDataSource</property>
<!-- DataSource properties (end) -->

<!-- JTA transaction properties (begin) -->
<property name="hibernate.transaction.factory_class">
  org.hibernate.transaction.JTATransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
  org.hibernate.transaction.JBossTransactionManagerLookup
</property>
<!-- JTA transaction properties (end) -->

<!-- CMT transaction properties (begin) ===
<property name="hibernate.transaction.factory_class">
  org.hibernate.transaction.CMTTransactionFactory
</property>
<property name="hibernate.transaction.manager_lookup_class">
  org.hibernate.transaction.JBossTransactionManagerLookup
</property>
==== CMT transaction properties (end) -->

You may replace the hibernate.dialect with one that corresponds to your database management system. The Hibernate reference guide enumerates the available database dialects in section 3.4.1 SQL dialects.

HashtableCacheProvider can be replaced with other supported cache providers. Refer to section 19.2 The second level cache of the Hibernate manual for a list of the supported cache providers.

The JBossTransactionManagerLookup may be replaced with a strategy appropriate to applications servers other than JBoss. See section 3.8.1 Transaction strategy configuration to find the lookup class that corresponds to each application server.

Note that the JNDI name used in hibernate.connection.datasource is, in fact, a resource manager reference, portable across application servers. Said reference is meant to be bound to an actual data source in the target application server at deployment time. In the included jboss.xml descriptor, the reference is bound to java:JbpmDS.

Out of the box, jBPM is configured to use the JTATransactionFactory. If an existing transaction is underway, the JTA transaction factory uses it; otherwise it creates a new transaction. The jBPM enterprise beans are configured to delegate transaction management to the container. However, if you use the jBPM APIs in a context where no transaction is active (say, in a web application), one will be started automatically.

If your own EJBs use container-managed transactions and you want to prevent unintended transaction creations, you can switch to the CMTTransactionFactory. With that setting, Hibernate will always look for an existing transaction and will report a problem if none is found.

Client components written directly against the jBPM APIs that wish to leverage the enterprise services must ensure that their deployment descriptors have the appropriate environment references in place. The descriptor below can be regarded as typical for a client session bean.

<session>

  <ejb-name>MyClientBean</ejb-name>
  <home>org.example.RemoteClientHome</home>
  <remote>org.example.RemoteClient</remote>
  <local-home>org.example.LocalClientHome</local-home>
  <local>org.example.LocalClient</local>
  <ejb-class>org.example.ClientBean</ejb-class>
  <session-type>Stateless</session-type>
  <transaction-type>Container</transaction-type>

  <ejb-local-ref>
    <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home>
    <local>org.jbpm.ejb.LocalTimerEntity</local>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnnectionFactory</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
  </message-destination-ref>

</session>

Provided the target application server was JBoss, the above environment references could be bound to resources in the target operational environment as follows. Note that the JNDI names match the values used by the jBPM enterprise beans.

<session>

  <ejb-name>MyClientBean</ejb-name>
  <jndi-name>ejb/MyClientBean</jndi-name>
  <local-jndi-name>java:ejb/MyClientBean</local-jndi-name>

  <ejb-local-ref>
    <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name>
    <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <jndi-name>java:JbpmDS</jndi-name>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <jndi-name>java:JmsXA</jndi-name>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <jndi-name>queue/JbpmJobQueue</jndi-name>
  </message-destination-ref>

</session>

In case the client component is a web application, as opposed to an enterprise bean, the deployment descriptor would look like this:

<web-app>

  <servlet>
    <servlet-name>MyClientServlet</servlet-name>
    <servlet-class>org.example.ClientServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>MyClientServlet</servlet-name>
    <url-pattern>/client/servlet</url-pattern>
  </servlet-mapping>

  <ejb-local-ref>
    <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name>
    <ejb-ref-type>Entity</ejb-ref-type>
    <local-home>org.jbpm.ejb.LocalTimerEntityHome</local-home>
    <local>org.jbpm.ejb.LocalTimerEntity</local>
    <ejb-link>TimerEntityBean</ejb-link>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <res-type>javax.jms.ConnectionFactory</res-type>
    <res-auth>Container</res-auth>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <message-destination-type>javax.jms.Queue</message-destination-type>
    <message-destination-usage>Produces</message-destination-usage>
    <message-destination-link>JobQueue</message-destination-link>
  </message-destination-ref>

</web-app>

The above environment references could be bound to resources in the target operational environment as follows, if the target application server was JBoss.

<jboss-web>

  <ejb-local-ref>
    <ejb-ref-name>ejb/TimerEntityBean</ejb-ref-name>
    <local-jndi-name>java:ejb/TimerEntityBean</local-jndi-name>
  </ejb-local-ref>

  <resource-ref>
    <res-ref-name>jdbc/JbpmDataSource</res-ref-name>
    <jndi-name>java:JbpmDS</jndi-name>
  </resource-ref>

  <resource-ref>
    <res-ref-name>jms/JbpmConnectionFactory</res-ref-name>
    <jndi-name>java:JmsXA</jndi-name>
  </resource-ref>

  <message-destination-ref>
    <message-destination-ref-name>jms/JobQueue</message-destination-ref-name>
    <jndi-name>queue/JbpmJobQueue</jndi-name>
  </message-destination-ref>

</jboss-web>

A process definition represents a formal specification of a business process and is based on a directed graph. The graph is composed of nodes and transitions. Every node in the graph is of a specific type. The type of the node defines the runtime behaviour. A process definition has exactly one start state.

A token is one path of execution. A token is the runtime concept that maintains a pointer to a node in the graph.

A process instance is one execution of a process definition. When a process instance is created, a token is created for the main path of execution. This token is called the root token of the process instance and it is positioned in the start state of the process definition.

A signal instructs a token to continue graph execution. When receiving an unnamed signal, the token will leave its current node over the default leaving transition. When a transition-name is specified in the signal, the token will leave its node over the specified transition. A signal given to the process instance is delegated to the root token.

After the token has entered a node, the node is executed. Nodes themselves are responsible for the continuation of the graph execution. Continuation of graph execution is done by making the token leave the node. Each node type can implement a different behaviour for the continuation of the graph execution. A node that does not propagate execution will behave as a state.

Actions are pieces of java code that are executed upon events in the process execution. The graph is an important instrument in the communication about software requirements. But the graph is just one view (projection) of the software being produced. It hides many technical details. Actions are a mechanism to add technical details outside of the graphical representation. Once the graph is put in place, it can be decorated with actions. The main event types are entering a node, leaving a node and taking a transition.

A process graph is made up of nodes and transitions.

Each node has a specific type. The node type determines what will happen when an execution arrives in the node at runtime. jBPM has a set of preimplemented node types that you can use. Alternatively, you can write custom code for implementing your own specific node behaviour.

Each node has 2 main responsibilities: First, it can execute plain java code. Typically the plain java code relates to the function of the node. E.g. creating a few task instances, sending a notification, updating a database,... Secondly, a node is responsible for propagating the process execution. Basically, each node has the following options for propagating the process execution:

jBPM contains --as any workflow and BPM engine-- a set of preimplemented node types that have a specific documented configuration and behaviour. But the unique thing about jBPM and the Graph Oriented Programming foundation. is that we open up the model for developers. Developers can write their own node behaviour very easy and use it in a process.

That is where traditional workflow and BPM systems are much more closed. They usually supply a fixed set of node types (called the process language). Their process language is closed and the executional model is hidden in the runtime environment. Research of workflow patterns (http://www.workflowpatterns.com) has shown that any process language is not powerfull enough. We have decided for a simple model and allow developers to write their own node types. That way the JPDL process language is open ended.

Next, we discuss the most important node types of JPDL.

Actually there are 2 ways to model a decision. The distinction between the two is based on *who* is making the decision. Should the decision made by the process (read: specified in the process definition). Or should an external entity provide the result of the decision.

When the decision is to be taken by the process, a decision node should be used. There are basically 2 ways to specify the decision criteria. Simplest is by adding condition elements on the transitions. Conditions are EL expressions or beanshell scripts that return a boolean.

At runtime the decision node will FIRST loop over its leaving transitions THAT HAVE a condition specified. It will evaluate those transitions first in the order as specified in the xml. The first transition for which the conditions resolves to 'true' will be taken. If all transitions with a condition resolve to false, the default transition (the first in the XML) is taken.

Another approach is to use an expression that returns the name of the transition to take. With the 'expression' attribute, you can specify an expression on the decision that has to resolve to one of the leaving transitions of the decision node.

Next aproach is the 'handler' element on the decision, that element can be used to specify an implementation of the DecisionHandler interface can be specified on the decision node. Then the decision is calculated in a java class and the selected leaving transition is returned by the decide-method of the DecisionHandler implementation.

When the decision is taken by an external party (meaning: not part of the process definition), you should use multiple transitions leaving a state or wait state node. Then the leaving transition can be provided in the external trigger that resumes execution after the wait state is finished. E.g. Token.signal(String transitionName) and TaskInstance.end(String transitionName).

The type node serves the situation where you want to write your own code in a node. The nodetype node expects one subelement action. The action is executed when the execution arrives in the node. The code you write in the actionhandler can do anything you want but it is also responsible for propagating the execution (Section 9.3.1, “Node responsibilities”.)

This node can be used if you want to use a JavaAPI to implement some functional logic that is important for the business analyst. By using a node, the node is visible in the graphical representation of the process. For comparison, actions --covered next-- will allow you to add code that is invisible in the graphical representation of the process, in case that logic is not important for the business analyst.

Actions are pieces of java code that are executed upon events in the process execution. The graph is an important instrument in the communication about software requirements. But the graph is just one view (projection) of the software being produced. It hides many technical details. Actions are a mechanism to add technical details outside of the graphical representation. Once the graph is put in place, it can be decorated with actions. This means that java code can be associated with the graph without changing the structure of the graph. The main event types are entering a node, leaving a node and taking a transition.

Note the difference between an action that is placed in an event versus an action that is placed in a node. Actions that are put in an event are executed when the event fires. Actions on events have no way to influence the flow of control of the process. It is similar to the observer pattern. On the other hand, an action that is put on a node (Section 9.3.7, “Nodetype node”) has the responsibility (Section 9.3.1, “Node responsibilities”) of propagating the execution.

Let's look at an example of an action on an event. Suppose we want to do a database update on a given transition. The database update is technically vital but it is not important to the business analyst.


public class RemoveEmployeeUpdate implements ActionHandler {
  public void execute(ExecutionContext ctx) throws Exception {
    // get the fired employee from the process variables.
    String firedEmployee = (String) ctx.getContextInstance().getVariable("fired employee");
    
    // by taking the same database connection as used for the jbpm updates, we 
    // reuse the jbpm transaction for our database update.
    Connection connection = ctx.getProcessInstance().getJbpmSession().getSession().getConnection();
    Statement statement = connection.createStatement();
    statement.execute("DELETE FROM EMPLOYEE WHERE ...");
    statement.execute(); 
    statement.close();
  }
}
<process-definition name="yearly evaluation">

  ...
  <state name="fire employee">
    <transition to="collect badge">
      <action class="com.nomercy.hr.RemoveEmployeeUpdate" />
    </transition>
  </state>
  
  <state name="collect badge">
  ...
  
</process-definition>

A script is an action that executes a beanshell script. For more information about beanshell, see the beanshell website. By default, all process variables are available as script-variables and no script-variables will be written to the process variables. Also the following script-variables will be available :

  • executionContext

  • token

  • node

  • task

  • taskInstance

<process-definition>
  <event type="node-enter">
    <script>
      System.out.println("this script is entering node "+node);
    </script>
  </event>
  ...
</process-definition>

To customize the default behaviour of loading and storing variables into the script, the variable element can be used as a sub-element of script. In that case, the script expression also has to be put in a subelement of script: expression.

<process-definition>
  <event type="process-end">
    <script>
      <expression>
        a = b + c;
      </expression>
      <variable name='XXX' access='write' mapped-name='a' />
      <variable name='YYY' access='read' mapped-name='b' />
      <variable name='ZZZ' access='read' mapped-name='c' />
    </script>
  </event>
  ...
</process-definition>

Before the script starts, the process variables YYY and ZZZ will be made available to the script as script-variables b and c respectively. After the script is finished, the value of script-variable a is stored into the process variable XXX.

If the access attribute of variable contains 'read', the process variable will be loaded as a script-variable before script evaluation. If the access attribute contains 'write', the script-variable will be stored as a process variable after evaluation. The attribute mapped-name can make the process variable available under another name in the script. This can be handy when your process variable names contain spaces or other invalid script-literal-characters.

A Superstate is a group of nodes. Superstates can be nested recursively. Superstates can be used to bring some hierarchy in the process definition. For example, one application could be to group all the nodes of a process in phases. Actions can be associated with superstate events. A consequence is that a token can be in multiple nested nodes at a given time. This can be convenient to check wether a process execution is e.g. in the start-up phase. In the jBPM model, you are free to group any set of nodes in a superstate.

Process composition is supported in jBPM by means of the process-state. The process state is a state that is associated with another process definition. When graph execution arrives in the process state, a new process instance of the sub-process is created and it is associated with the path of execution that arrived in the process state. The path of execution of the super process will wait till the sub process instance has ended. When the sub process instance ends, the path of execution of the super process will leave the process state and continue graph execution in the super process.

<process-definition name="hire">
  <start-state>
    <transition to="initial interview" />
  </start-state>
  <process-state name="initial interview">
    <sub-process name="interview" />
    <variable name="a" access="read,write" mapped-name="aa" />
    <variable name="b" access="read" mapped-name="bb" />
    <transition to="..." />
  </process-state>
  ...
</process-definition>

This 'hire' process contains a process-state that spawns an 'interview' process. When execution arrives in the 'first interview', a new execution (=process instance) of the 'interview' process is created. If no explicit version is specified, the latest version of the sub process as known when deploying the 'hire' process is used. To make jBPM instantiate a specific version the optional version attribute can be specified. To postpone binding the specified or latest version until actually creating the sub process, the optional binding attribute should be set to late. Then variable 'a' from the hire process is copied into variable 'aa' from the interview process. The same way, hire variable 'b' is copied into interview variable 'bb'. When the interview process finishes, only variable 'aa' from the interview process is copied back into the 'a' variable of the hire process.

In general, When a subprocess is started, all variables with read access are read from the super process and fed into the newly created sub process before the signal is given to leave the start state. When the sub process instances is finished, all the variables with write access will be copied from the sub process to the super process. The mapped-name attribute of the variable element allows you to specify the variable name that should be used in the sub process.

The graph execution model of jBPM is based on interpretation of the process definition and the chain of command pattern.

Interpretation of the process definition means that the process definition data is stored in the database. At runtime the process definition information is used during process execution. Note for the concerned : we use hibernate's second level cache to avoid loading of definition information at runtime. Since the process definitions don't change (see process versioning) hibernate can cache the process definitions in memory.

The chain of command pattern means that each node in the graph is responsible for propagating the process execution. If a node does not propagate execution, it behaves as a wait state.

The idea is to start execution on process instances and that the execution continues till it enters a wait state.

A token represents a path of execution. A token has a pointer to a node in the process graph. During waitstates, the tokens can be persisted in the database. Now we are going to look at the algorithm for calculating the execution of a token. Execution starts when a signal is sent to a token. The execution is then passed over the transitions and nodes via the chain of command pattern. These are the relevant methods in a class diagram.


When a token is in a node, signals can be sent to the token. Sending a signal is an instruction to start execution. A signal must therefore specify a leaving transition of the token's current node. The first transition is the default. In a signal to a token, the token takes its current node and calls the Node.leave(ExecutionContext,Transition) method. Think of the ExecutionContext as a Token because the main object in an ExecutionContext is a Token. The Node.leave(ExecutionContext,Transition) method will fire the node-leave event and call the Transition.take(ExecutionContext). That method will fire the transition event and call the Node.enter(ExecutionContext) on the destination node of the transition. That method will fire the node-enter event and call the Node.execute(ExecutionContext). Each type of node has its own behaviour that is implementated in the execute method. Each node is responsible for propagating graph execution by calling the Node.leave(ExecutionContext,Transition) again. In summary:

  • Token.signal(Transition)

  • --> Node.leave(ExecutionContext,Transition)

  • --> Transition.take(ExecutionContext)

  • --> Node.enter(ExecutionContext)

  • --> Node.execute(ExecutionContext)

Note that the complete calculation of the next state, including the invocation of the actions is done in the thread of the client. A common misconception is that all calculations *must* be done in the thread of the client. As with any asynchronous invocation, you can use asynchronous messaging (JMS) for that. When the message is sent in the same transaction as the process instance update, all synchronization issues are taken care of. Some workflow systems use asynchronous messaging between all nodes in the graph. But in high throughput environments, this algorithm gives much more control and flexibility for tweaking performance of a business process.

As explained in Section 9.10, “Graph execution”, jBPM runs the process in the thread of the client and is by nature synchronous. Meaning that the token.signal() or taskInstance.end() will only return when the process has entered a new wait state.

The jPDL feature that we describe here from a modelling perspective is Chapter 13, Asynchronous continuations.

In most situations this is the most straightforward approach because the process execution can easily be bound to server side transactions: the process moves from one state to the next in one transaction.

In some scenarios where in-process calculations take a lot of time, this behaviour might be undesirable. To cope with this, jBPM includes an asynchronous messaging system that allows to continue a process in an asynchronous manner. Of course, in a java enterprise environment, jBPM can be configured to use a JMS message broker instead of the built in messaging system.

In any node, jPDL supports the attribute async="true". Asynchronous nodes will not be executed in the thread of the client. Instead, a message is sent over the asynschronous messaging system and the thread is returned to the client (meaning that the token.signal() or taskInstance.end() will return).

Note that the jbpm client code can now commit the transaction. The sending of the message should be done in the same transaction as the process updates. So the net result of the transaction is that the token has moved to the next node (which has not yet been executed) and a org.jbpm.command.ExecuteNodeCommand-message has been sent on the asynchronous messaging system to the jBPM Command Executor.

The jBPM Command Executor reads commands from the queue and executes them. In the case of the org.jbpm.command.ExecuteNodeCommand, the process will be continued with executing the node. Each command is executed in a separate transaction.

So in order for asynchronous processes to continue, a jBPM Command Executor needs to be running. The simplest way to do that is to configure the CommandExecutionServlet in your web application. Alternatively, you should make sure that the CommandExecutor thread is up and running in any other way.

As a process modeller, you should not really be concerned with all this asynchronous messaging. The main point to remember is transaction demarcation: By default jBPM will operate in the transaction of the client, doing the whole calculation until the process enters a wait state. Use async="true" to demarcate a transaction in the process.

Let's look at an example:

...
<start-state>
  <transition to="one" />
</start-state>
<node async="true" name="one">
  <action class="com...MyAutomaticAction" />
  <transition to="two" />
</node>
<node async="true" name="two">
  <action class="com...MyAutomaticAction" />
  <transition to="three" />
</node>
<node async="true" name="three">
  <action class="com...MyAutomaticAction" />
  <transition to="end" />
</node>
<end-state name="end" />
...

Client code to interact with process executions (starting and resuming) is exactly the same as with normal (synchronous) processes:

...start a transaction...
JbpmContext jbpmContext = jbpmConfiguration.createContext();
try {
  ProcessInstance processInstance = jbpmContext.newProcessInstance("my async process");
  processInstance.signal();
  jbpmContext.save(processInstance);
} finally {
  jbpmContext.close();
}

After this first transaction, the root token of the process instance will point to node one and a ExecuteNodeCommandmessage will have been sent to the command executor.

In a subsequent transaction, the command executor will read the message from the queue and execute node one. The action can decide to propagate the execution or enter a wait state. If the action decides to propagate the execution, the transaction will be ended when the execution arrives at node two. And so on, and so on...

Context is about process variables. Process variables are key-value pairs that maintain information related to the process instance. Since the context must be storable in a database, some minor limitations apply.

Each path of execution (read: token) has its own set of process variables. Requesting a variable is always done on a token. Process instances have a tree of tokens (see graph oriented programming ). When requesting a variable without specifying a token, the default token is the root token.

The variable lookup is done recursively over the parents of the given token. The behaviour is similar to the scoping of variables in programming languages.

When a non-existing variable is set on a token, the variable is created on the root-token. This means that each variable has by default process scope. To make a variable token-local, you have to create it explicitely with:

ContextInstance.createVariable(String name, Object value, Token token);

Variables are stored in the database in a 2-step approach :

user-java-object <---> converter <---> variable instance

Variables are stored in VariableInstances. The members of VariableInstances are mapped to fields in the database with hibernate. In the default configuration of jBPM, 6 types of VariableInstances are used:

Converters convert between java-user-objects and the java objects that can be stored by the VariableInstances. So when a process variable is set with e.g. ContextInstance.setVariable(String variableName, Object value), the value will optionally be converted with a converter. Then the converted object will be stored in a VariableInstance. Converters are implementations of the following interface:

public interface Converter extends Serializable {
  boolean supports(Object value);
  Object convert(Object o);
  Object revert(Object o);
}

Converters are optional. Converters must be available to the jBPM class loader

The way that user-java-objects are converted and stored in variable instances is configured in the file org/jbpm/context/exe/jbpm.varmapping.properties. To customize this property file, put a modified version in the root of the classpath, as explained in Each line of the properties file specifies 2 or 3 class-names separated by spaces : the classname of the user-java-object, optionally the classname of the converter and the classname of the variable instance. When you refer your custom converters, make sure they are in the jBPM class path . When you refer to your custom variable instances, they also have to be in the the jBPM class path and the hibernate mapping file for org/jbpm/context/exe/VariableInstance.hbm.xml has to be updated to include the custom subclass of VariableInstance.

For example, take a look at the following xml snippet in the file org/jbpm/context/exe/jbpm.varmapping.xml.

    <jbpm-type>
      <matcher>
        <bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
          <field name="className"><string value="java.lang.Boolean" /></field>
        </bean>
      </matcher>
      <converter class="org.jbpm.context.exe.converter.BooleanToStringConverter" />
      <variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" />
    </jbpm-type>

This snippet specifies that all objects of type java.lang.Boolean have to be converted with the converter BooleanToStringConverter and that the resulting object (a String) will be stored in a variable instance object of type StringInstance.

If no converter is specified as in

    <jbpm-type>
      <matcher>
        <bean class="org.jbpm.context.exe.matcher.ClassNameMatcher">
          <field name="className"><string value="java.lang.Long" /></field>
        </bean>
      </matcher>
      <variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" />
    </jbpm-type>

that means that the Long objects that are put in the variables are just stored in a variable instance of type LongInstance without being converted.

The core business of jBPM is the ability to persist the execution of a process. A situation in which this feature is extremely useful is the management of tasks and tasklists for people. jBPM allows to specify a piece of software describing an overall process which can have wait states for human tasks.

A task instance can be assigned to an actorId (java.lang.String). All task instances are stored in one table of the database (JBPM_TASKINSTANCE). By querying this table for all task instances for a given actorId, you get the task list for that perticular user.

The jBPM task list mechanism can combine jBPM tasks with other tasks, even when those tasks are unrelated to a process execution. That way jBPM developers can easily combine jBPM-process-tasks with tasks of other applications in one centralized task-list-repository.

Task instances are the items in an actor's tasklist. Task instances can be signalling. A signalling task instance is a task instance that, when completed, can send a signal to its token to continue the process execution. Task instances can be blocking, meaning that the related token (=path of execution) is not allowed to leave the task-node before the task instance is completed. By default task instances are signalling and non-blocking.

In case more than one task instance are associated with a task-node, the process developer can specify how completion of the task instances affects continuation of the process. Following is the list of values that can be given to the signal-property of a task-node.

Task instance creation might be based upon a runtime calculation. In that case, add an ActionHandler on the node-enter event of the task-node and set the attribute create-tasks="false". Here is an example of such an action handler implementation:

public class CreateTasks implements ActionHandler {
  public void execute(ExecutionContext executionContext) throws Exception {
    Token token = executionContext.getToken();
    TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
      
    TaskNode taskNode = (TaskNode) executionContext.getNode();
    Task changeNappy = taskNode.getTask("change nappy");

    // now, 2 task instances are created for the same task.
    tmi.createTaskInstance(changeNappy, token);
    tmi.createTaskInstance(changeNappy, token);
  }
}

As shown in the example the tasks to be created can be specified in the task-node. They could also be specified in the process-definition and fetched from the TaskMgmtDefinition. TaskMgmtDefinition extends the ProcessDefinition with task management information.

The API method for marking task instances as completed is TaskInstance.end(). Optionally, you can specify a transition in the end method. In case the completion of this task instance triggers continuation of the execution, the task-node is left over the specified transition.

A process definition contains task nodes. A task-node contains zero or more tasks. Tasks are a static description as part of the process definition. At runtime, tasks result in the creation of task instances. A task instance corresponds to one entry in a person's task list.

With jBPM, push (personal task list) (Section 11.3.3, “The personal task list”) and pull (group task list) (Section 11.3.4, “The group task list”) model (see below) of task assignment can be applied in combination. The process can calculate the responsible for a task and push it in his/her tasklist. Or alternatively, a task can be assigned to a pool of actors, in which case each of the actors in the pool can pull the task and put it in the actor's personal tasklist.

Assigning task instances is done via the interface AssignmentHandler:

public interface AssignmentHandler extends Serializable {
  void assign( Assignable assignable, ExecutionContext executionContext );
}

An assignment handler implementation is called when a task instance is created. At that time, the task instance can be assigned to one or more actors. The AssignmentHandler implementation should call the Assignable methods (setActorId or setPooledActors) to assign a task. The Assignable is either a TaskInstance or a SwimlaneInstance (=process role).

public interface Assignable {
  public void setActorId(String actorId);
  public void setPooledActors(String[] pooledActors);
}

Both TaskInstances and SwimlaneInstances can be assigned to a specific user or to a pool of actors. To assign a TaskInstance to a user, call Assignable.setActorId(String actorId). To assign a TaskInstance to a pool of candidate actors, call Assignable.setPooledActors(String[] actorIds).

Each task in the process definition can be associated with an assignment handler implementation to perform the assignment at runtime.

When more than one task in a process should be assigned to the same person or group of actors, consider the usage of a swimlane (Section 11.6, “Swimlanes”)

To allow for the creation of reusable AssignmentHandlers, each usage of an AssignmentHandler can be configured in the processdefinition.xml. See the section on Delegation for more information on how to add configuration to assignment handlers.

The pooled actors denote the candidates for the task instance. This means that the task is offered to many users and one candidate has to step up and take the task. Users can not start working on tasks in their group task list immediately. That would result in a potential conflict that many people start working on the same task. To prevent this, users can only take task instances of their group task list and move them into their personal task list. Users are only allowed to start working on tasks that are in their personal task list.

To put a taskInstance in someone's group task list, you must put the user's actorId or one of the user's groupIds in the pooledActorIds. So specify the pooled actors, use one of the following:

To fetch the group task list for a given user, proceed as follows: Make a collection that includes the user's actorId and all the ids of groups that the user belongs to. With TaskMgmtSession.findPooledTaskInstances(String actorId) or TaskMgmtSession.findPooledTaskInstances(List actorIds) you can search for task instances that are not in a personal task list (actorId==null) and for which there is a match in the pooled actorIds.

The motivation behind this is that we want to separate the identity component from jBPM task assignment. jBPM only stores Strings as actorIds and doesn't know the relation between the users, groups and other identity information.

The actorId will always override the pooled actors. So a taskInstance that has an actorId and a list of pooledActorIds, will only show up in the actor's personal task list. Keeping the pooledActorIds around allows a user to put a task instance back into the group by just setting the actorId property of the taskInstance to null.

At creation of a task instance, the task controllers can populate the task instance variables and when the task instance is finished, the task controller can submit the data of the task instance into the process variables.

Note that you are not forced to use task controllers. Task instances also are able to 'see' the process variables related to its token. Use task controllers when you want to:

Tasks are intended to collect input from users. But there are many user interfaces which could be used to present the tasks to the users. E.g. a web application, a swing application, an instant messenger, an email form,... So the task controllers make the bridge between the process variables (=process context) and the user interface application. The task controllers provide a view of process variables to the user interface application.

The task controller makes the translation (if any) from the process variables to the task variables. When a task instance is created, the task controller is responsible for extracting information from the process variables and creating the task variables. The task variables serve as the input for the user interface form. And the user input can be stored in the task variables. When the user ends the task, the task controller is responsible for updating the process variables based on the task instance data.


In a simple scenario, there is a one-on-one mapping between process variables and the form parameters. Task controllers are specified in a task element. In this case, the default jBPM task controller can be used and it takes a list of variable elements inside. The variable elements express how the process variables are copied in the task variables.

The next example shows how you can create separate task instance variable copies based on the process variables:

<task name="clean ceiling">
  <controller>
    <variable name="a" access="read" mapped-name="x" />
    <variable name="b" access="read,write,required" mapped-name="y" />
    <variable name="c" access="read,write" />
  </controller>
</task>

The name attribute refers to the name of the process variable. The mapped-name is optional and refers to the name of the task instance variable. If the mapped-name attribute is omitted, mapped-name defaults to the name. Note that the mapped-name also is used as the label for the fields in the task instance form of the web application.

The access attribute specifies if the variable is copied at task instance creation, will be written back to the process variables at task end and wether it is required. This information can be used by the user interface to generate the proper form controls. The access attribute is optional and the default access is 'read,write'.

A task-node can have many tasks and a start-state can have 1 task.

If the simple one-to-one mapping between process variables and form parameters is too limiting, you can also write your own TaskControllerHandler implementation. Here's the TaskControllerHandler interface:

public interface TaskControllerHandler extends Serializable {
  void initializeTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
  void submitTaskVariables(TaskInstance taskInstance, ContextInstance contextInstance, Token token);
}

And here's how to configure your custom task controller implementation in a task:

<task name="clean ceiling">
  <controller class="com.yourcom.CleanCeilingTaskControllerHandler">
    -- here goes your task controller handler configuration --
  </controller>
</task>

A swimlane is a process role. It is a mechanism to specify that multiple tasks in the process should be done by the same actor. So after the first task instance is created for a given swimlane, the actor should be remembered in the process for all subsequent tasks that are in the same swimlane. A swimlane therefore has one assignment (Section 11.3, “Assignment”) and all tasks that reference a swimlane should not specify an assignment(Section 11.3, “Assignment”).

When the first task in a given swimlane is created, the AssignmentHandler of the swimlane is called. The Assignable that is passed to the AssignmentHandler will be the SwimlaneInstance. Important to know is that all assignments that are done on the task instances in a given swimlane will propagate to the swimlane instance. This behaviour is implemented as the default because the person that takes a task to fulfilling a certain process role will have the knowledge of that perticular process. So all subsequent assignements of task instances to that swimlane are done automatically to that user.

Swimlane is a terminology borrowed from UML activity diagrams.

A swimlane can be associated with the start task to capture the process initiator.

A task can be specified in a start-state. That task be associated with a swimlane. When a new task instance is created for such a task, the current authenticated actor will be captured with Authentication.getAuthenticatedActorId() (Section 18.2, “Authentication”) and that actor will be stored in the swimlane of the start task.

For example:

<process-definition>
  <swimlane name='initiator' />
  <start-state>
    <task swimlane='initiator' />
    <transition to='...' />
  </start-state>
  ...
</process-definition>

Also variables can be added to the start task as with any other task to define the form associated with the task. See Section 11.5, “Task controllers”

As on nodes, timers can be specified on tasks. See Section 12.1, “Timers”.

The special thing about timers for tasks is that the cancel-event for task timers can be customized. By default, a timer on a task will be cancelled when the task is ended (=completed). But with the cancel-event attribute on the timer, process developers can customize that to e.g. task-assign or task-start. The cancel-event supports multiple events. The cancel-event types can be combined by specifying them in a comma separated list in the attribute.

Management of users, groups and permissions is commonly known as identity management. jBPM includes an optional identity component that can be easily replaced by a company's own identity data store.

The jBPM identity management component includes knowledge of the organisational model. Task assignment is typically done with organisational knowledge. So this implies knowledge of an organisational model, describing the users, groups, systems and the relations between them. Optionally, permissions and roles can be included too in an organisational model. Various academic research attempts failed, proving that no generic organisational model can be created that fits every organisation.

The way jBPM handles this is by defining an actor as an actual participant in a process. An actor is identified by its ID called an actorId. jBPM has only knowledge about actorId's and they are represented as java.lang.Strings for maximum flexibility. So any knowledge about the organisational model and the structure of that data is outside the scope of the jBPM core engine.

As an extension to jBPM we will provide (in the future) a component to manage that simple user-roles model. This many to many relation between users and roles is the same model as is defined in the J2EE and the servlet specs and it could serve as a starting point in new developments. People interested in contributing should check the jboss jbpm jira issue tracker for more details.

Note that the user-roles model as it is used in the servlet, ejb and portlet specifications, is not sufficiently powerful for handling task assignments. That model is a many-to-many relation between users and roles. This doesn't include information about the teams and the organisational structure of users involved in a process.

The identity component comes with one implementation that evaluates an expression for the calculation of actors during assignment of tasks. Here's an example of using the assignment expression in a process definition:

<process-definition>
  ...
  <task-node name='a'>
    <task name='laundry'>
      <assignment expression='previous --> group(hierarchy) --> member(boss)' />
    </task>
    <transition to='b' />
  </task-node>
  ...

Syntax of the assignment expression is like this:

first-term --> next-term --> next-term --> ... --> next-term

where

first-term ::= previous |
               swimlane(swimlane-name) |
               variable(variable-name) |
               user(user-name) |
               group(group-name)

and 

next-term ::= group(group-type) |
              member(role-name)

This chapter describes how to work with timers in jBPM.

Upon events in the process, timers can be created. When a timer expires, an action can be executed or a transition can be taken.

Normally, a node is always executed after a token has entered the node. So the node is executed in the thread of the client. We'll explore asynchronous continuations by looking two examples. The first example is a part of a process with 3 nodes. Node 'a' is a wait state, node 'b' is an automated step and node 'c' is again a wait state. This process does not contain any asynchronous behaviour and it is represented in the picture below.

The first frame, shows the starting situation. The token points to node 'a', meaning that the path of execution is waiting for an external trigger. That trigger must be given by sending a signal to the token. When the signal arrives, the token will be passed from node 'a' over the transition to node 'b'. After the token arrived in node 'b', node 'b' is executed. Recall that node 'b' is an automated step that does not behave as a wait state (e.g. sending an email). So the second frame is a snapshot taken when node 'b' is being executed. Since node 'b' is an automated step in the process, the execute of node 'b' will include the propagation of the token over the transition to node 'c'. Node 'c' is a wait state so the third frame shows the final situation after the signal method returns.


While persistence is not mandatory in jBPM, the most common scenario is that a signal is called within a transaction. Let's have a look at the updates of that transaction. First of all, the token is updated to point to node 'c'. These updates are generated by hibernate as a result of the GraphSession.saveProcessInstance on a JDBC connection. Second, in case the automated action would access and update some transactional resources, those transactional updates should be combined or part of the same transaction.

Now, we are going to look at the second example, the second example is a variant of the first example and introduces an asynchronous continuation in node 'b'. Nodes 'a' and 'c' behave the same as in the first example, namely they behave as wait states. In jPDL, a node is marked as asynchronous by setting the attribute async="true".

The result of adding async="true" to node 'b' is that the process execution will be split up into 2 parts. The first part will execute the process up to the point where node 'b' is to be executed. The second part will execute node 'b' and that execution will stop in wait state 'c'.

The transaction will hence be split up into 2 separate transactions. One transaction for each part. While it requires an external trigger (the invocation of the Token.signal method) to leave node 'a' in the first transaction, jBPM will automatically trigger and perform the second transaction.


For actions, the principle is similar. Actions that are marked with the attribute async="true" are executed outside of the thread that executes the process. If persistence is configured (it is by default), the actions will be executed in a separate transaction.

In jBPM, asynchronous continuations are realized by using an asynchronous messaging system. When the process execution arrives at a point that should be executed asynchronously, jBPM will suspend the execution, produces a job message and send it to the command executor. The command executor is a separate component that, upon receipt of a message, will resume the execution of the process where it got suspended.

jBPM can be configured to use a JMS provider or its built-in asynchronous messaging system. The built-in messaging system is quite limited in functionality, but allows this feature to be supported on environments where JMS is unavailable.

The job executor is the component that resumes process executions asynchronously. It waits for job messages to arrive over an asynchronous messaging system and executes them. The two job messages used for asynchronous continuations are ExecuteNodeJob and ExecuteActionJob.

These job messages are produced by the process execution. During process execution, for each node or action that has to be executed asynchronously, a Job object will be dispatched to the MessageService. The message service is associated with the JbpmContext and it just collects all the messages that have to be sent.

The messages will be sent as part of JbpmContext.close(). That method cascades the close() invocation to all of the associated services. The actual services can be configured in jbpm.cfg.xml. One of the services, DbMessageService, is configured by default and will notify the job executor that new job messages are available.

The graph execution mechanism uses the interfaces MessageServiceFactory and MessageService to send messages. This is to make the asynchronous messaging service configurable (also in jbpm.cfg.xml). In Java EE environments, the DbMessageService can be replaced with the JmsMessageService to leverage the application server's capabilities.

Here's how the job executor works in a nutshell:

Jobs are records in the database. Jobs are objects and can be executed, too. Both timers and async messages are jobs. For async messages, the dueDate is simply set to the current time when they are inserted. The job executor must execute the jobs. This is done in 2 phases: 1) a job executor thread must acquire a job and 2) the thread that acquired the job must execute it.

Acquiring a job and executing the job are done in 2 separate transactions. A thread acquires a job by putting its name into the owner field of the job. Each thread has a unique name based on ip-address and sequence number. Hibernate's optimistic locking is enabled on Job-objects. So if 2 threads try to acquire a job concurrently, one of them will get a StaleStateException and rollback. Only the first one will succeed. The thread that succeeds in acquiring a job is now responsible for executing it in a separate transaction.

A thread could die between acquisition and execution of a job. To clean-up after those situations, there is one lock-monitor thread per job executor that checks the lock times. Jobs that are locked for more then 30 mins (by default) will be unlocked so that they can be executed by another job.

The required isolation level should be set to REPEATABLE_READ for hibernate's optimistic locking to work correctly. That isolation level will guarantee that

update JBPM_JOB job
set job.version = 2
    job.lockOwner = '192.168.1.3:2'
where 
    job.version = 1

will only result in 1 row updated in exactly 1 of the competing transactions.

Non-Repeatable Reads means that the following anomaly can happen: A transaction re-reads data it has previously read and finds that data has been modified by another transaction, one that has been committed since the transaction's previous read.

Non-Repeatable reads are a problem for optimistic locking and therefore isolation level READ_COMMITTED is not enough cause it allows for Non-Repeatable reads to occur. So REPEATABLE_READ is required if you configure more than one job executor thread.

This chapter describes the business calendar of jBPM. The business calendar knows about business hours and is used in calculation of due dates for tasks and timers.

The business calendar is able to calculate a due date by adding a duration to or subtracting it from a base date. If the base date is ommited, the 'current' date is used.

As mentioned the due date is composed of a duration and a base date. If this base date is ommitted, the duration is relative to the date (and time) at the moment of calculating the duedate. The format is:

duedate ::= [<basedate> +/-] <duration>

This chapter describes the out-of-the-box email support in jBPM jPDL.

There are four ways of specifying when emails should be sent from a process.

The fields to, recipients, subject and text can contain JSF-like expressions.

The variables in the expressions can be: swimlanes, process variables, transient variables beans configured in the jbpm.cfg.xml, ...

These expressions can be combined with the address resolving (Section 15.3.4, “Address resolving”) that is explained later in this chapter. For example, suppose that you have a swimlane called president in your process, then look at the following mail specification:

<mail actors="#{president}" subject="readmylips" text="nomoretaxes" />

That will send an email to to the person that acts as the president for that perticular process execution.

The purpose of logging is to keep track of the history of a process execution. As the runtime data of a process execution changes, all the delta's are stored in the logs.

Process logging, which is covered in this chapter, is not to be confused with software logging. Software logging traces the execution of a software program (usually for debugging purposes). Process logging traces the execution of process instances.

There are various use cases for process logging information. Most obvious is the consulting of the process history by participants of a process execution.

Another use case is Business Activity Monitoring (BAM). BAM will query or analyse the logs of process executions to find usefull statistical information about the business process. E.g. how much time is spend on average in each step of the process ? Where are the bottlenecks in the process ? ... This information is key to implement real business process management in an organisation. Real business process management is about how an organisation manages their processes, how these are supported by information technology *and* how these two improve the other in an iterative process.

Next use case is the undo functionality. Process logs can be used to implement the undo. Since the logs contain the delta's of the runtime information, the logs can be played in reverse order to bring the process back into a previous state.

Logs are produced by jBPM modules while they are running process executions. But also users can insert process logs. A log entry is a java object that inherits from org.jbpm.logging.log.ProcessLog. Process log entries are added to the LoggingInstance. The LoggingInstance is an optional extension of the ProcessInstance.

Various kinds of logs are generated by jBPM : graph execution logs, context logs and task management logs. For more information about the specific data contained in those logs, we refer to the javadocs. A good starting point is the class org.jbpm.logging.log.ProcessLog since from that class you can navigate down the inheritance tree.

The LoggingInstance will collect all the log entries. When the ProcessInstance is saved, all the logs in the LoggingInstance will be flushed to the database. The logs-field of a ProcessInstance is not mapped with hibernate to avoid that logs are retrieved from the database in each transactions. Each ProcessLog is made in the context of a path of execution (Token) and hence, the ProcessLog refers to that token. The Token also serves as an index-sequence generator for the index of the ProcessLog in the Token. This will be important for log retrieval. That way, logs that are produced in subsequent transactions will have sequential sequence numbers. (wow, that a lot of seq's in there :-s ).

The API method for adding process logs is the following.

public class LoggingInstance extends ModuleInstance {
  ...
  public void addLog(ProcessLog processLog) {...}
  ...
}

The UML diagram for logging information looks like this:


A CompositeLog is a special kind of log entry. It serves as a parent log for a number of child logs, thereby creating the means for a hierarchical structure in the logs. The API for inserting a log is the following.

public class LoggingInstance extends ModuleInstance {
  ...
  public void startCompositeLog(CompositeLog compositeLog) {...}
  public void endCompositeLog() {...}
  ...
}

The CompositeLogs should always be called in a try-finally-block to make sure that the hierarchical structure of logs is consistent. For example:

startCompositeLog(new MyCompositeLog());
try {
  ...
} finally {
  endCompositeLog();
}

JPDL specifies an xml schema and the mechanism to package all the process definition related files into a process archive.

A process archive is a zip file. The central file in the process archive is processdefinition.xml. The main information in that file is the process graph. The processdefinition.xml also contains information about actions and tasks. A process archive can also contain other process related files such as classes, ui-forms for tasks, ...

Deploying process archives can be done in 3 ways: with the process designer tool, with an ant task or programatically.

Deploying a process archive with the designer tool is supported in the starters-kit. Right click on the process archive folder to find the "Deploy process archive" option. The starters-kit server contains the jBPM webapp, which has a servlet to upload process archives called ProcessUploadServlet. This servlet is capable of uploading process archives and deploying them to the default jBPM instance configured.

Deploying a process archive with an ant task can be done as follows:

<target name="deploy.par">
  <taskdef name="deploypar" classname="org.jbpm.ant.DeployProcessTask">
    <classpath --make sure the jbpm-[version].jar is in this classpath--/>  
  </taskdef>  
  <deploypar par="build/myprocess.par" /> 
</target>

To deploy more process archives at once, use the nested fileset elements. The file attribute itself is optional. Other attributes of the ant task are:

Process archives can also be deployed programmatically with the class org.jbpm.jpdl.par.ProcessArchiveDeployer

What happens when we have a process definition deployed, many executions are not yet finished and we have a new version of the process definition that we want to deploy ?

Process instances always execute to the process definition that they are started in. But jBPM allows for multiple process definitions of the same name to coexist in the database. So typically, a process instance is started in the latest version available at that time and it will keep on executing in that same process definition for its complete lifetime. When a newer version is deployed, newly created instances will be started in the newest version, while older process instances keep on executing in the older process defintions.

If the process includes references to Java classes, the java classes can be made available to the jBPM runtime environment in 2 ways : by making sure these classes are visible to the jBPM classloader. This usually means that you can put your delegation classes in a .jar file next to the jbpm-[version].jar. In that case, all the process definitions will see that same class file. The java classes can also be included in the process archive. When you include your delegation classes in the process archive (and they are not visible to the jbpm classloader), jBPM will also version these classes inside the process definition. More information about process classloading can be found in the section on Delegation.

When a process archive gets deployed, it creates a process definition in the jBPM database. Process definitions can be versioned on the basis of the process definition name. When a named process archive gets deployed, the deployer will assign a version number. To assign this number, the deployer will look up the highest version number for process definitions with the same name and adds 1. Unnamed process definitions will always have version number -1.

Delegation is the mechanism used to include the users' custom code in the execution of processes.

Delegation classes contain user code that is called from within the execution of a process. The most common example is an action. In the case of action, an implementation of the interface ActionHandler can be called on an event in the process. Delegations are specified in the processdefinition.xml. 3 pieces of data can be supplied when specifying a delegation :

Next is a description of all the configuration types:

This is the default configuration type. The config-type field will first instantiate an object of the delegation class and then set values in the fields of the object as specified in the configuration. The configuration is xml, where the elementnames have to correspond with the field names of the class. The content text of the element is put in the corresponding field. If necessary and possible, the content text of the element is converted to the field type.

Supported type conversions:

<numbers>
  <element>one</element>
  <element>two</element>
  <element>three</element>
</numbers>

The text in the elements can be converted to any object that has a String constructor. To use another type then String, specify the element-type in the field element ('numbers' in this case).

Here's another example of a map:

<numbers>
  <entry><key>one</key><value>1</value></entry>
  <entry><key>two</key><value>2</value></entry>
  <entry><key>three</key><value>3</value></entry>
</numbers>

For example in the following class...

public class MyAction implements ActionHandler {
  // access specifiers can be private, default, protected or public
  private String city;
  Integer rounds;
  ...
}

...this is a valid configuration:

...
<action class="org.test.MyAction">
  <city>Atlanta</city>
  <rounds>5</rounds>
</action>
...

For some of the delegations, there is support for a JSP/JSF EL like expression language. In actions, assignments and decision conditions, you can write an expression like e.g. expression="#{myVar.handler[assignments].assign}"

The basics of this expression language can be found in the J2EE tutorial (http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPIntro7.html).

The jPDL expression language is similar to the JSF expression language. Meaning that jPDL EL is based on JSP EL, but it uses #{...} notation and that it includes support for method binding.

Depending on the context, the process variables or task instance variables can be used as starting variables along with the following implicit objects:

  • taskInstance (org.jbpm.taskmgmt.exe.TaskInstance)

  • processInstance (org.jbpm.graph.exe.ProcessInstance)

  • processDefinition (org.jbpm.graph.def.ProcessDefinition)

  • token (org.jbpm.graph.exe.Token)

  • taskMgmtInstance (org.jbpm.taskmgmt.exe.TaskMgmtInstance)

  • contextInstance (org.jbpm.context.exe.ContextInstance)

This feature becomes really powerfull in a JBoss SEAM environment. Because of the integration between jBPM and JBoss SEAM (http://www.jboss.com/products/seam), all of your backed beans, EJB's and other one-kind-of-stuff becomes available right inside of your process definition. Thanks Gavin ! Absolutely awsome ! :-)

The jPDL schema is the schema used in the file processdefinition.xml in the process archive.

Table 17.15. action

NameTypeMultiplicityDescription
nameattributeoptionalthe name of the action. When actions are given names, they can be looked up from the process definition. This can be useful for runtime actions and declaring actions only once.
classattibuteeither, a ref-name or an expressionthe fully qualified class name of the class that implements the org.jbpm.graph.def.ActionHandler interface.
ref-nameattibuteeither this or classthe name of the referenced action. The content of this action is not processed further if a referenced action is specified.
expressionattibuteeither this, a class or a ref-nameA jPDL expression that resolves to a method.
accept-propagated-eventsattributeoptional{yes|no|true|false}. Default is yes|true. If set to false, the action will only be executed on events that were fired on this action's element.
config-typeattributeoptional{field|bean|constructor|configuration-property}. Specifies how the action-object should be constructed and how the content of this element should be used as configuration information for that action-object.
asyncattibute{true|false}Default is false, which means that the action is executed in the thread of the execution. If set to true, a message will be sent to the command executor and that component will execute the action asynchonously in a separate transaction.
 {content}optionalthe content of the action can be used as configuration information for your custom action implementations. This allows the creation of reusable delegation classes.

Table 17.23. task

NameTypeMultiplicityDescription
nameattributeoptionalthe name of the task. Named tasks can be referenced and looked up via the TaskMgmtDefinition
blockingattributeoptional{yes|no|true|false}, default is false. If blocking is set to true, the node cannot be left when the task is not finished. If set to false (default) a signal on the token is allowed to continue execution and leave the node. The default is set to false, because blocking is normally forced by the user interface.
signallingattributeoptional{yes|no|true|false}, default is true. If signalling is set to false, this task will never have the capability of trigering the continuation of the token.
duedateattributeoptionalis a duration expressed in absolute or business hours
swimlaneattributeoptionalreference to a swimlane. If a swimlane is specified on a task, the assignment is ignored.
priorityattributeoptionalone of {highest, high, normal, low, lowest}. alternatively, any integer number can be specified for the priority. FYI: (highest=1, lowest=5)
assignmentelementoptionaldescribes a delegation that will assign the task to an actor when the task is created.
eventelement[0..*]supported event types: {task-create|task-start|task-assign|task-end}. Especially for the task-assign we have added a non-persisted property previousActorId to the TaskInstance
exception-handlerelement[0..*]a list of exception handlers that applies to all exceptions thrown by delegation classes thrown in this process node.
timerelement[0..*]specifies a timer that monitors the duration of an execution in this task. special for task timers, the cancel-event can be specified. by default the cancel-event is task-end, but it can be customized to e.g. task-assign or task-start.
controllerelement[0..1]specifies how the process variables are transformed into task form parameters. the task form paramaters are used by the user interface to render a task form to the user.

Table 17.25. assignment

NameTypeMultiplicityDescription
expressionattributeoptionalFor historical reasons, this attribute expression does not refer to the jPDL expression, but instead, it is an assignment expression for the jBPM identity component. Note that this implementation has a dependency on the jbpm identity component.
actor-idattributeoptionalAn actorId. Can be used in conjunction with pooled-actors. The actor-id is resolved as an expression. So you can refer to a fixed actorId like this actor-id="bobthebuilder". Or you can refer to a property or method that returns a String like this: actor-id="myVar.actorId", which will invoke the getActorId method on the task instance variable "myVar".
pooled-actorsattributeoptionalA comma separated list of actorIds. Can be used in conjunction with actor-id. A fixed set of pooled actors can be specified like this: pooled-actors="chicagobulls, pointersisters". The pooled-actors will be resolved as an expression. So you can also refer to a property or method that has to return, a String[], a Collection or a comma separated list of pooled actors.
classattributeoptionalthe fully qualified classname of an implementation of org.jbpm.taskmgmt.def.AssignmentHandler
config-typeattributeoptional{field|bean|constructor|configuration-property}. Specifies how the assignment-handler-object should be constructed and how the content of this element should be used as configuration information for that assignment-handler-object.
 {content}optionalthe content of the assignment-element can be used as configuration information for your AssignmentHandler implementations. This allows the creation of reusable delegation classes.

Security features of jBPM are still in alpha stage. This chapter documents the pluggable authentication and authorization. And what parts of the framework are finished and what parts not yet.

Authentication is the process of knowing on who's behalf the code is running. In case of jBPM this information should be made available from the environment to jBPM. Cause jBPM is always executed in a specific environment like a webapp, an EJB, a swing application or some other environment, it is always the surrounding environment that should perform authentication.

In a few situations, jBPM needs to know who is running the code. E.g. to add authentication information in the process logs to know who did what and when. Another example is calculation of an actor based on the current authenticated actor.

In each situation where jBPM needs to know who is running the code, the central method org.jbpm.security.Authentication.getAuthenticatedActorId() is called. That method will delegate to an implementation of org.jbpm.security.authenticator.Authenticator. By specifying an implementation of the authenticator, you can configure how jBPM retrieves the currently authenticated actor from the environment.

The default authenticator is org.jbpm.security.authenticator.JbpmDefaultAuthenticator. That implementation will maintain a ThreadLocal stack of authenticated actorId's. Authenticated blocks can be marked with the methods JbpmDefaultAuthenticator.pushAuthenticatedActorId(String) and JbpmDefaultAuthenticator.popAuthenticatedActorId(). Be sure to always put these demarcations in a try-finally block. For the push and pop methods of this authenticator implementation, there are convenience methods supplied on the base Authentication class. The reason that the JbpmDefaultAuthenticator maintains a stack of actorIds instead of just one actorId is simple: it allows the jBPM code to distinct between code that is executed on behalf of the user and code that is executed on behalf of the jbpm engine.

See the javadocs for more information.

Since developing process oriented software is no different from developing any other software, we believe that process definitions should be easily testable. This chapter shows how you can use plain JUnit without any extensions to unit test the process definitions that you author.

The development cycle should be kept as short as possible. Changes made to the sources of software should be immediately verifiable. Preferably, without any intermediate build steps. The examples given below will show you how to develop and test jBPM processes without intermediate steps.

Mostly the unit tests of process definitions are execution scenarios. Each scenario is executed in one JUnit testmethod and will feed in the external triggers (read: signals) into a process execution and verifies after each signal if the process is in the expected state.

Let's look at an example of such a test. We take a simplified version of the auction process with the following graphical representation:


Now, let's write a test that executes the main scenario:

public class AuctionTest extends TestCase {

  // parse the process definition
  static ProcessDefinition auctionProcess = 
      ProcessDefinition.parseParResource("org/jbpm/tdd/auction.par");

  // get the nodes for easy asserting
  static StartState start = auctionProcess.getStartState();
  static State auction = (State) auctionProcess.getNode("auction");
  static EndState end = (EndState) auctionProcess.getNode("end");

  // the process instance
  ProcessInstance processInstance;

  // the main path of execution
  Token token;

  public void setUp() {
    // create a new process instance for the given process definition
    processInstance = new ProcessInstance(auctionProcess);

    // the main path of execution is the root token
    token = processInstance.getRootToken();
  }
  
  public void testMainScenario() {
    // after process instance creation, the main path of 
    // execution is positioned in the start state.
    assertSame(start, token.getNode());
    
    token.signal();
    
    // after the signal, the main path of execution has 
    // moved to the auction state
    assertSame(auction, token.getNode());
    
    token.signal();
    
    // after the signal, the main path of execution has 
    // moved to the end state and the process has ended
    assertSame(end, token.getNode());
    assertTrue(processInstance.hasEnded());
  }
}

The functionality of jBPM is split into modules. Each module has a definition and an execution (or runtime) part. The central module is the graph module, made up of the ProcessDefinition and the ProcessInstance. The process definition contains a graph and the process instance represents one execution of the graph. All other functionalities of jBPM are grouped into optional modules. Optional modules can extend the graph module with extra features like context (process variables), task management, timers, ...


The pluggable architecture in jBPM is also a unique mechanism to add custom capabilities to the jBPM engine. Custom process definition information can be added by adding a ModuleDefinition implementation to the process definition. When the ProcessInstance is created, it will create an instance for every ModuleDefinition in the ProcessDefinition. The ModuleDefinition is used as a factory for ModuleInstances.

The most integrated way to extend the process definition information is by adding the information to the process archive and implementing a ProcessArchiveParser. The ProcessArchiveParser can parse the information added to the process archive, create your custom ModuleDefinition and add it to the ProcessDefinition.

public interface ProcessArchiveParser {

  void writeToArchive(ProcessDefinition processDefinition, ProcessArchive archive);
  ProcessDefinition readFromArchive(ProcessArchive archive, ProcessDefinition processDefinition);

}

To do its work, the custom ModuleInstance must be notified of relevant events during process execution. The custom ModuleDefinition might add ActionHandler implementations upon events in the process that serve as callback handlers for these process events.

Alternatively, a custom module might use AOP to bind the custom instance into the process execution. JBoss AOP is very well suited for this job since it is mature, easy to learn and also part of the JBoss stack.

Version 3, 29 June 2007

Copyright 2007 Free Software Foundation, Inc. http://fsf.org/

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.

0. Additional Definitions.

As used herein, this License refers to version 3 of the GNU Lesser General Public License, and the GNU GPL refers to version 3 of the GNU General Public License.

The Library refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.

An Application is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.

A Combined Work is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the Linked Version.

The Minimal Corresponding Source for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.

The Corresponding Application Code for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.

1. Exception to Section 3 of the GNU GPL.

You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.

2. Conveying Modified Versions.

If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:

3. Object Code Incorporating Material from Library Header Files.

The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:

4. Combined Works.

You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:

  1. Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.

  2. Accompany the Combined Work with a copy of the GNU GPL and this license document.

  3. For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.

  4. Do one of the following:

  5. Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)

5. Combined Libraries.

You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:

6. Revised Versions of the GNU Lesser General Public License.

The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License or any later version applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.

If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxys public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.

Revision History
Revision 0Tue May 11 2010David Le Sage
Initial creation of book by publican