Monday, September 24, 2012

Rules Engine Patterns - Part 3: Request Adjudication

In this pattern, the Rules Engine will mutate (adjudicate) model objects (requests) supplying the outcome of rules evaluated during the session.

Benefits:
  • Decisions made by rules engine are directly made on the model inserted into the rules session.
  • Knowledge of what to do based on the results (perhaps an infrastructural issue) can be handled outside of the rules engine.
Disadvantages:
  • There is a direct mutation of the model, which may not be palatable.
  • Blend request/adjudication concepts with the model, which may be a concern outside of the domain.
Example:  The state of Virginia has decided to automate Traffic Court using a set of empirically proven rules to evaluate the guilt of traffic violators.  In this example, SpeedingTicketCases will be adjudicated by the rules engine.  If the rule sets find the defendant guilty, it will simply set a guilty verdict (boolean "isGuilty") on the SpeedingTicketCase (using the "adjudicate" method).

SpeedingTicketCase.java

Represents the case being evaluated by the rules engine (not the speeding ticket itself).  If the defendant is guilty, it will be marked on the case itself.

package com.berico.ra;

public class SpeedingTicketCase {

 private boolean isGuilty;
 
 private String vehicleMake = null;
 
 private int mphOverSpeedLimit = -1;

 public SpeedingTicketCase( 
   String vehicleMake,
   int mphOverSpeedLimit) {

  this.vehicleMake = vehicleMake;
  this.mphOverSpeedLimit = mphOverSpeedLimit;
 }

 public boolean isGuilty() {
  return isGuilty;
 }
 
 public void adjudicate(boolean isGuilty){
  this.isGuilty = isGuilty;
 }

 public String getVehicleMake() {
  return vehicleMake;
 }

 public int getMphOverSpeedLimit() {
  return mphOverSpeedLimit;
 }
}

RequestAdjudication.drl

This is the rule set that will be used to determine whether a defendant is guilty.  In our case, regardless of how fast the car was going over the speed limit, Audis will always be guilty.  No one will believe, however, that a Honda can go more than 30 mph past the speed limit.  In such cases, the defendant will be cleared of the charge.

package com.berico.ra

rule "Automatically guilty if Vehicle is Audi"
  when
    speedingTicketCase : SpeedingTicketCase( vehicleMake == "Audi" )
        
  then
    speedingTicketCase.adjudicate(true);
end

rule "If 30 mph over speed limit and Honda, impossible!"
  when
    speedingTicketCase : SpeedingTicketCase( 
      vehicleMake == "Honda", mphOverSpeedLimit > 30 )
         
  then
    speedingTicketCase.adjudicate(false);
end

RequestAdjudicationApp.java

This application will drive the adjudication session.  We begin by creating some cases and inserting them into the rule session.  After calling "fireAllRules", we will evaluate the result of each case by examining the model objects directly.

package com.berico.ra;

import com.berico.BaseApp;

public class RequestAdjudicationApp extends BaseApp {

 @Override
 protected String getRuleFile() {
  
  return "RequestAdjudication.drl";
 }

 public RequestAdjudicationApp(){
  super();
  
  // Create a case that should be deemed "guilty".
  SpeedingTicketCase maryCase = new SpeedingTicketCase("Audi", 1);
  
  // Insert object into session.
  getSession().insert(maryCase);
  
  // Create a case that should be deemed "innocent".
  SpeedingTicketCase richardCase = new SpeedingTicketCase("Honda", 35);
  
  // Insert object into session.
  getSession().insert(richardCase);
  
  // Evaluate the rules against our objects.
  getSession().fireAllRules();
  
  // Dispose the rule session.
  getSession().dispose();
  
  // Print the results of the verdict for Mary
  System.out.println(
   String.format("Is Mary guilty?: %s", maryCase.isGuilty()));
  
  // Print the results of the verdict for Richard
  System.out.println(
   String.format("Is Richard guilty?: %s", richardCase.isGuilty()));
 }
 
 public static void main(String[] args){
  
  new RequestAdjudicationApp();
 }
}

On the console, you should see the following message:
Is Mary guilty?: true
Is Richard guilty?: false

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.