16.7. KIE Sessions

16.7.1. Stateless KIE Sessions

A stateless KIE session is a session without inference. A stateless session can be called like a function in that you can use it to pass data and then receive the result back.
Stateless KIE sessions are useful in situations requiring validation, calculation, routing and filtering.

16.7.1.1. Configuring Rules in a Stateless Session

Procedure 16.1. Task

  1. Create a data model like the driver's license example below:
    public class Applicant {
        private String name;
        private int age;
        private boolean valid;
        // getter and setter methods here
    }
    
  2. Write the first rule. In this example, a rule is added to disqualify any applicant younger than 18:
    package com.company.license
    
    rule "Is of valid age"
    when
        $a : Applicant( age < 18 )
    then
        $a.setValid( false );
    end
    
  3. When the Applicant object is inserted into the rule engine, each rule's constraints evaluate it and search for a match. (There is always an implied constraint of "object type" after which there can be any number of explicit field constraints.)
    In the Is of valid age rule there are two constraints:
    • The fact being matched must be of type Applicant
    • The value of Age must be less than eighteen.
    $a is a binding variable. It exists to make possible a reference to the matched object in the rule's consequence (from which place the object's properties can be updated).

    Note

    Use of the dollar sign ($) is optional. It helps to differentiate between variable names and field names.
  4. To use this rule, save it in a file with .drl extension (for example, licenseApplication.drl), and store it in a Kie Project. A Kie Project has the structure of a normal Maven project with an additional kmodule.xml file defining the KieBases and KieSessions. Place this file in the resources/META-INF folder of the Maven project. Store all the other artifacts, such as the licenseApplication.drl containing any former rule, in the resources folder or in any other subfolder under it.
  5. Create a KieContainer that reads the files to be built, from the classpath:
    KieServices kieServices = KieServices.Factory.get();
    
    KieContainer kContainer = kieServices.getKieClasspathContainer();
    This compiles all the rule files found on the classpath and put the result of this compilation, a KieModule, in the KieContainer.
  6. If there are no errors, you can go ahead and create your session from the KieContainer and execute against some data:
    StatelessKieSession kSession = kContainer.newStatelessKieSession();
    
    Applicant applicant = new Applicant( "Mr John Smith", 16 );
    
    assertTrue( applicant.isValid() );
    
    ksession.execute( applicant );
    
    assertFalse( applicant.isValid() );
    Here, since the applicant is under the age of eighteen, their application will be marked as "invalid".
Result

The preceding code executes the data against the rules. Since the applicant is under the age of 18, the application is marked as invalid.

16.7.1.2. Configuring Rules with Multiple Objects

Procedure 16.2. Task

  1. To execute rules against any object-implementing iterable (such as a collection), add another class as shown in the example code below:
    public class Applicant {
        private String name;
        private int age;
        // getter and setter methods here
    }
    
    public class Application {
        private Date dateApplied;
        private boolean valid;
        // getter and setter methods here
    }
    
  2. In order to check that the application was made within a legitimate time-frame, add this rule:
    package com.company.license
    
    rule "Is of valid age"
    when
        Applicant( age < 18 )
        $a : Application()     
    then
        $a.setValid( false );
    end
    
    rule "Application was made this year"
    when
        $a : Application( dateApplied > "01-jan-2009" )     
    then
        $a.setValid( false );
    end
    
  3. Use the JDK converter to implement the iterable interface. (This method commences with the line Arrays.asList(...).) The code shown below executes rules against an iterable list. Every collection element is inserted before any matched rules are fired:
    StatelessKieSession ksession = kbase.newStatelessKnowledgeSession();
    Applicant applicant = new Applicant( "Mr John Smith", 16 );
    Application application = new Application();
    assertTrue( application.isValid() );
    ksession.execute( Arrays.asList( new Object[] { application, applicant } ) );
    assertFalse( application.isValid() );
    

    Note

    The execute(Object object) and execute(Iterable objects) methods are actually "wrappers" around a further method called execute(Command command) which comes from the BatchExecutor interface.
  4. Use the CommandFactory to create instructions, so that the following is equivalent to execute( Iterable it ):
    ksession.execute( CommandFactory.newInsertIterable( new Object[] { application, applicant } ) );
    
  5. Use the BatchExecutor and CommandFactory when working with many different commands or result output identifiers:
    List<Command> cmds = new ArrayList<Command>();
    cmds.add( CommandFactory.newInsert( new Person( "Mr John Smith" ), "mrSmith" );
    cmds.add( CommandFactory.newInsert( new Person( "Mr John Doe" ), "mrDoe" );
    BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
    assertEquals( new Person( "Mr John Smith" ), results.getValue( "mrSmith" ) );
    

    Note

    CommandFactory supports many other commands that can be used in the BatchExecutor. Some of these are StartProcess, Query and SetGlobal.

16.7.2. Stateful KIE Sessions

A stateful session allow you to make iterative changes to facts over time. As with the StatelessKnowledgeSession, the StatefulKnowledgeSession supports the BatchExecutor interface. The only difference is the FireAllRules command is not automatically called at the end.

Warning

Ensure that the dispose() method is called after running a stateful session. This is to ensure that there are no memory leaks. This is due to the fact that knowledge bases will obtain references to stateful knowledge sessions when they are created.

16.7.2.1. Common Use Cases for Stateful Sessions

Monitoring
For example, you can monitor a stock market and automate the buying process.
Diagnostics
Stateful sessions can be used to run fault-finding processes. They could also be used for medical diagnostic processes.
Logistical
For example, they could be applied to problems involving parcel tracking and delivery provisioning.
Ensuring compliance
For example, to validate the legality of market trades.

16.7.2.2. Stateful Session Monitoring Example

Procedure 16.3. Task

  1. Create a model of what you want to monitor. In this example involving fire alarms, the rooms in a house have been listed. Each has one sprinkler. A fire can start in any of the rooms:
    public class Room 
    {
    	private String name
    		// getter and setter methods here
    }
    
    public class Sprinkler 
    {
    	private Room room;
    	private boolean on;
    	// getter and setter methods here
    }
    
    public class Fire 
    {
    	private Room room;
    	// getter and setter methods here
    }
    
    public class Alarm 
    {
    }
    
  2. The rules must express the relationships between multiple objects (to define things such as the presence of a sprinkler in a certain room). To do this, use a binding variable as a constraint in a pattern. This results in a cross-product.
  3. Create an instance of the Fire class and insert it into the session.
    The rule below adds a binding to Fire object's room field to constrain matches. This so that only the sprinkler for that room is checked. When this rule fires and the consequence executes, the sprinkler activates:
    rule "When there is a fire turn on the sprinkler"
    when
        Fire($room : room)
        $sprinkler : Sprinkler( room == $room, on == false )
    then
        modify( $sprinkler ) { setOn( true ) };
        System.out.println("Turn on the sprinkler for room "+$room.getName());
    end
    
    Whereas the stateless session employed standard Java syntax to modify a field, the rule above uses the modify statement. (It acts much like a "with" statement.)