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 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 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. |
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.
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.
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.
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.
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:
There is a simple set of guidelines for working with the jBpm cartridge that will get you started:
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.
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: