Tutorial

Introduction

In this tutorial, we’ll see how to use the MRules rule engine, by performing the necessary steps:

  • Defining requirements
  • Concieving Object model
  • Configuring the engine. We’ll write here the configuration for the two XML grammar
    • Simple
    • Complete
  • Executing the engine in a multi thread environment
    • Writing code allowing to read configuration and to execute rules.
    • Writing test code allowing to generate business case and simulate concurrent environment.

Business case

The goal here is to illustrate usage. So a case with a relatively simple configuration will be studied.

When subscribing to a web site, a user will recieve a welcome gift. The gift is chosen depending on user’s characteristics. Criterias and gifts evolve on a regular basis, so the rule engine will be responsible to read relevant data and attribute the correct gift.

User characteristics are:

  • Birth date, from which is deduced his age
  • Gender
  • Town

Rules are:

  • A man less than 25 years old recieves a t-shirt
  • A woman less than 30 years old recieves a swimsuit
  • A user more than 60 years old recieves a foie gras box
  • Other users recieve a bottle of wine

Object model

The object model is really simple here. A single Java bean will hold input and output data.

Rules configuration

Simple XML grammar configuration is the following:

Complete XML grammar configuration is the following:

Testing in a concurrent environment

Preparing

First, we’ll write two utility classes allowing to simulate multi threaded environment and to generate test cases.

The Rules Runner is an abstract class allowing to execute the rule engine on a list of beans. Implementations will hold the code dedicated to MRules invocation.

They might then be calles by a batch, a Servlet or a unit test like here, it does not change their purpose.

The RuleTestThread is a Thread which will create the test cases, execute the rule engine using an AbstractRulesRunner  implementation and test results. If an Exception is thrown, it will be stored for further usage. This class will allow to simulate the concurrent environment.

Implementation

Here, we’ill write the code which will effectively read configuration and execute the engine. Three possible implementations are proposed and compared here.

The main goal in this tutorial is to clarify target usage of the Rule Set:

  • The Rule Set instance may (and should) be unique. In that case, it’s shared between all Threads. Configuration reading and compilation phases only have to be performed more than once if configuration is modified.
  • The Execution Context is dedicated to one execution at a time an can’t be shared between processes. However, each Thread instanciates only one context and reuses it, as within it executions are not simultaneous and concurrent.

 

The first implementation allows to read the complete XML grammar, by using the centralized MRulesBuilder utility. Parameters must be provided to the builder, which will be responsible to build once and only once the instance, even if calls are concurrent.

Parameters are the same as when declaring the rule engine as a JNDI resource or injecting it with CDI.

The advantages of this code, even if slighlty more verbose, is that if configuration file is modified, it will be automatically reloaded thanks to the “checkhash” parameter.

 

The second implemetation also allows to read complete grammar, but without using the builder.

A static field is declared in valued at class initialization. This technique guarantees, because of JVM specifications, that the engine building phase (including the compilation phase) will only be performed once.

But if configuration changes, it will not be reloaded, except if a specific system is developped manually.

 

The last implementation allows to read the simple grammar, with the same static field technique.

Since the version 1.4.0 of MRules, the simple grammar allows to specify the context factory to use. Until 1.3.0, a compilation context had to be provided to the factory.

Execution

Launching will be done using a standard JUnit test, which will create 100 Threads per Rules Runner (so 300 in total) and execute them.

Logs show clearly that only 3 compilations are performed, one per Runner.

 

The test project will be available soon for download.