Click here to Skip to main content
Click here to Skip to main content

Basic Help on NxBRE (Rule Engine)

By , 16 Jun 2012
 

Introduction

In this article, we are going to see how we can apply dynamic business rules on an application without recompiling the code.

Background

My company required to build an ETL and my responsibility was to take care of the "T" Part.

You can found a brief about the DLL NxBRE here: http://sourceforge.net/projects/nxbre/. As I said I am not an expert of Rule engines, but this project might help you. 

It's nice to implement BRE in your application and your intelligence to code and writing business rules will speed up your application otherwise it may hamper performance.

Using the code 

You need VS 2010, this project will show you a small demo of Employee Tax and DA calculation depending on their Basic. Here is the XBRE file which contains the Rule:

<?xml version="1.0" encoding="UTF-8"?>
<xBusinessRules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:noNamespaceSchemaLocation="xBusinessRules.xsd">
  <Decimal id ="Tax" value ="10"/>
  <Decimal id ="DAp" value ="10"/>
 
  <Decimal id="5000" value="5000"/>
  <Decimal id="10000" value="10000"/>
  <Decimal id="15000" value="15000"/>
  <Decimal id="20000" value="20000"/>
  <Decimal id="30000" value="30000"/>
  <Decimal id="100000" value="100000"/>
  
  <!-- Calculation Of Tax -->
  
  <ObjectLookup id ="EmpObj" objectId ="EmpTexCal" member ="BasicSalary"/>
  <Logic>
    <If>
      <And>
        <Between leftId ="5000" rightId ="10000" valueId ="EmpObj">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="11.5"/>
      </Do>
    </If>
    <ElseIf>
      <And>
        <Between leftId ="10000" rightId ="15000" 
                  valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="13.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="15000" rightId ="20000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="14.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="20000" rightId ="30000" 
                      valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="15.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="30000" rightId ="100000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="17"/>
      </Do>
    </ElseIf>
  </Logic>
 
  <!-- <ObjectLookup id ="EmpObjOut" 
               objectId ="EmpTexCal" member ="TaxPercentage">
    <Argument valueId="Tax"/>
 </ObjectLookup> -->
  <!-- Calculation Of DA -->
  <Logic>
    <If>
      <And>
        <Between leftId ="5000" rightId ="10000" valueId ="EmpObj">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="25"/>
      </Do>
    </If>
    <ElseIf>
      <And>
        <Between leftId ="10000" rightId ="15000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="30"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="15000" rightId ="20000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="40"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="20000" rightId ="30000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="50"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="30000" rightId ="100000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="60"/>
      </Do>
    </ElseIf>
  </Logic>
  <!-- Example Of Evaluation -->
  <ObjectLookup id="ExpDAp"	type="NxBRE.Imp.Util.Evaluator,NxBRE.Imp" member="CreateExpression">
    <Argument value="(" />
    <Argument valueId="EmpObj" />
    <Argument value="/" />
    <Argument value="100" />
    <Argument value=")" />
    <Argument value="*" />
    <Argument valueId="DAp" />
  </ObjectLookup>
  <ObjectLookup id="EvalDAp"	type="NxBRE.Util.Compilation" member="Evaluate">
    <Argument valueId="ExpDAp" />
  </ObjectLookup>
  <ObjectLookup id="CastDAp"	type="NxBRE.Imp.Util.Casting,NxBRE.Imp" member="CastData">
    <Argument valueId="EvalDAp" />
    <Argument value="System.Decimal" />
  </ObjectLookup>
  <ObjectLookup id ="EmpObjOut" objectId ="EmpTexCal" member ="DA">
    <Argument valueId="CastDAp"/>
  </ObjectLookup>
</xBusinessRules> 

Here is how to read the XBRE file, I will explain the XBRE file later:

public ReadRule(string RuleFilePath)
{
    _FilePath = RuleFilePath;
    StringBuilder sb=new StringBuilder(255);

    if (GetShortPathName(_FilePath, sb, sb.Capacity) != 0)
        _factory = new BREFactoryConsole(_engineTraceLevel, _ruleBaseTraceLevel).NewBRE(new XBusinessRulesFileDriver(sb.ToString()));
}

You can change trace level to get trace result. I have two separate concerns: one is reading rule from a file and setting values for depending calculations.

Set value of depending variables. Set value of a particular object. 

public void SetObjectRefrance(ReadRule objRule, string ObjectId, object Obj)
{
    if (objRule.IsValidXML)
    {
        if (objRule.IsProcessed)
            objRule.Reset();
        objRule.Factory.RuleContext.SetObject(ObjectId, Obj);
    }
}

We can set any delegate of ExecuteRuleDelegate type through which we can call back our base code while performing rules.

public void SetDelegateRefrance(ReadRule objRule, string ObjectId, ExecuteRuleDelegate Delegate)
{
    if (objRule.IsValidXML)
    {
        if (objRule.IsProcessed)
            objRule.Reset();
        objRule.Factory.RuleContext.SetFactory(ObjectId, new BRERuleFactory(Delegate));
    }
}

In this rule engine we can split our rule concern and perform partial rule or we can perform the rule but fetch only partial result values.

* We have to set depending values or the Delegate.

public object GetRuleResult(ReadRule objRule, string ObjectId)
{
    try
    {
        if (!objRule.IsProcessed)
            objRule.ProcessRules();
        return objRule.Factory.RuleContext.GetResult(ObjectId).Result;
    }
    catch (Exception)
    {
    }

    return FlagResualt.NoProcessed;
}

Now I have created a combine function which will take care of all of the above functions:

public void EvaluateRule(ReadRule objRule, RuleRefrance[] RulesReferances, 
              RuleDelegate[] RulesDelegates, RuleResualt[] RuleReply)
{
    if (RulesReferances != null)
        AddObjects(objRule, 0, RulesReferances);
    if (RulesDelegates != null)
        AddDelegates(objRule, 0, RulesDelegates);
    // Process Rules
    if (!objRule.IsProcessed)
        objRule.ProcessRules();

    //if (RuleReply != null)
    GetObjectResult(objRule, 0, RuleReply);

}

GetObjectResult just sets values at our ORM or any other class using Reflection.

Now how to call all of this and get the rule output, it's very simple:

string RuleFilePath = "EmployeeTexCalRule.xbre";
ReadRule objRead = new ReadRule(RuleFilePath);
NxBRE.Imp.Implementation.Execution exec = new Imp.Implementation.Execution();
txtOut.Text = "";
var list = new DataAccess.DataAccessLayer().GetAllEmployeeDetails();
foreach (BusinessObjects.BO.EmployeeBO item in list)
{

    exec.EvaluateRule(objRead, new[] { new RuleRefrance() { ObjectId = "EmpTexCal", Object = item } }, null,
        new[] { new RuleResualt() { ObjClass = item, ObjectId = "Tax", PropertyName = "TaxPercentage" }, 
            new RuleResualt() { ObjClass = item, ObjectId = "EvalDAp", PropertyName = "DA" } });

    txtOut.Text += String.Format("Name : {0} BasicSalary : Rs.{1} Tax : {2}% DA : Rs.{3}", 
           item.Name, item.BasicSalary, item.TaxPercentage, item.DA) + Environment.NewLine;

} 

Output:

Name : Suvabrata Roy BasicSalary : Rs.50000 Tax : 17% DA : Rs.30000
Name : Arindam Jash BasicSalary : Rs.16000 Tax : 14.5% DA : Rs.6400
Name : Riya Debnath BasicSalary : Rs.8000 Tax : 11.5% DA : Rs.2000
Name : Sanjoy Debnath BasicSalary : Rs.25000 Tax : 15.5% DA : Rs.12500
Name : Sraboni Roy BasicSalary : Rs.10000 Tax : 11.5% DA : Rs.2500
Name : Ahsan Ali BasicSalary : Rs.12000 Tax : 13.5% DA : Rs.3600
Name : Pritam Shaw BasicSalary : Rs.12000 Tax : 13.5% DA : Rs.3600
Name : Rimi Saha BasicSalary : Rs.7000 Tax : 11.5% DA : Rs.1750

Now you need to know about the XBRE XML file:

Variables 

<Decimal id ="Tax" value ="10"/>
<Decimal id ="DAp" value ="10"/>
<Decimal id="5000" value="5000"/>
<Decimal id="10000" value="10000"/>
<Decimal id="15000" value="15000"/>
<Decimal id="20000" value="20000"/>
<Decimal id="30000" value="30000"/>
<Decimal id="100000" value="100000"/>

Basic Object: we will set employee object to it.

<ObjectLookup id ="EmpObj" objectId ="EmpTexCal" member ="BasicSalary"/> 

Logic of tax calculation:

<Logic>
    <If>
      <And>
        <Between leftId ="5000" rightId ="10000" valueId ="EmpObj">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="11.5"/>
      </Do>
    </If>
    <ElseIf>
      <And>
        <Between leftId ="10000" rightId ="15000" 
                      valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="13.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="15000" rightId ="20000" 
                  valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="14.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="20000" rightId ="30000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="15.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="30000" rightId ="100000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="17"/>
      </Do>
    </ElseIf>
</Logic>

Here is the code to set a value and execute a rule.

foreach (BusinessObjects.BO.EmployeeBO item in list)
{

    exec.EvaluateRule(objRead, new[] { new RuleRefrance() { ObjectId = "EmpTexCal", Object = item } }, null,
        new[] { new RuleResualt() { ObjClass = item, ObjectId = "Tax", PropertyName = "TaxPercentage" }, 
            new RuleResualt() { ObjClass = item, ObjectId = "EvalDAp", PropertyName = "DA" } });

    txtOut.Text += String.Format("Name : {0} BasicSalary : Rs.{1} Tax : {2}% DA : Rs.{3}", 
      item.Name, item.BasicSalary, item.TaxPercentage, item.DA) + Environment.NewLine;
}

Points of Interest

It is not the final project, and I apologies for not describing all the parts, but as I have time I will update this project and code.

Upcoming Features

  1. Apply rule on DataTable columns.
  2. DataTable to property data mapping and vice versa.
  3. How to manage multiple Rule files (Factory Pattern) 
  4. One nice IDE where we can drag and drop to create BR (Business Rule). (It will take some time to build :-))

Some more ...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Suvabrata Roy
Technical Lead
India India
I am working on .Net for 4+ years, I am willing learn new technologies, concepts etc.
 
While you learn its very impotent to share your thoughts with other so I share some of my projects.
 
Thanks & Regards,
Suvabrata Roy

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionThank you! PinmemberDavid Dossot1-Oct-12 6:34 
Questionanother question PinmemberCodingABC17-Sep-12 9:32 
QuestionDo you know how to access a class member from the xbre file? PinmemberCodingABC6-Sep-12 6:54 
GeneralMy vote of 5 PinmemberPetr Kohout16-Jun-12 22:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130617.1 | Last Updated 16 Jun 2012
Article Copyright 2012 by Suvabrata Roy
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid