Rules-based Validation using Drools, JSR303 and Spring

Validation and business rules are closely linked. Indeed validation logic could be thought of as being part of the implicit business rules for an application.It seems natural that integrating a business rules solution with a validation technology might be a natural step. In this post, I explore the possibility of integrating JSR303 and Drools to provide business rule driven validation within a Spring application. JSR303 is the standard Java method for data validation using annotations and Drools is a business rules engine that is a JBoss project and an implementation of JSR94, the standard Java rule engine API.

When to use (and when not to)

I don't think that this is a natural choice for all data validation needs. For a start, if the validation in your application is simple, the standard JSR303 annotations mixed with a few custom annotations might be enough. Integrating Drools comes at a cost in terms of architectural complexity and additional dependencies for you application. And although Drools is highly performance-optimised, a set of business rules in Drools will probably be slower than a set of custom Java statements.

However, there are significant benefits to complex applications - particularly if you are using Drools already. In that case, the complexity and dependency arguments are not valid.

The big benefit is the ability to externalise the business rules from the application and enable them to be edited without redeploying the application.

Drools overview

In a Drools application, business rules can be written in a powerful expression language called mvel (although XML can be used as well). In the Drools Expert documentation, the following basic example is given.

The rule consists of conditions (when) and consequences (then). In this rule, when the Applicant age property is less than 18, the valid property is set to false.

Often, business rules will need to access collaborators such as services or DAOs. These can be injected as "globals" in the rule definition. For example, the scenario above could be modified so that the applicant needs to be loaded from a DAO in order to check the age. The applicant identifier is a property in an ApplicationForm, submitted from a GUI or web application.We'll also introduce a new class to hold the validation result, rather than setting the validity on the model object itself, which is somewhat artificial. This object could be returned to the presentation tier to tell the user what went wrong.Error object to hold validation result:

In this version of the rule, the applicant is loaded from a DAO based on their identity. If the age of the applicant is less than 18, an error is inserted into the Errors object specifying the target object, field and message to return to the GUI. Obviously, this could be internationalized by putting a message code instead of the actual message.

That's an extremely brief overview of rules. Next, I'll quickly discuss the main API that Java programmers use when interacting with Drools. These will be used by the JSR303 validator when validating a bean using business rules.

At the most basic level, Drools stores business rules in a KnowledgeBase, from which can be created "sessions" which enable users to execute the rules based on facts, which are usually model objects inserted into the session.

There are two types of session: StatefulKnowldegeSession and StatelessKnowledgeSession. A StatelessKnowledgeSession is considered appropriate for use cases such as validation, because they are intended as a "one-shot" function call: pass in the facts, execute the rules, get a result. That's therefore the interface I will use for the integration with a JSR303 validation.Here is a simple example of creating a StatelessKnowledgeSession and executing the rules based on a collection of facts, each of which is inserted in turn before the rules are fired.

Spring integration

Conveniently, in Drools 5.1 some additional Spring integration was added that enables you to create KnowledgeBases and sessions declaratively in the application context, using a purpose-built namespace.

In this example, Spring is the "glue" bringing together the Drools and JSR303 parts. Here's the configuration.

I'm keeping things very simple - there is a lot more that the namespace can do in terms of configuring knowledge bases, agents, sessions etc.

JSR 303 Overview

JSR303 is a standard Java mechanism for validating JavaBeans using convenient annotations. Creating custom annotations is a matter of creating the annotation and an accompanying ConstraintValidator implementation, which will be automatically used by the Validator when it encounters the annotation on a bean getting validated.

The validator is also reasonably simple. A StatelessKnowledgeSession and a simple bean carrying a Map of the needed collaborators (to be set as globals) are injected into the constructor.When the isValid() method is called, an Errors object and the target of the validation are inserted into the session and the validation rules are fired. If the Errors object comes back with errors, validation has failed and a ConstraintViolation is built using the data in the Errors object.

Using the validator is very simple. First, the ApplicantForm object needs to be decorated with the @BusinessRulesConstraint annotation at class level so that the JSR303 validator will be triggered to use the BusienssRulesConstraintValidator.

package com.acme.app.form;

import java.util.Date;

import com.acme.app.validation.BusinessRulesConstraint;

@BusinessRulesConstraintpublic class ApplicationForm {

private Integer applicantId;

private Date date;

// getters/setters}

Then it is a matter of invoking the validator with a bean instance like this:

Summary

This post shows you an approach for integrating JSR303 and Drools in a Spring application, something you might want to do if you were using these technologies already in your application and it was sufficiently complex to warrant it. The steps involved are:

Create your domain objects and decorate them withe @BusinessRulesConstraint where business rule validation is to be used.

Create the .drl file with your validation logic in it.

Configure Spring as above with a KnowledgeBase containing your drl file as a resource, a StatelessKnowledgeSession derived from that KnowledgeBase, your collaborators for the rules and the JSR303 validator.

That's it!

Postscript: Maven configuration

For Maven users, this should be useful in getting all the dependencies for this example to work.