Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

1. Introduction

In this quick tutorial, we’re going to integrate Drools with Spring. If you're just getting started with Drools, check out this intro article.

2. Maven Dependencies

Let's start by adding the following dependencies to our pom.xml file:

<dependency>
    <groupId>org.drools</groupId>
    <artifactId>drools-core</artifactId>
    <version>7.0.0.Final</version>
</dependency>
<dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>7.0.0.Final</version>
</dependency>

The latest versions can be found here for drools-core and here for kie-spring.

3. Initial Data

Let's now define the data which will be used in our example. We're going to calculate the fare of a ride based on the distance traveled and the night surcharge flag.

Here's a simple object which will be used as a Fact:

public class TaxiRide {
    private Boolean isNightSurcharge;
    private Long distanceInMile;
    
    // standard constructors, getters/setters
}

Let's also define another business object which will be used for representing fares:

public class Fare {
    private Long nightSurcharge;
    private Long rideFare;
    
    // standard constructors, getters/setters
}

Now, let's define a business rule for calculating taxi fares:

global com.baeldung.spring.drools.model.Fare rideFare;
dialect  "mvel"

rule "Calculate Taxi Fare - Scenario 1"
    when
        taxiRideInstance:TaxiRide(isNightSurcharge == false && distanceInMile < 10);
    then
      	rideFare.setNightSurcharge(0);
       	rideFare.setRideFare(70);
end

As we can see, a rule is defined to calculate the total fare of the given TaxiRide.

This rule accepts a TaxiRide object and checks if the isNightSurcharge attribute is false and the distanceInMile attribute value is less than 10, then calculate the fare as 70 and sets the nightSurcharge property to 0.

The calculated output is set to Fare object for further use.

4. Spring Integration

4.1. Spring Bean Configuration

Now, let's move on to the Spring integration.

We're going to define a Spring bean configuration class – which will be responsible for instantiating the TaxiFareCalculatorService bean and its dependencies:

@Configuration
@ComponentScan("com.baeldung.spring.drools.service")
public class TaxiFareConfiguration {
    private static final String drlFile = "TAXI_FARE_RULE.drl";

    @Bean
    public KieContainer kieContainer() {
        KieServices kieServices = KieServices.Factory.get();

        KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
        kieFileSystem.write(ResourceFactory.newClassPathResource(drlFile));
        KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
        kieBuilder.buildAll();
        KieModule kieModule = kieBuilder.getKieModule();

        return kieServices.newKieContainer(kieModule.getReleaseId());
    }
}

KieServices is a singleton which acts as a single point entry to get all services provided by Kie. KieServices is retrieved using KieServices.Factory.get().

Next, we need to get the KieContainer which is a placeholder for all the object that we need to run the rule engine.

KieContainer is built with the help of other beans including KieFileSystem, KieBuilder, and KieModule.

Let's proceed to create a KieModule which is a container of all the resources which are required to define rule knowledge known as KieBase.

KieModule kieModule = kieBuilder.getKieModule();

KieBase is a repository which contains all knowledge related to the application such as rules, processes, functions, type models and it is hidden inside KieModule. The KieBase can be obtained from the KieContainer.

Once KieModule is created, we can proceed to create KieContainerwhich contains the KieModule where the KieBase has been defined. The KieContainer is created using a module:

KieContainer kContainer = kieServices.newKieContainer(kieModule.getReleaseId());

4.2. Spring Service

Let's define a service class which executes the actual business logic by passing the Fact object to the engine for processing the result:

@Service
public class TaxiFareCalculatorService {

    @Autowired
    private KieContainer kieContainer;

    public Long calculateFare(TaxiRide taxiRide, Fare rideFare) {
        KieSession kieSession = kieContainer.newKieSession();
        kieSession.setGlobal("rideFare", rideFare);
        kieSession.insert(taxiRide);
        kieSession.fireAllRules();
        kieSession.dispose();
        return rideFare.getTotalFare();
    }
}

Finally, a KieSession is created using KieContainer instance. A KieSession instance is a place where input data can be inserted. The KieSession interacts with the engine to process the actual business logic defined in rule based on inserted Facts.

Global (just like a global variable) is used to pass information into the engine. We can set the Global using setGlobal(“key”, value); in this example, we have set Fare object as Global to store the calculated taxi fare.

As we discussed in Section 4, a Rule requires data to operate on. We're inserting the Fact into session using kieSession.insert(taxiRide);

Once we are done with setting up the input Fact, we can request engine to execute the business logic by calling fireAllRules().

Finally, we need to clean up the session to avoid memory leak by calling the dispose() method.

5. Example in Action

Now, we can wire up a Spring context and see in action that Drools works as expected:

@Test
public void whenNightSurchargeFalseAndDistLessThan10_thenFixWithoutNightSurcharge() {
    TaxiRide taxiRide = new TaxiRide();
    taxiRide.setIsNightSurcharge(false);
    taxiRide.setDistanceInMile(9L);
    Fare rideFare = new Fare();
    Long totalCharge = taxiFareCalculatorService.calculateFare(taxiRide, rideFare);
 
    assertNotNull(totalCharge);
    assertEquals(Long.valueOf(70), totalCharge);
}

6. Conclusion

In this article, we learned about Drools Spring integration with a simple use case.

As always, the implementation of the example and code snippets are available over on GitHub.

November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

Generic footer banner
Comments are closed on this article!