Esteban's Blog

/dev/rnd

Guvnor’s Field Constraints

Baunax and I are working in a new feature for Guvnor: the possibility to create and apply constraints on Fact’s Fields. In order to achieve this, three main subprojects are working together: drools-verifier, drools-factconstraint and of course drools-guvnor. Field Constraints is part of Fact Constraints and Guvnor’s Working Sets enhancements.

Rules about Rules

Drools-verifier is an excellent project leaded by Toni Rikkola. It allows you to define rules about rules. Verifier decomposes rules into elemental parts (Pattern, Restriction, Field, etc) and inserts them as Facts that you can use to make inference. Drools-verifier already comes with a full set of verification rules used to test completeness, coherence, overlaps and more. But the interesting part is that you can expand the set of predefined rules by adding your owns.

We used the flexibility of dools-verifier to create a different set of verification rules: business restrictions rules. These rules can be customized by guvnor’s users to meet their business requirements. Basic examples could be “The age of a Person must be an integer between 0 and 120” or “The balance of an Account couldn’t be less than 0”. These rules are applied during rule’s creation time to help users to create consistent rules.

If you want to learn more about drools-verifier you can go here (It may be a bit outdated but Toni promised me he will update it soon)

Fact Constraint project

The main purpose of this project is to add support to Facts and Fields Constraints. These constraints are being implemented in guvnor, but the idea is to make them as much guvnor agnostic as we can. Part of this project was already shown when I posted about Working Sets. There I shown how we can limit the available Fact Types when authoring rules. Fact Constraint project has two other goals: to allow the definition of Constraints for Fact’s Fields and to provide Data Sources for Fact’s Fields too. Here I will explain how we think to achieve Fact’s Field constraints.

Constraint Interface

This interface is the base of all field’s constraints. The definition of this interface is the following:

public interface Constraint extends Serializable {
   public List<String> getArgumentKeys();
   public ValidationResult validate(Object value, ConstraintConfiguration config);
   public String getVerifierRule(ConstraintConfiguration config);
   public String getConstraintName();
}

The first method is used to retrieve all the configuration parameters needed by the Constraint. For example, an Integer Constraint may no need any parameter, but a Range Constraint will need for sure the maximum and minimum allowed values.

The validate() method was thought to provide real time validation. Given a value it must return if the value is allowed or not according to the constraint. We are now moving to drools-verifier for real time validation, so it is possible that this method disappears in the near future.

getVerifierRule() must return valid drools-verifier rules that implement the constraint logic. These rules are the verifier equivalent of the constraint.

Note that validate() and getVerifierRule() both receive a ConstraintConfiguration object as parameter. This object will contain all the arguments specified by the constraint along with the Fact’s name and Fact’s field being validated.

The last method is used to allow the constraint to define a name.

Constraints registration

At this moment, drools-factconstraint comes with a predefined set of constraints:

  • IntegerConstraint: forces a field to allow only integer values
  • MatchesConstraint: forces a field value to matches a regex.
  • NoMatchesConstraint: forces a field value to not match a regex.
  • NotNullConstraint: forces a field to have a value.
  • RangeConstraint: forces a field value to be between a predefined range.
  • InvalidFieldConstraint: the field containing this constraint couldn’t be used while authoring rules.

Although there is currently no mechanism to allow users to register their own constraints, it is planned to add this functionality soon.

Verifier rule example

To make it a little bit clear I will expose a fragment of the verifier’s rules generated by RangeConstraint. Here you can see how factconstraint uses verifier to perform the validation.

package org.drools.verifier.consequence

import org.drools.verifier.components.*;
import java.util.Map;
import java.util.HashMap;
import org.drools.verifier.report.components.VerifierMessage;
import org.drools.verifier.data.VerifierReport;
import org.drools.verifier.report.components.Severity;
import org.drools.verifier.report.components.MessageType;
import org.drools.base.evaluators.Operator;

global VerifierReport result;

function void addResult{0}(VerifierReport report, LiteralRestriction restriction, Severity severity, String message){
    Map<String,String> impactedRules = new HashMap<String,String>();
    report.add(new VerifierMessage(
        impactedRules,
        severity,
        MessageType.NOT_SPECIFIED,
        restriction,
        message ) );
}

rule "Range_Field_Constraint_Base_{0}"
    when
        $field :Field(
          objectTypeName == "{1}",
          name == "{2}"
        )
    then
end

/* Equal operator */

rule "Range_Field_Constraint_==_{0}" extends "Range_Field_Constraint_Base_{0}"
  when
     ($restriction :LiteralRestriction(
            fieldPath == $field.path,
            operator == Operator.EQUAL,
            (valueType == Field.DOUBLE || ==Field.INT),
            (doubleValue < {3} || > {4}))
      )
  then
      addResult{0}(result, $restriction, Severity.ERROR, "The value must be between {3} and {4}");
end

The values between brackets are replaced in runtime by RangeConstraint:

  • {0} an auto-generated unique id used to prevent name collision when multiple RangeConstraints are used.
  • {1} the Fact Type name.
  • {2} the Fact Type field name.
  • {3} the minimum allowed value.
  • {4} the maximum allowed value.

In the code snippet you can see some of the Fact Types used by drools-verifier along with their attributes. This is just one of the generated rules; the one who takes care about the equals sign.

When a validation error is found, a new entry is added to a VerifierReport instance. This instance is shared by all verifier rules.

Defining Field’s constraints in Guvnor

In guvnor, field’s constraints are related to Working Sets. Inside a working set you can add constraints to allowed Fact Types’ fields. When you add a constraint to a field you must define its arguments:

Range Constraint for Car.model

The image above shows a RangeConstraint applied to Car.model. You can see that RangeConstraint defines two arguments: max. value and min. value.

You can add multiple constraints to a single field.

Executing field’s constraints validations

Field’s constraints can be evaluated in two different moments: on demand or during rule authoring (real time validation). In order to perform on demand validation, you must use the “Verify” button created by Toni some time ago. This button was originally used to run drools-verifier’s default rules, but we now add the rules generated by the active field’s constraints to make a more complete evaluation. The active field’s constraints are those defined by the active Working Sets. A screencast created by Baunax showing how field’s constraints are evaluated on demand can be found here.

"Verify" button and the report generated by it

I’m now focused on real time validation. The idea is that evaluation of field’s constraints takes place while users are authoring rules, just like in any IDE. The patterns that don’t satisfy a constraint will be marked in the rule’s edition window. For real time validation just the active field’s constraints are used. The widgets that need to fire real time validation are: Expression Builder widget, Fact Pattern widget and Free Form Line Widget. Right now the only widget that fires real time validation is Free Form Line (It is not committed yet) .

In order to see real time constraint’s validation in action, I have prepared a little screencast:

Field's Constraint Real Time Validation screencast (click to open)

Conclussion

In Guvnor, it is possible to define field’s constraints when configuring Working Sets. Some predefined constraints comes with drools-factconstraint project (we are working to add a lot more). The idea is that users can define their owns rules to satisfy business restrictions and plug them to guvnor. Field’s constraints make use of drools-verifier project to create rules that implement constraint’s logic.

Field’s validation can be executed in two different ways: on demand or real time.

Remember that this is a really new feature and it could suffer major changes, so stay in touch to see how it evolves.

Advertisements

2 comments on “Guvnor’s Field Constraints

  1. enerseAlgorgo
    June 8, 2010

    great article, very informative

  2. Pingback: Guvnor Guided Editor: Custom Forms « Esteban's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Information

This entry was posted on April 5, 2010 by in drools, java and tagged , , , , , .
%d bloggers like this: