The Process Virtual Machine

by Tom Baeyens and Miguel Valdes Faura
May 8th, 2007.

Introduction

There are many process languages for Business Process Management (BPM), workflow
and orchestration. For simplicity we'll refer to that collection as workflow for short.
There are two aspects to workflow; the process modelling aspect and the software implementation
aspect. The biggest problem in workflow technologies today is that they don't
handle the dual nature of those technologies properly. The main goal of this paper is to
fix exactly that problem.

The Process Virtual Machine does not define a process language. Instead it
acknowledges some process language might be better suited for a certain situation then
another and hence, there will be multiple process languages coexisting. The Process
Virtual Machine will define a common model that can be shared between all the
graph based execution languages. It also includes a strategy on how process constructs
can be seen as software components. This will enable support for multiple process languages
and also it will show much clearer how process technology fits right into software
development projects.

Component technology

The reason for the fragmentation in process languages is that there are many environments
and features that can be handled by workflow. Up to now, the main focus was to build 'the
best' process language. There is no sign yet that process languages are converging to each
other in some way or another. So the new thing about Process Virtual Machine is the
idea that different environments are best served with dedicated process languages.

While every developer knows the relational model that underpins relational databases,
such a conceptual model is absent for workflow. The Process Virtual Machine will fix this
missing piece by defining a component model for process constructs. That way, complete
process languages can be built on top of the Process Virtual Machine as a set of process
construct implementations. Developers that know the Process Virtual Machine will much
better understand the current process engines that are currently available. Furthermore,
we expect that the Process Virtual Machine will be the basis for all next generation
workflow engines.

More and more, software development will be done in a mix of many languages. Aspects like a
domain model or gluecode that binds frameworks to the domain language are best expressed in a
general purpose programming language like Java. But a shift is taking place away from general
purpose programming languages and leverage more frameworks for specific aspects of software
development. Typically, the frameworks come with a library and Domain Specific Language
(DSL). Those frameworks and languages address certain parts of software development in a
more natural and easier way. Examples are process engines with process languages, rules engines
with rules languages, object relational mapping frameworks with the mapping metadata, parsers
based on grammars, inversion of control (IoC) containers with an object wiring language and
web frameworks with their configuration files that specify navigation.

Many of the Domain Specific Languages (DSL) that we see today are graph based execution
languages. For all of those, the Process Virtual Machine is the common foundation that can be
see as the masterpiece to federate DSL graph based languages by reducing maintenance, design
and implementation cost.

So process languages will be pluggable on top of the Process Virtual Machine.

Embeddable workflow

Just a few workflow automation projects can be realized only by using process languages.
The BPM Suites that preach the "no code" approach only target that kind of projects where
everything must be modelled as a process. We think that workflow, BPM and orchestration
can ease the implementation of some aspects of a software development project. And a software
development project usually combines many aspects, only some of which could be modelled as
processes.

In this view, workflow technology is much more broadly applicable then it is used today.
Because today's process engines are not embeddable enough and because of the current fragmentation
and confusion, developers still write homegrown workflow engines for their own project.

The concept of embeddable workflow means that a process engines can be easily integrated
into todays software development projects. This is in contrast with the traditional
monolithic BPM server approach.

In software development in general, there is a clear trend towards the use of more
Domain Specific Languages (DSL). Embeddable workflow really fits with that trend:
Process languages just become another language that developers can use in their
projects. Workflow is complementary to old fashion plain programming. The developer
should be free to select the language best suited for the job.

The following aspects are crucial to make the workflow engine embeddable:

Persistence: The workflow engine itself should be decoupled from
the actual persistence technology. First of all, persistence itself should
be optional and in case it is required, different persistence
technologies like e.g. JPA, Java serialization or XML should be pluggable.
In case a relational database is used for persistence,
the developer should have a choice to deploy the workflow engine's database tables
separate or alongside the application's database tables or in a separate database.
The latter can make the whole application much more manageable.

Services: The services that an engine might use such as a timer service or
an asynchronous message service should be pluggable so that different
implementations can be used in different environments like e.g. stardard
Java and enterprise Java.

Transactions: If the workflow engine's can work with the same database
connection as the application, there is no need for global or distrubuted
transactions. That definitely reduces complexity. Same reasoning applies
to sessions of the object relational mapper like e.g. Hibernate.

Libraries: Apart from the traditional monolithic deployment of a workflow
engine, it often can be much more practical to deploy just the engine's
libraries in the client application.

Testability: Executable processes are software so they should be tested
the same way. Tests should take process executions through different test
scenarios. This should of course be integrated with the rest of the
client application infrastructure.

Binding: It should be easy to bind the process logic to the rest of the
software development project. As we'll see in section Process
modelling, an executable process is always a combination of the graphical
diagram and technical details. Up to now, the focus of tooling is on editing the graphical
diagram. But software development projects usually contain many languages like e.g. Java,
process language and scripting languages. So we expect that tools will start to focus
more that coherence between different artifacts in one software project. For example,
a refactoring for renaming a Java class might span updates to Java classes and process
definition files.

