Google

Dec 14, 2012

Drools tutorial with Maven

Drools is a popular open source business rules and work flow engine. It helps you externalize the rules as opposed to embedding within the Java code. The rules are executed in the form of when given a($condition) then execute the ($consequence) This tutorial contains a number of artifacts highlighted below.


Step 1: Create a new Maven project with the standard src/main/java, src/main/resources, src/test/java, etc source folder directories. Create a new src/main/rules folder to define the rules using the "mvel" expresion language.
Update the pom.xml file as shown below with relevant dependencies and also add the build/resources to tell maven that sr/main/rules is a source folder.


 

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.myapp</groupId>
 <artifactId>drools-poc</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>

 <properties>
  <drools.version>5.3.1.Final</drools.version>
  <junit.version>4.7</junit.version>
 </properties>

 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>${junit.version}</version>
  </dependency>
  <!-- drools library -->
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-core</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <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>
  <!-- required for drools and spring integration -->
  <dependency>
   <groupId>org.drools</groupId>
   <artifactId>drools-spring</artifactId>
   <version>${drools.version}</version>
  </dependency>
  <dependency>
   <groupId>com.thoughtworks.xstream</groupId>
   <artifactId>xstream</artifactId>
   <version>1.2.2</version>
  </dependency>
 </dependencies>
 
 
 <build>
    <resources>
        <resource>
           <directory>src/main/rules</directory>
        </resource>
    </resources>
 </build>

</project>



Step 2: Define the domain classes like Applicant.java.

 

package com.company.license;

public class Applicant {

 private Integer id;
 private String name;
 private int age;
 
 public Applicant(Integer id, String name, int age) {
  super();
  this.id = id;
  this.name = name;
  this.age = age;
 }

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 
 @Override
 public String toString() {
  return "name=" + name + ", age=" + age;
 }

}


Step 3: Define the data access interface and implementation classes that retrieves data from a persistent source like file or database. The implementation is simplified to read from a pre-populated in-memory map.

 

package com.company.license;

public interface ApplicantDao {
    Applicant findApplicant(Integer applicantId);
}


The implementation of the above interface.

package com.company.license;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ApplicantDaoImpl implements ApplicantDao {
 
 private static final Map<Integer, Applicant> data = new ConcurrentHashMap<Integer, Applicant>();
 
 static {
  data.put(1, new Applicant(1, "John", 16));
  data.put(2, new Applicant(2, "Peter", 20));
 }

 public Applicant findApplicant(Integer applicantId) {
  Applicant applicant = data.get(applicantId);
  System.out.println("fetched applicant: " + applicant);
  return applicant;
 }
}



Step 4: Define the value object class that captures the user entry via a GUI. For example, ApplicantForm.java as shown below.

package com.company.license;

public class ApplicantForm {
 
 private Integer applicantId;
 private boolean eligible = true; // eligible by default

 public Integer getApplicantId() {
  return applicantId;
 }

 public void setApplicantId(Integer applicantId) {
  this.applicantId = applicantId;
 }

 public boolean isEligible() {
  return eligible;
 }

 public void setEligible(boolean eligible) {
  this.eligible = eligible;
 }
 
 @Override
 public String toString() {
  return "applicantId=" + applicantId + ", eligible=" + eligible;
 }
}

Step 5: Define the business rules via mvel expression language in a separate external file -- applicant-license.drl.

 

package com.company.license;

import com.company.license.ApplicantForm;
import com.company.license.Applicant;
import com.company.license.ApplicantDao;
import com.company.license.ApplicantDaoImpl;

global ApplicantDao applicantDao;
 
rule "is eligible for licence"
when
   $a : ApplicantForm();
   $applicant: Applicant( age < 18 ) from applicantDao.findApplicant($a.getApplicantId());
then
   $a.setEligible( false );
end


Step 6: Finally, the junit test class that makes use of drools to validate applicants. We will create 2 applicants, one with age >= 18, and another one with age < 18, to test the business rules engine (aka expert systems) of drools in action.


 

package com.company.license;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.ResourceFactory;
import org.drools.logger.KnowledgeRuntimeLogger;
import org.drools.logger.KnowledgeRuntimeLoggerFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class ApplicantLicenseTest {

 private KnowledgeBase kbase;

 @Before
 public void setup() {
  KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
  kbuilder.add(ResourceFactory.newClassPathResource("com/company/license/applicant-license.drl"),
    ResourceType.DRL);
  KnowledgeBuilderErrors errors = kbuilder.getErrors();
  if (errors.size() > 0) {
   for (KnowledgeBuilderError error : errors) {
    System.err.println(error);
   }
   throw new IllegalArgumentException("Could not parse knowledge.");
  }
  kbase = KnowledgeBaseFactory.newKnowledgeBase();
  kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());

 }

 @Test
 public void testApplicantLicense() {
  StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
  KnowledgeRuntimeLogger logger = KnowledgeRuntimeLoggerFactory.newFileLogger(ksession, "test");
  KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
  kbase.newStatefulKnowledgeSession();

  ApplicantForm applicant1 = new ApplicantForm();
  applicant1.setApplicantId(1);
  
  ApplicantForm applicant2 = new ApplicantForm();
  applicant2.setApplicantId(2);
    
  ksession.setGlobal("applicantDao", new ApplicantDaoImpl()); // assign the global dao
  
  ksession.insert(applicant1);
  ksession.insert(applicant2);
  ksession.fireAllRules();
  
  ksession.dispose();

  Assert.assertTrue(applicant1.isEligible() == false);//John is not eligible
  Assert.assertTrue(applicant2.isEligible() == true); //Peter is eligible
 }

}



Yo may also like:

Drools with Decision tables (Excel spreadsheet)
Drools example with spreadsheets

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home