spring boot

Drools – Invoke KIE Server API From Spring Boot App

The article shows how to invoke the Drools KIE server exposed REST API and execute business rules from within the Spring boot application.

We can create or update drools rules easily using the drools business central and deploy them on the KIE server. These rules on the KIE server can be invoked using the drools client library over the HTTP REST endpoint. In this article, we will learn how to invoke drools rules deployed on the KIE server using the REST API from a spring boot application.

Table of Contents

Creating rules using business central

In the previous article, we learned how to set up JBoss WildFly server.

Let’s create a simple object and a simple drools rule by creating a DRL file to calculate the income tax percentage.

The rule will return the income tax rate based on the below condition.

income tax drools rules example

Open the business central and click on the projects link in the Design section.

create drools project

On the Spaces page, click on the Add space button to create a new space. Enter the space name, description for the space, and click on Add button to create the new space.

I have created a space with the name ASB_Space.

add drools space

After the project space creation, open the created project space to add a drools project. We can create a new project or import the existing project into the business central using this screen.

Let’s create a new project with the name IT Calculator.

We can add assets under the created project by clicking on the Add asset button. We also have an option to import the assets.

The Group Id is the base package of the drools project. In our example, it is com.asb.example.

We can also add drools Package by clicking on the Package option in the Add Asset section.

Click on the Data object button to create a new drools data object with the name IncomeDetails.

drools data object creation

Next, click on the DRL file button to add a new drools DRL file and add the below rule definitions.

package com.asb.example;

import com.asb.example.IncomeDetails;
 
rule "Rs 0.0 – Rs 2.5 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 0 && incomeInRupees < 250000)
    then
        incomeDetails.setIncomeTaxPercentage(0.0);
end
 
rule "Rs 2.5 lakhs - Rs 5.0 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 250000 && incomeInRupees < 500000)
    then
        incomeDetails.setIncomeTaxPercentage(5.0);
end

rule "Rs. 5.00 lakhs- Rs 7.5 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 500000 && incomeInRupees < 750000)
    then
        incomeDetails.setIncomeTaxPercentage(10.0);
end

rule "Rs 7.5 lakhs – Rs 10.00 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 750000 && incomeInRupees < 1000000)
    then
        incomeDetails.setIncomeTaxPercentage(15.0);
end

rule "Rs 10.00 lakhs – Rs. 12.50 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 1000000 && incomeInRupees < 1250000)
    then
        incomeDetails.setIncomeTaxPercentage(20.0);
end

rule "Rs. 12.5 lakhs- Rs. 15.00 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 1250000 && incomeInRupees < 1500000)
    then
        incomeDetails.setIncomeTaxPercentage(25.0);
end

rule "> Rs. 15 Lakhs"
    when
        incomeDetails: IncomeDetails(incomeInRupees > 1500000)
    then
        incomeDetails.setIncomeTaxPercentage(30.0);
end

Finally, click on the validate button to validate syntax errors and click on the save button to save the rules file.

Deploying the rules

We can now build and deploy the drools project using the business central application as shown below.

workbench central build and deploy

Navigate to Menu > Execution Servers to view the deployed project details.

kie deployed project

Testing the drools REST API

Our drools project is deployment is successful. We can now access the REST APIs to invoke the drools rules.

Let’s use the curl commands to test the REST API.

curl --location --request POST 'http://localhost:8080/kie-server/services/rest/server/containers/instances/ITCalculator_1.0.0-SNAPSHOT' \
--header 'Authorization: Basic a2llc2VydmVyOmtpZXNlcnZlcjEh' \
--header 'Content-Type: application/json' \
--data-raw '{
    "commands": [
        {
            "insert": {
                "object": {
                    "IncomeDetails": {
                        "incomeInRupees": 2500000,
                        "incomeTaxPercentage": 0.0
                    }
                }
            }
        },
        {
            "get-objects": {
                "out-identifier": "import"
            }
        },
        {
            "fire-all-rules": {
                "max": 10,
                "out-identifier": "firedActivations"
            }
        }
    ]
}'