Scope

We already explained above that the Process Virtual Machine is a common foundation for graph
based execution languages. The languages for which the Process Virtual Machine can be
leveraged have three main characteristics:

Processes are represented graphically to facilitate communication between all
stakeholders

The process expresses some kind of execution flow

Processes can potentially include wait states from the perspective of the process
engine and be 'long running'

Any aspect in software development that meets these criteria can be built on top of the Process
Virtual Machine. It's not limited to workflow or BPM as we know it today. An example of such a
non trivial aspect might be pageflow; a language to describe navigation between pages in a web application.

Basics

Here follow the basic principles of the Process Virtual Machine. After the basics, we'll cover a
series of extensions that are needed to cover all features needed for real process languages.

A process is a graphical description of an execution flow. For example the procedure on processing expense
notes is a process. It can be deployed in a process engine. One process can have many executions. E.g. my
expense note of last Monday could have been handled by one execution of the expense note process. Another
example of a process is shown in Figure 1.

Figure 1: An example process for an insurance claim

The basic structure of a process is made up of nodes and transitions. Transitions have a sense of direction and
hence a process forms a directed graph. Nodes can also have a set of nested nodes. Figure 2 shows
how transitions and nodes can be modelled in a UML class diagram.

Figure 2: UML class diagram of nodes, transitions and the behaviour

Each node in the process has a piece of Java code associated as its behaviour. The interface to associate Java
code with a node is shown in Figure 3.

Figure 3: The Executable interface for specifying the behaviour of nodes

Now, let's look at the runtime data structure. An execution is a pointer that keeps track of
the current position in the process graph as indicated in Figure 4.

Figure 4: An execution points to the current position in the process graph

When a new execution is started for a given process, the initial node will be
positioned in the initial node of the process. After that, the execution is
waiting for an external trigger. The method and class structure of Exection's
is indicated in Figure 5.

Figure 5: UML class diagram of an Execution

An external trigger can be given with the proceed(String transitionName)
method on the execution. Such an external trigger is very similar to the signal operation
in finite state machines. The execution knows how to interpret the process graph.
By calling the proceed method, the execution will take the specified (or the default)
transition and arrives in the destination node of the transition. Then, the execution
will update its node pointer and invoke the node's behaviour.

The node's behaviour has got access to the current state of the process through the
execution that is passed in as a parameter. In the extensions that are described in
detail in the full paper show how for example variables or external services will be
available through the execution.

On the other hand, the node's behaviour has got control over the propagation of
execution. This means that the executable implementation can just behave as a wait
state, continue execution, create concurrent executions or update any information
in the execution.

Let's look at two example node behaviour implementations:

A task node

The reason why task management and workflow are so closely related is
because tasks for humans often translate to wait states for a software
system. Processes can easily combine software operations with
human tasks in the following way.

The first thing that is needed outside of the process execution engine
is a task repository, a place where tasks for people are kept. On top of
this component, there is a user interface that allows for people to see their
task list and complete them.

Then you can imagine the following behaviour implementation of a task
node. First, some external trigger has to be given (with the proceed method) so
that the process starts executing and arrives in the task node. The node behaviour
implementation will create a new task
for a given person in the task list component. That task also includes a
reference back to the execution. Then, the node behaviour returns without
propagating the execution. This means that the execution will be positioned
in the task node when the proceed invocation returns.

The taskName member field shows how configuration information that is
specified in the process definition file, should be injected into the
behaviour object.

So the execution can
then be persisted during while the system is waiting for the user to complete
the task. After some time, when the user completes the task, the task
management component will use the reference to the execution to provide a
trigger. This is done with the proceed method.
Then the execution resumes, leaves the task node and continues.

An email node

An email node is different from a task node in the sense that it is
automatic. An email has to be send and then the execution should immediately
be propagated over the default leaving transitions. That propagation of execution
is done with the invocation of the proceed method at the end of EmailNode's
behaviour implementation in Figure 7.

Similarly as with the task node, the member fields recipient, subject
and text are specified in the process definition file. The engine will inject the
values into the member fields. Those values might be the result of runtime evaluation of
expressions and also mappings might be applied.

Now, let's discuss the main features of the basic model that we have presented
so far.

Graphical representation

The basic Process Virtual Machine concepts show how graphical diagrams can be made
executable. Processes are made up of nodes and transitions, hence they have a direct relation
with the graphical representation. On the other hand, the behaviour member field
in the Node class defines the programming logic that is executed at runtime.

The graphical structure of the concepts defined in Process Virtual Machine cover most constructs
of process languages. Even advanced conctructs like e.g. UML super states can be mapped directly
to the nestedNodes relation as defined in Figure 2. Still, process languages can extend the basic
structure with new concepts such as e.g. timers, data flow or conditions.

Wait states

We also saw in the task node example that nodes can represent wait states. When an execution
arrives in a node and the execution.proceed() method is not invoked, the originaly proceed, invoked
by external client will return. That means that the execution is now in a wait state and
typically it is then waiting for an external trigger. Typically, that is the right time to
persist an execution.

