JBoss Drools

JBoss Drools Spreadsheet Example

This example illustrates JBoss Drools Spreadsheet Example. Before proceeding with this article, we assume readers have a basic knowledge about how a Java n-tier application works. We also assume readers have good understanding of JBoss Drools. For more information on JBoss Drools please refer the article JBoss Drools Best Practices.

1. Introduction

As we already know, Drools is a Rule Engine that uses the rule-based approach to decouple logic from the system. The logic is external to the system in the form of rules which when applied to data, results into the decision making. The rules can be written in .drl files or spreadsheets. In this example, we will see how and when to write rules in a Spreadsheet also called as Decision tables.

2. What is Drools Spreadsheet

Spreadsheets or Decision tables, are a concise visual representation for specifying which actions to perform depending on given conditions. We know rules are defined in a .drl file but if you have lots of similar rules with different values you can make use of Drools Spreadsheet.

Rules that share the same conditions with different parameters can be captured in a Spreadsheet. Drools support managing rules in a spreadsheet format. Supported formats are Excel (XLS), and CSV, which means that a variety of spreadsheet programs (such as Microsoft Excel, OpenOffice.org Calc amongst others) can be utilized.

Decision tables also called Spreadsheets, are a way to generate rules driven from the data entered into a spreadsheet. All the usual features of a spreadsheet for data capture and manipulation can be taken advantage of. Drools Decision Tables are excel based decision tables.

3. When to use Drools Spreadsheet

The main advantage of Drools is that the logic can also be changed by a non technical person. But if we look at the .drl file, any modification will also require technical knowledge. As the .drl becomes more complicated, the more difficult it will become for non technical persons like Business Analysts to edit the .drl file. Also frequent changes to the drools file is a cumbersome task. Hence spreadsheet format decision tables is a very good option to use where something is going to be changed frequently by non-programmers.

4. Drools Spreadsheet example

Lets see an example for Drools Spreadsheet here. We would be needing Java 8, Eclipse Oxygen, and Eclipse Drools plugin in order to proceed. We are using Drools libraries version 6.x for this example. In our previous Drools article we have seen how to install Drools eclipse plugin. Using that plugin, we will be seeing an example of Drools Decision table or spreadsheet here.

4.1 Creating a Drools Project

The Drools project can be created in eclipse by clicking on option File-> New-> Other.

Fig 1: Eclipse New Project

Type Drools in the wizard search box and select “Drools Project”. Click Next.

Fig 2: Select Drools Project

Enter project name as “JBossDroolsSpreadsheetExample” and click Next.

Fig 3: Enter project name

Select all the checkboxes and click Next.

Fig 4: Select all checkboxes

You might get a warning if the Drools Runtime is not defined like the one below. If so, click on “Configure Workspace Settings” and proceed with configuring the Drools runtime environment.

Fig 5: Configure Drools Runtime

Select the folder where Drools jar files are downloaded in your local filesystem as explained in previous article.

Fig 6: Select Drools jar folder

After clicking OK, select the drools runtime checkbox and click “Apply and Close”.

Fig 7: Click Apply and Close

Click “Finish” and a Drools project is created in the eclipse workspace.

Fig 8: Click Finish

The Drools project looks the one below.

Fig 9: Drools project structure

As we see, there are sample files created in the Drools project. The project will automatically create a sample .drl file Sample.drl  and a sample xls file Sample.xls, containing a rule. We can als find a java main class DroolsTest to test the rule. We can define the decision tables in an Excel spreadsheet (the .xls file) or a comma separated value (the .csv file) format.

4.2 Writing custom code needed for Drools Spreadsheet example

As we know rules are defined in a .drl file but if we have lots of similar rules with different values we can make use of Drools Decision Tables also called as Drools Spreadsheet. To understand this, lets see an example of Shopping Cart. Once a customer completes his shopping and add all the items to the cart, we will calculate the order price keeping in mind the customer’s attributes.

For example, if the customer has just registered to the site, there will be a 2% discount on the first purchase.

If the customer has a coupon, another 5% discount will be applied on the total price. The coupon code and the percentage amounts may vary. We may also want to add similar rules in future.

Before we start defining the rules in XLS, let’s go through the domain model.

Lets create a package com.myexample and we will be writing the following files to demonstrate our example:

  1. Product.java – Customer will add one or more products to the cart.
  2. Customer.java – It has reference to Cart. The other important attributes are the coupon code and whether the customer is new.
  3. Cart.java – Customer’s cart contain the cart items.
  4. CartItem.java – Each cart item contains product and quantity ordered.
  5. shopping_cart_customer.xls – Contains the shopping cart rule in a spreadsheet format.

