This page describes the schema of the processdefinition.xml file.
A process archive is a formal description of a business process. It is packaged
as a jar-formatted file, usually with an extension .par jBpm recognizes
that describing a process requires three types of data :
processdefinition.xml file. The bulk of this page explains
the schema of this file./classes subfolder.
<!DOCTYPE process-definition PUBLIC "-//jBpm/jBpm Mapping DTD 2.0 beta3//EN" "http://jbpm.org/dtd/processdefinition-2.0-beta3.dtd"> |
<!ELEMENT process-definition ( description?,
swimlane*,
type*,
start-state,
( state |
milestone |
process-state |
decision |
fork |
join
)*,
end-state,
action* ) >
<!ATTLIST process-definition name CDATA #REQUIRED >
|
<!ELEMENT state ( description?, assignment?, action*, transition+ ) > <!ATTLIST state name CDATA #REQUIRED > |
In jBpm the term state has the same meaning as in finite state machines (FSM) or UML state diagrams.
The purpose of modelling a business process in jBpm is to create a software system. We consider the process definition as a part of the software system being build. So the term state in jBpm is to be interpreted from the viewpoint of the software system of which jBpm is a part.
State is the central concept of jBpm. When starting to model a process in jBpm, the first thing to do is think about the states of the process. The states will serve as the basic framework of your process.
There is a very specific reason why jBpm is centered around the state concept. That is because state does not have a counterpart in programming languages. A software program is either running or it is not. A business process typically has related pieces of programming logic that are executed separately. jBpm allows to model these states between the related pieces of programming logic.
jPdl also defines control flow between the states with transitions, decisions, forks, joins and milestones. Note that the control flow defined between states. Wherever plain programming logic is more appropriate, process developers can specify an action on a process event. The phylisofy of jPdl is to extend java with state management and have the least overlap with programming language capabilities. This differentiates jPdl from other business process languages such as e.g. BPEL. Other process languages do not make that clear separation.
<ELEMENT assignment EMPTY >
<!ATTLIST assignment swimlane CDATA #IMPLIED
assignment (optional|required) #IMPLIED
authentication (optional|required|verify) #IMPLIED >
|
When a process execution arrives in a state, the workflow engine will wait until it is given an external trigger (with the jBpm API method ExecutionService.endOfState(...)). Inside that method, jBpm will calculate the next state of the process instance.
So a state can be seen as a dependancy upon an external actor. The external actor can be a human, a group or a system. There are numerous ways how states in a business process can relate to tasks which basically can be divided into two groups :
java.lang.String. To specify how jBpm must assign tokens
to actors, several events are relevant. Let's go over them one by one :
Whenever a client starts a new process instance or signals the end of a state, jBpm starts calculating the next state for a process instance.
The first thing we want to mention about assignments is that the first parameter of these API method calls is the actor. That parameter is used to specify on who's behalf the method is executed.
In case of starting a new process instance, a root-token is created in the start-state. In case of an endOfState, a tokenId needs to be specified as a parameter which is in some state. Then, jBpm will start calculating the new state for the token. For simplicity we will ignore concurrency for a moment. The token will travel over transitions and nodes until it arrives in a state node. At that moment, the token needs to be assigned to an actor. After the selection of the actor, jBpm will associate the selected actor with the token and the invoked method (startProcessInstance or endOfState) will return.
So when a token in a state has a reference to an actor, that means that execution of that process instance is waiting for that actor to provide an external trigger to the jBpm engine. In this case, a state in the process corresponds to a task for a user. jBpm calculates the tasklist by searching for all tokens that are assigned to the given actor. Now, the actor can select a token from the list and signal the end of state again.
Assignment has to more attributes that are not yet covered : assignment and authentication.
The attribute assignment can have 2 values : optional and required.
required means that after execution has arrived in a state, jBpm will check if the
token is actually assigned to an actor. An AssignmentException is thrown if this is violated.
If assignment is optional (=default), jBpm is allowed to leave a token unassigned when it
arrives in a state. The attribute authentication specifies constraints for which
actor is allowed to signal the end of a state. The actor is specified with the actorId parameter
in the method endOfState.
optional (=default) means that its not required
to specify on who's behalf the end of state is signalled. required means that
an actor needs to be specified and verify means that the end of state may only be
signalled by the actor that is assigned to the token.
For more about coping with group assignments, see the faqs.
<!ELEMENT swimlane ( description?, delegation? ) > <!ATTLIST swimlane name CDATA #REQUIRED > |
Typically, one person is responsible for multiple states in one process. In jBpm this is expressed by creating a swimlane and assigning all states for that actor to the swimlane. A swimlane in a business process can be seen as a role-name for an actor within the process. The jBpm interpretation of swimlane corresponds to the term swimlane used in UML 1.5. The first time when execution arrives in a state for a given swimlane, the actor is calculated.
public interface AssignmentHandler {
String selectActor( AssignmentContext assignerContext );
}
|
The delegation tag within a swimlane references an implementation of AssignmentHandler.
Then that actor is stored in a process variable with the same name as the swimlane. Next time when the process arrives in a state for the given swimlane, the jBpm engine will notice the variable and assign the token to the actor which was stored in the variable.
So swimlanes are defined on a process level and states reference swimlanes in the assignment.
The result of this calculation will be stored in a process variable with the same name as the swimlane. So then when the next state is reached of the same swimlane, that state is assigned to the same actor without using the AssignmentHandler again. Because the relation between a swimlane and the actor is stored in a variable, it is possible to manipulate that relation by updating the variable.
<!ELEMENT type ( description?, (delegation|transient), variable* ) > <!ATTLIST type java-type CDATA #IMPLIED > <!ELEMENT transient EMPTY > <!ELEMENT variable EMPTY > <!ATTLIST variable name CDATA #REQUIRED > |
A variable is a key-value pair associated with a process instance (=one process execution).
The key is a java.lang.String and the value is any
POJO's of any java type. So even
java-types, not know to jBpm can be used in process variables.
Variables store the context information of a process instance. Variables can be set in 3 ways :
When working with variables we have tried to mimic as much as possible the semantics of a java.util.Map thoughout the jBpm-API, . This means that a variable is only instantiated when it is inserted (read: set) and that any java-type can be used as value.
A type specifies how jBpm should store the value of a variable in the database. jBpm has a text field for storing values so the conversion between text and object is done with a Serializer :
public interface Serializer {
String serialize( Object object );
Object deserialize( String text );
}
|
A type can be seen as a reference to a Serializer. jBpm includes default Serializer implementations for following java-types :
java.lang.String java.lang.Long java.lang.Double |
Variables with a java-type that is supported by default do not have to be declared in the
processdefinition.xml. jBpm has a semi automatic typing mechanism : When a variable is
instantiated jBpm tries to calculate the type of the variable by examining the java-type
of the variable value. If the variable-value is a default supported java-type, that type
is used. Else, jBpm checks if the java-type of the variable-value corresponds with a type
declared in the processdefinition.xml (attribute java-type). Note that in this
matching jBpm also takes into consiceration the super-types of the variable-value. If no
such type is found, jBpm treats the variable as transient.
To avoid that jBpm has to execute the matching process, you can specify the variables in
each type.
<!ELEMENT start-state ( description?, transition+ ) >
<!ATTLIST start-state name CDATA #REQUIRED
swimlane CDATA #IMPLIED >
|
The start-state is the unique state in a process from which all process instances start. Note that at process-instance-start-time you can already feed variables in the process. Another important concept is that you can have multiple transitions leaving the start-state. In that case, you need to specify which transition should be taken when you start a process instance.
<!ELEMENT milestone ( description?, action*, transition ) > <!ATTLIST milestone name CDATA #REQUIRED> |
A milestone is a special kind of state that can be used for synchronizing between
two concurrent paths of execution. A milestone can be used in a situation where
one path of execution needs to wait upon an event in another path of execution.
If the milestone was not reached, execution has to wait in the milestone state until
the other concurrent path of execution has reached the milestone. If the milestone
was already reached, the execution just passes through the milestone state.
For more information on milestones and a graphical animation, see
the workflow patterns.
A milestone state is related with one or more actions that signal the reaching of a
milestone. Those actions can be modelled in the process with the default ActionHandler :
org.jbpm.delegation.action.MilestoneReachedActionHandler. So the action
that signals to the jbpm engine that a milestone has been reached could be scheduled
like this in a processdefinition.xml :
...
<milestone name="theMilestone">
<transition to="stateAfterMilestone" />
</milestone>
...
<state name="stateBeforeReachingMilestone" swimlane="initiator">
<transition to="stateAfterReachingMilestone">
<action>
<delegation class="org.jbpm.delegation.action.MilestoneReachedActionHandler">theMilestone</delegation>
</action>
</transition>
</state>
...
|
<!ELEMENT process-state ( description?, delegation, action*, transition+ ) > <!ATTLIST process-state name CDATA #REQUIRED> |
A process state corresponds to the invocation of a super-process. The parent process starts a sub-process when execution arrives in the process-state. The process remains in the process-state for the duration of the sub-process. When the sub-process finishes, the process-state is left.
<!ELEMENT decision ( description?, delegation, action*, transition+ ) > <!ATTLIST decision name CDATA #REQUIRED> |
A decision decides between multiple paths of execution which are exclusive. If you're a programmer, just think of it as an if-then-else construct. Of course, a decision can have as many leaving transitions as desired.
Note that a decision models a situation where the workflow engine decides which route to take based upon the context (= variables) and perhaps some external resources. As an alternative, you can model multiple transitions leaving a state. In that case, the jBpm client must decide which of the leaving transitions to take by including the selected transition name as a parameter in the endOfState method invocation.
<!ELEMENT fork ( description?, delegation?, action*, transition+ ) > <!ATTLIST fork name CDATA #REQUIRED corresponding-join CDATA #IMPLIED> |
A fork spawns multiple concurrent paths of execution. It is possible to specify custom fork behaviour with the ForkHandler interface. But the default behaviour (when no delegation is specified in the fork) is that one child-token is spawned for every leaving transition of the fork. So only for advanced exotic concurrency you'll need to implement a custom ForkHandler.
Normally, a fork has a related join which defines a concurrency block. With the default fork and join behaviour supports only strict nesting. The default fork and join do not support transitions that cross concurrency block boundaries.
public interface ForkHandler {
void fork( ForkContext forkContext ) throws ExecutionException;
}
|
<!ELEMENT join ( description?, delegation?, action*, transition ) >
<!ATTLIST join name CDATA #REQUIRED
corresponding-fork CDATA #IMPLIED>
|
A fork joins multiple concurrent paths of execution. It is possible to specify custom join behaviour with the JoinHandler interface. But the default behaviour (when no delegation is specified in the join) is that all tokens that have been spawned together in the corresponding fork. The last token to arrive in the join will trigger the parent token to proceed over the leaving transition of the join. So only for advanced exotic concurrency you'll need to implement a custom JoinHandler.
Constraint : a join can only have one leaving transition.
public interface JoinHandler {
void join( JoinContext joinContext ) throws ExecutionException;
}
|
<!ELEMENT end-state EMPTY > <!ATTLIST end-state name CDATA #REQUIRED> |
A process-definition has exactly one end-state. When the execution of a process instance arrives in the end-state, the process instance is finished.
<!ELEMENT transition ( action* )>
<!ATTLIST transition name CDATA #IMPLIED
to CDATA #REQUIRED>
|
Transitions specify directed connections between nodes. The transition element should be put inside the node from which the transition leaves.
<!ELEMENT action ( delegation ) >
<!ATTLIST action event-type (process-start|process-end|
state-enter|state-leave|state-after-assignment|
milestone-enter|milestone-leave|
decision-enter|decision-leave|
fork-enter|fork-every-leave|
join-every-enter|join-leave|
transition) #IMPLIED>
|
An action is a piece of java code that can be executed by the workflow engine upon an event during process execution.
The action is always defined as the child of an process-definition-element like
process-definition, state, transition, decision, ... . The parent element plus the
event-type define the exact moment during process execution when the action is executed. As you
can imagine, the possible event-type's of an action depend on the element by which the action is
contained. The event-type-names already suggest on which element they are applicable. You find
the complete story in the javadocs of
EventType.
public interface ActionHandler {
void execute( ExecutionContext executionContext );
}
|
<!ELEMENT delegation ( #PCDATA ) > <!ATTLIST delegation class CDATA #REQUIRED> |
When a process archive is deployed, the processdefinition.xml is parsed and that information
is stored in the jbpm database. All other files you add into the process archive are
stored in the db or in the file-system and associated with the process definition that is created.
As a client of the jbpm API you can access those files with ExecutionReadService.getFile( Long processDefinitionId,
String fileName )
The difference between a process archive and a process definition has to do with the
versioning mechanism