Rules Processing

This chapter shows an example of using the JBoss Drools rules engine with Apache Camel. In this example, we have a list of persons with their ages and salary, and based on some rule we will know if each of them is eligible or not for a loan or a credit. We will consume a CSV file, then we will tokenize it and convert each row to a Java object. After that, we will call the Drools engine using our Java object.

The DRL and CSV Files

The DRL (Drools Rule Language) file is where we define our rules:

package com.drools.camel.sample.model;

import com.drools.camel.sample.model.Person
rule "Is an Eligible User Depending On Age"
	when
		$person: Person( age > 20 , salary > 2000 )
	then
		$person.setEligible(true);
end

rule "Is an Eligible User Depending On Name"
	when
		$person: Person ( firstName  == "Gerald" , lastName  == "Ford" );
	then
		$person.setEligible(true);
end

The first rule will test if the person is older than 20 and his salary is more than 2000 so this person is eligible. The second will test the first name and the last name of the person; if the person is named Gerald Ford then this person is eligible, too.

The CSV file contains the list of persons:

Jimmy,Carter,25,1100
Gerald,Ford,20,1000
John,Kennedy,29,150000
Franklin,Roosevelt,28,20000

Spring Configuration

The Spring file allows us to specify the package where the Camel route is configured.

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring"
	xmlns:broker="http://activemq.apache.org/schema/core"
	xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">


	<camel:camelContext id="camelContext">
		<camel:package>com.drools.camel.sample</camel:package>
	</camel:camelContext>
</beans>

Java Classes

We implemented two Java classes. The first one is to define our model and the second one is to configure our Camel route.

As said before the class Person is our model, each row of our CSV file will be mapped to this class.

@CsvRecord(separator=",", crlf = "WINDOWS")
public class Person
{

   @DataField(pos = 1)
   private String firstName;
   @DataField(pos=2)
   private String lastName;
   @DataField(pos=3)
   private int age;
   @DataField(pos=4)
   private int salary;
   private boolean eligible;
   
   public String getFirstName()
   {
      return firstName;
   }
   public void setFirstName(String firstName)
   {
      this.firstName = firstName;
   }
   public String getLastName()
   {
      return lastName;
   }
   public void setLastName(String lastName)
   {
      this.lastName = lastName;
   }
   public int getAge()
   {
      return age;
   }
   public void setAge(int age)
   {
      this.age = age;
   }
     
   public int getSalary()
   {
      return salary;
   }
   public void setSalary(int salary)
   {
      this.salary = salary;
   }
   public boolean getEligible()
   {
      return eligible;
   }
   public void setEligible(boolean eligible)
   {
      this.eligible = eligible;
   }
   
   public Person()
   {
      super();
      // TODO Auto-generated constructor stub
   }
   public Person(String firstName, String lastName, int age, int salary, boolean eligible)
   {
      super();
      this.firstName = firstName;
      this.lastName = lastName;
      this.age = age;
      this.salary = salary;
      this.eligible = eligible;
   }
    @Override
   public String toString()
   {
      // TODO Auto-generated method stub
      return this.firstName +" "+this.lastName +" Age: "+this.age+" Eligible: "+this.eligible;
   }
   
}

The class below is where we configure our Camel route.

public class CamelDroolsContext extends RouteBuilder
{
   private static Logger log = Logger.getLogger(CamelDroolsContext.class);
   @Override
   public void configure() throws Exception
   {

      onException(IllegalArgumentException.class)
            .maximumRedeliveries(2)
            .handled(true)
            .log("*** IllegalArgumentException: The data format doesn't match with the model one ${body}");
      from("file://target/droolsExample?fileName=TestDrools.txt").split(body().tokenize("\n")).unmarshal().bindy(
            BindyType.Csv, "com.drools.camel.sample.model").process(new Processor()
      {
         @SuppressWarnings("unchecked")
         public void process(Exchange exchange) throws Exception
         {
            launchDroolsRules((List<Map<String, Person>>) exchange.getIn().getBody());
         }

      }).to("mock:result");

   }

   public static void launchDroolsRules(List<Map<String, Person>> persons) throws Exception
   {
      KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
      knowledgeBuilder.add(ResourceFactory.newClassPathResource("TestRules.drl"), ResourceType.DRL);
      KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
      if (knowledgeBuilder.hasErrors())
      {
         System.err.println(knowledgeBuilder.getErrors().toString());
      }
      kbase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());

      StatelessKnowledgeSession ksession = kbase.newStatelessKnowledgeSession();

      for (Map <String, Person> person : persons)
      {
         for (String key : person.keySet())
         {

            Person man=person.get(key);
            log.trace("Before Running Drools: Person: " +man.toString());
            log.trace("Running Drools");
            ksession.execute(person.get(key));
            log.trace("After Running Drools: Person: " +man.toString());
         }
      }
   }
}

The first method is to configure our route, we have override the configure method of RouteBuilder class. The second one is to launch our Drools rules, we built a knowledge session and then for each person we have in the CSV file we execute the drl file.

Result

Here is the result we get after running the example.

Before Running the Drools: Person: Jimmy Carter Age: 25 Eligible: false
Running Drools
After Running the Drools: Person: Jimmy Carter Age: 25 Eligible: false
Before Running the Drools: Person: Gerald Ford Age: 20 Eligible: false
Running Drools
After Running the Drools: Person: Gerald Ford Age: 20 Eligible: true
Before Running the Drools: Person: John Kennedy Age: 29 Eligible: false
Running Drools
After Running the Drools: Person: John Kennedy Age: 29 Eligible: true
Before Running the Drools: Person: Franklin Roosevelt Age: 28 Eligible: false
Running Drools
After Running the Drools: Person: Franklin Roosevelt Age: 28 Eligible: true