Here follows the code as described above.

Customer will add one or more products to the cart.

Product.java

package com.myexample;

public class Product {
	private int price;
	private String desc;

	public Product(String desc, int price) {
		this.desc = desc;
		this.price = price;
	}

	public int getPrice() {
		return price;
	}

	public String getDesc() {
		return desc;
	}

	public String toString() {
		return "product: " + desc + ", price: " + price;
	}
}

Customer has reference to Cart. The other important attributes are the coupon code and whether the customer is new.

Customer.java

package com.myexample;

public class Customer {
	private Cart cart;
	private String coupon;
	private boolean isNew;

	public static Customer newCustomer() {
		Customer customer = new Customer();
		customer.isNew = true;
		return customer;
	}

	public boolean getIsNew() {
		return isNew;
	}

	public void addItem(Product product, int qty) {
		if (cart == null) {
			cart = new Cart(this);
		}

		cart.addItem(product, qty);
	}

	public String getCoupon() {
		return coupon;
	}

	public void setCoupon(String coupon) {
		this.coupon = coupon;
	}

	public Cart getCart() {
		return cart;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Customer new? ").append(isNew).append("\nCoupon: ").append(coupon).append("\n").append(cart);

		return sb.toString();
	}
}

Customer’s cart contain the cart items.

Cart.java

package com.myexample;

import java.util.ArrayList;
import java.util.List;

public class Cart {
	private Customer customer;
	private List cartItems = new ArrayList();
	private double discount;

	public Cart(Customer customer) {
		this.customer = customer;
	}

	public void addItem(Product p, int qty) {
		CartItem cartItem = new CartItem(this, p, qty);
		cartItems.add(cartItem);
	}

	public double getDiscount() {
		return discount;
	}

	public void addDiscount(double discount) {
		this.discount += discount;
	}

	public int getTotalPrice() {
		int total = 0;
		for (CartItem item : cartItems) {
			total += item.getProduct().getPrice() * item.getQty();
		}
		return total;
	}

	public Customer getCustomer() {
		return customer;
	}

	public List getCartItems() {
		return cartItems;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

	public int getFinalPrice() {
		return getTotalPrice() - (int) getDiscount();
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (CartItem cartItem : cartItems) {
			sb.append(cartItem).append("\n");
		}
		sb.append("Discount: ").append(getDiscount()).append("\nTotal: ").append(getTotalPrice())
				.append("\nTotal After Discount: ").append(getFinalPrice());

		return sb.toString();
	}

}

Each cart item contains Product and the quantity ordered.

CartItem.java

package com.myexample;

public class CartItem {
	private Cart cart;
	private Product product;
	private int qty;

	public CartItem(Cart cart, Product product, int qty) {
		this.cart = cart;
		this.product = product;
		this.qty = qty;
	}

	public Product getProduct() {
		return product;
	}

	public int getQty() {
		return qty;
	}

	public String toString() {
		return product + ", qty: " + qty;
	}

}

The rule that we want to write in XLS is:

package com.sample;
import com.myexample.Customer;
import com.myexample.Product;

rule "If Coupon==DISC01, apply 5% discount"
when
$customer:Customer(coupon == "DISC01" )
then
$customer.getCart().addDiscount(((double)$customer.getCart().getTotalPrice())*0.05d);
end

rule "If consumer is new, apply 2% discount"
when
$customer:Customer($customer.isNew())
then
$customer.getCart().addDiscount(((double)$customer.getCart().getTotalPrice())*0.02d);
end

We will now write the above in XLS.

4.3 Decision Table in XLS (shopping_cart_customer.xls)

The decision table or spreadsheet has many sections.

The first section (the header section we can say) will include the package, import classes, functions, variables etc. and some notes that we can write.

  1. RuleSet defines the package
  2. Import specifies the used classes, including static imported functions
  3. Notes can be any text

The second section starts with ‘RuleTable’.

  1. ‘RuleTable’ denotes the start of the decision table.
  2. It groups rules that operate on the same domain object and conditions.
  3. The next line defines column types.
  4. The column types are: NAME, CONDITION and ACTION
  5. We will use NAME to specify a rule name. If we don’t specify a name, it gets auto-generated.
  6. CONDITION defines the rule condition
  7. ACTION is a rule action.

In the next section, we declare the shared objects.