We can see the response as shown below.

{
  "type": "SUCCESS",
  "msg": "Container ITCalculator_1.0.0-SNAPSHOT successfully called.",
  "result": {
    "execution-results": {
      "results": [
        {
          "value": [
            {
              "com.asb.example.IncomeDetails": {
                "incomeInRupees": 2500000,
                "incomeTaxPercentage": 30.0
              }
            }
          ],
          "key": "import"
        },
        {
          "value": 1,
          "key": "firedActivations"
        }
      ],
      "facts": []
    }
  }
}

We may receive multiple response objects, as by default, drools store the state in the session. While invoking the REST endpoint using a java client, we can use stateless sessions.

Integrating drools API in Spring boot application

Our drools rule deployed we are also able to invoke it over REST API. Let’s integrate the drools REST API with the help of the java client and execute the drools rules.

We will create a REST API that accepts income as an input parameter, passes this input to the rule engine, and returns the calculated income tax percentage as a response.

Advertisements

To integrate the drools with the spring application, we may download the drools Kjar from the configured drools repository, where it is deployed, or directly replicate the data object structure in our application.

In this example, we will replicate the data object inside the spring boot application.

Create spring boot application

Create a spring boot application with spring-boot-starter-web and kie-server-client maven dependencies.

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
		<groupId>org.kie.server</groupId>
		<artifactId>kie-server-client</artifactId>
		<version>${kie.version}</version>
</dependency>

In our example, we are using the kie-server-client dependency version 7.60.0.Final, that we can specify in the properties section of the pom.xml file.

<properties>
		<java.version>11</java.version>
		<kie.version>7.60.0.Final</kie.version>
</properties>

Add the required configurations

We can add the drools API configuration properties in the application.properties configuration file of the Spring boot application under the /src/main/resources/ directory.

kie.containerId=ITCalculator_1.0.0-SNAPSHOT
kie.server.user=kieserver
kie.server.pwd=kieserver1!
kie.server.url=http://localhost:8080/kie-server/services/rest/server

server.port=8082

Also, create a data object similar to the drools data object created earlier on drools business central.

package com.asb.example;

public class IncomeDetails {

	private int incomeInRupees;
	private double incomeTaxPercentage;

	public int getIncomeInRupees() {
		return incomeInRupees;
	}

	public void setIncomeInRupees(int incomeInRupees) {
		this.incomeInRupees = incomeInRupees;
	}

	public double getIncomeTaxPercentage() {
		return incomeTaxPercentage;
	}

	public void setIncomeTaxPercentage(double incomeTaxPercentage) {
		this.incomeTaxPercentage = incomeTaxPercentage;
	}
}

Invoking the drools rules over REST API

Let’s create a service class and add the below code.

package com.asb.example;

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

