JBoss.orgCommunity Documentation

Chapter 5. Persistence

5.1. Runtime state
5.1.1. Binary persistence
5.1.2. Safe points
5.1.3. Configuring persistence
5.2. Process definitions
5.3. History log
5.3.1. Persisting process events in a database

Drools Flow allows the persistent storage of the different kinds of information, i.e. the process runtime state, the process definitions and the history information.

Whenever a process is started, a process instance is created, which represents the execution of the process in that specific context. For example, when executing a process that specifies how to process a sales order, one process instance is created for each sales request. The process instance represents the current execution state in that specific context, and contains all the information related to that process instance. Note that it only contains the minimal runtime state that is needed to continue the execution of that process instance at some later time (and for example does not include information about the history of that process instance if that information is no longer needed in the process instance at some later stage, see the history log).

The runtime state of an executing process can be persisted, for example in a database. This allows for example to restore the state of execution of all running processes in case of unexpected failure, or to temporarily remove running instances from memory when they are no longer needed and restore them at some later time. Drools Flow allows you to plug in different persistence strategies. By default (if you do not configure the process engine otherwise), process instances are not persisted.

By default, the engine does automatically persist the runtime data. It is however pretty straightforward to configure the engine to do this, by adding a config file and the necessary dependencies. The persistence itself is based on the Java Persistence API (JPA) and can thus work with several persistence mechanisms. We are using Hibernate by default (but feel free to check out other alternatives). We're using the H2 database underneath to store the data (but again you're free to choose your own alternative).

First of all, you need to add the necessary dependencies to your classpath. If you're using the Eclipse IDE, you can do that by adding the jars to your Drools runtime directory (see the chapter on the Eclipse IDE), or by manually adding these dependencies to your project. First of all you need the drools-process-enterprise jar, as that contains the necessary code to persist the runtime state whenever necessary. Next, you also need various other dependencies, but these are different depending on the persistence solution and database you are using. In our case (using Hibernate and the H2 database), the following list of dependencies is needed:

Next, you need to configure the Drools engine to persist the state of the engine whenever necessary. You can do this by simply specifying this in your session configuration. There are various ways to do this, but using a simple drools.session.conf file in a META-INF directory on your classpath is probably the easiest way (check the documentation for other ways of configuring your session, for example by providing a KnowledgeSessionConfiguration when first creating your session). In this config file you need to do two things: tell the engine that it needs to use a command service underneath (as commands are used to determine safe points during the execution of the engine), and use the JPA-based implementations of 3 internal components (the process instance manager, the work item manager and the signal manager), as these components will then be able to look up the necessary information from persistence using JPA. The drools.session.conf file should thus look like this:

drools.commandService = org.drools.persistence.session.SingleSessionCommandService
drools.processInstanceManagerFactory = org.drools.persistence.processinstance.JPAProcessInstanceManagerFactory
drools.workItemManagerFactory = org.drools.persistence.processinstance.JPAWorkItemManagerFactory
drools.processSignalManagerFactory = org.drools.persistence.processinstance.JPASignalManagerFactory

By default, the drools-process-enterprise jar contains a configuration file that configures JPA to use hibernate and the H2 database, called persistence.xml in the META-INF directory, as shown below. You will need to override these if you want to change the default. We refer to the JPA and Hibernate documentation for more information on how to do this.

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

  <persistence-unit name="org.drools.persistence.jpa">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>org.drools.persistence.jpa.ByteArrayObject</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
      <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>	        
      <property name="hibernate.connection.url" value="jdbc:h2:mem:mydb" />
      <property name="hibernate.connection.username" value="sa"/>
      <property name="hibernate.connection.password" value="sasa"/>	
      <property name="hibernate.connection.autocommit" value="false" /> 	               
      <property name="hibernate.max_fetch_depth" value="3"/>
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="hibernate.show_sql" value="false" />		    
    </properties>        
  </persistence-unit>
</persistence>

After adding the necessary dependencies and the configuration file to your project, you can simply use the StatelessKnowledgeSession just the way you used to do. The engine will underneath translate your invocations to commands that will persist the state of the engine after each successful execution of a command. For example, the following code snippet shows how to create a session and start a process. Note that this snippet does not show anything about persistence (as the config file configures all that for you, and the engine takes care of it automatically), so the example looks just like normal Drools code. You can however always destroy your session and create a new one (or one session could continue the work that was started in another session), as the runtime state is persisted safely in a database, and can be retrieved whenever necessary.

  StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession();
  long processInstanceId = session.startProcess("org.drools.test.TestProcess").getId();
  session.dispose();

Note that we only persist the minimal state that is needed to continue execution of the process instance at some later point. This for example means that it does not contain information about already executed nodes if that information is no longer relevant, or that process instances that have been completed or aborted are removed from the database. If you however want to search for history-related information, you should use the history log, as explained later.

Process definitions are usually stored in an XML format. These files can easily be stored on a file system during development. However, whenever you want to make your knowledge accessible to one or more engines in production, we recommend using a knowledge repository that (logically) centralizes your knowledge (in one or more knowledge repositories).

Guvnor is a sub-project that provides exactly that: it consists of a repository for storing different kinds of knowledge (not only process definitions but also rules, object models, etc.), allows easy retrieval of this knowledge (for example using WebDAV or by using a rule agent that automatically downloads the information from Guvnor when creating a knowledge base), and provides a web application that allows business users to view and possibly update the information in the knowledge repository. Check out the Drools Guvnor documentation for more information on how to do this.

In many cases it is useful (if not necessary) to store information about the execution on process instances, so that this information can be used afterwards for example to verify what actions have been executed for a particular process instance, or to monitor and/or analyze the efficiency of a particular process, etc. Storing history information in the runtime database is usually not a good idea (as this would result in ever-growing runtime data, and monitoring and analysis queries might influence the performance of your runtime engine). That is why history information about the execution of process instances is stored separately.

This history log of execution information is created based on the events generated by the process engine during execution. The Drools runtime engine provides a generic mechanism to listen to different kinds of events. The necessary information can easily be extracted from these events and persisted, for example in a database. Filters can be used to only store the information you find relevant.

The drools-bam module contains an event listener that stores process-related information in a database (using hibernate). The database contains two tables, one for process instance information and one for node instance information (see figure below):

To log process history information in a database like this, you need to register the logger on your session (or working memory) like this:

      StatefulKnowledgeSession session = ...
      new WorkingMemoryDbLogger(session);

Note that this logger is just a logger like any other audit logger. This means you can add one or more filters using the addFilter method to make sure that only relevant information is stored in the database. If you use more than one filter, only information that is accepted by all your filters will be persisted in the database.

To specify the database where the information should be stored, modify the hibernate.cfg.xml file. By default, it uses an in memory database (H2). Check out the hibernate documentation if you do not know how to do this.

All this information can easily be queried and can be used in a lot of different use cases, ranging from creating a history log for one specific process instance to analyzing the performance of all instances of a specific process. The org.drools.process.auditProcessInstanceDbLog class shows some examples on how to retrieve all process instances, one specific process instance (by id), all process instances for one specific process, all node instances of a specific process instance, etc. You can of course easily create your own hibernate queries or access the information in the database directly.