  1. Our shared object here is $customer:Customer.
  2. It exposes the Customer object as a $customer variable.
  3. Note that the first two columns are merged into one column because they share the same type.

In the next line we define the individual conditions or code blocks (in case of actions).

  1. coupon gets converted to customer.getCoupon()
  2. isNew gets converted to customer.getIsNew()
  3. Action contains the code that applies when the condition is satisfied.
    $customer.getCart().addDiscount(((double)$customer.getCart().getTotalPrice())*$param);
  4. $param is substituted by the value provided in the last section

Next, we provide some meaningful description of the column/action.

In the final section, we provide the actual values where each line represents one rule. If a cell doesn’t have a value, then that condition/action is ignored. Please refer the spreadsheet below.

Fig 10: shopping cart rules spreadsheet

4.4 Running the Spreadsheet Example

To run this example, we will have to create a customer object and add some product items to the cart. Then we will load the spreadsheet in XLS and build the KnowledgeBase to create a stateless knowledge session. The spreadsheet needs a special configuration that is encapsulated in the DecisionTableConfiguration class. This configuration specifies the type of spreadsheet and it is then passed to the knowledge builder. Since the rules are in XLS format, we have to use the DecisionTableInputType.XLS object as the input type.

DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
dtconf.setInputType(DecisionTableInputType.XLS);
KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
knowledgeBuilder.add(ResourceFactory.newClassPathResource("shopping_cart_customer.xls"),
                ResourceType.DTABLE, dtconf);

Here is the complete code of DroolsSpreadsheetExample class.

DroolsSpreadsheetExample.java

package com.myexample;

import org.kie.api.io.ResourceType;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.DecisionTableConfiguration;
import org.kie.internal.builder.DecisionTableInputType;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.runtime.StatelessKnowledgeSession;

public class DroolsSpreadsheetExample {
	private static StatelessKnowledgeSession session;

	public static void main(String[] args) throws Exception {
		KnowledgeBase knowledgeBase = createKnowledgeBaseFromSpreadsheet();
		session = knowledgeBase.newStatelessKnowledgeSession();

		Customer customer = new Customer();
		Product p1 = new Product("Laptop", 15000);
		Product p2 = new Product("Mobile", 5000);
		Product p3 = new Product("Books", 2000);
		customer.addItem(p1, 1);
		customer.addItem(p2, 2);
		customer.addItem(p3, 5);
		customer.setCoupon("DISC01");
		session.execute(customer);

		System.out.println("First Customer\n" + customer);

		Customer newCustomer = Customer.newCustomer();
		newCustomer.addItem(p1, 1);
		newCustomer.addItem(p2, 2);
		session.execute(newCustomer);

		System.out.println("*********************************");
		System.out.println("Second Customer\n" + customer);
	}

	private static KnowledgeBase createKnowledgeBaseFromSpreadsheet() throws Exception {
		DecisionTableConfiguration dtconf = KnowledgeBuilderFactory.newDecisionTableConfiguration();
		dtconf.setInputType(DecisionTableInputType.XLS);
		KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
		knowledgeBuilder.add(ResourceFactory.newClassPathResource("shopping_cart_customer.xls"), ResourceType.DTABLE,
				dtconf);
		if (knowledgeBuilder.hasErrors()) {
			throw new RuntimeException(knowledgeBuilder.getErrors().toString());
		}
		KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
		knowledgeBase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());
		return knowledgeBase;
	}
}

The complete eclipse code structure looks like the screenshot below:

Fig 11: Complete code structure in eclipse

We can now run the Project using Right Click on DroolsSpreadsheetExample class -> Run As -> Java Application. Please see the output as below:

Fig 12: Running the Spreadsheet example

This is the Output Console.

Fig 13: Eclipse output console

5. Download the Eclipse Project

This example illustrates JBoss Drools Spreadsheet example with code sample.

Download
You can download the full source code of this example here: JBossDroolsSpreadsheetExample

Neha Goel

Neha holds a Bachelors degree in Computer Science and Engineering. Currently she is working as a Sr. Programmer Analyst for a client in USA and has a total of 9+ years of Java/J2EE experience.Her expertise includes participation in all stages of SDLC. She has experience with multiple web based and enterprise based applications. She has a very impressive understanding in Object oriented architecture, analysis, design and software development using latest technologies like Java, J2EE , Restful Services, Spring, Hibernate, JDBC, JSP, Servlets, GWT, ATG etc.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button