Abstract

These pages describe the 'jBPM' cartridge. jBPM is a workflow engine that is now part of the JBoss product line. This cartridge is able to generate process definitions and handlers from UML activity graphs.

Modeling for jBpm

Modeling for the jBpm cartridge is actually very simple, for a single jBpm process you will need to model a usecase containing an activity graph, and a class which will own the operations to call in specific areas of the graph.

The activity graph

The activity graph will determine the content of the process definition XML descriptor, all transitions, states and swimlanes will be analyzed and a suitable descriptor is emitted. More formally, we will be considering the following model elements for the jBpm cartridge:

use-case The use-case is used to envelop the activity graph, stereotypes and tagged values will be modeled on the use-case rather than directly on the activity graph.
activity graph The activity graph explicitly describes the process flow, almost all types of supported model elements will be used to describe the process.
swimlane Specific action roles are represented using swimlanes (the technical UML term for a swimlane is partition), states can be assigned to a specific swimlane, denoting the user/role assigned to it. A swimlane optionally take one or more assigment expression tagged values, use andromda_process_jbpm_assignment_expression. A swimlane will result in the generation of an assignment handler, the user assigned to this swimlane will subsequently be assigned to all tasks in it.
initial state A single initial state represents the start of the process, it typically has a single outgoing transition.
state A state element represents a jBpm state, which is a node in which the process is waiting for a signal. A state may contain deferrable call-events (see below).
action state Action states are a specific type of state without indicating the process is waiting, you would typically use an action state as a pass-through state or a state in which a few tasks are created or events are triggered.
decision point Use decision points when you want to have the process split up in different directions based on a specific decision. Each decision point will result in the generation of a decision handler. A decision point is required to have a non-empty name.
call-event Each event will result in the generation of an action handler (if the state does not carry the <<Task>> stereotype and if the event itself carries the <<Before Signal>>, <<After Signal>>, <<Node Enter>>, <<Node Leave>> or <<Timer>>)
transition Transitions tie all other elements used in an activity graph together, they represent the different directions a flow can take. Just as with action states transitions may use a call-event to defer control to an operation.
final state One or more final states represent the end of the process. A final state is required to have a non-empty name.
class Per activity graph a single class is used containing the operations to which will be deferred from within the action states or transitions. Each operation will result in the generation of a handler. See the next section for more information.

The handler class

Once in a while you will want to defer control to a specific operation, implemented in jBpm by means of Handler interfaces. For each such operation to which is deferred the cartridge will generate a class, implementing the necessary interfaces. By default this implementation is empty so it needs manual editing.

In order to be able to defer to such an operation you will need to assign the class as the context of the activity graph, UML tools often have different ways of achieving this (if at all). MagicDraw allows you to right-click the class to popup the menu, select the 'Assign...' item and select the appropriate graph from the select before clicking the 'Assign' button.

Below you'll find examples of such handlers.

Node classes

Having the process definition descriptor generated is nice, but it's not enough to have a good workflow experience since working with the jBpm API is kind of cumbersome: suppose you're in a state with two outgoing transitions and you need to signal one of them, in this case you'll use the name of the transition, but if that name does not match any of the existing names you'll have a runtime error. This is a very common mistake to make as the process might change over time and transitions might be renamed, and not to mention the introduction of typos.

For this reason the jBpm cartridge generates a layer of classes that'll make it significantly easier to work with the underlying process. For each node a class is generate containing a set of methods ensuring proper execution on the process instance.

Take a look at the example below to get an idea of what has been discussed so far.

Integrating jBpm in your own applications

Using jBpm in your own applications will require you to setup the jBpm database schema and inject the process definitions, this can be done by the generated ProcessManager class. It contains operations to create, clean and drop the schema and a method to insert all process definitions. Once this is done you will be able to work with the node classes so you'll be able to persist your processes. Please refer to the jBpm documentation for more information.

Good to know

There are a few things you should know about the jBpm cartridge. It's important to realize that using a modeling tool such as a UML editor offers a level of abstraction but also makes you lose a certain degree of control over the generated file. For this reason you need to understand some of the decisions behind the cartridge, in jBpm something can be implemented in many different ways but the cartridge consistently applies the same patterns, something humans rarely do.

Patterns

Most of the time you won't need to customize anything, and if you do you will have a set of tagged values and stereotypes at your disposal that will allow you to tweak the generated code. Here's a list of patterns applied by the cartridge:

  • all tasks are blocking by default, the process can't continue until all tasks have finished
  • no task is signaling, in order to continue to the next state you will always have to explicitly signal the process
  • assignment is done on the level of the swimlane, all tasks that are part of that swimlane will have the same actor assigned to it

Modeling

There is a simple set of guidelines for working with the jBpm cartridge that will get you started:

  • tasks are modeled as deferrable call-events on an action state, give these events the <<Task>> stereotype
  • if you want to schedule the timely execution of an action you should model a deferrable call-event with the <<Timer>> stereotype, you can do this on an action state or on a regular state
  • most, but not all, of the model elements require a name, it's a good practice to give descriptive names; don't be afraid of using spaces
  • in real processes it's a good idea to have a naming convention for your elements: states should sounds like 'request sent', 'form stored', 'filing issue' or 'updating record', use the present tense for transitions and tasks: 'send request' or 'store form'

Example

Although not displaying everything, the following diagram shows how a process can be modeled (the events, use-case and handler operations aren't shown). The generated process description file is found below.

images/example.gif


The next two code fragments show a comparison between regular jBpm access and access via the classes generated by the cartridge, we'll be using the example process above.


And this is a code snippet showing how the same thing can be achieved using the generated node classes, notice how much easier it is to read the code, even for this very simple example.


More elaborate cases such as ones involving decision points, forks, timers, etc.. will yield the proper methods in these node classes, that way if something changes in the process model your compiler will tell you if your code is out of sync'.

Here are the generated assignment handlers for the customer swimlane, you're looking at the generated parent and implementation classes:


There's a timer in the notifying customer node, more specifically on the event deferring to the sendNotification operation, here are the corresponding action handler classes:


More will be added later...