JBoss.orgCommunity Documentation

Drools Flow User Guide

5.0.0.MR2


1. Introduction
2. Getting Started
2.1. Installation
2.2. Creating your first process
2.3. Executing your first process
3. Rule Flow
3.1. Assigning rules to a ruleflow group
3.2. A simple ruleflow
3.3. How to build a rule flow
3.4. Using a rule flow in your application
3.5. Different types of nodes in a ruleflow
4. Rules and Processes
4.1. Why use rules in processes?
4.2. Why integrate rules and processes in a single engine?
4.3. Approach
4.3.1. Teaching a rules engine about processes
4.3.2. Inversion of control
4.4. Example
4.4.1. Evaluating a set of rules in your process
4.4.2. Using rules for evaluating constraints
4.4.3. Assignment rules
4.4.4. Describing exceptional situations using rules
4.4.5. Modularizing concerns using rules
4.4.6. Using rules to dynamically alter the behaviour of the process
4.4.7. Integrated tooling
4.4.8. Domain-specific rules and processes
5. Domain-specific processes
5.1. Introduction
5.2. Example: Notifications
5.2.1. Creating the work definition
5.2.2. Registering the work definition
5.2.3. Using your new work item in your processes
5.2.4. Executing work items
5.3. Testing processes using work items
5.4. Future
6. Debugging processes
6.1. A simple example
6.2. Debugging the process
6.2.1. The Process Instances View
6.2.2. The Audit View
Index

Drools Flow is a workflow and process engine that allows advanced integration of processes and rules.

This section describes how to get started with Drools Flow. It will guide you to create and exectue your first Drools Flow process.

The best way to get started is to use the Drools Eclipse IDE. This is a plugin for the Eclipse developement environment that allows users to create, execute and debug Drools processes and rules.

To get started, you need an Eclipse 3.3.x, as well as the Eclipse Graphical Editing Framework (GEF) plugin installed. Eclipse can be downloaded from http://www.eclipse.org/downloads/ (choose either the Eclipse IDE for Java Developers or the Eclipse Classic). Eclipse GEF can also be downloaded from http://www.eclipse.org/gef/downloads/ (choose the corresponding version) or by using an update site.

Download the Drools Eclipse IDE plugin from http://www.jboss.org/auth/drools/downloads.html (the latest snapshot build can also be downloaded from https://hudson.jboss.org/hudson/job/drools/lastSuccessfulBuild/artifact/trunk/target/), unzip it in your eclipse folder and (re)start Eclipse. If installation was successful, the Drools menu action should appear in the top menu bar.

You should switch to the Drools perspective within Eclipse first, as this will open all the relevant views for you. You can do this by clicking on the Open Perspective button (top right of your screen) and selecting Other ... -> Drools.

A new project wizard can be used to setup an executable project to start using processes immediately. This will setup a basic structure, classpath, sample process and execution code to get you started. To create a new Drools Project, select File -> New -> Project ... and in the Drools folder, select Drools Project. This should open the following dialog:

Give your project a name and click Next. In the following dialog you can select which elements are added to your project by default. Since we are creating a new process, deselect the first two checkboxes and select the last two. This will generate a sample process and a class to execute this process in your project.

The end result should look like this and contains:

The RuleFlow editor contains a graphical representation of your process definition. It consists of nodes that are connected. The editor shows the overall control flow, while the details of each of the elements can be viewed (and edited) in the Properties View at the bottom. The editor contains a palette at the left that can be used to drag-and-drop new nodes, and an outline view at the right.

This process is a simple sequence of three nodes. The start node defines the start of the process. It is connected to an action node (called 'Hello' that simply prints out 'Hello World' to the standard output. You can see this by clicking on the Hello node and checking the action property in the properties view below. This node is then connected to an end node, signalling the end of the process.

While it is probably easier to edit processes using the graphical editor, user can also modify the underlying XML directly. The XML for our sample process is shown below (note that we did not include the graphical information here for simplicity). The process element contains parameters like the name and id of the process, and consists of three main subsections: a header (where information like variables, globals and imports can be defined), the nodes and the connections.

<?xml version="1.0" encoding="UTF-8"?>
<process xmlns="http://drools.org/drools-4.0/process"
         xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
         xs:schemaLocation="http://drools.org/drools-4.0/process drools-processes-4.0.xsd"
         type="RuleFlow" name="ruleflow" id="com.sample.ruleflow" package-name="com.sample" >

  <header>
  </header>

  <nodes>
    <start id="1" name="Start" x="16" y="16" />
    <actionNode id="2" name="Hello" x="128" y="16" >
      <action type="expression" dialect="mvel" >System.out.println("Hello World");</action>
    </actionNode>
    <end id="3" name="End" x="240" y="16" />
  </nodes>

  <connections>
    <connection from="1" to="2" />
    <connection from="2" to="3" />
  </connections>

</process>

To execute this process, right-click on RuleFlowTest.java and select Run As - Java Application. When the process in executed, the following output should appear on the console:

Hello World

If you look at the RuleFlowTest code (see below), you will see that executing a process requires a few steps:

package com.sample;

import java.io.InputStreamReader;
import java.io.Reader;

import org.drools.RuleBase;
import org.drools.RuleBaseFactory;
import org.drools.StatefulSession;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;

/**
 * This is a sample file to launch a ruleflow.
 */
public class RuleFlowTest {

  public static final void main(String[] args) {
    try {
      //load the process
      RuleBase ruleBase = createKnowledgeBase();
      // create a new session
      StatefulSession session = ruleBase.newStatefulSession();
      // start a new process instance
      session.startProcess("com.sample.ruleflow");
    } catch (Throwable t) {
      t.printStackTrace();
    }
  }

  /**
   * Creates the knowledge base by loading the process definition.
   */
  private static RuleBase createKnowledgeBase() throws Exception {
    // create a builder
    PackageBuilder builder = new PackageBuilder();
    // load the process
    Reader source = new InputStreamReader(
      RuleFlowTest.class.getResourceAsStream("/ruleflow.rf"));
    builder.addProcessFromXml(source);
    // create the knowledge base 
    Package pkg = builder.getPackage();
    RuleBase ruleBase = RuleBaseFactory.newRuleBase();
    ruleBase.addPackage(pkg);
    return ruleBase;
  }

}

Congratulations, you have successfully executed your first process! You can now start experimenting and designing your own process by modifying our example. Note that you can validate your process by clicking on the green check box action in the upper toolbar. Processes will also be validated upon save and errors will be shown in the error view. Or you can continue reading our documentation to learn about our more advanced features.


Drools already provides some functionality to define the order in which rules should be executed, like salience, activation groups, etc. When dealing with (possibly a lot of) large rule-sets, managing the order in which rules are evaluated might become complex. Ruleflow allows you to specify the order in which rule sets should be evaluated by using a flow chart. This allows you to define which rule sets should be evaluated in sequence or in parallel, to specify conditions under which rule sets should be evaluated, etc. This chapter contains a few ruleflow examples.

A rule flow is a graphical description of a sequence of steps that the rule engine needs to take, where the order is important. The ruleflow can also deal with conditional branching, parallelism, synchonization, etc.

To use a ruleflow to describe the order in which rules should be evaluatied, you should first group rules into rulefow-groups using the ruleflow-group rule attribute ("options" in the GUI). Then you should create a ruleflow graph (which is a flow chart) that graphically describe the order in which the rules should be considered (by specifying the order in which the ruleflow-groups should be evaluated).

Ruleflows can only be created by using the graphical ruleflow editor which is part of the Drools plug-in for Eclipse. Once you have set up a Drools project (check the IDE chapter if you do not know how to do this), you can start adding ruleflows. When in a project, use "control+N" to launch the new wizard, or right-click the directory you would like to put your ruleflow in and select "New ... Other ...":


Choose the section on "Drools" and then pick "RuleFlow file". This will create a new .rf file.

Next you will see the graphical ruleflow editor. Now would be a good time to switch to the "Drools perspective" (if you haven't done so already) - this will tweak the UI so it is optimal for rules. Then ensure that you can see the "properties" panel down the bottom of the Eclipse window, as it will be necessary to fill in the different properties of the elements in your ruleflow. If you cannot see the properties view, open it using the Menu Window - Show View - Other ..., and under the General folder select the Properties view.


The RuleFlow editor consists of a palette, a canvas and an outline view. To add new elements to the canvas, select the element you would like to create in the palette and then add them to the canvas by clicking on the preferred location. For example, click on the RuleFlowGroup icon in the Component Pallette of the GUI - you can then draw a few rule flow groups. Clicking on an element in your ruleflow allows you to set the properties of that element.

Click on a ruleflow group, and you should see the following:


You can see here you set the visible name, but you also need to set the actual group name that is used in the rules.

Next step is to join the groups together (if its a simple sequence of steps) - you use this by using "create connection" from the component palette. You should also create an "End" node (also from the component palette).

In practice, if you are using ruleflow, you will most likely be doing more then setting a simple sequence of groups to progress though. You are more likely modeling branches of processing. In this case you use "Split" and "Join" items from the component pallette. You use connections to connect from the start to ruleflow groups, or to Splits, and from splits to groups, joins etc. (i.e. basically like a simple flow chart that models your processing). You can work entirely graphically until you get the graph approximately right.


The above flow is a more complex example. This example is an insurance claim processing rule flow. A description: Initially the claim data validation rules are processed (these check for data integrity and consistency, that all the information is there). Next there is a decision "split" - based on a condition which the rule flow checks (the value of the claim), it will either move on to an "auto-settlement" group, or to another "split", which checks if there was a fatality in the claim. If there was a fatality then it determines if the "regular" of fatality specific rules will take effect. And so on. What you can see from this is based on a few conditions in the rule flow the steps that the processing takes can be very different. Note that all the rules can be in one package - making maintenance easy. You can separate out the flow control from the actual rules.


Split types (referring to the above): When you click on a split, you will see the above properties panel. You then have to choose the type: AND, OR, and XOR. The interesting ones are OR and XOR: if you choose OR, then any of the "outputs" of the split can happen (ie processing can proceed in parallel down more then one path). If you chose XOR, then it will be only one path.

If you choose OR or XOR, then in the row that has constraints, you will see a button on the right hand side that has "..." - click on this, and you will see the constraint editor. From this constraint editor, you set the conditions which the split will use to decide which "output path" will be chosen.


Choose the output path you want to set the constraints for (eg Autosettlement), and then you should see the following constraint editor:


This is a text editor where the constraints (which are like the condition part of a rule) are entered. These constraints operate on facts in the working memory (eg. in the above example, it is checking for claims with a value of less than 250). Should this condition be true, then the path specified by it will be followed.

Once you have a valid ruleflow (you can check its valid by pressing the green "tick" icon in the IDE), you can add a rule flow to a package just like a drl. However, the IDE creates two versions of your ruleflow: one containing the ruleflow definition (*.rfm) and one containing additional graphical information (*.rf). When adding a ruleflow to a package, you should make sure that you are adding the .rfm file to your ruleflow (and not the .rf file).

Reader rfm = ... (rule flow reader, select your .RFM file here)
packageBuilder.addRuleFlow(rfm);
    

Alternatively, you can upload the .rf file to the BRMS (as a ruleflow asset) and it will automatically be included in packages that are deployed from it.

Ruleflows are only executed if you explicitly state that they should be executed. This is because you could potentially define a lot of ruleflows in your package and the engine has no way to know when you would like to start each of these. To activate a particular ruleflow, you will need to start the process by calling the startProcess method on the working memory. For example, if you want to start a particular workflow after you have asserted your facts into the working memory, use:

workingMemory.startProcess("ID_From_your_Ruleflow_properties");

(The ruleflow id can be specified in the properties view when you click the background canvas of your ruleflow). And then call fireAllRules(). This will start executing rules, taking the order specified in the ruleflow into account. Thats it !

You can also start a ruleflow process from within a rule consequence using

drools.getWorkingMemory().startProcess("ID_From_your_Ruleflow_properties");

A ruleflow is a flow chart where different types of nodes are linked using connections. It has the following properties: a (unique) id, a (display) name and a version. Global and imports can be defined that can be reused throughout the entire process. You can also specify how the connections are visualized on the canvas using the connection layout property:


RuleFlow supports different types of nodes:

  1. Start: the start of the ruleflow. A ruleflow should have exactly one start node. The start node cannot have incoming cnnections and should have one outgoing connection. It contains one property "name" which is the display name of the node. Whenever ruleflow process is started, the ruleflow will start executing here and automatically continue to the first node linked to this start node.

  2. End: the end of the ruleflow. A ruleflow should have one or more end nodes. The end node should have one incoming connection and cannot have outgoing connections. It contains one property "name" which is the display name of the node. When an end node is reached in the ruleflow, the ruleflow is terminated. If a ruleflow is terminated, all nodes that are still active in this ruleflow are cancelled first (which is possible if parallel paths are used).

  3. RuleSet: represents a set of rules. The rules are evaluated when the node is reached. A RuleFlowGroup node should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node, and the property "ruleflow-group" which is used to specify the name of the ruleflow-group that represents the set of rules of this RuleFlowGroup node. Rules can use the ruleflow-group attribute to become part of a ruleflow group. When a RuleSet node is reached in the ruleflow, the engine will start executing rules that are part of the corresponding ruleflow-group (if any). Execution will automatically continue to the next node if there are no more active rules in this ruleflow-group. This means that, during the execution of a ruleflow-group, it is possible that new activations belonging to the currently active ruleflow-group are added to the agenda due to changes made to the facts by the other rules. Note that the ruleflow will immediately continue with the next node if it encounters a ruleflow-group where there are no active rules at that point. If the ruleflow-group was already active, the ruleflow-group will remain active and exeution will only continue if all active rules of the ruleflow-group has been completed.

  4. Split: allows you to create branches in your ruleflow. A split node should have one incoming connection and two or more outgoing connections. It contains a property "name" which is the display name of the node. There are three types of splits currently supported:

    1. AND means that the control flow will continue in all outgoing connections simultaneously (paralellism).

    2. XOR means that exactly one of the outgoing connections will be chosen (decision). Which connection is decided by evaluating the constraints that are linked to each of the outgoing connections. Constraints are specified using the same syntax as the left-hand side of a rule. The constraint with the lowest priority number that evaluates to true is selected. Note that you should always make sure that at least one of the outgoing connections will evaluate to true at runtime (the ruleflow will throw an exception at runtime if it cannot find at least one outgoing connection). For example, you could use a connection which is always true (default) with a high priority number to specify what should happen if none of the other connections can be taken.

    3. OR means that all outgoing connections whose condition evaluates to true are selected. Conditions are similar to the XOR split, except that the priorities are not taken into account. Note that you should make sure that at least one of the outgoing connections will evaluate to true at runtime (the ruleflow will throw an exception at runtime if it cannot find an outgoing connection).

  5. Join: allows you to synchronize multiple branches. A join node should have two or more incoming connections and one outgoing connection. It contains a property "name" which is the display name of the node. There are three types of splits currently supported:

    1. AND means that is will wait until all incoming branches are completed before continuing.

    2. XOR means that it continues if one of its incoming branches has been completed.

    3. Discriminator means that it continues if one of its incoming branches has been completed.

  6. Event wait (milestone): represents a wait state. An event wait should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node, and the property "constraint" which specifies how long the ruleflow should wait in this state before continuing. For example, a milestone constraint in an order entry application might specify that the ruleflow should wait until (a fact in the working memory specifies that) no more errors are found in the given order. Constraints are specified using the same syntax as the left-hand side of a rule. When a wait node is reached in the ruleflow, the engine will check the associated constraint. If the constraint evaluates to true directly, the flow will continue imediately. Otherwise, the flow will continue if the constraint is satisfied later on, for example when a facts in the working memory is inserted, updated or removed.

  7. SubProcess: represents the invocation of another process from withing this ruleflow. A sub-process node should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node, and the property "processId" which specifies the id of the process that should be executed. When a SubProcess node is reached in the ruleflow, the engine will start the process with the given id. If the property "Wait for completion" is true, the subflow node will only continue if that subflow process has terminated its execution (completed or aborted); otherwise it will continue immediately after starting the sub-process. If the property "independent" is true, the sub-process is started as an independent process, which means that the subflow process will not be terminated if this process reaches an end node; otherwise the active sub-process will be cancelled on termination (or abortion) of the process. A SubProcess can also define in- and out-mappings for variables. The value of variables in this process with given variable name in the in-mappings will be used as parameters (with the associated parameter name) when starting the process. The value of the variables in the sub-process with the given variable name in the out-mappings will be copied to the variables of this process when the sub-process has been completed. Note that can only use out-mappings when "Wait for completion" is set to true.

  8. Action: represents an action that should be executed in this ruleflow. An action node should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node, and the property "action" which specifies the action that should be executed. The action should specify which dialect is used to specify the action (e.g. Java or MVEL), and the actual action code. The action code can refer to any globals and the special 'drools' variable which implements KnowledgeHelper, and can for example be used to access the working memory (drools.getWorkingMemory()). When an action node is reached in the ruleflow, it will execute the action and continue with the next node.

  9. WorkItem: represents an (abstract) item of work that should be executed in this ruleflow. A WorkItem node should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node. The type of work is uniquely identified by the work item name. When a WorkItem node is reached in the ruleflow, it will execute start the associated work item. If the property "Wait for completion" is true, the WorkItem node will only continue if the created work item has terminated its execution (completed or aborted); otherwise it will continue immediately after starting the work item. Each type of work item can define parameters that describe that type of work. For example, an email node (work item name "Email" will define properties like 'from', 'to', 'subject' and 'text'. The user can either fill in values for these parameters directly, or define a parameter mapping that will copy the value of the given variable in this process to the given parameter (if both are specified, the mapping will have precedence). Each type of work can also define result parameters that will be returned after the work item has been completed. A result mapping can be used to copy the value of the given result parameter to the given variable in this process. Note that can only use out-mappings when "Wait for completion" is set to true. The user can define their own types of work items (see the section about pluggable work items).

  10. Timer: represents a timer that can trigger one or multiple times after a given period of time. A Timer node should have one incoming connection and one outgoing connection. It contains a property "name" which is the display name of the node. The "TimerDelay" property specifies how long (in milliseconds) the timer should wait before triggering the first time. The "Timerperiod" specifies the timer will between two subsequenct triggers. A period of 0 means that the timer should only be executed once. When a timer node is reached in the ruleflow, it will execute the associated timer. The timer is cancelled if the timer node is cancelled (e.g. by completing the running process).

Drools Flow is a workflow and process engine that allows advanced integration of processes and rules. This chapter gives an overview of how to integrate rules and processes, ranging from simple to advanced.

Workflow languages that depend purely on process constructs (like nodes and connections) to describe the business logic of (a part of) an application tend to be quite complex. While these workflow constructs are very well suited to describe the overall control flow of an application, it can be very difficult to describe complex logic and exceptional situations. Therefore, executable processes tend to become very complex. We believe that, by extending a process engine with support for declarative rules in combination with these regular process constructs, this complexity can be kept under control.

Workflow languages describe the order in which activities should be performed using a flow chart. A process engine is responsible for selecting which activities should be executed based on the current state of the executing processes. Rules on the other hand are composed of a set of conditions that describe when a rule is applicable and an action that is executed when the rule is applicable. The rules engine is then responsible for evaluating and executing the rules. It decides which rules need to be executed based on the current state of the application.

Workflow processes are very good at describing the overall control flow of (possibly long-running) applications. However, processes that are used to define complex business decisions or contain a lot of exceptional situations or need to respond to various external events tend to become very complex. Rules on the other hand are very good at describing complex decisions and reasoning about large amounts of data or events. It is however not trivial to define long-running processes using rules.

In the past, users were forced to choose between defining their business logic using either a process or rules engine. Problems that required complex reasoning about large amounts of data used a rules engine, while users that wanted to focus on describing the control flow of their processes were forced to use a process engine. However, businesses nowadays might want to combine both processes and rules in order to be able to define all their business logic in the format that best suits their needs.

Basically, both a rules and a process engine will derive the next steps that need to be executed by looking at its knowledge base (a set of rules or processes respectively) and the current known state of the application (the data in the working memory or the state of the executing process instances respectively). If we want to integrate rules and processes, we need an engine that can decide the next steps taking into account the logic that is defined inside both the processes and the rules.

The drools-examples project contains a sample process (org.drools.examples.process.order) that illustrates some of the advantages of being able to combine processes and rules. This process describes an order application where incoming orders are validated, possible discount are calculated and shipping of the goods is requested.

One of the goals of our unified rules and processes framework is to allow users to extend the default programming constructs with domain-specific extensions that simplify development in a particular application domain. While Drools has been offering constructs to create domain-specific rule languages for some time now, this tutorial describes our first steps towards domain-specific process languages.

Most process languages offer some generic action (node) construct that allows plugging in custum user actions. However, these actions are usually low-level, where the user is required to write custom code to implement the work that should be incorporated in the process. The code is also closely linked to a specific target environment, making it difficult to reuse the process in different contexts.

Domain-specific languages are targeted to one particular application domain and therefore can offer constructs that are closely related to the problem the user is trying to solve. This makes the processes and easier to understand and self-documenting. We will show you how to define domain-specific work items, which represent atomic units of work that need to be executed. These work items specify the work that should be executed in the context of a process in a declarative manner, i.e. specifying what should be executed (and not how) on a higher level (no code) and hiding implementation details.

So we want work items that are:

Users can easily define their own set of domain-specific work items and integrate them in our process language(s). For example, the next figure shows an example of a process in a healthcare context. The process includes domain-specific work items for ordering nursing tasks (e.g. measuring blood pressure), prescribing medication and notifying care providers.

Let's start by showing you how to include a simple work item for sending notifications. A work item represent an atomic unit of work in a declarative way. It is defined by a unique name and additional parameters that can be used to describe the work in more detail. Work items can also return information after they have been executed, specified as results. Our notification work item could thus be defined using a work definition with four parameters and no results:

  Name: "Notification"
  Parameters
  From [String]
  To [String]
  Message [String]
  Priority [String]

The Drools engine contains a WorkItemManager that is responsible for executing work items whenever necessary. The WorkItemManager is responsible for delegating the work items to WorkItemHandlers that execute the work item and notify the WorkItemManager when the work item has been completed. For executing notification work items, a NotificationWorkItemHandler should be created (implementing the WorkItemHandler interface):

package com.sample;

import org.drools.process.instance.WorkItem;
import org.drools.process.instance.WorkItemHandler;
import org.drools.process.instance.WorkItemManager;

public class NotificationWorkItemHandler implements WorkItemHandler {

  public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
    // extract parameters
    String from = (String) workItem.getParameter("From");
    String to = (String) workItem.getParameter("To");
    String message = (String) workItem.getParameter("Message");
    String priority = (String) workItem.getParameter("Priority");
    // send email
    EmailService service = ServiceRegistry.getInstance().getEmailService();
    service.sendEmail(from, to, "Notification", message);
    // notify manager that work item has been completed
    manager.completeWorkItem(workItem.getId(), null);
  }

  public void abortWorkItem(WorkItem workItem, WorkItemManager manager) {
    // Do nothing, notifications cannot be aborted
  }

}

This WorkItemHandler sends a notification as an email and then immediate notifies the WorkItemManager that the work item has been completed. Note that not all work items can be completed directly. In cases where executing a work item takes some time, execution can continue asynchronously and the work item manager can be notified later. In these situations, it might also be possible that a work item is being aborted before it has been completed. The abort method can be used to specify how to abort such work items.

WorkItemHandlers should be registered at the WorkItemManager, using the following API:

  workingMemory.getWorkItemManager().registerWorkItemHandler(
    "Notification", new NotificationWorkItemHandler());

Decoupling the execution of work items from the process itself has the following advantages:

This section describes how to debug processes. This means that the current state of your running processes can be inspected and visualized during the execution. We use a simple example throughout this section to illustrate the debugging capabilities. The example will be introduced first, followed by an illustration on how to use the debugging capabilities.

We now add four breakpoints during the execution of the process (in the order in which they will be encountered):

When debugging the application, one can use the following debug views to track the execution of the process:

The process instances view shows the currently running process instances. The example shows that there is currently one running process (instance), currently executing one node (instance), i.e. RuleSet node. When double-clicking a process instance, the process instance viewer will graphically show the progress of the process instance. At each of the breakpoints, this will look like: