Writing and executing our first rule

Now that we have our project structure ready, we can write our first rule. For that, we will create a new empty text file. This will be a static resource, therefore, we need to place it in the src/main/resources directory. This text file needs to have the .drl extension so that it can be picked up as a rule file. In the .drl files, we will write as many rules as we want. Now, we will start easy with just one rule.

Let's write our first rule to classify the items based on what they cost us. Our rules.drl text file will look similar to the following:

package myfirstproject.rules
import org.drools.devguide.eshop.model.Item;
import org.drools.devguide.eshop.model.Item.Category;
rule "Classify Item - Low Range"
    when
        $i: Item(cost < 200)
    then
        $i.setCategory(Category.LOW_RANGE);
end

This rule checks for each item that costs less than 200 USD and automatically tags it with a category, in this case, LOW_RANGE. For our shop, it makes sense to differentiate our items in different ranges so that we can apply different discounts and marketing strategies for them. This classification process can be done automatically using rules, which centralize the point where we have this business definition of what LOW_RANGE, MID_RANGE or HIGH_RANGE items they are.

In general, these files will be structured as follow:

  • Package definition: This is the same as in Java, we will declare a package for our rules
  • Imports section: We need to import all the classes that we are going to use in of our rules
  • (Optional) declared types and events: We will look at this in more detail in Chapter 4, Improving our Rule Syntax
  • Rules: (1..N)/Queries (1..N)

Before analyzing further, let's try to execute the rule and see what happens. In order to execute and test our new rule, we need to create a Java class, where we bootstrap the Rule Engine and provide the required information for it to work. We can just create an empty class with a main method, bootstrap the engine, and start using it right away.

In order to do this, we just create an App.java class for this example and place it in the src/main/java/ directory so that it can be compiled by Maven. For this example, we have created the org/drools6/book directory that follows the standard Java package structure, as follows:

package org.drools6.book;
import ...

public class App {
  public static void main( String[] args ) {
    System.out.println( "Bootstrapping the Rule Engine ..." );
    //1) Bootstrapping a Rule Engine Session
    KieServices ks = KieServices.Factory.get();
    KieContainer kContainer = ks.getKieClasspathContainer();
    KieSession kSession =  kContainer.newKieSession();
        
    Item item = new Item("A", 123.0,234.0);  
    System.out.println( "Item Category: " + item.getCategory());
    //2) Provide information to the Rule Engine Context
    kSession.insert(item);
    //3) Execute the rules that are matching
    int fired = kSession.fireAllRules();
    System.out.println( "Number of Rules executed = " + fired );
    System.out.println( "Item Category: " + item.getCategory());
  }
}

As you can see in the previous example, there are three main stages, as shown in the following:

  • Bootstrapping the Rule Engine session: We will look at what KieServices, KieContainer, and KieSession's main responsibilities are in Chapter 3, Drools Runtime. For now, we need to know that KieSession represents a running instance of the Rule Engine with a specific configuration and set of rules. It holds the evaluation algorithm used to match the rules against our domain objects.
  • Letting the Rule Engine know about our data: We are responsible for providing all the information to the engine so that it can operate on it. In order to do this, we use the insert() method on KieSession. We can also remove the information from the Rule Engine context using the delete() method or update the information using the modify() method. We will look at the KieSession operations in Chapter 3, Drools Runtime.
  • If the information that we provided matches with one or more defined rules, we will get Matches. Calling the fireAllRules() method will execute these matches. We will learn more about Matches in Chapter 3, Drools Runtime.
  • You will need to compile the project in order to execute this class and you can do this by executing from the terminal or your IDE, as follows:
    > mvn clean install
    

This will compile and package your project, look for the Build Success output in the terminal. After executing this line, you will find the /target directory containing a myfirst-drools-project-1.0.0.jar jar file that you can use to execute the previously compiled class using the following line:

mvn exec:java -Dexec.mainClass="org.drools6.book.App"

You will see the following output on the terminal:

user$ mvn exec:java -Dexec.mainClass="org.drools6.book.App"

[INFO] Scanning for projects...

[INFO]

[INFO] ------------------------------------------------------------------------

[INFO] Building myfirst-drools-project 1.0.0

[INFO] ------------------------------------------------------------------------

[INFO]

[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) @ myfirstproject ---

Bootstrapping the Rule Engine ...

...

Item Category: NA

Number of Rules executed = 1

Item Category: LOW_RANGE

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 2.945 s

[INFO] Finished at: 2015-04-02T09:55:08+01:00

[INFO] Final Memory: 20M/257M

[INFO] ------------------------------------------------------------------------

As you can see, the rule was executed as the category of the item was changed accordingly with what the rule says. I would encourage you to change the cost of the item to effectively see that the rule will not be executed if the cost is over the value defined in the rule. You can also add more items with different costs to KieSession and see what happens.

Using CDI to bootstrap the Rule Engine

The Contexs and Dependency Injection (CDI) http://www.cdi-spec.org is a set of standardized APIs defined to provide our applications with these features, while it allows us to choose the context and dependency injection container that we want. CDI is now becoming a part of the Java SE specification and its adoption is growing every year. For this reason and due to the Drools Project added a lot of support for the CDI environment, this section briefly shows how to simplify our Hello World example that we wrote in the previous section.

In order to use CDI in our projects, we need to add a couple of dependencies to our project, as follows:

<dependencies>
  ...
  <dependency>
    <groupId>javax.enterprise</groupId>
    <artifactId>cdi-api</artifactId>
  </dependency>
  <dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se-core</artifactId>
  </dependency>
</dependencies>

The javax.enterprise:cdi-api artifact contains all the interfaces defined in the CDI specification and org.jboss.weld.se:weld-se-core is the container that we are going to use, which implements the CDI interfaces. By adding these dependencies, we will be able to @Inject our KieSessions and the Weld container will take care of bootstrapping the Rule Engine for us.

CDI works based on the principle of convention over configuration and it introduced the need to add a new file in src/main/resources/META-INF/ called beans.xml, which will be used to configure how the container has the access to our beans in the projects and some other configurations. Notice the similarity with the kmodule.xml file that we introduced earlier. This is an example content of an empty beans.xml file, which is used by the CDI containers to know the jars that need to be parsed and made available to the container to @Inject beans, as follows:

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

As soon as we have the dependencies to the container and the beans.xml file, the container can scan the class path (meaning our project and its dependencies) and look for beans to inject, we can start using these features in our application.

The following class represents the same simple example that creates a default KieSession with our first rule and then interacts with it.

The following code snippet initializes KieSession via CDI and interacts with it, as follows:

public class App {
    @Inject
    @KSession 
    KieSession kSession;
    
    public void go(PrintStream out){
        Item item = new Item("A", 123.0,234.0);
        out.println( "Item Category: " + item.getCategory());
        kSession.insert(item);
        int fired = kSession.fireAllRules();
        out.println( "Number of Rules executed = " + fired );
        out.println( "Item Category: " + item.getCategory());
    }
    
    public static void main( String[] args )
    {
        // Bootstraping the WELD CDI container
        Weld w = new Weld();
        WeldContainer wc = w.initialize();
        App bean = wc.instance().select(App.class).get();
        bean.go(System.out);
        w.shutdown();
    }
}

Notice that the main(...) method is now bootstrapping the Weld container and for this reason, our bean (App) can inject any bean. In this case, the @KSession annotation is in charge of bootstrapping the engine and creating a fresh instance for us to use. We will look at the annotations provided by the CDI extension in Chapter 3, Drools Runtime.

Consider this as another very valid option to interact with the Drools Rule Engine. If you are working with a Java EE container such as WildFly AS (http://www.wildfly.org), which is constructed on top of a core that is purely based on CDI, this way of working will be the way to go.

For this example, we are using WELD, which is the reference CDI implementation at http://weld.cdi-spec.org. Notice that you can use any other CDI implementation, such as Apache Open Web Beans at http://openwebbeans.apache.org.

Now, in order to understand how the rule is being applied and executed, we should clearly understand the language that we are using to write the rules called Drools Rule Language (DRL). The following section covers a more detailed view of this language. The next chapter will cover the execution side in more detail, explaining what is going on when we bootstrap the rule engine session and how to configure it for different purposes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.144.59