How to call external function from drools drl files

    2 Votes

In this problem statement we are going to demonstrate "Calling external functions from Drools drl file". Depending upon the city and the kind of product (Combination of City and Product), rule should calculate the local tax related to that city. We have created a drools project for the above problem statement and have used 2 drl files. I have taken two cities in consideration(Chicago and Boston) and 4 types of products (GROCERIES, MEDICINES, WATCHES, LUXURY_GOODS)

The taxes on Medicines in both the cities I have considered is taken zero considering our new government doesn’t take taxes on medicines.

Before going into external method invocation, we will start with a simple example. For groceries, I have assumed tax as 2$ in Chicago and 1$ in Boston. I have used the same selling price to demonstrate different outputs.

Here is the model to hold the each itemType:

package com.sample;
import java.math.BigDecimal;

public class ItemCity {

public enum City {
Chicago, Boston
}

public enum Type {
GROCERIES, MEDICINES, WATCHES, LUXURY_GOODS
}

private City purchaseCity;
private BigDecimal sellPrice;
private Type typeofItem;
private BigDecimal localTax;

public City getPurchaseCity() {
return purchaseCity;
}

public void setPurchaseCity(City purchaseCity) {
this.purchaseCity = purchaseCity;
}

public BigDecimal getSellPrice() {
return sellPrice;
}

public void setSellPrice(BigDecimal sellPrice) {
this.sellPrice = sellPrice;
}

public Type getTypeofItem() {
return typeofItem;
}

public void setTypeofItem(Type typeofItem) {
this.typeofItem = typeofItem;
}

public BigDecimal getLocalTax() {
return localTax;
}

public void setLocalTax(BigDecimal localTax) {
this.localTax = localTax;
}
}

Now, we will create two drools files for each city. Our first drl file is Chicago.drl (Rule file to execute Rules for Chicago City)

package droolsexample

//list any import classes here.
import com.sample.ItemCity;
import java.math.BigDecimal;

//declare any global variables here
dialect "java"
rule "Chicago Medicine Item" when item : ItemCity(purchaseCity == ItemCity.City.Chicago, typeofItem == ItemCity.Type.MEDICINES) then BigDecimal tax = new BigDecimal(0.0); item.setLocalTax(tax.multiply(item.getSellPrice())); end rule "Chicago Groceries Item" when item : ItemCity(purchaseCity == ItemCity.City.Chicago, typeofItem == ItemCity.Type.GROCERIES) then BigDecimal tax = new BigDecimal(2.0); item.setLocalTax(tax.multiply(item.getSellPrice())); end

Now we will create our second rule file, Boston.drl (DRL file to execute rules for Boston City).

package droolsexample

//list any import classes here.
import com.sample.ItemCity;
import java.math.BigDecimal;

//declare any global variables here
dialect "java"

rule "Boston Medicine Item"
when
     item : ItemCity(purchaseCity == ItemCity.City.Boston, typeofItem == ItemCity.Type.MEDICINES)
then
     BigDecimal tax = new BigDecimal(0.0);
     item.setLocalTax(tax.multiply(item.getSellPrice()));
end


rule "Boston Groceries Item"
when
      item : ItemCity(purchaseCity == ItemCity.City.Boston, typeofItem == ItemCity.Type.GROCERIES)
then
     BigDecimal tax = new BigDecimal(1.0);
     item.setLocalTax(tax.multiply(item.getSellPrice()));
end


I have written the drl files based on city as it gives me flexibility to add n number of rule files later, if new cities are being added. To demonstrate that all rules are getting triggered from my rule files, I have used two item types (MEDICINES & GROCERIES) where medicine is tax free and groceries is taxed as per the city.

My test class which loads the rule files and insert the facts into the session and gives me the output is Droolstest.java file.

package com.sample;

import java.math.BigDecimal;
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.runtime.StatefulKnowledgeSession;
import com.sample.ItemCity.City;
import com.sample.ItemCity.Type;

