How to create time based rules

User Rating: 3 / 5

Star ActiveStar ActiveStar ActiveStar InactiveStar Inactive
 

In this tutorial we will learn how to create time based rules using Drools rules engine. When combined with a timer, a Drools rule can be an useful option, to monitor some attributes and perform some actions accordingly. 

Let's see at first an example of Drools rules  which can be activated on a timer configuration:

rule "Send SMS every 15 minutes"
    timer (cron:* 0/15 * * * ?)
when
    $a : Alarm( on == true )
then
    channels[ "sms" ].insert( new Sms( $a.mobileNumber, "The alarm is still on" );
end

As you can see the timer configuration is equivalent to the well-known cron expression and will re-evaluate the  this rule every 15 minutes. Now let's build an example application which will show how you can monitor an attribute (f.e. the amount of memory of a Server) using a Drool rule,

The following rule, will be evaluated every 5 seconds and will monitor the "memory" attribute of the Server fact. If the value drops below a certain amount (f.e. 1000 MB) a warning is printed, and the event is added to the “global” Event class:


package com.sample
import java.util.Date
import java.util.List
import com.sample.app.Server

global com.sample.app.Event event


rule "Server memory"
dialect "mvel"
timer (cron:0/5 * * * * ?)


when
$server : Server(memory < 1000)
then
System.out.println("Warning low memory detected!");
event.add(new java.util.Date() + " - WARNING: Server " + $server.name + " has low memory " + $server.memory);


end

And here’s the JUnit test class which is going to execute this rule:

package com.sample.app;

import java.util.Date;

import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.impl.ClassPathResource;
import org.drools.runtime.StatefulKnowledgeSession;
import org.drools.runtime.rule.FactHandle;
import org.junit.Test;
 
public class DBRulesTest {

    private FactHandle serverHandle;

    @Test
    public void memoryTest() throws InterruptedException {

        final StatefulKnowledgeSession ksession = createKnowledgeSession();
        Event myevent = new Event();
        ksession.setGlobal("event", myevent);

        final Server node1 = new Server(1500,"server1");
         

        new Thread(new Runnable() {
            public void run() {
                ksession.fireUntilHalt();
            }
        }).start();

        serverHandle = ksession.insert(node1);
        
        int memory = 1500;
        for (int i=0;i<5;i++){
            Thread.sleep(6000);
            memory = memory - 200;
       
            node1.setMemory(memory);
            ksession.update(serverHandle, node1);
            
        }

        ksession.halt();
        System.out.println(myevent.getEvents());
    }

    private StatefulKnowledgeSession createKnowledgeSession() {
        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
        kbuilder.add(new ClassPathResource("myrule.drl", getClass()), ResourceType.DRL);

        if (kbuilder.hasErrors()) {
            if (kbuilder.getErrors().size() > 0) {
                for (KnowledgeBuilderError kerror : kbuilder.getErrors()) {
                    System.err.println(kerror);
                }
            }
        }

        KnowledgeBase kbase = kbuilder.newKnowledgeBase();
        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
        return ksession;
    }

}

As you can see, this example uses the org.drools.runtime.StatefulKnowledgeSession which is the main interface for interacting with the Drools engine. It has methods for inserting, updating, and retracting facts. StatefulKnowledgeSession is also used to set the session's global variables. Probably, the most interesting part of its API is the fireAllRules method, which is used to execute all rules. In our example, since we want to complete the cron timer's functionality, it is necessary to maintain the working memory continually checking if there are activations created to automatically fire them. To implement it we have used the fireUntilHalt() method, which will keep firing the activations created until none remains in the agenda.

Here’s the expected output on the console, which should be triggered, once the memory of the server is set to a value under 1000:

Warning low memory detected!
Warning low memory detected!
Warning low memory detected!

And here’s what has been recorded into the Event class:
[Wed May 01 22:36:15 CEST 2013> WARNING: Server server1 has low memory 900, Wed May 01 22:36:20 CEST 2013> WARNING: Server server1 has low memory 900, Wed May 01 22:36:25 CEST 2013> WARNING: Server server1 has low memory 700]

The Event class contains barely a static ArrayList where we record events:


package com.sample.app;

import java.util.ArrayList;
import java.util.List;

public class Event {

    static List<String> events = new ArrayList();

    public static List<String> getEvents() {
        return events;
    }

    public static void add(String log) {
        events.add(log);
    }
}


Advertisement