With wait states, processes can now express execution flows that spans software operations
(typically in a transaction) and wait states when the engine must wait for an external trigger.
This is also known as long running processes.

Synchronous execution

When an client invokes the proceed method, the exection will start to interpret and execute
the process in that thread. An execution typically starts by taking a transition and then executing
the destination node. When the execution invokes the behaviour of the destination node, it passes
itself as the parameter. The node behaviour can then in turn propagate the execution onward
by calling the proceed method on the execution again. Note that this is still done in the
thread of the client, which is still waiting for the original proceed invocation to return.

In other words, the execution is always interpreted in the thread of the client. When the
the execution is not propagated any more, the nested proceed invocations start returning since
the proceed should be the last operation in the behaviour's execute method. The proceed
invocation will be blocking for the caller until a wait state is reached.

The default behaviour is to have synchronous executions because it limits the number of transactions
and hence improves performance. But in case there are many automatic things to be done before the
process execution reaches another wait state, Asynchronous
continuations have to be considered.

Interpretation

The bulk of the interpretation of the process is delegated to the behaviour implementations.
The only responsibility of the execution is to follow the transition to it's destination node
and update the node pointer accordingly. That way, the execution's node pointer will always
indicate the current state.

This is important because it means that the bulk of the behaviour of the engine is
pluggable. The essence of interpreting a graph is baked in the component model. But all the
rest is left up to the process construct implementations. That is why it is possible to
build such diverse process languages on top of the same framework.

Another way of describing the responsibilities of the node implementations is the following:
First, they can use any Java API to perform any kind of business logic like sending emails,
creating tasks, calling web services and so on. To do this, the implementations have access to
the contextual information about the process like process variables,
services from the environment and configuration information that gets
injected into the member variables. After the business logic, node implementations can propagate
the control flow of the process execution. The basic scenarios are wait states and propagation of
the incoming execution over one a leaving transition. But in more exotic scenarios, the node
implementation can reorganise the complete runtime execution datastructure as well.

Extensions

The previous sections explained the basic operations of the Process Virtual Machine.
In the next sections we'll describe a set of extensions to this basic model to show how advanced
features can be build on top.

Variables

Process variables can contain contextual information associated with a single execution.
For example, in a payraise process, the desired amount and the reason could be process
variables.

Process variables can be added to the basic Process Virtual Machine by
associating a set of key value pairs within an execution.

Processes or nodes can have variable declarations. Some process languages mandate variable
declarations and others don't. So that is why the key value pairs should be dynamic, just
like a HashMap in Java. The variable declarations could be used at runtime to initialize,
destroy or to check for avaiability of a certain variable.

Process variables should be Plain Old Java Objects (POJO) because the component programming
model is in Java. Process languages like BPEL only store xsd types or XML snippets. In that
case, the process language itself is responsible of translating those datatypes into the desired
POJO type.

Persistence is optional, so in general, it should be possible to store any POJO object in the
process variables. Only when an execution is stored, transformations should be applied to map
the POJO's to their persistable format.

The section about Concurrent paths of execution will
introduce a tree of executions. That tree also defines a natural scoping structure for process
variables.

Actions

An action is the crucial concept that will enable modelling freedom for the analyst, while the
developer has to make the process executable.

An action is a piece of programming logic that is inserted invisibly in the process graph. For
example, perform a certain database update when leaving this node. Or, delete a certain file when
this transition is taken. Actions can also be described as listeners to process events.

An event is a point in the process where actions can be specified. The three most common
events are entering a node, leaving a node and taking a transition. As an implementation detail,
we mention that the Execution class can be enhanced with a fire method
in the API. That way, clients, actions and node behaviour implementations can all fire events.
Despite the goal of being hidden from the graphical diagram, in Figure 8, we indicate how the
actions are related to the diagram just to serve this explanation.

Figure 8: Most common events

But it is good to use the
combination of a process element and a plain event type string to identify an event. That way,
much more event types can be defined and even users could define their own event type.

Events can also be propagated. The process can have a hierarchical structure with nested nodes.
If a process language implements a construct like e.g. UML super states, events on a nested node
can be propagated to the enclosing superstate. That propagation can continue recursively until the
level of the process defintion itself. So super states or processes might listen to all events of
a certain type that are fired inside. For example, invoke this action for every transition that
is taken within this superstate.

Concurrent paths of execution

One path of execution can point to one single location in the process
graph. In some situations, there parts in the process that can progress
independently. For instance, the shipping and billing part of a process.
In those scenarios, multiple paths of execution are needed to keep track of the
state for one complete process execution. To support this, the executions can be
structured in a parent-child relation. A new execution for a given process
acts as the main path of execution. To create concurrent paths of execution,
child executions can be created. Typically, the parent execution will
remain inactive in the fork (aka and-split) while the child executions
are executing.

Several fork and join behaviours can be implemented in as node behaviours.
The fork typically launches a new execution over each of its leaving transitions.
Optionally, guard conditions might be added to prevent some of the concurrent executions
from being created.

Note that process concurrency mostly doesn't require multithreaded calculations.
Assume for a second that no actions are involved and that all nodes right after the
fork (aka and split) behave as wait states, like illustrated in figure 9. In that case,
one database transaction should contain the operations to inactivate the parent execution
and to add the two new child executions each referencing their respective wait state.

Figure 9: Concurrent paths of execution

Calculating the updates for that single transaction doesn't need to be done in two
separate threads. In fact, those threads would have to be synchronized anyway because they
operate on the same database transaction.

The main difference is in the join behaviour. We'll describe two examples of join
implementations just to illustrate that any type of join behaviour can be implemented.
The Process Virtual Machine itself doesn't include a fixed mechanism for process
concurrency. Instead, the different forms of concurrency can just be implemented just like
any other process construct.

As long as all paths leaving a fork arrive at the same join and no other paths can
arrive at that join, a simple join implementation can be build that takes advantage of the
hierarchical structure of the executions: When an execution arrives in a join, it first marks
the incoming execution as deactivated and then checks if there are any active siblings left.
If there are no active siblings left, the parent execution is reactivated, positioned in the
fork and that execution is propagated over the default leaving transition.

Another approach is to count the number of executions that have arrived in a join. If that
number just got the same as the number of arriving transitions, a new execution will be
created, positioned in the join and propagated over the default transition. In this case the
complete execution tree needs to be pruned for inactive executions after a join has been
triggered.

This type of join implementation can handle unstructured combinations of forks and
joins. I leave it up to the imagination of the reader to find the differences with the
previously explained join behaviour. The most important point is that different types of
fork and join behaviours can be implemented on top of the Process Virtual Machine.

Process composition

Process composition means that a node in one process can reference another process.
When an execution arrives in such a process node, that execution will wait in that node
until a complete execution of the referenced process is completed.

Figure 10: Process composition

This can be added to the process virtual machine by leveraging the hierarchical relation
of the execution tree that was created for concurrent paths of execution. When an
execution arrives in a process node, a child execution can be created for the referenced
process like illustrated in Figure 10.

A check needs to be added when executions complete. In this case, executions
that are completed need to check wether there is a parent execution available. If that is
the case, that execution need to be propagated. The parent execution, one that
originally arrived in the process node, will then leave that process node and continue
over the default transition.

Asynchronous continuations

Up to now, all propagation of the execution was done synchronously. In some situations that
might be problematic. For example
suppose a process where a large pdf file has to be generated automatically after a user has
completed a task. And most likely, the invocation of execution.proceed() will be
done in the request-response cycle of the web application for the user. In that case,
the web response is unnecessarily delayed with the generation of the pdf because that is
done inside of the proceed method invocation. In general, this means that
the client that is calling the Execution.proceed will be blocked until the process
has reached a new wait state.

The Process Virtual Machine can be extended to handle these situations by using an asynchronous
message queue. To see how that works, we first must define what the atomic operations are. Atomic
operations cannot be interrupted. Here, we'll define two atomic operations: Executing a node and
taking a transition. So execution of a node and of a transition cannot be interrupted. But
inbetween those atomic operations, a thread can decide to stop the interpretation and instruct
another thread to continue the interpretation asynchronously from that point forward.

In the node and transition elements, an extra configuration flag can be added. Let's call it the
asynchronous flag. When a node has the asynchronous flag set, it will be executed asynchronously at
runtime. Similar for transitions.

Remember that the execution is responsible for interpreting the graph, finding the destination
node of a transition and executing the behaviour of that node. Now, when an execution arrives in
an asynchronous node, the node will not be executed. But instead, a message is being sent
over an asynchronous messaging system. The message contains a reference to the execution and the
instruction to execute that node. After that, the Execution.proceed returns and the
transaction, that contains both the process updates and the production of the asynchronous message,
can be committed.

At the other end of the queue, there is a component called the job executor. That component
will start a new transaction, fetch a message from the queue and perform the instructions in the
message. In our scenario, this means that the node will be executed. When that is done, the
transaction will be committed. That transaction included consumption of the message and the new
process updates.

Figure 11: Asynchronous continuations

This can also be seen as a kind of transaction demarcation. Because by default the interpretation
of the graph will continue until a wait state is reached. But with asynchronous continuations, it's
possible to mark a position in the process where the current transaction should be committed and
a new transaction should be started automatically.

The tradeoff for asynchronous continuations is exception handling versus response times.
We already saw in the beginning of this section that response time can be significantly reduced
by introducing asynchronous continuations. But on the other hand, the downside can be that
the original caller is not aware of any problems that might arise further in the process.
For example, a task node is followed by an email notification node and suppose that it is
crucial that this notification is sent. When the email notification
node is marked as asynchronous, the task completion will be faster, but that user might not
get a notification when the mail server is down.

