JBoss.orgCommunity Documentation

Drools Guvnor

5.0.0.MR2


1. The Guvnor (Business Rule Management System)
1.1. Introduction
1.1.1. What is a BRMS?
1.1.2. Features outline
1.2. Administration guide
1.2.1. Installation
1.2.2. Database configuration
1.2.3. Security - Authentication and basic access
1.2.4. Fine grained permissions and security
1.2.5. Data management
1.3. Architecture
1.3.1. Building from source
1.3.2. Re-usable components
1.3.3. Versioning and Storage
1.3.4. Contributing
1.4. Quick start guide
1.4.1. Quick start guide
1.4.2. BRMS concepts
1.4.3. The fact model (object model)
1.4.4. The business user perspective
1.4.5. Deployment: Integrating rules with your applications
1.4.6. WebDAV and HTTP
Index

This section introduces the BRMS. See the other relevant sections for installation, usage and administration.


BRMS stands for Business Rules Management System.

This is the component of JBoss Rules which covers rule management, storage, editing and deployment. A Web based user interface is provided so this tool can be used by people who don't work in IDEs or text editors, but it is intended for a wide audience.

A BRMS allows people to manage rules in a multi user environment, it is a single point of truth for your business rules, allowing change in a controlled fashion, with user friendly interfaces.

This chapter covers installation and administration issues of the BRMS.

The BRMS is a web application that can run in multiple environments, and be configured to suit most situations. There is also some initial setup of data, and export/import functions covered.

Installation for most people is very simple. The BRMS application is deployed as a .war file, which can be deployed in application servers or servlet containers with little or no configuration if you are happy with the defaults.

