Red Hat Training

A Red Hat training course is available for JBoss Enterprise SOA Platform

Chapter 3. Configuration

Read this chapter and studied the examples to learn how to configure the jBPM.
The simplest way to configure the Business Process Manager is by putting the jbpm.cfg.xml configuration file into the root of the classpath. If the file is not available for use as a resource, the default minimal configuration will be used instead. This minimal configuration is included in the jBPM library (org/jbpm/default.jbpm.cfg.xml.) If a jBPM configuration file is provided, the values it contains will be used as the defaults. Hence, one only needs to specify the values that are to be different from those in the default configuration file.
The jBPM configuration is represented by a Java class called org.jbpm.JbpmConfiguration. Obtain it by making use of the singleton instance method (JbpmConfiguration.getInstance().)

Note

Use the JbpmConfiguration.parseXxxx methods to load a configuration from another source.
static JbpmConfinguration jbpmConfiguration = JbpmConfinguration.parseResource("my.jbpm.cfg.xml");
The JbpmConfiguration is "thread safe" and, hence, can be kept in a static member.
Every thread can use a JbpmConfiguration as a factory for JbpmContext objects. A JbpmContext will usually represent one transaction. They make services available inside context blocks which 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 both a set of services and the configuration settings available to the Business Process Manager. The services are configured by the values in the jbpm.cfg.xml file. They make it possible for the jBPM to run in any Java environment, using whatever services are available within said environment.
Here are the default configuration settings for the JbpmContext:
<jbpm-configuration>

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

<!-- configuration resource files pointing to default
     configuration files in jbpm-{version}.jar -->
<string name='resource.hibernate.cfg.xml' value='hibernate.cfg.xml' />
  
  <!-- <string name='resource.hibernate.properties'
       value='hibernate.properties' /> -->
  <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' />

  <int name='jbpm.byte.block.size' value="1024" singleton="true" />
  <bean name='jbpm.task.instance.factory' 
    class='org.jbpm.taskmgmt.impl.DefaultTaskInstanceFactoryImpl'
    singleton='true' />
    
  <bean name='jbpm.variable.resolver' 
    class='org.jbpm.jpdl.el.impl.JbpmVariableResolver'
    singleton='true' />
    
    <string name='jbpm.mail.smtp.host' value='localhost' />
    
    <bean name='jbpm.mail.address.resolver' 
        class='org.jbpm.identity.mail.IdentityAddressResolver' 
        singleton='true' />
    <string name='jbpm.mail.from.address' value='jbpm@noreply' />

    <bean name='jbpm.job.executor' 
        class='org.jbpm.job.executor.JobExecutor'>
      <field name='jbpmConfiguration'><ref bean='jbpmConfiguration' />
      </field>
      <field name='name'><string value='JbpmJobExecutor' /></field>
      <field name='nbrOfThreads'><int value='1' /></field>
      <field name='idleInterval'><int value='60000' /></field>
      <field name='retryInterval'><int value='4000' /></field>
      <!-- 1 hour -->
      <field name='maxIdleInterval'><int value='3600000' /></field> 
      <field name='historyMaxSize'><int value='20' /></field>
      <!-- 10 minutes -->
      <field name='maxLockTime'><int value='600000' /></field> 
      <!-- 1 minute -->
      <field name='lockMonitorInterval'><int value='60000' /></field> 
       <!-- 5 seconds -->
      <field name='lockBufferTime'><int value='5000' /></field>
    </bean>
</jbpm-configuration>
The above file contains three parts:
  1. a set of service implementations which configure the JbpmContext. (The possible configuration options are detailed in the chapters that cover specific service implementations.)
  2. all of the mappings linking references to configuration resources. If one wishes to customize one of the configuration files, update these mappings. To do so, always back up the default configuration file (jbpm-3.x.jar) to another location on the classpath first. Then, update the reference in this file, pointing it to the customized version that the jBPM is to use.
  3. miscellaneous configurations for use by the jBPM. (These are described in the chapters that cover the specific topics in question.)
The default configuration has been optimized for a simple web application environment which has minimal dependencies. The persistence service obtains a JDBC connection which is used by all of the other services. Hence, all of the workflow operations are centralized as they are placed in a single transaction on a JDBC connection (without the need for a transaction manager.)
JbpmContext contains convenience methods for most of the common process operations. They are demonstrated in this code sample:
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

There is no need to call any of the save methods explicitly because the XxxForUpdate methods are designed to register the loaded object for "auto-save."
It is possible to specify multiple jbpm-contexts. To do so, make sure that each of them is given a unique name attribute. (Retrieve named contexts by using JbpmConfiguration.createContext(String name);.)
A service element specifies its own name and associated service factory. The service will only be created when requested to do so by JbpmContext.getServices().getService(String name).

Note

One can also specfy the factories as elements instead of attributes. This is necessary when injecting some configuration information into factory objects.
Note that the component responsible for creating and wiring the objects and parsing the XML is called the object factory.

3.1.  Customizing Factories

Warning

