There's no perfect rule to model your workflow, it depends on the needs of your process, on the actors involved, and so on. Anyway I wanted to share with you some rules of thumb on which developers usually agree. Give me your feedback if you agree or you want to propose alternatives.
1) Keep your JBPM executionContext tidy
In the very first JBPM projects I have seen, I realized dwevelopers sometimes use the executionContext to feed lots of variables to the process. Adding variables to the execution Context is fundamental in order to control execution flow, anyway don't be tempted to put everything inside it !
For example: supposing you are designing a trouble ticketing system : you probably would need to store some additional information about the Actor, for example: name, surname, email. So you're mixing in the execution context both Model variables and Process variables !
Model this fields in an EJB and simply keep an ticketid in your executionContext. This is a sample EJB which used Seam to communicate with the biz process:
Remember that adding domain variables in the execution Context besides being a bad design choice, it will badly ontribute to slow down your process.
2) Use Exception handler only to set variables or to notify errors
JBPM has a built-in exception handler which can be applied to single nodes or to the overall process
You may be tempted to use exception handling in JBPM to decide execution flow: don't try it !
The mechanism of jBPM is not completely similar to the java exception handling. In java, a caught exception can have an influence on the control flow. In the case of jBPM, control flow cannot be changed by the jBPM exception handling mechanism. The exception is either caught or uncaught. Uncaught exceptions are thrown to the client (e.g. the client that called the token.signal()) or the exception is caught by a jBPM exception-handler. For caught exceptions, the graph execution continues as if no exception has occurred.
The best practice to use them is to perform some corrective action (set variables, send email, jms message etc.) and then either continue the graph execution (the behaviour you observe) or else rethrow an exception for the transaction to fail and the token to end up in the node it started from.
It is also a good design to catch business exceptions within your Actions and set some process variables, dependent on what exception is thrown.Then you can model a Decision in your process, which takes a special path of execution.
3) Want JBPM failover ? Wrap JBPM calls in a clustered SLSB !
jBPM is a state machine: process descriptions and runtime status are persisted to a database but in a cluster they are not automatically failed-over. If a cluster node fails while executing some external trigger (ui, timer, jms, whatever) execution will stop and have to be started again. Depending on the transaction context you're in this could be done automatically (redelivered jms, re-executed timer) or require ui interaction (error message for user if cluster node goes down requesting repeat).
Therefore, while the process description is persistent, workflow failover must be performed manually. jBPM can be used to build a fully failsafe, clusterable hotfailover worklfow solution, but it doesn't come out of the box.
So what's the easiest way to add these features to your workflow ? for most cases the best solution would be to encapsulate the jBPM API calls that you need in your application in a stateless session bean and cluster this last one.
Adding clustering capabilities to your EJB is not at all complicated, refer to this article:
4) Use superstates wherever possible
A Superstate is a group of nodes: its' a convenient way to group nodes into related sets, denoting for instance phases in a process. For example, one application could be to group all the nodes of a process in phases. Actions can be associated with superstate events. A consequence is that a token can be in multiple nested nodes at a given time. This can be convenient to check wether a process execution is e.g. in the start-up phase.
So it's a good design choice to split your process into superstates when every state represents a phase of the process, but there's one more reason why I advocate the use of superstates: JBPM is a state machine and as such doesn't deliver a built-in graphical environment. There's actually an Eclipse plugin which let you write graphically your process but it's not the best BPM front-end on the market: icons are too large, too ugly and you can't define custom icons for different type of nodes (at least as it comes out of the Box). If you have ever drawn a 100 nodes process with JBPM you probably did what I did: I designed by myself a new front-end layer from JBPM, because the picture of the process was huge and completely a mess.
If you are not willing to design a new front-end for JBPM then use extensively superstates wherever possible, it will keep your process (jpg) more readable and your boss won't faint when you show a 5 pages process picture!
5) Extend JBPM Api rather then messing with complex process modelling
Sometimes developers (me too!) don't look for the simpler solution: maybe modelling your process with jbpm built-in nodes leads to an unnecessarily complex process.
Think Simple.... jBPM is very extensible (actionhandlers, custom node types ) and sometimes easier then doing plain modeling with existing nodes which can make things unnecessarily complex.
For example: supposing that you have the requirement to assign a task within a particular swimlane depending on the geographic location. (if a task takes place in New York it's assigned to user A, if it takes place in Chicago then it's assigned to user B)
Take the org.jbpm.taskmgmt.def.Task.java and add the following fields/methods:
Now update the hibernate config file for Task.java which is Task.hbm.xml
Finally modify JpdlXmlReader.java so that this new property is injected into the Task class when
the process is read from the DB.
Another example of customization can be applied to your queries: supposing you want to filter your Tasks using lots of criteria : think about a TaskList rendered with JSF and a Task Filter window where you can filter Task on priority, date, Actor, Task name and so on.
One way to do it, without making things too complex is adding filters to the TaskInstance: simply open TaskInstance hibernate file and add some hibernate filters there:
Notice that parameters passed to the filters begin with ":" while other fields (like _ID) belong to the TaskInstance. Then when you're populating your Datatable, enable the filters selected:
6) Hire a Drool developer if you have complex rules
A workflow engine (or Graph Oriented Programming in general) is about specifying a graph that represents an execution. The nodes can represent wait states.
A rules engine is about specifying a set of rules and then applying an inference algorithm for a given set of facts. How could Drools fit with JBPM ? one best practice could be using JBPM to "externalize" all or part of logic contained in the Handlers in a rule engine. In other words JBPM engine could be driven by Drools rules engine.
As with other points, also this approach is not applicable in all situations: ask yourself a few things
How complex are my Java Action Handlers ? if you just need to read some data from a database, but not much more, it is probably best not to use a rule engine. However, where there is even a moderate amount of processing implemented in Java, it is worthwhile to consider the use of Drools when implementing your JBPM Handlers. This is because most applications develop complexity over time, and Drools will let you cope easily with this, especially if the lifetime of your application is medium or long. Furthermore Drools helps you cope with future changes by specifying the business rule in one or more easy-to-configure XML files.
One more score for drools is that Drools "guides" developers to write code correctly do "the right thing." and at the same time rules are much easier to read then code so also your staff will be more comfortable with it.
Furthermore, used correctly, Drools can remember not only the information, but also the results of previous tests using this information, giving the entire application a speed boost.
7) To BPEL or not to BPEL
BPEL is an XML language which describes long running web service interactions. It is used mainly to orchestrate message exchanges centrally and as such is a key ingredient in SOA.
What has BPEL in common with JPDL ?
- Both languages have a procedural notation
- Interaction with external agents
- Scheduling of activities
- Exception handling
- Error recovery
Even if they have some common points, the concrete expression of these elements leads to distinct audiences: for example talking about procedural notation:
JPDL reflects organizational procedures with simple meaning
BPEL describes structured constructs with complex semantics
Also the interaction with external agents is exploited differentely:
BPEL is document oriented and as such is mainly used in company boundaries
JPDL is object oriented and so it's a backbone in company componets
BPEL delegates interaction with people to partner services
jPDL offers integrated task management
So when should I use BPEL ?
When you need that your processes are portable even outside the Java platform. BPEL processes can be executed on orchestration servers based on Java platform or on any other software platform (for example .NET). This is particularly important in business-to-business interactions where different partners use different platforms
When there's no direct human involvement, rather you need specific support for long running business processes.
When you need to achieve transaction compensation in a relatively easy way. Compensation, or undoing steps in the business process that have already completed successfully, is one of the most important concepts in business processes. The goal of compensation is to reverse the effects of previous activities that have been carried out as part of a business process that is being abandoned.
Use JPDL when these criteria are not met.<