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:
- a set of service implementations which configure the
JbpmContext
. (The possible configuration options are detailed in the chapters that cover specific service implementations.) - 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. - 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-context
s. 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
<service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />
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 theorg.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 thejbpm.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. Theorg.jbpm.db.hibernate.ConverterEnumType
class is used to map the identifiers to thesingleton
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.