A mistake commonly made by people when they are trying to customize factories is to mix long and short notation together. (Examples of the short notation can be seen in the default configuration file.)
Hibernate logs StateObjectStateException exceptions and generates a stack trace. In order to remove the latter, set org.hibernate.event.def.AbstractFlushingEventListener to FATAL. (Alternatively, if using log4j, set the following line in the configuration: for that: log4j.logger.org.hibernate.event.def.AbstractFlushingEventListener=FATAL
&lt;service name='persistence' 
    factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' /&gt;

Important

If one needs to note specific properties on a service, only the long notation can be used.
<service name="persistence">
    <factory>
        <bean class="org.jbpm.persistence.db.DbPersistenceServiceFactory">
            <field name="dataSourceJndiName">
                <string value="java:/myDataSource"/>
            </field>
            <field name="isCurrentSessionEnabled"><true /></field>
            <field name="isTransactionEnabled"><false /></field>
        </bean>
    </factory>
</service>

3.2.  Configuration Properties

jbpm.byte.block.size
File attachments and binary variables are stored in the database in the form of a list of fixed-sized, binary objects. (The aim of this is to improve portability amongst different databases. It also allows one to embed the jBPM more easily.) This parameter controls the size of those fixed-length chunks.
jbpm.task.instance.factory
To customize the way in which task instances are created, specify a fully-qualified classname against this property. (This is often necessary when one intends to customize, and add new properties to, the TaskInstance bean.) Ensure that the specified classname implements the org.jbpm.taskmgmt.TaskInstanceFactory interface. (Refer to Section 8.10, “ Customizing Task Instances ” for more information.)
jbpm.variable.resolver
Use this to customize the way in which jBPM looks for the first term in "JSF"-like expressions.
jbpm.class.loader
Use this property to load jBPM classes.
jbpm.sub.process.async
Use this property to allow for asynchronous signaling of sub-processes.
jbpm.job.retries
This configuration determines when a failed job is retired. If you examine the configuration file, you can set the entry so that it makes a specified number of attempts to process such a job before retiring it.
jbpm.mail.from.address
This property displays where a job has come from. The default is jbpm@noreply.

3.3. Other Configuration Files

There are a number of configuration files in the jBPM which can be customized:
hibernate.cfg.xml
This contains references to, and configuration details for, the Hibernate mapping resource files.
To change the hibernate.cfg.xml file used by jBPM, set the following property in the jbpm.cfg.xml file:
<string name="resource.hibernate.cfg.xml" value="new.hibernate.cfg.xml"/> The file jbpm.cfg.xml file is located in ${soa.home}/jboss-as/server/${server.config}/jbpm.esb
org/jbpm/db/hibernate.queries.hbm.xml
This file contains those Hibernate queries to be used in the jBPM sessions (org.jbpm.db.*Session.)
org/jbpm/graph/node/node.types.xml
This file is used to map XML node elements to Node implementation classes.
org/jbpm/graph/action/action.types.xml
This file is used to map XML action elements to Action implementation classes.
org/jbpm/calendar/jbpm.business.calendar.properties
This contains the definitions of "business hours" and "free time."
org/jbpm/context/exe/jbpm.varmapping.xml
This specifies the way in which the process variables values (Java objects) are converted to variable instances for storage in the jBPM database.
org/jbpm/db/hibernate/jbpm.converter.properties
This specifies the id-to-classname mappings. The ids are stored in the database. The org.jbpm.db.hibernate.ConverterEnumType class is used to map the identifiers to the singleton objects.
org/jbpm/graph/def/jbpm.default.modules.properties
This specifies which modules are to be added to a new ProcessDefinition by default.
org/jbpm/jpdl/par/jbpm.parsers.xml
This specifies the phases of process archive parsing.

3.4.  Logging Optimistic Concurrency Exceptions

When it is run in a cluster configuration, the jBPM synchronizes with the database by using optimistic locking. This means that each operation is performed in a transaction and if, at the end, a collision is detected, then the transaction in question is rolled back and has to be handled with a retry. This can cause org.hibernate.StateObjectStateException exceptions. If and when this happens, Hibernate will log the exceptions with a simple message,
optimistic locking
            failed
.
Hibernate can also log the StateObjectStateException with a stack trace. To remove these stack traces, set the org.hibernate.event.def.AbstractFlushingEventListener class to FATAL. Do so in log4j by using the following configuration:
log4j.logger.org.hibernate.event.def.AbstractFlushingEventListener=FATAL
In order to log jBPM stack traces, set the log category threshold above ERROR for the package.

3.5. Object Factory

The Object Factory can build objects to the specification contained in a "beans-like" XML configuration file. This file dictates how objects are to be created, configured and wired together to form a complete object graph. Also use the Object Factory to inject configurations and other beans into a single bean.
In its most elementary form, the Object Factory is able to create both basic types and Java beans from such a configuration, as shown in the following examples:
<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"));]]>
This code shows how to configure lists:
<beans>
    <list name="numbers">
        <string>one</string>
        <string>two</string>
        <string>three</string>
    </list>
</beans>
This code demonstrates how to configure 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>
Use direct field injection and property setter methods to configure beans:
<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>
You can refer to beans. The object referenced does not have to be a bean itself: it can be a string, an integer or anything you want.
<beans>
    <bean name="a" class="org.jbpm.A" />
    <ref name="b" bean="a" />
</beans>
Beans can be built with any constructor, as this code shows:
<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>
Beans can be constructed using a factory method:
<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>
Beans can be constructed using 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>
Use the attribute singleton="true" to mark each named object as a singleton. Doing so will ensure that a given object factory always returns the same object for each request.

Note

Singletons cannot be shared between different object factories.
The singleton feature causes differentiation between the methods named getObject and getNewObject. Normally, one should use getNewObject as this clears the object factory's object cache before the new object graph is constructed.
During construction of the object graph, the non-singleton objects are stored in the object factory's cache. This allows references to one object to be shared. Bear in mind that the singleton object cache is different from the plain object cache. The singleton cache is never cleared, whilst the plain one is cleared every time a getNewObject method is started.
Having studied this chapter, one now has a thorough knowledge of the many ways in which the jBPM can be configured.