Chapter 6. Configuration

The simplest way to configure jBPM is by putting the jbpm.cfg.xml configuration file in the root of the classpath. If that file is not found as a resource, the default minimal configuration will be used that is included in the jbpm library. Note that the minimal configuration does not have any configurations for persistence.

The jBPM configuration is represented by the java class org.jbpm.JbpmConfiguration. Most easy way to get a hold of the JbpmConfiguration is to make use of the singleton instance method JbpmConfiguration.getInstance().

If you want to load a configuraiton from another source, you can use the JbpmConfiguration.parseXxxx methods.

static JbpmConfinguration jbpmConfiguration = JbpmConfinguration.getInstance();

The JbpmConfiguration is threadsafe and hence can be kept in a static member. All threads can use the JbpmConfiguration as a factory for JbpmContext objects. A JbpmContext typically represents one transaction. The JbpmContext makes services available inside of a context block. A context block 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 a set of services and the configuration available to jBPM. These services are configured in the jbpm.cfg.xml configuration file and make it possible for jBPM to run in any Java environment and use whatever services are available in that environment.

Here's a typical configuration for the JbpmContext as you can find it in src/config.files/jbpm.cfg.xml:

<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' />

  <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' />

</jbpm-configuration>

In this configuration file you can see 3 parts:

The default configured set of services is targetted at a simple webapp environment and minimal dependencies. The persistence service will obtain a jdbc connection and all the other services will use the same connection to perform their services. So all of your workflow operations are centralized into 1 transaction on a JDBC connection without the need for a transaction manager.

JbpmContext contains convenience methods for most of the common process operations:

  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 that the XxxForUpdate methods will register the loaded object for auto-save so that you don't have to call one of the save methods explicitely.

It's possible to specify multiple jbpm-contexts, but then you have to make sure that each jbpm-context is given a unique name attribute. Named contexts can be retrieved with JbpmConfiguration.createContext(String name);

A service element specifies the name of a service and the service factory for that service. The service will only be created in case it's asked for with JbpmContext.getServices().getService(String name).

The factories can also be specified as an element instead of an attribute. That might be necessary to inject some configuration information in the factory objects. The component responsible for parsing the XML, creating and wiring the objects is called the object factory.

6.1. Customizing factories

A common mistake when customizing factories is to mix the short and the long notation. Examples of the short notation can be seen in the default configuration file and above: E.g.

  ...
  <service name='persistence' factory='org.jbpm.persistence.db.DbPersistenceServiceFactory' />

If specific properties on a service need to be specified, the short notation can't be used, but instead, the long notation has to be used like this: E.g.

  <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> 

6.2. Configuration properties

jbpm.byte.block.size: File attachments and binary variables are stored in the database. Not as blobs, but as a list of fixed sized binary objects. This is done to improve portability amongst different databases and improve overall embeddability of jBPM. This parameter controls the size of the fixed length chunks.

jbpm.task.instance.factory: To customize the way that task instances are created, specify a fully qualified class name in this property. This might be necessary when you want to customize the TaskInstance bean and add new properties to it. See also Section 12.10, “Customizing task instances” The specified class should implement org.jbpm.taskmgmt.TaskInstanceFactory.

jbpm.variable.resolver: To customize the way that jBPM will look for the first term in JSF-like expressions.

6.3. Other configuration files

Here's a short description of all the configuration files that are customizable in jBPM.

6.3.1. Hibernate cfg xml file

This file contains hibernate configurations and references to the hibernate mapping resource files.

Location: hibernate.cfg.xml unless specified otherwise in the jbpm.hibernate.cfg.xml property in the jbpm.properties file. In the jbpm project the default hibernate cfg xml file is located in directory src/config.files/hibernate.cfg.xml

6.3.2. Hibernate queries configuration file

This file contains hibernate queries that are used in the jBPM sessions org.jbpm.db.*Session.

Location: org/jbpm/db/hibernate.queries.hbm.xml

6.3.3. Node types configuration file

This file contains the mapping of XML node elements to Node implementation classes.

Location: org/jbpm/graph/node/node.types.xml

6.3.4. Action types configuration file

This file contains the mapping of XML action elements to Action implementation classes.

Location: org/jbpm/graph/action/action.types.xml

6.3.5. Business calendar configuration file

Contains the definition of business hours and free time.

Location: org/jbpm/calendar/jbpm.business.calendar.properties

6.3.6. Variable mapping configuration file

Specifies how the values of the process variables (java objects) are converted to variable instances for storage in the jbpm database.

Location: org/jbpm/context/exe/jbpm.varmapping.xml

6.3.7. Converter configuration file

Specifies the id-to-classname mappings. The id's are stored in the database. The org.jbpm.db.hibernate.ConverterEnumType is used to map the ids to the singleton objects.

Location: org/jbpm/db/hibernate/jbpm.converter.properties

6.3.8. Default modules configuration file

specifies which modules are added to a new ProcessDefinition by default.

Location: org/jbpm/graph/def/jbpm.default.modules.properties

6.3.9. Process archive parsers configuration file

specifies the phases of process archive parsing

Location: org/jbpm/jpdl/par/jbpm.parsers.xml

6.4. jBPM debug logs in JBoss

When running jPDL in JBoss and you want to see the debug logs of jBPM, replace the file conf/log4j.xml in the jboss server configuration take with the file deploy/log4j.xml in your jPDL distribution. In the suite, the full location of the file to be replaced is [jpdl.home]/server/server/jbpm/conf/log4j.xml.

6.5. Logging of optimistic concurrency exceptions

When running in a cluster, jBPM synchronizes on the database. By default with optimistic locking. This means that each operation is performed in a transaction. And if at the end a collision is detected, then the transaction is rolled back and has to be handled. E.g. by a retry. So optimistic locking exceptions are usually part of the normal operation. Therefor, by default, the org.hibernate.StateObjectStateExceptions the that hibernate throws in that case are not logged with error and a stack trace, but instead a simple info message 'optimistic locking failed' is displayed.

Hibernate itself will log the StateObjectStateException including a stack trace. If you want to get rid of these stack traces, put the level of org.hibernate.event.def.AbstractFlushingEventListener to FATAL. If you use log4j following line of configuration can be used for that:

log4j.logger.org.hibernate.event.def.AbstractFlushingEventListener=FATAL

If you want to enable logging of the jBPM stack traces, add the following line to your jbpm.cfg.xml:

<boolean name="jbpm.hide.stale.object.exceptions" value="false" />

.

6.6. Object factory

The object factory can create objects according to a beans-like xml configuration file. The configuration file specifies how objects should be created, configured and wired together to form a complete object graph. The object factory can inject the configurations and other beans into a bean.

In its simplest form, the object factory is able to create basic types and java beans from such a configuration:

<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"));

Also you can configure lists:

<beans>
  <list name="numbers">
    <string>one</string>
    <string>two</string>
    <string>three</string>
  </list>
</beans>

and 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>

Beans can be configured with direct field injection and via property setters.

<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>

Beans can be referenced. The referenced object doesn't have to be a bean, it can be a string, integer or any other object.

<beans>
  <bean name="a" class="org.jbpm.A" />
  <ref name="b" bean="a" />
</beans>

Beans can be constructed with any constructor

<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>

... or with a factory method on a bean ...

<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>

... or with 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>

Each named object can be marked as singleton with the attribute singleton="true". That means that a given object factory will always return the same object for each request. Note that singletons are not shared between different object factories.

The singleton feature causes the differentiation between the methods getObject and getNewObject. Typical users of the object factory will use the getNewObject. This means that first the object factory's object cache is cleared before the new object graph is constructed. During construction of the object graph, the non-singleton objects are stored in the object factory's object cache to allow for shared references to one object. The singleton object cache is different from the plain object cache. The singleton cache is never cleared, while the plain object cache is cleared at the start of every getNewObject method.