Chapter 13. Persistence and Transactions

13.1. Process Instance State

Red Hat JBoss BPM Suite allows persistent storage of information. For example, you can persistently store process runtime state to ensure that you will be able to resume your process instance in case of failure. While logs of current and previous process states are stored by default, you can store process definitions and logging information as well.

13.1.1. Runtime State

When you start a process, Red Hat JBoss BPM Suite creates a process instance, which represents the execution of the process in the specific context. For example, when you start a process that specifies how to process a sales order, Red Hat JBoss BPM Suite creates a process instance for each order. Process instances contain all the related information and minimal runtime state required to continue the execution at any time. However, it does not include process instance logs unless needed for execution of the process instance.

You can make the runtime state of an executing process persistent, for example, in a database. This allows you to restore the state of execution of all running processes in case of failure, or to temporarily remove running instances from memory and restore them later. Red Hat JBoss BPM Suite allows you to plug in different persistence strategies. Note that process instances are not persistent by default.

When you configure the Red Hat JBoss BPM Suite engine to use persistence, it automatically stores the runtime state in a database without further prompting. When you invoke the engine, it ensures that all changes are stored at the end of that invocation. If you encounter a failure and restore the engine from the database, do not manually resume the execution. Process instances automatically resume execution if they are triggered.

Inexperienced users should not directly access and modify database tables containing runtime persistence data. Changes in the runtime state of process instances which are not done by the engine may have unexpected results. If you require information about the current execution state of a process instance, use the history log.

13.1.2. Binary Persistence

Binary persistence, or marshaling, converts the state of the process instance into a binary dataset. Binary persistence is a mechanism used to store and retrieve information persistently. The same mechanism is also applied to the session state and work item states.

When you enable persistence of a process instance:

  • Red Hat JBoss BPM Suite transforms the process instance information into binary data. Custom serialization is used instead of Java serialization for performance reasons.
  • The binary data is stored together with other process instance metadata, such as process instance ID, process ID, and the process start date.

The session can also store other forms of state, such as the state of timer jobs, or data required for business rules evaluation. Session state is stored separately as a binary dataset along with the ID of the session and metadata. You can restore the session state by reloading a session with given ID. Use ksession.getId() to get the session ID.

13.1.3. Data Model Description

Each entity of the data model is described below.

Figure 13.1. Data Model

A data model that provides SessionInfo

The SessionInfo entity contains the state of the (knowledge) session in which the process instance is running.

Table 13.1. SessionInfo

FieldDescriptionNullable

id

The primary key.

NOT NULL

lastModificationDate

The last time that entity was saved to a database.

 

rulesByteArray

The state of a session.

NOT NULL

startDate

The session start time.

 

OPTLOCK

A version field containing a lock value.

 

The ProcessInstanceInfo entity contains the state of the process instance.

Table 13.2. ProcessInstanceInfo

FieldDescriptionNullable

instanceId

The primary key.

NOT NULL

lastModificationDate

The last time that the entity was saved to a database.

 

lastReadDate

The last time that the entity was retrieved from the database.

 

processId

The ID of the process.

 

processInstanceByteArray

The state of a process instance in form of a binary dataset.

NOT NULL

startDate

The start time of the process.

 

state

An integer representing the state of a process instance.

NOT NULL

OPTLOCK

A version field containing a lock value.

 

The EventTypes entity contains information about events that a process instance will undergo or has undergone.

Table 13.3. EventTypes

FieldDescriptionNullable

instanceId

A reference to the ProcessInstanceInfo primary key and foreign key constraint on this column.

NOT NULL

element

A finished event in the process.

 

The WorkItemInfo entity contains the state of a work item.

Table 13.4. WorkItemInfo

FieldDescriptionNullable

workItemId

The primary key.

NOT NULL

name

The name of the work item.

 

processInstanceId

The (primary key) ID of the process. There is no foreign key constraint on this field.

NOT NULL

state

The state of a work item.

NOT NULL

OPTLOCK

A version field containing a lock value.

 

workitembytearay

The work item state in as a binary dataset.

NOT NULL

The CorrelationKeyInfo entity contains information about correlation keys assigned to the given process instance. This table is optional. Use it only when you require correlation capabilities.

Table 13.5. CorrelationKeyInfo

FieldDescriptionNullable

keyId

The primary key.

NOT NULL

name

The assigned name of the correlation key.

 

processInstanceId

The ID of the process instance which is assigned to the correlation key.

NOT NULL

OPTLOCK

A version field containing a lock value.

 

The CorrelationPropertyInfo entity contains information about correlation properties for a correlation key assigned the process instance.

Table 13.6. CorrelationPropertyInfo

FieldDescriptionNullable

propertyId

The primary key.

NOT NULL

name

The name of the property.

 

value

The value of the property.

NOT NULL

OPTLOCK

A version field containing a lock value.

 

correlationKey_keyId

A foreign key mapped to the correlation key.

NOT NULL

The ContextMappingInfo entity contains information about the contextual information mapped to a KieSession. This is an internal part of RuntimeManager and can be considered optional when RuntimeManager is not used.

Table 13.7. ContextMappingInfo

FieldDescriptionNullable

mappingId

The primary key.

NOT NULL

CONTEXT_ID

The context identifier.

NOT NULL

KSESSION_ID

The KieSession identifier.

NOT NULL

OPTLOCK

A version field containing a lock value.

 

13.1.4. Safe Points

During the process engine execution, the state of a process instance is stored in safe points. When you execute a process instance, the engine continues the execution until there are no more actions to be performed. That is, the process instance has been completed, aborted, or is in the wait state in all of its paths. At that point, the engine has reached the next safe state, and the state of the process instance (and all other process instances that it affected) is stored persistently.

13.2. Audit Log

Storing information about the execution of process instances can be useful when you need to, for example:

  • Verify which actions have been executed in a particular process instance.
  • Monitor and analyze the efficiency of a particular process.

However, storing history information in the runtime database can result in the database rapidly increasing in size. Additionally, monitoring and analysis queries might influence the performance of your runtime engine. This is why process execution history logs are stored separately.

13.2.1. Audit Data Model

The jbpm-audit module contains an event listener that stores process-related information in a database using Java Persistence API (JPA). The data model contains the following entities:

  • The ProcessInstanceLog table contains the basic log information about a process instance.
  • The NodeInstanceLog table contains information about which nodes were actually executed inside each process instance. Whenever a node instance is entered from one of its incoming connections or is exited through one of its outgoing connections, that information is stored in this table.
  • The VariableInstanceLog table contains information about changes in variable instances. The execution engine generates log entries after a variable changes, by default. Alternatively, you can log entries before the variable value changes.
  • The AuditTaskImpl table contains information about tasks that can be used for queries.
  • The BAMTaskSummary table collects information about tasks. The Business Activity Monitor engine then uses the information to build charts and dashboards.
  • The TaskVariableImpl table contains information about task variable instances.
  • The TaskEvent table contains information about changes in task instances. It contains a timeline view of events (for example claim, start, or stop) for the given task.

13.2.2. Audit Data Model Description

All audit data model entities contain following elements:

Table 13.8. ProcessInstanceLog

FieldDescription

id

The primary key and ID of the log entity. Cannot have the null value.

duration

The duration of a process instance since its start date.

end_date

The end date of a process instance when applicable.

externalId

An optional external identifier used to correlate various elements, for example deployment ID.

user_identity

An optional identifier of the user who started the process instance.

outcome

The outcome of a process instance, for example the error code.

parentProcessInstanceId

The process instance ID of the parent process instance.

processId

The ID of the executed process.

processInstanceId

The process instance ID. Cannot have the NULL value.

processname

The name of the process.

processversion

The version of the process.

start_date

The start date of the process instance.

status

The status of process instance that maps to process instance state.

Table 13.9. NodeInstanceLog

FieldDescription

id

The primary key and ID of the log entity. Cannot have the NULL value.

connection

The identifier of the sequence flow that led to this node instance.

log_date

The event date.

externalId

An optional external identifier used to correlate various elements, for example deployment ID.

nodeid

The node ID of the corresponding node in the process definition.

nodeinstanceId

The instance ID of the node.

nodename

The name of the node.

nodetype

The type of the node.

processId

The ID of the executed process.

processInstanceId

The process instance ID.

type

The type of the event (0 = enter, 1 = exit). Cannot have the NULL value.

workItemId

An optional identifier of work items available only for certain node types.

Table 13.10. VariableInstanceLog

FieldDescription

id

The primary key and ID of the log entity. Cannot have the NULL value.

externalId

An optional external identifier used to correlate various elements, for example deployment ID.

log_date

The date of the event.

processId

The ID of the executed process.

processInstanceId

The process instance ID.

oldvalue

The previous value of the variable at the time of recording of the log.

value

The value of the variable at the time of recording of the log.

variableid

The variable ID in the process definition.

variableinstanceId

The ID of the variable instance.

Table 13.11. AuditTaskImpl

FieldDescription

id

The primary key and ID of the log entity.

activationTime

The time of the task activation.

actualOwner

The actual owner assigned to this task. This field is set only when a user claims the task.

createdBy

The user who created the task.

createdOn

The date of the task creation.

deploymentId

The deployment ID to which this task belongs.

description

The task description.

dueDate

The due date set on this task.

name

The name of the task.

parentId

The parent task ID.

priority

The priority of the task.

processId

The process definition ID to which this task belongs.

processInstanceId

The process instance ID with which this task is associated.

processSessionId

The KieSession ID used to create this task.

status

The current status of the task.

taskId

The identifier of task.

workItemId

The work item ID assigned to this task ID (on process side).

Table 13.12. BAMTaskSummary

FieldDescription

id

The primary key and ID of the log entity. Cannot have the null value.

createdDate

The date of the task creation.

duration

Duration since the task was created.

endDate

The date when the task reached an end state (that is: complete, exit, fail, or skip).

processInstanceId

The process instance ID.

startDate

The date when the task was started.

status

The current status of the task.

taskId

The identifier of the task.

taskName

The name of the task.

userId

The user ID assigned to the task.

Table 13.13. TaskVariableImpl

FieldDescription

id

The primary key and ID of the log entity. Cannot have the null value.

modificationDate

The last time when the variable was modified.

name

The name of the task.

processId

The ID of the process that the process instance is executing.

processInstanceId

The process instance ID.

taskId

The identifier of the task.

type

The type of the variable, that is input or output of the task.

value

The value of a variable.

Table 13.14. TaskEvent

FieldDescription

id

The primary key and ID of the log entity. Cannot have the null value.

logTime

The date when this event was saved.

message

The log event message.

processInstanceId

The process instance ID.

taskId

The identifier of the task.

type

The type of the event, which corresponds to the life cycle phases of the task.

userId

The user ID assigned to the task.

workItemId

The identifier of the work item to which the task is assigned.

13.2.3. Storing Process Events in a Database

To log process history in a database, register a logger in your session:

EntityManagerFactory emf = ...;
StatefulKnowledgeSession ksession = ...;
AbstractAuditLogger auditLogger = AuditLoggerFactory.newJPAInstance(emf);
ksession.addProcessEventListener(auditLogger);

// Invoke methods on your session here.

Modify persistence.xml to specify a database. You need to include audit log classes as well (ProcessInstanceLog, NodeInstanceLog, and VariableInstanceLog). See the example:

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

  <persistence
    version="2.0"
    xsi:schemaLocation="
      http://java.sun.com/xml/ns/persistence
      http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd
      http://java.sun.com/xml/ns/persistence/orm
      http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>jdbc/jbpm-ds</jta-data-source>
      <mapping-file>META-INF/JBPMorm.xml</mapping-file>

      <class>org.drools.persistence.info.SessionInfo</class>
      <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
      <class>org.drools.persistence.info.WorkItemInfo</class>
      <class>org.jbpm.persistence.correlation.CorrelationKeyInfo</class>
      <class>org.jbpm.persistence.correlation.CorrelationPropertyInfo</class>
      <class>org.jbpm.runtime.manager.impl.jpa.ContextMappingInfo</class>
      <class>org.jbpm.process.audit.ProcessInstanceLog</class>
      <class>org.jbpm.process.audit.NodeInstanceLog</class>
      <class>org.jbpm.process.audit.VariableInstanceLog</class>

      <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
        <property name="hibernate.max_fetch_depth" value="3"/>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.transaction.jta.platform"
                  value="org.hibernate.service.jta.platform.internal.BitronixJtaPlatform"/>
      </properties>
    </persistence-unit>
  </persistence>

13.2.4. Storing Process Events in a JMS Queue

Synchronous storing of history logs and runtime data in one database may be undesirable due to performance reasons. In that case, you can use JMS logger to send data into a JMS queue instead of directly storing it in a database. You can also configure it to be transactional in order to avoid issues with inconsistent data, for example when the process engine transaction is reversed.

Example configuration of JMS queue:

ConnectionFactory factory = ...;
Queue queue = ...;
StatefulKnowledgeSession ksession = ...;
Map<String, Object> jmsProps = new HashMap<String, Object>();

jmsProps.put("jbpm.audit.jms.transacted", true);
jmsProps.put("jbpm.audit.jms.connection.factory", factory);
jmsProps.put("jbpm.audit.jms.queue", queue);

AbstractAuditLogger auditLogger =
  AuditLoggerFactory.newInstance(Type.JMS, session, jmsProps);
ksession.addProcessEventListener(auditLogger);

// Invoke methods of your session here.

13.2.5. Auditing Variables

Process and task variables are stored as string (similar to variable.toString()) in audit tables by default. This is not always efficient, for example, when you need to query by the process or task instance variables:

public class Person implements Serializable {

  private static final long serialVersionUID = -5172443495317321032L;
  private String name;
  private int age;

  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getAge() {
    return age;
  }

  public void setAge(int age) {
    this.age = age;
  }

  @Override
  public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
  }
}

In this example, when you want to query all the people with certain age, querying becomes inefficient.

Thus, variable audit is based on VariableIndexer, which extracts relevant parts of the variables that will be stored in audit log:

/**
* Variable indexer that allows to transform variable instance
* into other representation (usually String) to be able to use it for queries.
*
* @param <V> type of the object that will represent indexed variable
*/

public interface VariableIndexer<V> {

 /**
  * Tests if given variable shall be indexed by this indexer.
  *
  * NOTE: Only one indexer can be used for given variable.
  *
  * @param	variable  variable to be indexed
  * @return	true      if variable should be indexed with this indexer
  */

  boolean accept(Object variable);

 /**
  * Performs index/transform operation of the variable.
  * Result of this operation can be either single value
  * or list of values to support complex type separation.
  * For example, when variable is of type Person that has name,
  * address, and phone, indexer could build three entries
  * out of it to represent individual fields:
  *
  * person  = person.name
  * address = person.address.street
  * phone   = person.phone
  *
  * That will allow more advanced queries to be used to find
  * relevant entries.
  *
  * @param	name      name of the variable
  * @param	variable  actual variable value
  * @return
  */

  List<V> index(String name, Object variable);
}

The default indexer (that is indexer accepting toString()) produces a single audit entry for a single variable. However, you can create a custom indexer which indexes variables into separate audit entries:

public class PersonTaskVariablesIndexer implements TaskVariableIndexer {

  @Override
  public boolean accept(Object variable) {
    if (variable instanceof Person) {
      return true;
    }

    return false;
  }

  @Override
  public List<TaskVariable> index(String name, Object variable) {
    Person person = (Person) variable;
    List<TaskVariable> indexed = new ArrayList<TaskVariable>();

    TaskVariableImpl personNameVar = new TaskVariableImpl();
    personNameVar.setName("person.name");
    personNameVar.setValue(person.getName());

    indexed.add(personNameVar);

    TaskVariableImpl personAgeVar = new TaskVariableImpl();
    personAgeVar.setName("person.age");
    personAgeVar.setValue(person.getAge()+"");

    indexed.add(personAgeVar);

    return indexed;
  }
}

This allows you to search all the process instances or tasks that contain the person instance of age 34 by querying for:

  • Variable name: person.age
  • Variable value: 34

13.2.6. Building and Registering Custom Indexers

You can build indexers for both process and task variables. They are supported by different interfaces because they produce different type of objects representing audit view of the variable. To create a custom indexer, follow these steps:

  1. Implement following interfaces to build custom indexers:

    • Process variables: org.kie.internal.process.ProcessVariableIndexer.
    • Task variables: org.kie.internal.task.api.TaskVariableIndexer.
  2. Implement the following methods:

    • accept: indicates what types are handled by given indexer. Only one indexer can index any given variable. The first that accepts the variable will index it.
    • index: the method for indexing the variable.
  3. Package the implementation into a jar file, including following files:

    • For process variables: META-INF/services/org.kie.internal.process.ProcessVariableIndexer with list of fully qualified class names that represent the process variable indexers (single class name per line).
    • For task variables: META-INF/services/org.kie.internal.task.api.TaskVariableIndexer with list of fully qualified class names that represent the task variable indexers (single class name per line).

The ServiceLoader service registers indexers. When you start indexing, all the registered indexers are examined. If no applicable indexer is found, the default indexer (toString() based) is used.

13.3. Transactions

Red Hat JBoss BPM Suite engine supports Java Transaction API (JTA). The engine executes any method you invoke in a separate transaction unless you set transaction boundaries. Transaction boundaries allow you to combine multiple commands into one transaction.

Register a transaction manager before using user-defined transactions. The following sample code uses Bitronix transaction manager. It also uses JTA to specify transaction boundaries:

// Create the entity manager factory and register it in the environment:
EntityManagerFactory emf =
  Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
env.set(EnvironmentName.TRANSACTION_MANAGER,
  TransactionManagerServices.getTransactionManager());

// Create a new knowledge session that uses JPA to store the runtime state:
StatefulKnowledgeSession ksession =
  JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);

// Start the transaction:
UserTransaction ut =
  (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
ut.begin();

// Perform multiple commands inside one transaction:
ksession.insert(new Person("John Doe"));
ksession.startProcess("MyProcess");

// Commit the transaction:
ut.commit();

If you use Bitronix as the transaction manager, you must provide jndi.properties in your root classpath to register the Bitronix transaction manager in JNDI.

  • If you use the jbpm-test module, jndi.properties is included by default.
  • If you are not using jbpm-test module, create jndi.properties manually with the following content:

    java.naming.factory.initial=bitronix.tm.jndi.BitronixInitialContextFactory

If you use a different JTA transaction manager, modify the transaction manager property in persistence.xml:

<property
  name  = "hibernate.transaction.jta.platform"
  value = "org.hibernate.transaction.JBossTransactionManagerLookup"
/>
Warning

Using the (runtime manager) Singleton strategy with JTA transactions (UserTransaction or CMT) is not recommended because of a race condition. It can result in an IllegalStateException with a message similar to "Process instance X is disconnected".

Avoid this condition by explicitly synchronizing around the KieSession instance when invoking the transaction in the user application code:

synchronized (ksession) {
  try {
    tx.begin();

    // use ksession application logic

    tx.commit();
  } catch (Exception e) {
    ...
  }
}

13.4. Implementing Container Managed Transaction

You can embed Red Hat JBoss BPM Suite inside an application that executes in Container Managed Transaction (CMT) mode, such as Enterprise Java Beans (EJB).

To configure the transaction manager, follow these steps:

  1. Implement the dedicated transaction manager:

    org.jbpm.persistence.jta.ContainerManagedTransactionManager
  2. Insert the transaction manager and persistence context manager into the environment before you create or load your session:

    Environment env = EnvironmentFactory.newEnvironment();
    
    env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
    env.set(EnvironmentName.TRANSACTION_MANAGER,
      new ContainerManagedTransactionManager());
    env.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER,
      new JpaProcessPersistenceContextManager(env));
    env.set(EnvironmentName.TASK_PERSISTENCE_CONTEXT_MANAGER,
      new JPATaskPersistenceContextManager(env));
  3. Configure JPA provider (example Hibernate and WebSphere):

    <property name="hibernate.transaction.factory_class"
              value="org.hibernate.transaction.CMTTransactionFactory"/>
    <property name="hibernate.transaction.jta.platform"
              value="org.hibernate.service.jta.platform.internal.WebSphereJtaPlatform"/>
Note

To ensure that the container is aware of process instance execution exceptions, make sure that exceptions thrown by the engine are sent to the container to properly reverse the transaction.

Using the CMT Dispose KieSession Command

If you dispose of your KieSession directly when running in the CMT mode, you may generate exceptions, because Red Hat JBoss BPM Suite requires transaction synchronization. Use org.jbpm.persistence.jta.ContainerManagedTransactionDisposeCommand to dispose of your session.

13.5. Using Persistence

Red Hat JBoss BPM Suite engine does not save runtime data persistently by default. To use persistence, you need to:

  • Add necessary dependencies.
  • Configure a datasource.
  • Configure the Red Hat JBoss BPM Suite engine.

