JBoss Drools Tutorial

User Rating: 4 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Inactive
 

This tutorial is updated with the release 6 of JBoss Drools.

What is a Rule Engine ?

The term Rule Engine can be referred to any system that uses rules, in any form, that can be applied to data to produce outcomes; it may refer to simple systems like form validation or more complex systems like dynamic expression engines. In a few words a Rule engine allow you to say "What to do" and not "How to do it".

Why using a Rule Engine ?

Rule systems are capable of solving very, very hard problems, providing an explanation of how the solution was arrived at and why each "decision" along the way was made.
Among the main benefit of a Rule engine can be mentioned:

  • Logic and Data Separation: Breaking your domain objects from business rules can lead to a mach easier to maintain application as it can shield from changes in the future, since the logic is all laid out in rules.
  • Speed and Scalability: Many times we apply "if" conditions that we didn't really need. The Rete algorithm, as implemented by Drools, replaces all of the if ... then statements with an optimized network.
  • Centralization of Knowledge: By using rules, you create a repository of knowledge (a knowledgebase) which can be considered as a single point of truth, for business policy (for instance) - ideally rules are so readable that they can also serve as documentation
  • Tool Integration: Writing rules means also to get accustomed with Rule language, validation and debugging. Eclipse provide an excellent tool to deliver and test your Rules.
  • Understandable Rules: JBoss Drools rules can make it easy to express solutions to difficult problems and consequently have those solutions verified (rules are much easier to read then code).Often, business users are more comfortable with expressing things that they know to be true, than to express things in an if...then format. Examples of things that you might hear from a business expert are:

"We need to buy that estate if the price is not over 1000000 $ and estate agency doesn't claim more then 5000 $"
"We buy shares when the price goes over 15 Euro before next week"

By focusing on what we know to be true, rather than the mechanics of how to express it in Java code, the above statements are much more clean than exposing it with traditional "if...then" clause

Developing applications with JBoss Drools

In order to run a basic example of JBoss Drools you can use two main approaches:

1) Download the Drools Runtime from http://www.drools.org/download/download.html and use the libraries contained in the Runtime to execute your Rules

2) Use a Maven project and add Drools dependencies in it.

To get started very quickly we will use the latter approach, therefore the only thing needed is a JDK and Maven installed. In our example we will use as IDE JBoss Developer Studio with the BPM Plugin installed. However that's not strictly needed, also a basic Maven project with the right dependencies will work.

Installing the BPM Plugin (optional)

The BPM plugin can be easily installed from the JBoss Central UI by searching for "drools" projects:

drools tutorial jboss

This will trigger the installation of all required Plugins for creating Drools projects. The advantage of Installing this plugin is that you can use the IDE to edit new Rules, Debug or Test them.

install plugin drools

Now restart JBoss Developer Studio for changes to take effect.

An Hello World Drool Project

With the Drools plugin activated, you will be able to create a New Drools project from the "New..." Menu

wizarddrools 

Click Next. In the following Window, choose the initial project contents. We will just need a blank project with the correct Maven folders:

wizarddrools2

Finish off, by choosing the Maven GroupId, ArtifactId and Version and how to Build the Project. As we said, we will use Maven to build the Project. If you want to use the Drools Runtime, you will be requested to install and point to the Drools Home directory.

wizarddrools3

Now that you have a basic project, we will add two core pieces:

  1. A simple Rule which interacts with a Java instance (a fact) passed to the Rule
  2. A Java main class to execute the Rule

Let's add at first a new Rule. From the File menu choose to add a new Rule:

drools new rule

As you can see, you will be requested to enter a Rule file name and the Type of resource Rule. In our case we will create the Rule.drl file name as part of a rule package. The rule will be in the rules package name. Here is the simple Rule:

package drools

import com.sample.Message;

rule "Hello World"
dialect "mvel"
when
m : Message( status == Message.HELLO, message : message )
then

modify ( m ) { message = "Goodbye cruel world",
status = Message.GOODBYE };
System.out.println( message );
end

rule "Good Bye"
dialect "java"
when
Message( status == Message.GOODBYE, message : message )
then
System.out.println( message );

end

This example is provided with 2 Rules: the first Rule ("HelloWorld") checks the value of the field status in the class Message, if the value equals to the constant Message.HELLO then a new value for status is setted and a goodbye message is printed.

On the other hand the "Good bye" Rule will check as well the value of field status. If it's equal to Message.GOODBYE then we've reached the bottom of our Rules and we exit printing a message.

Everything clear ? maybe not. Let's see closer a few pieces of this Rule:

m : Message( status == Message.HELLO, message : message )

  What does this mean ?

This is the Pattern element: the most important Conditional Element. It consists of zero or more constraints and has an optional pattern binding. A constraint can be either a Field Constraint, Preducate or a Constraint Group. Constraints can be separated by the following symbols ',', '&&' or '||'.

So this simply says that the Rule will be activated for each Message object inserted into the working memory whose status is Message.HELLO. Besides that, two variable binds are created: "message" variable is bound to the message attribute and "m" variable is bound to the object matched pattern itself.

  And the dialect "mvel" keyword ?

When writing Rules you have the option to use Java Language and MVEL sytnax to modify objects passed to the Working memory. MVEL's syntax allows you to apply a block of setters in one statement, with the engine being automatically notified of the changes at the end of the block.

modify ( m ) {

message = "Goodbye cruel world",
status = Message.GOODBYE

};

Ok, so we've our Rule. We will need to add the Message class which will be our "fact" transferred to the Drools Runtime:

package com.sample;

public class Message {

	public static final int HELLO = 0;
	public static final int GOODBYE = 1;

	private String message;
	private int status;

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

}

In order to execute them we'll create a Java Class named App:

package com.sample;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class App {
	public static void main( String[] args ) {
		System.out.println( "Bootstrapping the Rule Engine ..." );
 
		KieServices ks = KieServices.Factory.get();
		KieContainer kContainer = ks.getKieClasspathContainer();
		KieSession kSession =  kContainer.newKieSession();

		Message message = new Message();   
		message.setMessage( "Hello World" );   
		message.setStatus( Message.HELLO );
		kSession.insert(message);
 
		int fired = kSession.fireAllRules();
		System.out.println( "Number of Rules executed = " + fired );
		System.out.println( "Message Status: " + message.getStatus());
	}
}

This class does the following actions:

  1. Bootstraps the Rule Engine session: The KieSession represents a running instance of the Rule Engine with a specific configuration and set of rules. It holds the evaluation algorithm used to match the rules against our domain objects.
  2. Lets the Rule Engine to know about our data: We are responsible for providing all the information to the engine so that it can operate on it. This is done through the insert() method on KieSession.
  3. Next, if the information that we provided matches with one or more available rules, we will get Matches. Calling the fireAllRules() method will execute these matches.

The last thing we need to do in order to complete our project, is a file in the src/main/resources/META-INF/ directory called kmodule.xml. This file is used to configure how to load the rules defined in the project in the rule engine. For now, the content of kmodule.xml will be quite simple as we will be using all the default configurations. Here is a sample content of it:

<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://jboss.org/kie/6.0.0/kmodule">
</kmodule>

Here is how your project should look like:

drools project

Build the project with:

$ mvn clean install

And you can run it with:

$ mvn exec:java -Dexec.mainClass="com.sample.App"

When executed the output will be:

Hello World
Goodbye cruel world
Number of Rules executed = 2
Message Status: 1

This is a very trivial example just to get accustomed with JBoss Drools environment: in the following articles we'll see how a rules engine can significantly reduce the complexity of components that implement the business-rules logic in your Java applications. By expressing your rules using JBoss Drools declarative approach your application has higher chance of being more maintainable and extensible than one that doesn't.

Running the Project without JBoss Developer Studio

If you are not using JBoss Developer Studio or Eclipse to develop your project, as simple environment Maven based will work. Just create a new Maven project with a basic archetype:

mvn -B archetype:generate -DarchetypeGroupId=com.sample \
  -DgroupId=com.sample \
  -DartifactId=DemoDrools

Now, you have to include manually the required Class files, the Rules and the configuration files. Finish off by setting the correct dependencies in your pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	<modelVersion>4.0.0</modelVersion>

	<groupId>com.sample</groupId>
	<artifactId>DemoDrools</artifactId>
	<version>1.0.0-SNAPSHOT</version>

	<name>Drools :: Sample Maven Project</name>
	<description>A sample Drools Maven project</description>

	<properties>
		<runtime.version>6.4.0.Final</runtime.version>
	</properties>

	<repositories>
		<repository>
			<id>jboss-public-repository-group</id>
			<name>JBoss Public Repository Group</name>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
			<releases>
				<enabled>true</enabled>
				<updatePolicy>never</updatePolicy>
			</releases>
			<snapshots>
				<enabled>true</enabled>
				<updatePolicy>daily</updatePolicy>
			</snapshots>
		</repository>
	</repositories>

	<dependencies>
		<dependency>
			<groupId>org.kie</groupId>
			<artifactId>kie-api</artifactId>
			<version>${runtime.version}</version>
		</dependency>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-core</artifactId>
			<version>${runtime.version}</version>
		</dependency>

		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-decisiontables</artifactId>
			<version>${runtime.version}</version>
		</dependency>
	</dependencies>
</project>

Advertisement

JBoss CheatSheet for Admins