Chapter 7. Pageflows and business processes

JBoss jBPM is a business process management engine for any Java SE or EE
environment. jBPM lets you represent a business process or user
interaction as a graph of nodes representing wait states, decisions,
tasks, web pages, etc. The graph is defined using a simple, very readable,
XML dialect called jPDL, and may be edited and visualised graphically using
an eclipse plugin. jPDL is an extensible language, and is suitable for
a range of problems, from defining web application page flow, to traditional
workflow management, all the way up to orchestration of services in a SOA
environment.

Seam applications use jBPM for two different problems:

Defining the pageflow involved in complex user interactions. A jPDL
process definition defines the page flow for a single conversation.
A Seam conversation is considered to be a relatively short-running
interaction with a single user.

Defining the overarching business process. The business process may span
multiple conversations with multiple users. Its state is persistent in
the jBPM database, so it is considered long-running. Coordination of
the activities of multiple users is a much more complex problem than
scripting an interaction with a single user, so jBPM offers sophisticated
facilities for task management and dealing with multiple concurrent paths
of execution.

Don't get these two things confused ! They operate at very different levels
or granularity. Pageflow, conversation
and task all refer to a single
interaction with a single user. A business process spans many tasks.
Futhermore, the two applications of jBPM are totally orthogonal. You can
use them together or independently or not at all.

You don't have to know jDPL to use Seam. If you're perfectly happy defining
pageflow using JSF or Seam navigation rules, and if your application is more
data-driven that process-driven, you probably don't need jBPM. But we're
finding that thinking of user interaction in terms of a well-defined graphical
representation is helping us build more robust applications.

7.1. Pageflow in Seam

There are two ways to define pageflow in Seam:

Using JSF or Seam navigation rules - the stateless navigation
model

Using jPDL - the stateful navigation model

Very simple applications will only need the stateless navigation
model. Very complex applications will use both models in different
places. Each model has its strengths and weaknesses!

7.1.1. The two navigation models

The stateless model defines a mapping from a set of named, logical
outcomes of an event directly to the resulting page of the view.
The navigation rules are entirely oblivious to any state held by
the application other than what page was the source of the event.
This means that your action listener methods must sometimes make
decisions about the page flow, since only they have access to the
current state of the application.

The stateful model defines a set of transitions between a set of
named, logical application states. In this model, it is possible
to express the flow of any user interaction entirely in the jPDL
pageflow definition, and write action listener methods that are
completely unaware of the flow of the interaction.

The JSF/Seam navigation rules are much simpler.
(However, this obscures the fact that the underlying Java code
is more complex.)

The jPDL makes the user interaction immediately understandable,
without us needing to even look at the JSP or Java code.

In addition, the stateful model is more constrained.
For each logical state (each step in the page flow), there are a
constrained set of possible transitions to other states. The stateless
model is an ad hoc model which is suitable to
relatively unconstrained, freeform navigation where the user decides
where he/she wants to go next, not the application.

The stateful/stateless navigation distinction is quite similar to
the traditional view of modal/modeless interaction. Now, Seam
applications are not usually modal in the simple sense of the
word - indeed, avoiding application modal behavior is one of the
main reasons for having conversations! However, Seam applications
can be, and often are, modal at the level of a particular
conversation. It is well-known that modal behavior is something
to avoid as much as possible; it is very difficult to predict the
order in which your users are going to want to do things! However,
there is no doubt that the stateful model has its place.

The biggest contrast between the two models is the back-button
behavior.

7.1.2. Seam and the back button

When JSF or Seam navigation rules are used, Seam lets the user freely
navigate via the back, forward and refresh buttons. It is the
responsibility of the application to ensure that conversational
state remains internally consistent when this occurs. Experience
with the combination of web application frameworks like Struts
or WebWork - that do not support a conversational model - and
stateless component models like EJB stateless session beans
or the Spring framework has taught many developers that this is
close to impossible to do! However, our experience is that in
the context of Seam, where there is a well-defined conversational
model, backed by stateful session beans, it is actually quite
straightforward. Usually it is as simple as combining the use
of no-conversation-view-id with null
checks at the beginning of action listener methods. We consider
support for freeform navigation to be almost always desirable.

In this case, the no-conversation-view-id
declaration goes in pages.xml. It tells
Seam to redirect to a different page if a request originates
from a page rendered during a conversation, and that conversation
no longer exists:

On the other hand, in the stateful model, backbuttoning is
interpreted as an undefined transition back to a previous state.
Since the stateful model enforces a defined set of transitions
from the current state, back buttoning is be default disallowed
in the stateful model! Seam transparently detects the use of the
back button, and blocks any attempt to perform an action from
a previous, "stale" page, and simply redirects the user to
the "current" page (and displays a faces message). Whether you
consider this a feature or a limitation of the stateful model
depends upon your point of view: as an application developer,
it is a feature; as a user, it might be frustrating! You can
enable backbutton navigation from a particular page node by
setting back="enabled".

This allows backbuttoning from the
checkout state to any previous
state!

Of course, we still need to define what happens if a request
originates from a page rendered during a pageflow, and the
conversation with the pageflow no longer exists. In this case,
the no-conversation-view-id declaration
goes into the pageflow definition:

The first line installs jBPM, the second points to a jPDL-based
pageflow definition.

7.2.2. Starting pageflows

We "start" a jPDL-based pageflow by specifying the name of the
process definition using a @Begin,
@BeginTask or @StartTask
annotation:

@Begin(pageflow="numberguess")
public void begin() { ... }

Alternatively we can start a pageflow using pages.xml:

<page>
<begin-conversation pageflow="numberguess"/>
</page>

If we are beginning the pageflow during the RENDER_RESPONSE
phase—during a @Factory or @Create
method, for example—we consider ourselves to be already at the page being
rendered, and use a <start-page> node as the first node
in the pageflow, as in the example above.

But if the pageflow is begun as the result of an action listener invocation,
the outcome of the action listener determines which is the first page to be
rendered. In this case, we use a <start-state> as
the first node in the pageflow, and declare a transition for each possible
outcome:

The view-id is the JSF view id. The <redirect/>
element has the same effect as <redirect/> in a
JSF navigation rule: namely, a post-then-redirect behavior, to overcome problems
with the browser's refresh button. (Note that Seam propagates conversation contexts
over these browser redirects. So there is no need for a Ruby on Rails style "flash"
construct in Seam!)

The transition name is the name of a JSF outcome triggered by clicking
a command button or command link in numberGuess.jsp.

<h:commandButton type="submit" value="Guess" action="guess"/>

When the transition is triggered by clicking this button, jBPM will activate the
transition action by calling the guess() method of the
numberGuess component. Notice that the syntax used for
specifying actions in the jPDL is just a familiar JSF EL expression, and that
the transition action handler is just a method of a Seam component in the
current Seam contexts. So we have exactly the same event model for jBPM events
that we already have for JSF events! (The One Kind of Stuff
principle.)

In the case of a null outcome (for example, a command button with no
action defined), Seam will signal the transition with no
name if one exists, or else simply redisplay the page if all transitions
have names. So we could slightly simplify our example pageflow and this button:

However, this is considered an inferior style, since it moves responsibility for
controlling the flow out of the pageflow definition and back into the other
components. It is much better to centralize this concern in the pageflow itself.

7.2.4. Controlling the flow

Usually, we don't need the more powerful features of jPDL when defining pageflows.
We do need the <decision> node, however:

7.3. Business process management in Seam

A business process is a well-defined set of tasks that must
be performed by users or software systems according to
well-defined rules about who can perform
a task, and when it should be performed.
Seam's jBPM integration makes it easy to display lists of
tasks to users and let them manage their tasks. Seam also
lets the application store state associated with the business
process in the BUSINESS_PROCESS context,
and have that state made persistent via jBPM variables.

A simple business process definition looks much the same as a
page flow definition (One Kind of Stuff),
except that instead of <page> nodes,
we have <task-node> nodes. In a
long-running business process, the wait states are where the
system is waiting for some user to log in and perform a task.

It is perfectly possible that we might have both jPDL business
process definitions and jPDL pageflow definitions in the
same project. If so, the relationship between the two is that
a single <task> in a business process
corresponds to a whole pageflow
<pageflow-definition>

7.4. Using jPDL business process definitions

7.4.1. Installing process definitions

We need to install jBPM, and tell it where to find the
business process definitions:

7.4.6. Performing a task

To begin work on a task, we use either @StartTask
or @BeginTask on the listener method:

@StartTask
public String start() { ... }

Alternatively we can begin work on a task using pages.xml:

<page>
<start-task />
</page>

These annotations begin a special kind of conversation that has
significance in terms of the overarching business process. Work done
by this conversation has access to state held in the business
process context.

If we end the conversation using @EndTask, Seam
will signal the completion of the task:

@EndTask(transition="completed")
public String completed() { ... }

Alternatively we can use pages.xml:

<page>
<end-task transition="completed" />
</page>

(Alternatively, we could have used <end-conversation>
as shown above.)

At this point, jBPM takes over and continues executing the business process
definition. (In more complex processes, several tasks might need to be
completed before process execution can resume.)

Please refer to the jBPM documentation for a more thorough overview of
the sophisticated features that jBPM provides for managing complex
business processes.