import org.kie.api.KieServices;
import org.kie.api.command.BatchExecutionCommand;
import org.kie.api.command.Command;
import org.kie.api.command.KieCommands;
import org.kie.api.runtime.ExecutionResults;
import org.kie.internal.command.CommandFactory;
import org.kie.server.api.marshalling.MarshallingFormat;
import org.kie.server.api.model.ServiceResponse;
import org.kie.server.client.KieServicesConfiguration;
import org.kie.server.client.KieServicesFactory;
import org.kie.server.client.RuleServicesClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class TaxCalculatorService {

	@Value("${kie.containerId}")
	private String containerId;

	@Value("${kie.server.user}")
	private String user;

	@Value("${kie.server.pwd}")
	private String password;

	@Value("${kie.server.url}")
	private String url;

	private String outIdentifier = "response";

	public IncomeDetails calculateIncomeTax(IncomeDetails incomeObj) {

		IncomeDetails response = null;

		KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(url, user, password, 60000);
		config.setMarshallingFormat(MarshallingFormat.JSON);

		RuleServicesClient client = KieServicesFactory.newKieServicesClient(config)
				.getServicesClient(RuleServicesClient.class);

		BatchExecutionCommand batchExecutionCommand = batchCommand(incomeObj);
		ServiceResponse<ExecutionResults> result = client.executeCommandsWithResults(containerId,
				batchExecutionCommand);

		if (result.getType() == ServiceResponse.ResponseType.SUCCESS) {
			response = (IncomeDetails) result.getResult().getValue(outIdentifier);
		} else {
			System.out.println("Something went wrong!!");
		}
		return response;
	}

	private BatchExecutionCommand batchCommand(IncomeDetails incomeObj) {
		List<Command<?>> cmds = buildCommands(incomeObj);
		return CommandFactory.newBatchExecution(cmds);
	}

	private List<Command<?>> buildCommands(IncomeDetails incomeObj) {
		List<Command<?>> cmds = new ArrayList<>();
		KieCommands commands = KieServices.Factory.get().getCommands();
		cmds.add(commands.newInsert(incomeObj, outIdentifier));
		cmds.add(commands.newFireAllRules());
		return cmds;
	}
}

In the above code, we are importing the drools configuration properties like drools URL, kie server credentials, etc.

We then create a KieServicesConfiguration object with the imported configuration properties.

We also created a RuleServicesClient instance to execute the drools commands.

The KieCommands object can be used to create new drools command. We create a list of commands and create a BatchExecutionCommand object and execute the rules.

The outIdentifier is used to set an identifier for the output of the drools rules execution.

Create a REST API and pass the income in rupees, as shown below.

package com.asb.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TaxCalculatorController {

	@Autowired
	private TaxCalculatorService taxCalculatorService;

	@GetMapping("/calculateTax")
	public ResponseEntity<IncomeDetails> getIncomeTax(@RequestParam(required = true, name = "income") Integer income) {
		IncomeDetails incomeObj = new IncomeDetails();
		incomeObj.setIncomeInRupees(income);
		return new ResponseEntity<IncomeDetails>(taxCalculatorService.calculateIncomeTax(incomeObj), HttpStatus.OK);
	}
}

The controller has an GET endpoint /calculateTax. This endpoint revives an integer request parameter income.

This input parameter is passed to the drools rule engine to calculate the income tax rate.

We are invoking the service that we created earlier to calculate the income tax calculation result.

Run and test the API

Run the spring boot application and invoke the REST API.

Pass the income details to calculate the income tax rate.

spring boot drools rest api

Conclusion

In this article we learned how drools business central helps in creating the drools rules.

We also created a simple rule by creating object and a DRL file. We then deployed the rules on the KIE server and tested the rules using Postman.

Finally, we invoked drools rules over HTTP from the Spring boot application.

The example code is available on Github.

4 comments

  1. Why i am getting Unauthorized 401 response while accessing the rule api from business central.
    ” Unexpected HTTP response code when requesting URI ‘http://localhost:8080/kie-server/services/rest/server’! Error code: 401, message: ErrorUnauthorized” plz assist what going wrong your response is helpful

    1. From the logs it’s seems you are getting authentication error while invoking the kie server api from spring bot.

      Check the kie server credentials specified in the application.properties of the spring boot application is correct or not.

  2. I think the error is because of the user credentials that you are using while invoking the kie server.
    Try to access the kie server from browser and check if the credentials are working or not..

  3. I am getting below error when i hit endpoint. – http://localhost:8082/result/calculateTax?income=70000
    i have followed above mentioned step. please help me to resolve the below error

    org.kie.server.api.exception.KieServicesHttpException: Unexpected HTTP response code when requesting URI ‘http://localhost:8080/kie-server/services/rest/server/containers/’! Error code: 401, message: ErrorUnauthorized

Leave a Reply