13.5.1. Adding Dependencies

To use persistence, add necessary dependencies to the classpath of your application. If you are using Red Hat JBoss Development Studio with Red Hat JBoss BPM Suite runtime default configuration, all necessary dependencies are already present for the default persistence configuration. Otherwise, ensure that the necessary JAR files are added to your Red Hat JBoss BPM Suite runtime directory.

Following is a list of dependencies for the default combination with Hibernate as the JPA persistence provider, an H2 in-memory database, and Bitronix for JTA-based transaction management. Dependencies needed for your project will vary depending on your solution configuration.

jbpm-persistence-jpa.jar file is necessary for saving the runtime state. Therefore, always make sure it is available in your project.

  • jbpm-persistence-jpa (org.jbpm)
  • drools-persistence-jpa (org.drools)
  • persistence-api (javax.persistence)
  • hibernate-entitymanager (org.hibernate)
  • hibernate-annotations (org.hibernate)
  • hibernate-commons-annotations (org.hibernate)
  • hibernate-core (org.hibernate)
  • commons-collections (commons-collections)
  • dom4j (dom4j)
  • jta (javax.transaction)
  • btm (org.codehaus.btm)
  • javassist (javassist)
  • slf4j-api (org.slf4j)
  • slf4j-jdk14 (org.slf4j)
  • h2 (com.h2database)

13.5.2. Manually Configuring Red Hat JBoss BPM Suite Engine to Use Persistence

Use JPAKnowledgeService to create a knowledge session based on a knowledge base, a knowledge session configuration (if necessary), and the environment. Ensure that the environment contains a reference to your Entity Manager Factory. For example:

// Create the entity manager factory and register it in the environment:
EntityManagerFactory emf =
  Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa");
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);

// Create a new knowledge session that uses JPA to store the runtime state:
StatefulKnowledgeSession ksession =
  JPAKnowledgeService.newStatefulKnowledgeSession(kbase, null, env);
int sessionId = ksession.getId();

// Invoke methods on your session here:
ksession.startProcess("MyProcess");
ksession.dispose();

Additionally, you can use JPAKnowledgeService to recreate a session based on a specific session ID. For example:

// Recreate the session from database using the sessionId:

ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(sessionId, kbase, null, env);

Note that only the minimal state that is required to continue execution of the process instance is saved. You cannot retrieve information related to already executed nodes if that information is no longer necessary. To search for history-related information, use the history log.

Add persistence.xml to META-INF to configure JPA. Following example uses Hibernate and H2 database:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence
  version="2.0"
  xsi:schemaLocation="
    http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd
    http://java.sun.com/xml/ns/persistence/orm
    http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
  xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <persistence-unit name="org.jbpm.persistence.jpa" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>jdbc/jbpm-ds</jta-data-source>
    <mapping-file>META-INF/JBPMorm.xml</mapping-file>

    <class>org.drools.persistence.info.SessionInfo</class>
    <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class>
    <class>org.drools.persistence.info.WorkItemInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationKeyInfo</class>
    <class>org.jbpm.persistence.correlation.CorrelationPropertyInfo</class>
    <class>org.jbpm.runtime.manager.impl.jpa.ContextMappingInfo</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
      <property name="hibernate.max_fetch_depth" value="3"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.transaction.jta.platform"
                value="org.hibernate.service.jta.platform.internal.BitronixJtaPlatform"/>
    </properties>
  </persistence-unit>
</persistence>

In this example, persistence.xml refers to a data source called jdbc/jbpm-ds. If you run your application in an application server, these containers typically allow you to use custom configure file for the data sources. See your application server documentation for further details.

Following example shows you how to set up a data source:

PoolingDataSource ds = new PoolingDataSource();

ds.setUniqueName("jdbc/jbpm-ds");
ds.setClassName("bitronix.tm.resource.jdbc.lrc.LrcXADataSource");
ds.setMaxPoolSize(3);
ds.setAllowLocalTransactions(true);
ds.getDriverProperties().put("user", "sa");
ds.getDriverProperties().put("password", "sasa");
ds.getDriverProperties().put("URL", "jdbc:h2:mem:jbpm-db");
ds.getDriverProperties().put("driverClassName", "org.h2.Driver");
ds.init();