/**
* This is a sample class to launch a rule.
*/
public class DroolsTest {

public static final void main(String[] args) {
try {
// load up the knowledge base
KnowledgeBase kbase = readKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

ItemCity item1 = new ItemCity();
item1.setPurchaseCity(City.Chicago);
item1.setTypeofItem(Type.MEDICINES);
item1.setSellPrice(new BigDecimal(10));
ksession.insert(item1);

ItemCity item2 = new ItemCity();
item2.setPurchaseCity(City.Chicago);
item2.setTypeofItem(Type.GROCERIES);
item2.setSellPrice(new BigDecimal(10));
ksession.insert(item2);

ItemCity item3 = new ItemCity();
item3.setPurchaseCity(City.Boston);
item3.setTypeofItem(Type.MEDICINES);
item3.setSellPrice(new BigDecimal(10));
ksession.insert(item3);

ItemCity item4 = new ItemCity();
item4.setPurchaseCity(City.Boston);
item4.setTypeofItem(Type.GROCERIES);
item4.setSellPrice(new BigDecimal(10));
ksession.insert(item4);

ksession.fireAllRules();

System.out.println(item1.getPurchaseCity().toString() + " " + item1.getLocalTax().intValue());
System.out.println(item2.getPurchaseCity().toString() + " " + item2.getLocalTax().intValue());
System.out.println(item3.getPurchaseCity().toString() + " " + item3.getLocalTax().intValue());
System.out.println(item4.getPurchaseCity().toString() + " " + item4.getLocalTax().intValue());
} catch (Throwable t) {
t.printStackTrace();
}
}

private static KnowledgeBase readKnowledgeBase() throws Exception {
    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
    kbuilder.add(ResourceFactory.newClassPathResource("Chicago.drl"), ResourceType.DRL);
    kbuilder.add(ResourceFactory.newClassPathResource("Boston.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.");
}
    KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
    return kbase;
}
}

If you run the above program, the output is as shown below:
Chicago 0
Chicago 20
Boston 0
Boston 10

So for both Chicago and Boston when the item is medicine, the local tax is zero. But if the item is groceries, the tax is as per the city. More rules can be added in the drl files for the other products. Now to our main part, Calling a external function from a drl file.

I am demonstrating how to call a static function from a java file within your DRL file. Creating a class HelloCity.java in the same package com.sample

package com.sample;

public class HelloCity {
public static void writeHello(String name) {
     System.out.println("HELLO " + name + "!!!!!!");
}
}

I then add the import statement in my drl file to call the writeHello method from my drl file. We are going to make few changes to our old Chicago.drl file. First we import "HelloCity" class file to the rule. Then we add code to invoke a function in "HelloCity" class file.

package droolsexample

//list any import classes here.
import com.sample.ItemCity;
import java.math.BigDecimal;
import com.sample.HelloCity;

//declare any global variables here
dialect "java"

rule "Chicago Medicine Item"
when
      item : ItemCity(purchaseCity == ItemCity.City.Chicago, typeofItem == ItemCity.Type.MEDICINES)
then
      BigDecimal tax = new BigDecimal(0.0);
      item.setLocalTax(tax.multiply(item.getSellPrice()));
      HelloCity.writeHello(item.getPurchaseCity().toString());
end

rule "Chicago Groceries Item"
when
     item : ItemCity(purchaseCity == ItemCity.City.Chicago, typeofItem == ItemCity.Type.GROCERIES)
then
     BigDecimal tax = new BigDecimal(2.0);
     item.setLocalTax(tax.multiply(item.getSellPrice()));
end

I ran the program again and the output is as below:
HELLO Chicago!!!!!!
Chicago 0
Chicago 20
Boston 0
Boston 10

We can see the difference in the output compared to our previous result. First line in our output is printed based on external java file method invocation. Advantages of calling a java method is that, we can write any utility/helper function in java and it can be called any time from a drl file.

Popular Videos

communication

How to speak so that people want to listen.

Got a tip or Question?
Let us know

Related Articles

Basic Drools Concepts
Steps to install DROOLS plugin and create DROOLS Project in Eclipse
Creating Drools Knowledgebase, Knowledgesession and Facts
How to debug drools in eclipse with example