Rate this page del.icio.us  Digg slashdot StumbleUpon

JBoss Drools how-to: Tuning Guvnor, part 1

by

Guvnor is the business rules management system in Drools 5. When you deploy it out of the box, you get an unsecured web application that stores data in Jackrabbit’s embedded Derby database.

The first half of this series explains how to tune Guvnor deployed on JBoss Application Server 4.2.3. This means that we will use the container’s configuration files and security infrastructure. We will cover enabling password validation based on an OpenLDAP server, moving from the default data repository, and enabling SSL for better security in part 2.

  1. Installation
  2. Quick introduction
  3. Enable user/password validation

Installation

We will deploy Guvnor as an exploded archive on the JBoss Application Server.

  1. Download JBoss AS 4.2.3.GA and extract it to:
     /data/jboss-4.2.3.GA
    
  2. Download Guvnor M1 and extract it to the deploy directory under:
     /data/jboss-4.2.3.GA/server//deploy/drools-guvnor.war
    
  3. From now on we’ll use:
    $JBOSS_SERVER as /data/jboss-4.2.3.GA/server/
    $GUVNOR as /data/jboss-4.2.3.GA/server//deploy/drools-guvnor.war
    
  4. To verify a successful deployment, start the server:
    $ /data/jboss-4.2.3.GA/bin/run.sh -c 
    

    You should see the response below:

    JBoss Bootstrap Environment
    
    JBOSS_HOME: /data/jboss-4.2.3.GA
    
    JAVA: /usr/local/jdk1.5.0_11/bin/java
    
    JAVA_OPTS: -Dprogram.name=run.sh -server -Xms128m -Xmx512m -Dsun.rmi.dgc.client.gcInterval=3600000-Dsun.rmi.dgc.server.gcInterval=3600000 -Djava.net.preferIPv4Stack=true
    
    CLASSPATH: /data/jboss-4.2.3.GA/bin/run.jar:/usr/local/jdk1.5.0_11/lib/tools.jar
    
    =========================================================================
    
    17:13:53,732 INFO  [Server] Starting JBoss (MX MicroKernel)...
    17:13:53,734 INFO  [Server] Release ID: JBoss [Trinity] 4.2.3.GA (build: SVNTag=JBoss_4_2_3_GA date=200807181417)
    17:13:53,736 INFO  [Server] Home Dir: /data/jboss-4.2.3.GA
    .
    .
    .
    17:14:38,366 INFO  [TomcatDeployer] deploy, ctxPath=/drools-guvnor, warUrl=.../deploy/drools-guvnor.war/.
    .
    .
    

Navigate to http://localhost:8080/drools-guvnor and login as ‘admin’ without any password.

Fig 1. Guvnor

Fig 1. Guvnor

Guvnor is now up and running. Let’s see how we can get started quickly.

Quick introduction

Before you can start using Guvnor for rule authoring, you need to perform some basic setup. We will need to create a category, make a package, and upload your facts. Let’s log in.

Categories
You will need to create at least one category, under which you will store your rules. Categories are for classification purposes. You will normally want to provide meaningful names like ‘Insurance’ or ‘Discount,’ but for this test instance, we’ll just create ‘MyNewCategory.’ On the left side click on the ‘Administration’ tab, expand the ‘Admin’ list, and then click on ‘Categories’:

cat

Fig 2. cat

Create a category by clicking on ‘New category’ and providing a name.

Packages
A package is a place where rules are stored. It also includes globals and imports of all the facts and other classes we would like to use in our rules–for example, ArrayLists or Iterators. To create a package, expand the ‘Package’ tab and click on ‘Create New’ -> ‘New Package’

Fig 3. pack

Fig 3. pack

You can create a new package by providing its name (our example is myNewPackage) or by importing one from a drl file. In either case, you will need to provide the facts you’re going to use in your rules.

Facts
Next, you will create classes you would like to use in your rules. For this example, I’ll use a Driver and a Car class:

Driver.java
package kijanowski.eu;

public class Driver {

        private String name;
        private int age;
        private Car car;

        public Driver() {}

        public Driver(String name, int age, Car car) {
                this.name = name;
                this.age = age;
                this.car = car;
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }

        public int getAge() {
                return age;
        }

        public void setAge(int age) {
                this.age = age;
        }

        public Car getCar() {
                return car;
        }

        public void setCar(Car car) {
                this.car = car;
        }

}


Car.java
package kijanowski.eu;

public class Car {

        private String color;
        private double value;

        public Car() {}

        public Car(String color, double value) {
                this.color = color;
                this.value = value;
        }

        public String getColor() {
                return color;
        }

        public void setColor(String color) {
                this.color = color;
        }

        public double getValue() {
                return value;
        }

        public void setValue(double value) {
                this.value = value;
        }

}

Compile these java files (if not already done by your IDE) and create an java archive:

$ javac -d . *.java
$ jar cf model.jar kijanowski

