Delegation

Delegation is the mechanism used to include the users' custom code in the execution of processes.

The jBPM class loader

The jBPM class loader is the class loader that loads the jBPM classes. Meaning, the classloader that has the library jbpm-3.x.jar in its classpath. To make classes visible to the jBPM classloader, put them in a jar file and put the jar file besides the jbpm-3.x.jar. E.g. in the WEB-INF/lib folder in the case of webapplications.

The process class loader

Delegation classes are loaded with the process class loader of their respective process definition. The process class loader is a class loader that has the jBPM classloader as a parent. The process class loader adds all the classes of one particular process definition. You can add classes to a process definition by putting them in the /classes folder in the process archive. Note that this is only useful when you want to version the classes that you add to the process definition. If versioning is not necessary, it is much more efficient to make the classes available to the jBPM class loader.

If the resource name doesn't start with a slash, resources are also loaded from the /classes directory in the process archive. If you want to load resources outside of the classes directory, start with a double slash ( // ). For example to load resource data.xml wich is located next to the processdefinition.xml on the root of the process archive file, you can do clazz.getResource("//data.xml") or classLoader.getResourceAsStream("//data.xml") or any of those variants.

Configuration of delegations

Delegation classes contain user code that is called from within the execution of a process. The most common example is an action. In the case of action, an implementation of the interface ActionHandler can be called on an event in the process. Delegations are specified in the processdefinition.xml. 3 pieces of data can be supplied when specifying a delegation :

  • 1) the class name (required) : the fully qualified class name of the delegation class.
  • 2) configuration type (optional) : specifies the way to instantiate and configure the delegation object. By default the default constructor is used and the configuration information is ignored.
  • 3) configuration (optional) : the configuration of the delegation object in the format as required by the configuration type.

Next is a description of all the configuration types:

config-type field

This is the default configuration type. The config-type field will first instantiate an object of the delegation class and then set values in the fields of the object as specified in the configuration. The configuration is xml, where the elementnames have to correspond with the field names of the class. The content text of the element is put in the corresponding field. If necessary and possible, the content text of the element is converted to the field type.

Supported type conversions:

  • String doesn't need converting, of course. But it is trimmed.
  • primitive types such as int, long, float, double, ...
  • and the basic wrapper classes for the primitive types.
  • lists, sets and collections. In that case each element of the xml-content is consitered as an element of the collection and is parsed, recursively applying the conversions. If the type of the elements is different from java.lang.String this can be indicated by specifying a type attribute with the fully qualified type name. For example, following snippet will inject an ArrayList of Strings into field 'numbers':
    <numbers>
      <element>one</element>
      <element>two</element>
      <element>three</element>
    </numbers>

    The text in the elements can be converted to any object that has a String constructor. To use another type then String, specify the element-type in the field element ('numbers' in this case).

    Here's another example of a map:

    <numbers>
      <entry><key>one</key><value>1</value></entry>
      <entry><key>two</key><value>2</value></entry>
      <entry><key>three</key><value>3</value></entry>
    </numbers>
  • maps. In this case, each element of the field-element is expected to have one subelement key and one element value. The key and element are both parsed using the conversion rules recursively. Just the same as with collections, a conversion to java.lang.String is assumed if no type attribute is specified.
  • org.dom4j.Element
  • for any other type, the string constructor is used.

For example in the following class...

public class MyAction implements ActionHandler {
  // access specifiers can be private, default, protected or public
  private String city;
  Integer rounds;
  ...
}

...this is a valid configuration:

...
<action class="org.test.MyAction">
  <city>Atlanta</city>
  <rounds>5</rounds>
</action>
...

config-type bean

Same as config-type field but then the properties are set via setter methods, rather then directly on the fields. The same conversions are applied.

config-type constructor

This instantiator will take the complete contents of the delegation xml element and passes this as text in the delegation class constructor.

config-type configuration-property

First, the default constructor is used, then this instantiator will take the complete contents of the delegation xml element, and pass it as text in method void configure(String);. (as in jBPM 2)