Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

RuleRunner

0.00/5 (No votes)
25 Apr 2012CPOL6 min read 13.3K   56  
RuleRunner is a simple decisioning algorithm that is driven by a properties file.

Introduction

RuleRunner is a light-weight Java class that leverages hash maps and a simple decisioning algorithm to determine the best result value for a given key field within the context of the lookup. The service supports separation of business rules from the application code and promotes clean generic code practices. Rules are externalized to a properties file which can be loaded upon request or loaded at application startup to increase performance. It is especially handy when you need to determine field values based on boolean conditions that frequently change. These conditions (or rules) are configured in a properties file and therefore don't require recompilation. The rules can handle nested levels of decisioning criteria to derive the appropriate result. This service will not compute results; it will decide which result best fits a given field based on relevant context information provided at the time of the lookup.

The way it works is simple. Similar to a properties file lookup, you call the service with a key and it returns a value. The difference is that you can also optionally pass up to 3 context field values which will be used to derive the best possible match. The algorithm uses decision tree and fall-through logic that starts searching for the property with all supplied context field values. If a rule (tested as a boolean expression) is not found for all context fields provided, it starts to generalize the search and apply wild cards.

For example, if you search for a property called "welcomeStatement" and you specifically want the welcome statement for the company "MSN" (context field1) and the country "USA" (context field2), you would submit the lookup for the property along with the 2 context field values. The algorithm would first search for a specific welcomeStatement value where the company is "MSN" and the country is "USA". If it finds one, it returns the property value. If it does not, it will see if there is a more generic welcome statement for MSN that applies to all countries (country becomes a wildcard "*"). If it finds one, it will return this value. If it does not, it will search for a generic welcome statement for all companies (company becomes a wildcard "*") in the country "USA". If it finds one, it will return this value. If it does not, it will search for a generic welcomeStatement that applies to all companies and all countries (both become wildcards "*") and act very much like a standard property lookup. The fall through logic has a specific sequence which must be clearly understood prior to writing rules. It is well documented in the Java class. This fall-through logic is powerful since it avoids the need to spell out every single permutation. For example, if you were to write a query in the form "select value from welcomeStatement_table where company = X and country = Y, you'd need to enter all possible permutations in the table.

Background

On a recent assignment, I was tasked with re-factoring a 4000+ line of code java class that was riddled with hardcoding and other poor development practices. Given that the code would be subject to change, I developed RuleRunner to externalize the rules so that a Business Analyst and QA tester could interpret and maintain rules as appropriate. I extracted over 1000 rules and was able to train BA members to configure rules going forward. The zip file attached contains a document written in laymen terms meant for non-technical folks to quickly grasp how to write rules. I used this tool to populate default values (with slight variances based on conditions) when building an outgoing web service xml document but I think it would work just as well for a number of different applications. In fact, demo2 attached shows how you can populate all default values in a single call to the service and have the properties file drive the process.

While developing the service, I found that the decisioning algorithm was useful but the service could be greatly improved if it could handle dynamic values. Remember, the service doesn't calculate/derive values but does a good job at decisioning. I was able to achieve this by including a hashmap of key/value pairs for the dynamic content (example, key="randomMessage" with an associated value as calculated/derived by the calling class prior to the service call). The trick to this is to prefix the value for the given rule in the properties file with a dollar sign ($) to indicate that the value should NOT be substituted as is (static). The service will go through the regular decisioning/fall-through logic and do a final step to determine if the value found from the rule is static or dynamic. If the value starts with a "$" (dynamic), the algorithm will strip the "$" and search the dynamic content hashmap using the rule value found as the key to derive the calculated value to return.

Below is a code snippet demonstrating how RuleRunner could be used to refactor code. It externalizes all conditional logic to a properties file and replaces the class code with one simple call to retrieve the value for a property from the RuleRunner service. The example also includes the hVars hashmap to address dynamic content for "randomMessage" as described above.

Using the code

Extract all files to a folder on your computer where the java.exe launcher is in your path and run the demo classes as standalone java applications passing two arguments, company and country. Read (1) Writing rules with Rule Runner.doc below for more context. The attached ZIP file contains the following:

1

Writing rules with Rule Runner.doc

This document is written in laymen terms to describe how to read and write rules for RuleRunner.

2

RuleRunner.java

RuleRunner.class

The RuleRunner engine.

3

RuleRunnerDemo1.java

RuleRunnerDemo1.class

This demo illustrates use of RuleRunner to execute a rule that will retrieve a value for a key field based on two context fields. This example will follow the tutorial example to retrieve the correct welcome statement given the company and country it applies too. Although RuleRunner supports 3 context fields per rule and rules can be linked to support endless context fields, this example is purposely limited to 2 context fields to facilitate understanding. Execute this demo as a stand alone java application passing 2 arguments: company and country.

(E.g., java RuleRunnerDemo1 MSN Spain)

4

RuleRunnerDemo2.java

RuleRunnerDemo2.class

This demo illustrates use of RuleRunner to execute a call that will run all rules in the properties file. In order to run individual rules, RuleRunner does not require that all key fields have the same context columns to dictate their criteria, but in order to use this feature, all key fields must adhere to this restriction. In this example, there are 3 key fields in the Rules file (welcomeStatement, logo and goodbyeStatement). All key fields in this example use the same context columns to determine their values, company and country. The call will evaluate each key field and retrieve the correct values relative to the company and country context fields. Execute this demo as a stand alone java application passing 2 arguments: company and country.

(E.g.: java RuleRunnerDemo2 MSN Spain)

5

demoRules.properties

This properties file contains the rules for both demos above.

History

Initial release v0.1 06/2009.

License

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