Import the new model to your package. From the ‘Packages’ tab click on ‘Create New’ -> ‘Upload new Model jar’:

Fig 4. pack2

Fig 4. pack2

Provide a name and select myNewPackage as the destination package. Provide a path (or click on Browse and navigate) to your facts archive. Finally, click on Upload.

When you choose myNewPackage from the ‘Packages’ tab, you should see the imported facts:

Fig 5. pack3

Fig 5. pack3

Before these facts are available in rules, you need to save this package. Click on ‘Save and validate configuration’.

Rules
Now you can create rules. From the ‘Package’ tab select ‘Create New’ -> ‘New Rule’. Provide a name, choose a category, and select your favorite rule format with myNewPakage as the destination package:

Fig 6. pack4

Fig 6. pack4

A simple example is shown below:

Fig 7. pack5

Fig 7. pack5

Validate and save your rule by first choosing ‘Validate’ and–if all is ok–then ‘Save changes’. Now you can make this package and all its rules available to your applications.
Choose your package and click on ‘Save and validate configuration.’ Before building it, click on ‘Show package source’ to have a look at the whole package. When you’re done looking at the source, choose ‘Build package’. You should be able to access the package under http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/myNewPackage/LATEST and in drl format at http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/myNewPackage/LATEST.drl.

Now let’s create a simple Drools application that will use a package served by Guvnor.

Open Eclipse and create a new Drools project (as described in Introduction into Rule Engines) or use your favorite IDE (don’t forget to add drools-core.jar and mvel.jar to your classpath). Add model.jar to your classpath and create a test class:

package kijanowski.eu;

import org.drools.RuleBase;
import org.drools.WorkingMemory;
import org.drools.agent.RuleAgent;
import java.util.Iterator;

public class GuvnorTest {

        public static final void main(String[] args) {

                RuleAgent agent = RuleAgent.newRuleAgent("/Guvnor.properties");
                RuleBase ruleBase = agent.getRuleBase();

                WorkingMemory workingMemory = ruleBase.newStatefulSession();

                Driver d = new Driver("Jarek", 20, null);
                workingMemory.insert(d);

                workingMemory.fireAllRules();

                for (Iterator i = workingMemory.iterateObjects(); i.hasNext();) {
                        System.out.println(i.next().getClass().getCanonicalName());
                }
        }

}

This time we don’t read a package from the filesystem, but are configuring our rule agent with a properties file. One fact is inserted, rules are fired, and, in the end, we iterate over all facts in the working memory to make sure a Car fact has been inserted. We expect this will happen, don’t we? Check the rule if you’re in doubt. Let’s have a look at the properties file:

url=http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/myNewPackage/LATEST

We provide the url that points to our package. There are a lot more attributes you can provide (read the Guvnor docs for details). When the application is run, you should get following output:

RuleAgent(default) INFO (Wed Jul 23 20:31:28 CEST 2008): Configuring with newInstance=false, secondsToRefresh=-1
RuleAgent(default) INFO (Wed Jul 23 20:31:28 CEST 2008): Configuring package provider : URLScanner monitoring URLs:  http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/myNewPackage/LATEST
RuleAgent(default) INFO (Wed Jul 23 20:31:29 CEST 2008): Applying changes to the rulebase.
RuleAgent(default) INFO (Wed Jul 23 20:31:29 CEST 2008): Adding package called myNewPackage
kijanowski.eu.Driver
kijanowski.eu.Car

This was just a quick introduction into Guvnor. A much more exhaustive description can be found in the Guvnor documentation.

Enable user/password validation

When deploying Guvnor, everyone can access it using the admin username–a password isn’t verified. However, Guvnor is designed to allow access to different users, who may have different skills and rights. Controlling access may be critical. To enable username/password validation, we need to edit Guvnor’s security configuration. This is located in:

$GUVNOR/WEB-INF/components.xml

We will want to set JAAS as the new authorization and authentication service. Comment out:

    

and add:

    

That’s all from the apps side. To configure JBoss AS, add the following to $JBOSS_SERVER/conf/login-config.xml:

    
       
          <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag = "required">
           props/guvnor-users.properties
           props/guvnor-roles.properties
          
       
    

We have chosen the file-based login module. We now need to create two files, where we will provide the admin username, password, and role:

$JBOSS_SERVER/conf/props/guvnor-users.properties
admin=admin123
$JBOSS_SERVER/conf/props/guvnor-roles.properties
admin=admin

We have now created an ‘admin’ user with the password ‘admin123′ and its role is ‘admin’.

You may want to have all your users in a database or directory. For all available login modules, have a look at this wiki.

In the current Drools 5M1 release, only the admin role is supported. You may want to have a look at drools-guvnor/src/main/java/org/drools/guvnor/server/security/RoleTypes.java for other roles implemented in future releases.