In case an exception occurs in the job executor, an automatic retry mechanism could be used.
Most message queueing systems have a configurable number of retries before the message is sent
to the dead letter queue. Administrators could monitor that dead letter queue or a timer
could be added to notify the stakeholders of the process execution in case of asynchronous
failure.

Process updates

A set of process updates describe modifications to a particular process. For example
additions and removals of nodes, transitions or actions.

With process updates, the Process Virtual Machine can be extended for two new use cases:
Process inheritence and per instance process customizations.

Suppose a situation where for each country there is a process on how banks must do efforts
to detect suspecious stock transactions. And suppose that most that the basic layout of all
those processes would be the same. There are only some minor details, that are different.
In that case, it might be an option to describe a single default process and then define
a kind of process inheritence. A specialized process might be defined as a reference to another
process plus a set of updates. Of course, the execution's interpretation algorithm have to
be modified to take these process modifications into account.

The second use case is updates per execution. Suppose that a user wants to monitor all
progress for a specific execution. In that case, he could add an action on a process definition
for the transition event. That means that the notification action will be executed for each
transition that is taken in the whole process.

Another example of updates per execution is removing transitions for a given execution.
Suppose that in the process, there is a distinct handling for urgent packets from the
handling of normal packets. Now imagine that early in the process, a user can recognizes
a client that always tries to get the fast delivery while he's not entitled to it. Then
this might be implemented with process updates by letting the user remove the transition
for urgent handling.

Figure 12: Process update for a single execution

History

While a process is being executed, history logs can be generated. Those history
logs can contain information about when transitions were taken, when nodes are entered
and when nodes are completed. Also the process variable updates and tasks can
produce logs. Basically, the whole execution of a process can be logged.

One way to add configurability and flexibility is to define a loging service.
The execution and the nodes can then generate log objects in the form of
Java objects and pass them to the logging service. That way, log
filtering and transformations can be applied centrally. Also different forms
of storage can be configured in the logging service.

If the logs keep complete track of all the updates that are done in a process,
the logs can be used to generate compensating transactions. A compensating
transaction means that a new transaction will undo the effects of previous
transactions. A technique to do this could be to walk through the logs in
reverse order and restore the begin state as indicated in the log entries.

Persistence

Up to now, the Process Virtual Machine was explained in terms of objects, without
any reference to persistence. This is possible because of Object Relational Mapping
(ORM) technologies such as Hibernate. ORM can
translate between objects and database records. On the Java platform the database is
accessed using JDBC. Object relational mappers can also make abstraction of the
differences in the SQL dialects of databases.

The algorithms we have defined for process interpretation never use the database
directly. Persistence of processes and executions can therefor be offered as a separate
service. That way, process languages that don't need persistence, like e.g. pageflow
are not required to use a database.

The data in a workflow database can be split into three main compartiments
like illustrated in Figure 13: Static process definition information, runtime
execution information and history logs.

Figure 13: The three parts of a workflow database

The object relational mapper
will take a complete process object graph and translate that into records in the database.
That way, the complete process structure can stored in the database. For example, the node
objects in the process object graph will be inserted as records in the nodes table.
Since process definition information normally doesn't change, it can be cached in memory.
In jBPM's case that is done using the second level cache of Hibernate.

The runtime process execution information is typically updated in every transaction
that includes a workflow operation because the execution's node pointer will have moved to
a next node. In Figure 14, you can see the scenario of the workflow persistence operations
in one transaction.

In this scenario, the starting situation is that an execution was already
persisted in the database and now an external client wants to provide an external trigger to resume the
process execution. So the execution record in the database has a foreign key column that
references the node in the nodes table. To get started, the client needs the id of the
execution.

In the first step, the client start a transaction and loads the execution object using the
object relational mapper using the id.

Figure 14: The persistence scenario of a runtime workflow transaction

In the second step, the client will invoke some methods on the execution object. Typically this
will be the proceed-method. In general, methods will be invoked on the runtime
datastructure. After those method invocations, the execution is pointing to a new node. This
second step was executed without any consideration of persistence.

In the third step, the changes made to the execution object will be saved in the database.
It's the task of the object relational mapper at this stage to analyse the execution java
object structure and compare it with the data that was originally loaded from the database.
The object relational mapper will then issue the nessecary insert, update and delete SQL
statements to bring the database in sync with the execution object graph.

In the case where an execution just moves to the another node, the result will be a
single update statement where only the foreign key column of the execution will have to be
changed to the id of the node to which the execution is pointing after the method invocation.

Then, the transaction can be committed.

Another aspect of object relational mapping solutions that deserves attention in this context
is optimistic locking. ORM solutions like Hibernate have a built-in mechanism for optimistic
concurrency control. A version column is added to the database and each time an object is
updated, the version number will be increased as well. But with each update, in the where clause
an extra condition is added that specifies the version of the object that was originally loaded.
If execution of that SQL statement returns that zero rows were updated, that transaction knows
it was working with stale data and the transaction should be rolled back. For more about this, see
the hibernate reference manual.