When you have downloaded the BRMS distribution (which you can get from http://labs.jboss.com/jbossrules/downloads), you will find the drools-jbrms.war file in the zip file. Copy the WAR file into the deployment directory of you app server, and then start your app server. If you need to customize some settings, you can first "explode" (unzip) the war file, and change any configuration settings, and then either zip it up, or deploy it "exploded".

Once the drools-jbrms.war has been placed in the deployment directory, and the application server started, you should navigate to http://localhost/drools-jbrms and check that the BRMS appears. (Obviously substitute the URL for what your application server is configured to).

Once that shows up, you are deployed and ready to go !

The BRMS uses the JCR standard for storing assets (such as rules). The default implementation is Apache Jackrabbit (http://jackrabbit.apache.org/). This includes an out of the box storage engine/database, which you can use as is, or configure to use an existing RDBMS if needed.

When you run the BRMS for the first time (starting up the app server), it will create a database in the [app server directory]/bin/ directory (assuming you used on of the JBoss platforms). There is a repository.xml file, and a repository directory that are automatically created.

The location of the data store should be a secure location, that is backed up. The default location may not be suitable for this, so the easiest way is to set a more suitable location. If you want to change this, please make sure you have stopped the BRMS (ie stopped the app server or undeployed the application).

To change the location, unzip the WAR file, and locate the components.xml file in the WEB-INF directory. This is a JBoss Seam configuration file (Seam is the framework used) which allows various parts of the system to be customized. When you have located the components.xml file, you should see something like the following:

<component name="repositoryConfiguration">
 <!--
  *** This is for configuring the "home" directory for the repository storage. the directory must exist. ***
     <property name="homeDirectory">/home/michael/RulesRepository_001</property>
   -->  

   ...
</component>

Find the component with a name of "repositoryConfiguration" and the property with the name of "homeDirectory".

If you un comment this (as in the example above it is commented out), you can set whatever path you need for the repository data to be stored in. You can also use this to move the repository around. In that case, when you have set the location in the components.xml you can simply move the repository.xml AND the repository directory to the new location that you set in the components.xml.

If there is no repository at the location specified (or in the default location) then the BRMS will create a new empty one.

There are many more options which can be configured in the repository.xml, but for the most part, it is not recommended to change the defaults.

Please note that giving someone access to the BRMS indicates a level of trust. Being able to editing and build rules is providing a great deal of power to a user. Thus you should not open up the BRMS to your entire organisation - but instead to a select few. Use https (http with TLS/SSL) whereever possible (even internally in a companies network this is a good idea). Use this power wisely - this not a "run of the mill" application that provides read/write access to a database, but something much more power. Just imagine you are spider man - with great power comes great responsibility (of course even more so for super man).

Security is configured by using the components.xml file in the war file. To customize this, you will need to unzip the war file, and locate the components.xml file which is in the WEB-INF directory.

The JAAS standard is used as the underlying authentication and authorization mechanism, the upshot of which means its very flexable and able to integrate into most existing environments.

Out of the box, the BRMS shows a login screen, but no security credentials are enforced - the user name is used, but no password check is performed. To enforce authentication, you need to configure it to use an appropriate user directory (you may have Active Directory or similar already).

In the components.xml file, you should located a security configuration section like the following:

<!-- SECURITY CONFIGURATION -->
    
<!-- default (will take any username, useful if you want to keep track of users but not authenticate -->
<security:identity authenticate-method="#{defaultAuthenticator.authenticate}"/>

<!-- NO authentication. This will bypass the login screen when you hit the app. Everyone is "guest" -->
<!-- <security:identity authenticate-method="#{nilAuthenticator.authenticate}"/> -->   

As you can see from above, the 2 "out of the box" options are pass through - which means any user is allowed in, or bypassed, in which case there is no login screen (eg you may be securing access to the app via a web server anyway).

Every application server supports advanced configurations which can work with your existing security infrastructure. The case of JBoss AS will be shown here as an example.

<security:identity authenticate-method="#{authenticator.authenticate}" 
                      jaas-config-name="other"/>

This will use the "other" jaas config in JBoss AS. If you look in [jboss install dir]/server/default/conf you will see a login-config.xml file. This file contains various configs. If you use "other" like the one above, then it will look for users.properties and roles.properties in the conf directory for usernames and passwords to authenticate against (this is fine for a fixed small number of users).

LDAP is perhaps the most popular choice for larger enterprises, so following is an example that works with Active Directory. You can get much more information on how to configure JBoss AS for all scenarios with LDAP from http://wiki.jboss.org/wiki/Wiki.jsp?page=LdapLoginModule and http://wiki.jboss.org/wiki/Wiki.jsp?page=LdapExtLoginModule.

<application-policy name="brms">
    <authentication>
        <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required" >
            <!--
                Some AD configurations may require searching against
                the Global Catalog on port 3268 instead of the usual
                port 389.  This is most likely when the AD forest
                includes multiple domains.
            -->
            <module-option name="java.naming.provider.url">ldap://ldap.jboss.org:389</module-option>
            <module-option name="bindDN">JBOSS\someadmin</module-option>
            <module-option name="bindCredential">password</module-option>
            <module-option name="baseCtxDN">cn=Users,dc=jboss,dc=org</module-option>
            <module-option name="baseFilter">(sAMAccountName={0})</module-option>

            <module-option name="rolesCtxDN">cn=Users,dc=jboss,dc=org</module-option>
            <module-option name="roleFilter">(sAMAccountName={0})</module-option>
            <module-option name="roleAttributeID">memberOf</module-option>
            <module-option name="roleAttributeIsDN">true</module-option>
            <module-option name="roleNameAttributeID">cn</module-option>

            <module-option name="roleRecursion">-1</module-option>
            <module-option name="searchScope">ONELEVEL_SCOPE</module-option>
        </login-module>
    </authentication>
</application-policy>

To use the above, you would put jaas-config-name="brms" in the security:identity tag in the components.xml for the BRMS.

Similar configuration examples can be found for other directory services.

LDAP isn't the final word, you can use JDBC against a database of user name, or you can write your own login module to use any sort of weird and wonderful authentication and authorization systems that you may have to deal with (that would be an extreme case, but its possible). Refer to JBoss AS documentation (or documentation for your existing application server).

The above section talks about establishing identity and access for users. This section talks about granting specific permissions to these users (to control data visibility and access). This can be used to partition data, or to control access for "non power users" which can limit the damage they can do.


A common need and desire of the web interface of Guvnor is to be able to have users of different technical abilities interact with it. Another need is to be able to allocate people different sets of data to "own".

Typically users identities are managed in a centralised directory - application servers can integrate with these directories (eg active directory, LDAP) so users to guvnor can be authenticated without having to create another duplicate identity. It is also possible (thanks to JAAS) to define what users have the "admin" role for Guvnor (note that an Admin user of Guvnor doesn't have to really be a system administrator). Further to this, guvnor augments this identity with data specific permissions, which are managed in Guvnor itself.


Note that the above users identities are not stored in Guvnor, only their permission mappings are which are specific to Guvnor.

There are really 2 system wide roles: Users who are Administrators and users who are not. Easy ! Administrators can see and do anything. Out of the box, the permission system is turned off, and every user is an administrator (this is pretty much how things used to work). There is also a system setting in components.xml that can turn the permissions system on and off (so people can manually override if needs be). A administrator can also give other users admin rights, regardless of their roles in the external directory service.


There are several types of permissions: Per package: Package Administrator ("owns" a package - can deploy etc, but has no administrative rights to the system). Package developer - this permissions allows users to create new items, edit etc - but only at the package level (not deploy). They can also run and create tests. Package readonly - well this one is pretty obvious. Per Category: This is the "interesting" one - as assets (rules) can be tagged with multiple categories, you can use these to assign permissions to an "analyst" type of user. A user can be assigned multiple categories. A user can then edit and view any asset that is tagged in that category (regardless of package). A user that only has category permissions will not be shown any package views or details, and will only see the simple categories view. This allows administrators and managers to control exactly what these users can and can't see. Note that per category permissions can also be set as "read only" so a user can view all the assets in a category, but not make changes to them.


The per category "analist" permissions are quite useful - you can also augment their permissions with a specific package (so on top of their category rights, they can see and play with a particular package - which may be used as a "practice" area, or test area for instance). The above provides a few ways to manage permissions in a coarse or fine grained way, as suits the different types of users.

Everyone loves having their own logo on screen - this is to ensure that the people using the application don't forget who they work for or what product they are using for more then a nanosecond (the consequences of them forgetting are too terrible con contemplate).

To achieve, this, you can "explode" the deployment war file, and locate the JBRMS.html file.

<html>
<head>
  <meta name='gwt:module' content='org.drools.brms.JBRMS'>
  <link rel='stylesheet' href='JBRMS.css'>
  <title>JBoss Business Rules Management System</title>
     <link rel="shortcut icon" href="images/drools.gif" type="image/gif">
     <link rel="icon" href="images/drools.gif" type="image/gif">
 </head>
 <body>
     <div class="headerBarblue"><img src="images/jbossrules_hdrlogo.png" width="279" height="70" /></d
 <!-- This script is the bootstrap stuff that simply must be there; it is sent down uncompressed --> 
  <script language='javascript' src='gwt.js'></script>
  <iframe id='__gwt_historyFrame' style='width:0;height:0;border:0'></iframe>
</body>
</html>

The above is the contents of the JBRMS.html file - it is fairly empty (as most of the work is done by the GWT - the GUI is built dynamically in the browser). The parts you can customise are the style sheet - you can either edit the JBRMS.css (or better yet, take a copy, and change the style to be what you need), the "shortcut icon" (its what shows in the address bar in the browser etc - also change the "icon" link to be the same so it works in IE), and the header logo. The rest should be left as is, to allow the GWT components to be loaded and attached to the page. This html page is loaded only once by the browser when the user accesses the BRMS web GUI.

The best way to customize is to take a copy of the JBRMS.html - and then edit. You can also change the URL by editing the web.xml via the normal means.

This section covers the technical aspects of the Business Rules Management System (BRMS), it is not necessary to use this if you are integrating or an end user of the BRMS application. However, JBoss Rules is open source, so build instructions form part of the manual.

You may want to build from source if you want to re-use components, or embed the application within another.


The above diagram shows the major components of the system and how they integrate and are deployed. The User Guide has more details on the parts that are highly configurable (eg database).

The BRMS is deployed as a war, which provides user interfaces over the web, and provides binary packages via URLs (or files). It utilized the JSR-170 standard for data storage (JCR). JBoss Seam is used as the component framework, and GWT is used as the widget toolkit for constructing the ajax based web user interface.

This section will go over the steps necessary to build various components. Mostly this is automated, but the manual process is described for thoroughness.

Each module has a ready to go and up to date eclipse project configuration, so they can merely be imported into the eclipse workspace. These projects are generated by Maven (mvn eclipse:eclipse to refresh them in case they are wrong or outdated). They have been manually modified to have project dependencies (this means the code can be stepped through when debugging).

Some environment variables are required in eclipse (for Window: >Preferences->Java->Build path->Classpath variables): the M2_REPO, as normal, to point to where Maven downloads shared dependencies. GWT_HOME should point to where you installed GWT. GWT_DEV must point to the platform specific "dev" jar that ships with the version of GWT you have.

How to launch from Eclipse: unit tests can be launched, as normal (in which case only M2_REPO setup is needed, GWT does not need to be downloaded seperately), or it can be launched it in hosted mode using the GWT browser, which is great for debugging (from GUI to back end, the code can be stepped through, and changes made on the fly and simply hit refresh). There is a JBRMS.launch file in in the drools-jbrms directory. To launch the JBRMS in debug mode, open the Run dialog (Run->Run), and then choose JBRMS from the list. Launching this will open a new window, with the BRMS in debug mode, ready to go

Normally

Downloading and debugging the BRMS with GWT is optional, so if there are no GUI issues being worked on then this step can be safely skipped.

If you are reading this, you must be the impatient type who wants to kick the tyres (and light the fires) and have a look around as soon as possible. This section will provide a quick end to end tour of the steps involved (but does not go through the concepts in detail). This assumes you have installed the repository correctly, and are able to access the main login screen.

You can also consult the wiki: http://wiki.jboss.org/wiki/Wiki.jsp?page=RulesRepository for some tutorials and user tips (it IS a wiki, so you can even contribute your own tips and examples and even upload files if you desire !).


The above picture shows the main feature areas of the BRMS.

  • Info: This is the initial screen, with links to resources.

  • Rules: This is the category and business user perspective.

  • Package: This is where packages are configured and managed.

  • Deployment: this is where deployment snapshots are managed.

  • Admin: Administrative functions (categories, statuses, import and export)


Categories allow rules (assets) to be labeled (or tagged) with any number of categories that you define. This means that you can then view a list of rules that match a specific category. Rules can belong to any number of categories. In the above diagram, you can see this can in effect create a folder/explorer like view of assets. The names can be anything you want, and are defined by the BRMS administrator (you can also remove/add new categories - you can only remove them if they are not currently in use).

Generally categories are created with meaningful name that match the area of the business the rule applies to (if the rule applies to multiple areas, multiple categories can be attached). Categories can also be used to "tag" rules as part of their life-cycle, for example to mark as "Draft" or "For Review".


The view above shows the category editor/viewer that is seen when you open an asset. In this example you can see the asset belongs to 2 categories, with a "+" button to add additional items (use the trash can item to remove them). This means that when either category is used to show a list of assets, you will see that asset.

In the above example, the first Category "Finance" is a "top level" category. The second one: "HR/Awards/QAS" is a still a single category, but its a nested category: Categories are hierarchical. This means there is a category called "HR", which contains a category "Awards" (it will in fact have more sub-categories of course), and "Awards" has a sub-category of QAS. The screen shows this as "HR/Awards/QAS" - its very much like a folder structure you would have on your hard disk (the notable exception is of course that rules can appear in multiple places).

When you open an asset to view or edit, it will show a list of categories that it currently belongs to If you make a change (remove or add a category) you will need to save the asset - this will create a new item in the version history. Changing the categories of a rule has no effect on its execution.


The above view shows the administration screen for setting up categories (there) are no categories in the system by default. As the categories can be hierarchical you chose the "parent" category that you want to create a sub-category for. From here categories can also be removed (but only if they are not in use by any current versions of assets).

As a general rule, an asset should only belong to 1 or 2 categories at a time. Categories are critical in cases where you have large numbers of rules. The hierarchies do not need to be too deep, but should be able to see how this can help you break down rules/assets into manageable chunks. Its ok if its not clear at first, you are free to change categories as you go.

The BRMS supports a (growing) list of formats of assets (rules). Here the key ones are described. Some of these are covered in other parts of the manual, and the detail will not be repeated here.

Guided editor style "Business rules": (also known as "BRL format"). These rules use the guided GUI which controls and prompts user input based on knowledge of the object model. This can also be augmented with DSL sentences.

IMPORTANT: to use the BRL guided editor, someone will need to have you package configured before hand.

Also note that there is a guided editor in the Eclipse plug in, most of the details in this section can also apply to it.


The above diagram shows the editor in action. The following description apply to the letter boxes in the diagram above:

A: The different parts of a rule. The "WHEN" part is the condition, "THEN" action, and "(options)" are optional attributes that may effect the operation of the rule.

B: This shows a pattern which is declaring that the rule is looking for a "Driver" fact (the fields are listed below, in this case just "age"). Note the green triangle, it will popup a list of options to add to the fact declaration: you can add more fields (eg their "location"), or you can assign a variable name to the fact (which you can use later on if needs be). As well as adding more fields to this pattern - you can add "multiple field" constraints - ie constraints that span across fields (eg age > 42 or risk > 2). The popup dialog shows the options.

C: The small "-" icons indicate you can remove something - in this case it would remove the whole Driver fact declaration. If its the one below, it would remove just the age constraint.

D: The "+" symbols allow you to add more patterns to the condition or the action part of the rule, or more attributes. In all cases, a popup option box is provided. For the "WHEN" part of the rule, you can choose to add a constraint on a fact (it will give you a list of facts), or you can use another conditional element, the choices which are : "There is no" - which means the fact+constraints must not exist, "There exists" - which means that there exists at least one match (but there only needs to be one - it will not trigger for each match), and "Any of" - which means that any of the patterns can match (you then add patterns to these higher level patterns). If you just put a fact (like is shown above) then all the patterns are combined together so they are all true ("and").

E: This shows the constraint for the "age" field. (Looking from left to right) the green triangle allows you to "assign" a variable name to the "age" field, which you may use later on in the rule. Next is the list of constraint operations - this list changes depending on the data type. After that is the value field - the value field will be one of: a) a literal value (eg number, text), b) a "formula" - in which case it is an expression which is calculated (this is for advanced users) or b) a variable (in which case a list will be provided to choose values from). After this there is a horizontal arrow icon, this is for "connective constraints" : these are constraints which allow you to have alternative values to check a field against, for example: "age is less than 42 or age is not equal to 39" is possibly this way.

F: This shows an "action" of the rule, a rule consists of a list of actions. In this case, we are asserting/inserting a new fact, which is a rejection (with the "reason" field set to an explanation). There are quite a few other types of actions you can use: you can modify an existing fact (which tells the engine the fact has changed) - or you can simply set a field on a fact (in which case the engine doesn't know about the change - normally because you are setting a result). You can also retract a fact. In most cases the green arrow will give you a list of fields you can add so you can change the value. The values you enter are "literal" - in the sense that what you type is what the value is. If it needs to be a calculation, then add an "=" at the start of the value - this will be interpreted as a "formula" (for advanced users only) ! and the calculation will be performed (not unlike a spreadsheet).

G: This is where the rule options live. In this case, only salience is used which is a numeric value representing the rules "priority". This would probably be the most common option to use.


In the above example, you can see it is using a mixture of literal values, and formulas. The second constraint on the "Person" fact, is a formula (in this case it is doing a silly calculation on the persons age, and checking something against their name - both "age" and "name" are fields of the Person fact in this case. In the 3rd line (which says "age is less than .." - it is also using a formula, although, in this case the formula does a calculation and returns a value (which is used in the comparison) - in the former case, it had to return True or False (in this case, its a value). Obvious formulas are basically pieces of code - so this is for experienced users only.

Looking at the "Board" pattern (the second pattern with the horizontal grey bar): this uses a top level conditional element ("There is no") - this means that the pattern is actually looking for the "non existence" of a fact that matches the pattern. Note the "Any of:" - this means that EITHER the "type" field constraint is matched, or the "name" field is matched (to "myname" in the case above). This is what is termed a Multiple field constraint (you can nest these, and have it as complex as you like, depending on how much you want the next person to hate you: Some paraphrased advice: Write your rules in such as way as if the person who has to read/maintain them is a psychopath, has a gun, and knows where you live).


The above dialog is what you will get when you want to add constraints to the Person fact. In the top half are the simple options: you can either add a field straight away (a list of fields of the Person fact will be shown), or you can add a "Multiple field constraint" - of a given type (which is described above). The Advanced options: you can add a formula (which resolves to True or False - this is like in the example above: "age < (age * 2) ...."). You can also assign a Variable name to the Person fact (which means you can then access that variable on the action part of the rule, to set a value etc).

Data enumerations are an optional asset type that technical folk can configure to provide drop down lists for the guided editor. These are stored and edited just like any other asset, and apply to the package that they belong to.

The contents of an enum config are a mapping of Fact.field to a list of values to be used in a drop down. That list can either be literal, or use a utility class (which you put on the classpath) to load a list of strings. The strings are either a value to be shown on a drop down, or a mapping from the code value (what ends up used in the rule) and a display value (see the example below, using the '=').


In the above diagram - the "MM" indicates a value that will be used in the rule, yet "Mini Mal" will be displayed in the GUI.

Getting data lists from external data sources: It is possible to have the BRMS call a piece of code which will load a list of Strings. To do this, you will need a bit of code that returns a java.util.List (of String's) to be on the classpath of the BRMS. Instead of specifying a list of values in the BRMS itself - the code can return the list of Strings (you can use the "=" inside the strings if you want to use a different display value to the rule value, as normal). For example, in the 'Person.age' line above, you could change it to:

 'Person.age' : (new com.yourco.DataHelper()).getListOfAges()

This assumes you have a class called "DataHelper" which has a method "getListOfAges()" which returns a List of strings (and is on the classpath). You can of course mix these "dynamic" enumerations with fixed lists. You could for example load from a database using JDBC. The data enumerations are loaded the first time you use the guided editor in a session. If you have any guided editor sessions open - you will need to close and then open the rule to see the change. To check the enumeration is loaded - if you go to the Package configuration screen, you can "save and validate" the package - this will check it and provide any error feedback.

There are a few other advanced things you can do with data enumerations.

Drop down lists that depend on field values: Lets imagine a simple fact model, we have a class called Vehicle, which has 2 fields: "engineType" and "fuelType". We want to have a choice for the "engineType" of "Petrol" or "Diesel". Now, obviously the choice type for fuel must be dependent on the engine type (so for Petrol we have ULP and PULP, and for Diesel we have BIO and NORMAL). We can express this dependency in an enumerattion as:

 'Vehicle.engineType' : ['Petrol', 'Diesel']
 'Vehicle.fuelType[engineType=Petrol]' : ['ULP', 'PULP' ]
 'Vehicle.fuelType[engineType=Diesel]' : ['BIO', 'NORMAL' ]  

This shows how it is possible to make the choices dependent on other field values. Note that once you pick the engineType, the choice list for the fuelType will be determined.

Loading enums programmatically: In some cases, people may want to load their enumeration data entirely from external data source (such as a relational database). To do this, you can implement a class that returns a Map. The key of the map is a string (which is the Fact.field name as shown above), and the value is a java.util.List of Strings.

public class SampleDataSource2 {

  public Map<String>, List<String>> loadData() {
    Map data = new HashMap();

    List d = new ArrayList();
    d.add("value1");
    d.add("value2");
    data.put("Fact.field", d);

    return data;
 }

}

And in the enumeration in the brms, you put:

=(new SampleDataSource2()).loadData()

The "=" tells it to load the data by executing your code.

Mode advanced enumerations: In the above cases, the values in the lists are calculated up front. This is fine for relatively static data, or small amounts of data. Imagine a scenario where you have lists of countries, each country has a list of states, each state has a list of localities, each locality has a list of streets and so on... You can see how this is a lot of data, and it can not be loaded up. The lists should be loaded dependent on what country was selected etc...

Well the above can be addressed in the following fashion:

      'Fact.field[dependentField1, dependentField2]' : '(new com.yourco.DataHelper()).getListOfAges("@{dependentField1}", "@{dependentField2}")'
    

Similar to above, but note that we have just specified what fields are needed, and also on the right of the ":" there are quotes around the expression. This expression will then be evaluated, only when needed, substituting the values from the fields specified. This means you can use the field values from the GUI to drive a database query, and drill down into data etc. When the drop down is loaded, or the rule loaded, it will refresh the list based on the fields. 'depenentField1' and 'dependentField2' are names of fields on the 'Fact' type - these are used to calculate the list of values which will be shown in a drop down if values for the "field".

Configuring packages is generally something that is done once, and by someone with some experience with rules/models. Generally speaking, very few people will need to configure packages, and once they are setup, they can be copied over and over if needed. Package configuration is most definitely a technical task that requires the appropriate expertise.

All assets live in "packages" in the BRMS - a package is like a folder (it also serves as a "namespace"). A home folder for rule assets to live in. Rules in particular need to know what the fact model is, what the namespace is etc.


The above picture shows the package explorer. Clicking on an asset type will show a list of matches (for packages with thousands of rules, showing the list may take several seconds - hence the importance of using categories to help you find your way around).

So whilst rules (and assets in general) can appear in any number of categories, they only live in one package. If you think of the BRMS as a file system, then each package is a folder, and the assets live in that folder - as one big happy list of files. When you create a deployment snapshot of a package, you are effectively copying all the assets in that "folder" into another special "folder".

The package management feature allows you to see a list of packages, and then "expand" them, to show lists of each "type" of asset (there are many assets, so some of them are grouped together):

The asset types:


From the package explorer you can create new rules, or new assets. Some assets you can only create from the package explorer. The above picture shows the icons which launch wizards for this purpose. If you hover the mouse over them, a tooltip will tell you what they do.


One of the most critical things you need to do is configure packages. This is mostly importing the classes used by the rules, and globals variables. Once you make a change, you need to save it, and that package is then configured and ready to be built. For example, you may add a model which has a class called "com.something.Hello", you would then add "import com.something.Hello" in your package configuration and save the change.


Finally you would "build" a package. Any errors caught are then shown at this point. If the build was successful, then you will have the option to create a snapshot for deployment. You can also view the "drl" that this package results in. WARNING: in cases of large numbers of rules, all these operations can take some time.

It is optional at this stage to enter the name of a "selector" - see the admin section for details on how to configure custom selectors for your system (if you need them - selecters allow you to filter down what you build into a package - if you don't know what they are for, you probably don't need to use them).

For any rule base application, a fact model is needed to drive the rules. The fact model typically overlaps with the applications domain model, but in general it will be decoupled from it (as it makes the rules easier to manage over time).

There are 2 ways to to do this: you can upload jar files containing classes which your application and the rules both use, or you can use models that are declared along with the rules.


When a jar is uploaded, it will add import statements to the package configuration (you can then review and change them).

Using declared models, you will see an editor like the following:


In here you can define types, and add fields (each field has a type). The type of a field is suggested by a list (but this list is not exhaustive):


These fact models can be used like normal fact objects, however the way you create them is different (as they are not on your applications classpath). To create these objects, they are available from the RuleBase instance.

          // Retrieve the generated fact type
        FactType cheeseFact = ruleBase.getFactType( "org.drools.generatedbeans.Cheese" );

        // Create a new Fact instance
        Object cheese = cheeseFact.newInstance();

        cheeseFact.set( cheese,
                        "type",
                        "stilton" );

The "cheese" object above can then be inserted into working memory just like a normal pojo based fact.

Note that the namespace of the declared type is the package namespace where it was declared (in the above case "org.drools.generatedbeans").

Why would you chose declared types over jar files: generally this reinforces the fact that the model "belongs" to the rulebase, rather then the application, and allows the model to have a lifecycle separate from the application. It also removed the hassle of keeping jar files in sync between rules and the applications that use the rules.

Its all very interesting to manage rules, but how to you use or "consume" them in your application? This section covers the usage of the RuleAgent deployment component that automates most of this for you.

The rule agent is a component which is embedded in the core runtime of the rules engine. To use this, you don't need any extra components. In fact, if you are using the BRMS, your application should only need to include the drools-core dependencies in its classpath (drools and mvel jars only), and no other rules specific dependencies.

Note that there is also a drools-ant ant task, so you can build rules as part of an ant script (for example in cases where the rules are edited in the IDE) without using the BRMS at all - the drools-ant task will generate .pkg files the same as the BRMS.

Once you have "built" your rules in a package in the BRMS (or from the ant task), you are ready to use the agent in your target application.

To use the rule agent, you will use a call in your applications code like:

RuleAgent agent = RuleAgent.newRuleAgent("/MyRules.properties");     
RuleBase rb = agent.getRuleBase(); 
rb.newStatefulSession.... 
//now assert your facts into the session and away you go !

IMPORTANT: You should only have one instance of the RuleAgent per rulebase you are using. This means you should (for example) keep the agent in a singleton, JNDI (or similar). In practice most people are using frameworks like Seam or Spring - in which case they will take care of managing this for you (in fact in Seam - it is already integrated - you can inject rulebases into Seam components). Note that the RuleBase can be used multiple times by multiple threads if needed (no need to have multiple copies of it).

This assumes that there is a MyRules.properties in the root of your classpath. You can also pass in a Properties object with the parameters set up (the parameters are discussed next).

The following shows the content of MyRules.properties:

##
## RuleAgent configuration file example
##

newInstance=true
file=/foo/bar/boo.pkg /foo/bar/boo2.pkg
dir=/my/dir
url=http://some.url/here http://some.url/here
localCacheDir=/foo/bar/cache
poll=30


name=MyConfig

You can only have one type of key in each configuration (eg only one "file", "dir" etc - even though you can specify multiple items by space separating them). Note also, instead of a discrete properties file, you can construct a java.utils.Properties object, and pass it in to the RuleBase methods.

Referring to the above example, the "keys" in the properties are:

Following shows the deployment screen of the BRMS, which provides URLs and downloads of packages.


You can see the "Package URI" - this is the URL that you would copy and paste into the agent .properties file to specify that you want this package. It specifies an exact version (in this case to a snapshot) - each snapshot has its own URL. If you want the "latest" - then replace "NewSnapshot" with "LATEST".

You can also download a .pkg file from here, which you can drop in a directory and use the "file" or "dir" feature of the RuleAgent if needed (in some cases people will not want to have the runtime automatically contact the BRMS for updates - but that is generally the easiest way for many people).

The drools execution server (drools-server) module is a war which you can deploy to execute knowledgebases (rulebases) remotely for any sort of client application. This is not limited to JVM application clients, but any technology that can use HTTP, and either XML or JSON. Currently this execution server is for stateless sessions (which also makes it easy to scale out).

A "restful" style of interface is provided, with URLs defining what knowledgebase is being accessed. Client applications then execute knowledgebases remotely via HTTP(S). The rule execution server uses the rule agent described in the sections above.

drools-server is a war file, which can be deployed in a application server (such as JBoss AS). As the service is stateless, it is possible to have have as many of these services deployed as you need to serve the client load. The war file should be expanded to a folder for deployment (which will be clear later) - so you can deploy this as a folder called drools-server.war.

Once the war has been deployed, you should be able to go to http://localhost:8080/drools-server and see a page like the above (obviously substitute a correct server address). The page shown should provide information on how to use it, and indicates that it is healthy.

To configure a "knowledgebase" - you create a properties file with a rule agent configuration in it (see the section above for details on the options in the rule agent configuration). The name of this properties file will be the name in the URL that you use to access this servive. So lets take the example of teamallocation.properties: an agent configuration for a service that will allocated some piece of work to a team. teamallocation.properties should contain details on what packages are to be loaded, and from where.

Place teamallocation.properties in the WEB-INF/classes directory in the war directory (and restart the server if needed). Importantly, you will ALSO need any jar files that your rules need placed in the WEB-INF/lib directory of each execution server instance (eg your model, if you are using pojo models, or supporting classes if needed - you may not need any). Typically if you are using the execution server, your client code will not use a object model jar to talk to the service so

Once this is done, the server is accessed via a url of the pattern: http://your-server/drools-server/knowledgebase/{agent configuration name}. So in the example above it would be:

http://your-server/drools-server/knowledgebase/teamallocation

You can see from this that you can have as many agents configured as you like, perhaps for many concurrent versions of knowledgebases.

Consuming the service is quite simple, you need to choose to use either XML or JSON. By default XML is used, but by setting the Content-Type HTTP header to application/json, JSON will be used (JSON can be more performant in some circumstances).

Client libraries: one of the nice things about a REST service is that no special client libraries are required, regardless of the langugae used. In java however, Apache commons "HttpClient" is recommended as an easier API to use then the defaults. Only HTTP is required (of course https can be used for secure transport if on an untrusted network).

A sample request:

<knowledgebase-request>
  <globals>
    <named-fact>
      <id>myglobal</id>
      <fact class="org.drools.server.ExampleFact">
        <carType>Saab</carType>
        <carPrice>42</carPrice>
      </fact>
    </named-fact>
  </globals>
  <inOutFacts>
    <named-fact>
      <id>myfact</id>
      <fact class="org.drools.server.ExampleFact">
        <carType>BMW</carType>
        <carPrice>50</carPrice>
      </fact>
    </named-fact>
  </inOutFacts>
  <inFacts>
    <anon-fact>
      <fact class="org.drools.server.ExampleFact">
        <carType>Audi</carType>
        <carPrice>55</carPrice>
      </fact>
    </anon-fact>
    <anon-fact>
      <fact class="org.drools.server.ExampleFact">
        <carType>Mercedes</carType>
        <carPrice>65</carPrice>
      </fact>
    </anon-fact>
  </inFacts>
</knowledgebase-request>

Elements of the request: note that there are 3 parts: globals, inOutFacts and inFacts. Both globals and inOutFacts are returned in the response message. Globals and inOutFacts are named (each name must be unique) for this purpose (in the case of globals, the name of the global is the name used in the rules). The "id" tag is used for the name. Note that the "fact" tag refers to a fact as used by the knowledgebase - the fields inside that enclosing tag are defined by the fact class itself. If a fact class has a nested class, then the data for that nested data would show up as <nestedFactFieldName> - where nestedFactFieldName is the name of the field in the "parent" class. Inside that tag are the tags with the values of the fields for that nested data (the class name is not needed as that is derived from the parent fact).

A sample response:

<knowledgebase-response>
  <globals>
    <named-fact>
      <id>myglobal</id>
      <fact class="org.drools.server.ExampleFact">
        <carType>Saab</carType>
        <carPrice>42</carPrice>
      </fact>
    </named-fact>
  </globals>
  <inOutFacts>
    <named-fact>
      <id>myfact</id>
      <fact class="org.drools.server.ExampleFact">
        <carType>BMW</carType>
        <carPrice>50</carPrice>
      </fact>
    </named-fact>
  </inOutFacts>
</knowledgebase-response>

Elements of response: Similar to the request (note the enclosing tags are different) - of course only the global and inOutFacts have their state returned.

JSON: (Javascript Object Notation) follows the same basic object graph layout as the requests above. Some notes: in JSON, @class is used to indicate the type of the fact that the rules use. Also, in javascript, associative arrays (maps) are indicated by "{" and "}", and arrays via "[" and "]". In some cases, if there would be a list (array) but only 1 element of data is present, then "[" will not be shown. eg {"a" : "b"} can have the same meaning as [{"a" : "b"}] in results.

A sample request:

{"knowledgebase-request":
{"globals":{"named-fact":{"id":"myglobal","fact":{"@class":"org.drools.server.ExampleFact","carType":"Saab","carPrice":42}}},
"inOutFacts":{"named-fact":{"id":"myfact","fact":{"@class":"org.drools.server.ExampleFact","carType":"BMW","carPrice":50}}},
"inFacts":{"anon-fact":[{"fact":{"@class":"org.drools.server.ExampleFact","carType":"Audi","carPrice":55}},{"fact":{"@class":"org.drools.server.ExampleFact","carType":"Mercedes","carPrice":65}}]}}}

A sample response:

{"knowledgebase-response":
{"globals":{"named-fact":{"id":"myglobal","fact":{"@class":"org.drools.server.ExampleFact","carType":"Saab","carPrice":42}}},
"inOutFacts":{"named-fact":{"id":"myfact","fact":{"@class":"org.drools.server.ExampleFact","carType":"BMW","carPrice":50}}}}}

Following is an example code snippet showing how a knowledgebase is accessed using JSON from Ruby:

    require 'json'
    http = Net::HTTP.new('localhost', 8080)
    path = "/drools-server/knowledgebase/teamallocation"
    post_data = {"knowledgebase-request" => {                     
                  :globals => {"named-fact" => [{:id => "a", :fact => {"@class" => "teamallocation.Assignment"}}]},
                  :inFacts => {"anon-fact" => [{:fact => {"@class" => "teamallocation.Claim", "value" => 150}}]},
                  :inOutFacts => {"named-fact" => [{:id => "x", :fact => {"@class" => "teamallocation.Team", "specialty" => "FATAL"}},
                                                   {:id => "y", :fact => {"@class" => "teamallocation.Team"}}]}
                                            }                    
                 }
    headers = {
      "Content-Type" => "application/json"
    }
    resp, data = http.post(path, post_data.to_json, headers)
    
    
    answer = JSON.parse(data)
    #digging out the results:
    puts answer["knowledgebase-response"]["globals"]["named-fact"]["fact"]["teamName"]
    #if there is more then one fact, they are a list
    puts answer["knowledgebase-response"]["inOutFacts"]["named-fact"][0]["fact"]["specialty"]