14 responses to “JBoss Drools how-to: Tuning Guvnor, part 1”

  1. Michael Neale says:

    Thats a really nice writeup Jaroslaw ! Very thorough.

  2. Kristjan says:

    Thanks for this walk through :)

  3. Sudhish says:

    hi Jaroslaw Kijanowski,

    I downloaded the drools guvnor application and made changes to the UI part built using GWT. But I am not able to build the application using the GWT build script provided with the application. I am getting the following error.
    [taskdef] Could not load definitions from resource de/samaflost/gwttasks/antlib.xml. It could not be found. Could you please help me in solving the issue?
    thanks and regards
    Sudhish

  4. Sudhish says:

    hi Jaroslaw Kijanowski,
    Can you please help me in customizing the Drools Guvnor application. I have made changes in the classes inside the package client and exported the application into the Jboss server, but the changes i made are not getting reflected. what could be wrong with the aplication? Am I doing anything wrong? Do I need to build the application using any scripts??

  5. Jaroslaw says:

    Hi Sudhish,
    could you please ask both questions in the Drools user mailing list (http://www.jboss.org/drools/lists.html) again? This way you reach a wider audience and get faster replies.

  6. David Croft says:

    There is a minor typo in the tutorial. Here is the corrected text:

    props/guvnor-users.properties
    props/guvnor-roles.properties

  7. David Croft says:

    Here is another attempt at it with the angle brackets escaped:



    flag = "required">
    props/guvnor-users.properties
    props/guvnor-roles.properties

  8. David Croft says:

    Another attempt:



    flag = "required">
    props/guvnor-users.properties
    props/guvnor-roles.properties


  9. Jarek Kijanowski says:

    Right, thanks David, this is the way to go. Don’t know why the full content hasn’t been displayed.

  10. Jagan says:

    Thanks for a nice and simple tutorial.I am new to rule engines and tried to do this tutorial.when I ran the GuvnorTest class in eclipse got “Nullpointer exception”.I placed Guvnor.properties file in the same directory as test class.Could you please let me know Where exactly this properties file should be placed?

  11. Adrian Bell says:

    Pretty good tutorial this, but has anyone got it to work?

    Regards

  12. Jarek Kijanowski says:

    @Jagan:
    Put the file in the root of your project. If you have a test class com.sample.Test which is compiled into /myApp/classes/com/sample/Test.class, then put the properties file into /myApp/classes.

    @Adrian:
    Yeah, I got it working ;) What’s exactly failing? Please note that this is for Drools5 M1. BTW, we’re expecting to have a CR1 the next days.

  13. VenkataRamesh says:

    I am getting the following exceptions. please help me
    RuleAgent(default) INFO (Thu Mar 05 14:36:00 IST 2009): Configuring with newInstance=false, secondsToRefresh=-1
    RuleAgent(default) INFO (Thu Mar 05 14:36:00 IST 2009): Configuring package provider : URLScanner monitoring URLs: http://localhost:8080/drools-guvnor/org.drools.guvnor.Guvnor/package/kijanowski.eu/LATEST
    RuleAgent(default) EXCEPTION (Thu Mar 05 14:36:01 IST 2009): org.drools.rule.Rule; Serializable incompatible with Externalizable. Stack trace should follow.
    java.io.InvalidClassException: org.drools.rule.Rule; Serializable incompatible with Externalizable
    at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.skipCustomData(Unknown Source)
    at java.io.ObjectInputStream.readExternalData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.skipCustomData(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.skipCustomData(Unknown Source)
    at java.io.ObjectInputStream.readExternalData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at org.drools.rule.Package.readExternal(Package.java:176)
    at java.io.ObjectInputStream.readExternalData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at org.drools.agent.HttpClientImpl.fetchPackage(HttpClientImpl.java:59)
    at org.drools.agent.URLScanner.readPackage(URLScanner.java:138)
    at org.drools.agent.URLScanner.getChangeSet(URLScanner.java:110)
    at org.drools.agent.URLScanner.loadPackageChanges(URLScanner.java:88)
    at org.drools.agent.RuleAgent.checkForChanges(RuleAgent.java:330)
    at org.drools.agent.RuleAgent.refreshRuleBase(RuleAgent.java:298)
    at org.drools.agent.RuleAgent.configure(RuleAgent.java:284)
    at org.drools.agent.RuleAgent.init(RuleAgent.java:208)
    at org.drools.agent.RuleAgent.newRuleAgent(RuleAgent.java:176)
    at org.drools.agent.RuleAgent.newRuleAgent(RuleAgent.java:148)
    at org.drools.agent.RuleAgent.newRuleAgent(RuleAgent.java:216)
    at kijanowski.eu.GuvnorTest.main(GuvnorTest.java:12)

    Regards

    Venkata Ramesh

  14. Jarek Kijanowski says:

    Most probably you’re using incompatible versions of Drools and Guvnor. They must be the same, so if you use Drools 5 CR1, then you have also to use Guvnor 5 CR1.

    Yes, CR1 is out :)

    Moreover please ask these kind of questions in the rules user list (http://jboss.org/drools/lists.html) so everyone can benefit.