development

Persisting custom process variables in different DB on jBPM

Intro

So you want to store the data used in your process separately from jBPM database schema.

To achieve this, you need to use Pluggable Variable Persistence. This is an objective post on the requirements to implement PVP on your project.

TLDR;

Sample project repo with a working example: pvp-sample

  • The persistable classes needs to be serializable and have @Table and @Id annotations from
  • Add JPA Marshalling Strategy
  • The app server needs to be able to access the database (via Datasource for example)
  • Configure the project persistence unit

How-to

Used on this example creation:

  • jBPM 7.14 (upstream version of RHPAM 7.2)
  • PostgreSQL 9.6
  • PostgreSQL driver: postgresql-9.4.1212.jar

To get an instance of postgres up and running with Docker, check post Run and access postgresql db in 30 secs.

The following datasource can be configured on EAP:

<datasource jndi-name="java:/jboss/datasources/PostgresDS" pool-name="PostgresDS">
    <connection-url>jdbc:postgresql://localhost:5432/database_name</connection-url>
    <driver-class>org.postgresql.Driver</driver-class>
    <datasource-class>org.postgresql.ds.PGSimpleDataSource</datasource-class>
    <driver>postgresql-9.4.1212.jar</driver>
    <security>
        <user-name>database_username</user-name>
        <password>database_password</password>
    </security>
    <validation>
        <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/>
        <background-validation>true</background-validation>
        <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLExceptionSorter"/>
    </validation>
</datasource>   

Due to the usage of two different datasources, it is required to use XA Datasources. It is possible to use com.arjuna.ats.arjuna.allowMultipleLastResources=true system property only for test purposes.

The server was started with one additional property:

$JBPM_HOME/bin/standalone.sh -Dcom.arjuna.ats.arjuna.allowMultipleLastResources=true

During start up, if you see errors related to psql syntax like:

ERROR: syntax error at or near "generated"

Probably you forgot the set the system properties with proper dialect and/or DS: org.kie.server.persistence.dialect and org.kie.server.persistence.ds

After started, import this pvp-example project. You can use the following curl commands:

curl --request GET  --header 'Authorization: Basic c2FsYWJveTpzYWxhYm95'  --url http://localhost:8080/jbpm-console/rest/spaces/MySpace/projects

curl --request POST --url http://localhost:8080/jbpm-console/rest/spaces/MySpace/git/clone --header 'Authorization: Basic c2FsYWJveTpzYWxhYm95' --header 'Content-Type: application/json'  --header 'cache-control: no-cache'  --data '{"name":"pvp-example","description":"Plugable persistence variable on processes custom data object.","gitURL":"git@github.com:kmacedovarela/pvp-example.git"}'

Note that:

  • The persistable Person.java class:
    • Is serializable
    • Is annotated with @javax.persistence.Table(name = “tableName”) and with @javax.persistence.Entity
    • And has an id annotated with @javax.persistence.Id
  • JPAMarshaller is configured as a Marshalling Strategy (kie-deployment-descriptor.xml ). The first parameter refers to the persistence unit configured on the project Persistence (persistence.xml) configuration and points to the datasource where the custom objects are going to be persisted.
new org.drools.persistence.jpa.marshaller.JPAPlaceholderResolverStrategy("testPU", classLoader)	
JPA Marshaller configured for a specific persistence unit named “testPU”
“testPU” Persistence unit configuration used by marshaller. Hibernate is also configured to log sql for demonstration purposes.

This is all you need in order to persist custom process variables on another database.

When the project “Deploy” action is triggered, the following evidence shows up on the log

02:26:16,594 INFO  [stdout] (default task-13) Hibernate: create table Person (id int8 not null, age int4, name varchar(255), primary key (id))
02:26:16,651 INFO  [stdout] (default task-13) Hibernate: create sequence PERSON_ID_SEQ start 1 increment 1
02:26:17,700 INFO  [org.kie.server.services.impl.KieServerImpl] (default task-13) Container pvp-example_2.0.0 (for release id org.kvarela:pvp-example:2.0.0) successfully started

When starting an instance of the process, the following logs appear:

02:28:19,262 INFO  [stdout] (default task-25) Hibernate: select nextval ('PERSON_ID_SEQ')
02:28:19,276 INFO  [stdout] (default task-25) Hibernate: insert into Person (age, name, id) values (?, ?, ?)

And the table has the following data used on process instance creation:

jpasample=# select * from person;
 id | age |     name      
----+-----+---------------
  1 |  28 | Karina Varela
(1 row)

How to join custom data with the process instance?

The relationship between the process instance and the persisted object is not implemented by default.

This mapping is achieved with MappedVariable table. It can get automatically populated by jBPM with the process instance id, and the custom object id, allowing the implementation of custom advanced queries (more on Advanced Queries post, by Maciej).

There are also good information on Maciej’s blog about PVP and the reading is recommended.

Tip: in order to achieve the automatic relationship mentioned, extend “org.drools.persistence.jpa.marshaller.VariableEntity” on the persistent class.