The graph execution model of jBPM is based on interpretation of the process definition and the chain of command pattern.
Interpretation of the process definition means that the process definition data is stored in the database. At runtime the process definition information is used during process execution. Note for the concerned : we use hibernate's second level cache to avoid loading of definition information at runtime. Since the process definitions don't change (see process versioning) hibernate can cache the process definitions in memory.
The chain of command pattern means that each node in the graph is responsible for propagating the process execution. If a node does not propagate execution, it behaves as a wait state.
The idea is to start execution on process instances and that the execution continues till it enters a wait state.
A token represents a path of execution. A token has a pointer to a node in the process graph. During waitstates, the tokens can be persisted in the database. Now we are going to look at the algorithm for calculating the execution of a token. Execution starts when a signal is sent to a token. The execution is then passed over the transitions and nodes via the chain of command pattern. These are the relevant methods in a class diagram.
When a token is in a node, signals can be sent to the token. Sending a
signal is an instruction to start execution. A signal must therefore specify
a leaving transition of the token's current node. The first transition is the
default. In a signal to a token, the token takes its current node
and calls the Node.leave(ExecutionContext,Transition)
method. Think
of the ExecutionContext as a Token because the main object in an ExecutionContext
is a Token. The Node.leave(ExecutionContext,Transition)
method will
fire the node-leave
event and call the
Transition.take(ExecutionContext)
. That method will fire
the transition
event and call the
Node.enter(ExecutionContext)
on the destination node of the
transition. That method will fire the node-enter
event and
call the Node.execute(ExecutionContext)
. Each type of node
has its own behaviour that is implementated in the execute method. Each node
is responsible for propagating graph execution by calling the
Node.leave(ExecutionContext,Transition)
again. In summary:
Note that the complete calculation of the next state, including the invocation of the actions is done in the thread of the client. A common misconception is that all calculations *must* be done in the thread of the client. As with any asynchronous invocation, you can use asynchronous messaging (JMS) for that. When the message is sent in the same transaction as the process instance update, all synchronization issues are taken care of. Some workflow systems use asynchronous messaging between all nodes in the graph. But in high throughput environments, this algorithm gives much more control and flexibility for tweaking performance of a business process.