Donnerstag, 23. Mai 2013

Drools Post 2 - The first Drool rule

I said, I will use Eclipse as IDE (or more precisely I will use Spring Tool Suite (STS) because I am using Spring quite often). Besides, Maven is required. Now lets start.

I just installed the JBoss Drools Plugin using the update site (http://download.jboss.org/drools/release/5.5.0.Final/org.drools.updatesite/). As you can see I am using 5.5.0.Final and not 6.0.0 because currently it has BETA status. Also there seems to be some problems when using Java 7, because the plugin is not working with compiled classes of the newest Java version.

After the installation of the plugin there should be some new possibilities. For example when you create a new file in your project, it should be possible to select Drools resources.


Now lets use on of these new possibilites. Lets create a new "Drools Project". I named it "drools-playground". I hate if some framework or library requires the creation of a project. Perhaps I want to use different frameworks or tools within one project... but lets see. We have to create a new Drools Runtime (seems to be some kind of library folder). After this is done we have our project. I just added the Spring nature (which works fine), but after I tried to add a Maven nature to the project nothing works :) - or perhaps I just have to wait.

It seems that Jeremy (from the book) had the same idea, so instead of creating a Drools Project, he creates a maven project from the scratch. I think, this is what I should have done from the beginning.

So lets do it... for me its always interesting which artifacts are required to get started, so I will post them here. Remember this is just to get started with drools:

   <!-- Drools -->
   <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-core</artifactId>
      <version>${drools.version}</version>
   </dependency>
   <dependency>
      <groupId>org.drools</groupId>
      <artifactId>drools-compiler</artifactId>
      <version>${drools.version}</version>
   </dependency>
   <dependency>
      <groupId>org.drools</groupId>
      <artifactId>knowledge-api</artifactId>
      <version>${drools.version}</version>
   </dependency>

I use a property to set the version of drools. Just to make it complete, here is it:

   <properties>
      <drools.version>5.5.0.Final</drools.version>
   </properties>

This is more the way I like it. So whats next, we should start with a small example right.So what do I want to do... well because I am doing lots of stuff in production industry lets use an example from this domain. I want to monitor sensor values. So just a simple rule:
  • when a sensor measures a value greater than 50.0 then show a warning message
I know that it is not this realistic, but I want to start with small things. So what do we need? First of all some sensor and some sensor value. Normally, this would be quite difficult, because we have a sensor that produces data in a predefined time frame (for example each 50ms) and publishs it using TCP/IP or other low or high level protocol. But lets focus on Drools. So I will write a sensor class that produces a random sensor value (in a predefined interval) when requested.

Finally I have to classes SensorValue and SensorSimulator. A sensor value has a timestamp, a value and an id. Just to make it a little bit more interesting the type of the value is generic. The sensor simulator simple creates a sensor value each time his method nextValue() is called. After I cleanup my stuff I will upload the source code, so if anyone out there reads this and wants to use the produced stuff feel free :-).

A first rule

Now the interesting part begins. After doing the necessary POJO and programming stuff, I want to formulate the rule. First a so called DRL file has to be generated. This can either be done in the simple way, by using the Eclipse Text Editor or by using the more comfortable Eclipse PlugIn. Because I installed the plugin and I wanted to see what this plugin can do, I will use this method. I also created a folder src/main/rules to store my rules at this location. So here is the rule:

   package net.meisen.sensor

   import net.meisen.sensor.simulation.SensorValue

   rule "Critical value"

      when
         $v : SensorValue ( value >50.0 )
      then
         System.err.println("Critical sensor value state.");

   end

That was very easy. The rule is formulated using the MVFLEX Expresison Language. It consists of  a package name, the required imports (in my case the POJO) and the rules. A rule contains a when part and a then part.

Getting it to work

Now to test my little rule, I want to use a test. So I have an initialization and the tests.

   public class RuleTest {

      private BasicSensorSimulator<Double> simulator;

      private StatefulKnowledgeSession ksession;

      @Before
      public void init() {
         simulator = new BasicSensorSimulator<Double>();
         simulator.setRange(new DoubleRange(51.0, 100.0));

         KnowledgeBuilder kbuilder = 
            KnowledgeBuilderFactory.newKnowledgeBuilder();
         kbuilder.add(ResourceFactory.newClassPathResource("/rules
            /sensor_value_rule.drl", SensorValue.class), 
            ResourceType.DRL);
         if (kbuilder.hasErrors()) {
            System.err.println(kbuilder.getErrors().toString());
            fail();
         }

         KnowledgeBase kbase = 
            KnowledgeBaseFactory.newKnowledgeBase();        
         kbase.addKnowledgePackages(kbuilder.
            getKnowledgePackages());
         ksession = kbase.newStatefulKnowledgeSession();
      }

      @Test
      public void testRule() {
         ksession.insert(simulator.nextValue());
         ksession.fireAllRules();
         ksession.dispose();
      }

Very simple, but it does what it has to do. I get the expected warning:
Critical sensor value state.

What have I done? First I created a KnowledgeBuilder, which is responsible, as far as I understand, for loading and transforming the rules, so that the knowlege packages become available. These packages are used to create the knowledge base or more precisely to initializes it. Finally, this knowledge base can provide us with session. One important thing is that, in the example, I am using a stateful session. In contradiction to a stateless session such a session remembers changes when rules are fired and checks if such a change result in new evaluation results for already checked rules.

During the test I just insert some data into the session and trigger the rule engine to fire the different rules. Firing a rule means to check if the conditions are fulfilled and if something has to be done.As Jeremy points out: "Whenever you work with a session, it's important to always remember to use the dispose() function to dispose of it when you're done. If you don't, the garbage collector won't be able to free up the resources for you, and that means problems."

Keine Kommentare:

Kommentar veröffentlichen