But the result of all this optimistic locking is that process engines based on the Process Virtual
Machine can scale by synchronizing on the database, using this light weight concurreny control mechanism.
As long a they all are working on the same database and use this optimistic concurrency, all
process updates comming from multiple systems will be synchronized.

Timers

To add timers to the Process Virtual Machine, a timer service is required that can schedule
timers to be executed in the future. Timers must have the ability to contain some contextual
information and reference the program logic that needs to be executed when the timer expires.

Let's look at the typical scenario where a wait state needs to be monitored with a timer. For
example, if a user task is not completed within 2 days, notify the manager.

To implement this, the timer service as described above can addressed from actions on the
node-enter and node-leave events as indicated in Figure 15. When the node enters, a timer is created
with a given duedate and it is scheduled with the timer service. Then the node will behave as a wait
state until an external trigger is given.

Figure 15: A node with a timer

Suppose now that an external trigger is given before the duedate of the timer. Then the
execution will leave the node and the cancellation action will be executed. This action will
cancel the timer that was created upon entering the node.

If on the other hand, the external trigger is not given, the execution will still be
positioned in the node when the timer fires. In that case, the programming logic of the
timer is executed. In our example that was the notification to the manager.

Services

In this section about services, we'll discuss an implementation aspect of the Process
Virtual Machine that is crucial for embeddabity of the engine inside of the client
application.

Whenever the execution or the node behaviour implementation needs some kind of service,
always consider using a self made interface. Examples of such services are the asynchronous
message service and the timer service as discussed above. That way, different implementations
can be provided in different environments. For example, in a Java enterprise environment,
the asynchronous message service will probably need to be tied to JMS. Whereas in a
standard environment this might be done using an in-memory queue.

A simple way to make all external services available to the execution and all the
node behaviour implementations is to add a context property to the execution. The context
can manage a set of named services and objects. The client knows in which environment it
is running, so it constructs the context object and injects it in the execution before
a method is invoked on it.

This mechanism can be given an extra dimension when an Inversion of Control (IoC) container
is used for the context. In that case, transactional services can be lazy created on
demand during execution of a process. The typical XML based configuration files of the
IoC containers can be leveraged to specify which implementations for the services need
to be used.

Features

In this section we explain the essential features of process languages and how they relate to the
Process Virtual Machine. Where the PVM basics and extensions explains a strategy on implementing
a common foundation for process engines, this section describes more the essential features of BPM
Systems and how the Process Virtual Machine relates to those features.

Process modelling

First we need to distinct between two categories of processes: descriptive process models and
executable processes.

The purpose of descriptive process models is to describe business processes to other people.
They support various kinds of notations like BPMN, Event-driven Process Chains (EPC) or UML acitivty
diagrams. The main goal of these languages is to define precise semantics of the notational
elements, resulting in an expressive graphical language. The modeller can use the graphical constructs
in great freedom for the purpose of communicating the process to the reader. Apart from the
expressive notation, they may also provide value in managing large sets of interrelated diagrams and
models. These processes are not executable on a runtime environment.

The second catogory aims to make process models executable on a runtime environment aka
process engine. In this case, executable process models are in fact software artifacts that
specify the behaviour of a computer system. In that respect executable processes are exactly
the same as a programs in a Object Oriented (OO) programming language like e.g. Java, even while
the format and language are completely different. So in this case, the executable process as
a whole is not so free any more. Because it has to specify a particular desired behaviour
of a software system.

The Process Virtual Machine defines a model for the implementation of process engines.
As for any process that is executable on a process engine, processes for the Process Virtual
Machine are a combination of a graphical process elements and related technical details.
So the graphical diagram of an executional process can be seen as a kind of projection that
excludes those technical details.

The big value of this combination is that the process diagram can serve as a common
language between all stakeholders of a process, regardless of their technical skills.
This is shown in Figure 16.

Figure 16: Technical details of a process

Business analyst have vary different technical skills. Some have none. Some have a little
bit of technical skills from a previous life as a developer and other people might actually
combine the roles of developer and business analyst. This translates into Figure 16 as
the dotted line that can shift up or down.

To translate that into the concepts of the Process Virtual Machine, there are three levels
of detail.

Process structure: These are the nodes and transitions. The graphical structure is
the highest level that can always serve as a communication starting point. Even
for technical illiterates.

Node type: In process engines, the node type defines an exact runtime behaviour.
In the Process Virtual Machine this is corresponds to the node behaviour implementations.
That is the second level of detail. This typically also corresponds to the process constructs
available in the pallette of the graphical editor. For example, a task node, a decision
a web service invocation node and so on.

Configurations: The finest level of detail is the configurations that customize the
process construct for a particular use of the node type. In terms of the Process Virtual Machine,
this corresponds to the member field values that are injected into the Executable behaviour
implementation objects. In graphical editors, usually a form pops up when selecting a node
in the diagram to enter those configuration details. Examples of configurations are the URL
for a web service invocation, the role or swimlane for a task assignment, the condition
for a decision and so on.

On top of these three traditional levels, the Process Virtual Machine has two features that
we want to highlight that still give a great deal of modelling freedom to the business analyst,
even for executable business processes.

First of all, if the desired behaviour of a node in a process doesn't match with any of the
available process constructs in a process language, a developer is always free do write program
logic to implement custom behaviour in the nodes. Secondly, in case the developer needs to add
a piece of programming logic to make the process executable and this is of no interest to the
business analyst, an action can be used to inject this piece program logic without a change
in the graphical representation of the diagram. This provides an extra level of separation
between the graphical representation and the technical execution details, keeping as much
modelling freedom for the business analyst.

Business Intelligence (BI)

Business intelligence is about extracting information from the history of process
executions that is useful for business people. As described above in History,
a lot of information can be captured from process executions. Each time an external trigger
is given or when a transition is taken, this can be logged in the history database.

Now the nice thing is that from those history logs, meaningful business level information
can be captured. For example, "How long does each step in the
process take on average?" or "What percentage of priority claims are handled within two weeks?"
It is not a coincidence that these meaningful questions can be easily answered by the workflow
engine's history logs because the graphical diagram was built in collaboration with business
people.

There are many ways on how that historic information can be logged and processed. While
outside of the scope of the Process Virtual Machine, we still want to highlight the typical
processing and usage of historic infomration. Often process engines log every event in a kind
of flat list style during runtime. Then, at some point (e.g. when the process execution finishes)
the flat list of logs is processed and transformed in a separate database schema that is optimized
for querying.

Workflow engines usually record these history logs by default. Many statistics typically come
out of the box and it is very easy to define new meaningfull queries on this business intelligence database.
While with old fashion plain programming, this will take a lot more time and make the overall
project more complex. So when in doubt about using a workflow process or plain programming, consider
wether this kind of information is important for your application.

Task management

Task management means that all people know exactly what they should do and when no
tasks are done twice. Therefor, the right information needs to be provided to the right
people at the right time. The benefits of proper task management are outside the scope
of this paper. The goal of this section is to give you an idea of what task management
is and how it relates to the Process Virtual Machine.

A task management component maintains a set of tasks. Task management features include
direct (push) and group (pull) assignment, task forms, reassignments, notifications, and
so on. The task list for a given user is typically made available through a web application
and an API. The combination of task notifications and the related preferences that can be
customized by users is also known as 'user awareness'.

Now, we'll zoom in to the relation between the Process Virtual Machine and a task management
component. A process contains a mix of tasks for people and automatic activities. Looking from
the perspective of the workflow engine, a user task represent a wait state. As we already
described above, support for wait states is exactly one of the most important features of the
Process Virtual Machine and workflow in general. So that is why process technologies and task
management go hand in hand.

The most common scenario is when a node in the process corresponds to a single user task.
In that case, a task node behaviour can be implemented as follows. When an Execution
arrives in a task node, it can add task entry to the task management component. Then, the
execution should wait in the task node. The new task will now appear in the assigned user's
task list. As an integration between the workflow engine and the task management component,
the task must keep a reference to the execution.

After some time, the assigned user might select that task from the task list and complete
it with the user interface or te API. When a task with a related execution is completed,
the task management component is responsible to invoke the execution's proceed.
So completing the task triggers the execution to resume its execution.

Notifications can be built on top of Process Virtual Machine events with actions. Tasks
can propagate their events like e.g. assign, duedate expired or completed to the
execution. Once that integration is in place, listeners to those events can be
specified as actions in the process definition or dynamically added to the execution at
runtime. The dynamic subscription to task events is a crucial feature for user awareness.

This concludes the basic integration between task management and process execution. The
many variations to this theme, like e.g. dynamic task creation, swimlanes and
others can be handled by the pvm but they don't really contribute to the purpose of this
article.

Cooperative applications and Human Interaction Management (HIM)

From a workflow perspective, an expense notes process is completely different from
building a new leasure palm-tree resort with those nice red coctails and waitresses in
miniscule biki... Anyway, the difference that we want to highlight is that an expense note
process is completely known and all possible scenarios can be modelled upfront. Whereas
for a leasure resort, there will be no fixed process at the start. That kind of processes
will be defined on the fly. The category of software systems that support those kind of
ad hoc processes is called cooperative applications or Human Interaction Management (HIM).

The Process Virtual Machine as described above suggests that all processes are as
predictable as submitting an expense note. That is because a distinction is made between
the process model --with Node's and Transitions-- on the one hand
and the runtime execution structure --with the Execution-- on the other hand.
Let's call this the static approach, reflecting the static process definition.

As a side note, the more frequent a process is executed, the more predictible all the
scenarios will be and the more compelling it will be to automate that process. So that
is why we took the approach with a single static definitions having many executions
as the default one.

Cooperative processes can also be implemented easily on top of the process virtual machine.
An execution is created before any process nodes and transitions are defined. Then typically
people, roles and task nodes are created on the fly while the process is executing.
So each process execution will create its own process model, whereas in the static approach
the single static process model will be used for many executions.

From an implementation perspective, storing, updating and removing parts of the process
model is done similarly as with executional data. The only issue to keep in mind is that
process definition caching needs to be turned off in such use cases.

The nice thing is that with the Process Virtual Machine its possible to build processes
that mix the static and the cooperative approach. As explained in "Process
updates", a basic fixed model can be defined and updates to that model can be
associated to the Execution.

Asynchronous architectures

Asycnrhonous architectures are another environment where workflow technology can be
very useful. In such architectures, multiple machines or components communicate through
queues or other forms of asynchronous messaging.

If you look at one component in such an architecture, it will receive many messages
(or service invocations) that are related to one overall execution flow. That overall
execution flow can be modelled and implemented as an executable process. The
period between the response sent by the component and the next related message that is
expected by the component translates to a wait state in the process.

This principle applies to various environments. For example a web services environment
like e.g. an Enterprise Service Bus (ESB). In that case BPEL is the most appropriate language.
In essence, with BPEL, new web services can be scripted as a function of other web services.
But other languages like e.g. jPDL can be very convenient to orchestrate a set of Message
Driven Beans (MDB) in a Java enterprise environment.

Process languages

This section describes the process languages for which we have proven that they can be
build on top of the Process Virtual Machine.

BPEL

BPEL is a standardized service orchestration language. If you can excuse us for the
overly simplified statement, we describe BPEL as an executable language to script web services
as a function of other web services.

BPEL is a language that fits right on top of an Enterprise Service Bus (ESB), which is
a piece of integration infrastructure. Because an ESB targets integration, services are
typically described in WSDL and based on XML technologies. That is where BPEL fits with
ESB's. BPEL is also based on WSDL and XML technologies.

XPDL

XPDL is a standardized BPM process language. The background of BPM Systems (BPMS) and
hence of XPDL is very different from BPEL. XPDL processes describe a combination of user
tasks and automated activities. All references to resources, automatic activities and applications
are adressed indirectly, meaning there is no implicit assumption of a technological environment
such as enterprise Java or an ESB.

XPDL 2.0 defines a complete mapping with BPMN. BPMN standardizes a graphical
notation that defines the shapes, icons and decorations of process models.

jPDL

jPDL is a process language of the JBoss jBPM platform. This language is in essense
the simplest wrapper around the Process Virtual Machine, to make it available in a
Java environment. jPDL processes can reference Plain Old Java Objects (POJO) directly.
The process variables and API's are based on standard Java too.

SEAM pageflow

This is a language that describes the navigation between web pages of a SEAM application
graphically. Nodes in the diagram represent pages and transitions represent the navigation
between the pages.

The nice thing about the SEAM pageflow language is that it really shows the diversity of
languages that can be built on top of the Process Virtual Machine. For instance, pageflow
doesn't need persistence nor transaction while pageflow executions need to be serialized in
the HTTP session.

Conclusion

First of all, this paper has outlined the essential principles of workflow, BPM and
orchestration. This is already very crucial knowledge for understanding today's workflow
and BPM systems. But the bigger goals of this article is to facilitate a big step forward
in resolving the current fragmentation and confusion around workflow technologies. Both
developers and workflow tool vendors will benefit significantly from a unified model for
workflow.

Secondly, a component model was introduced that shows how a base framework can be
build in a programming language that allows for multiple process languages to be developed
on top. This served as a clear illustration for developers to indicate what exactly a
workflow engine does and when this technology is appropriate. The bigger goal of this
component model is also targetted at workflow tool vendors. Both jBPM in collaboration with
Bonita and Orchestra, and Microsoft independently developed a very similar component model.
We believe that engines based on this component model will be much more broadly applicable
because of their support for multiple process languages in multiple environments, whereas
most of the current workflow systems only cover a very small niche of use cases.

As a third item, a realistic and practical approach is detailed that acknowledges and
copes with the dual nature of Business Process Management (BPM). Non technically skilled
business people are focussed on the graphical diagram. But we have shown that an executable
business process always has a graphical and a technical part. The graphical diagram
serves as the common language between the business analyst and the developer.

About the authors

Tom Baeyens

Tom Baeyens is the founder and lead developer of JBoss jBPM, the open source platform for workflow, BPM and
orchestration engines. His mission is to bring the value of BPM technology to the developer community. Tom is
frequent speaker on this subject at international conferences working for Red Hat. He's also participating in
the Java Community Process. Tom blog is called Process Developments
and can be found at http://processdevelopments.blogspot.com/.

Miguel Valdes Faura

Miguel Valdes Faura is the Workflow Project Manager working for Bull R&D. He
is also member of the OW2 Technical Council in which he is leading the Bonita
workflow project. Before that he has worked in Spain in different European
projects based on J2EE platform and Open Source application servers. He joined INRIA, the French Research Institute in Computer
Sciences, on February 2001 co-founding the Bonita Workflow System. He is a regular speaker at international conferences : JavaOne,
Internet Global Congress, Open Source World Conference, javaHispano Conference, ObjectWebCon, COSGov, JavaBin...