|
Rule Project "ExternalRulesFromGUI"
Step 1. Defining GUI
Step 2. Defining
Implementation Approach
Step 3.
Setting Up Rule Templates
Step 4. Supporting Java
Classes
Step 5.
Creating Graphical Form Layouts in Excel
Step 6. Deploying and Executing the Web Application
OpenRules allows you to keep your business rules in
Excel data tables that correspond to the columns
(conditions and actions) of Excel's templates based on which the proper
rule tables will be executed.
Step 1. Defining Graphical User Interface
This project intends to create a web
application that will consist of two parts:
1) Data input and Rule Engine
Execution
2) Online Rules Editing
The view "Generate Customer Greeting"
will allow to enter basic information about a customer and generate a
greeting like "Good Morning, Mrs. Robinson!" based on the current time.
Here is an example of the proper view:

By clicking on the button "Generate Greeting" a user
could produce a new greeting in accordance with the latest greeting and
salutation rules. By clicking on the buttons "Greeting Rules" a user
will be taken to a web-based rule editor to modify the Greeting Rules:

By clicking on the buttons "Salutation Rules" a user
will be taken to a web-based rule editor to modify the Salutation Rules:

This editors shows not how to make changes in the rule
attributes but also allows a user to add rules by clicking on "the
hyperlink "Add Rule" or to delete rules by clicking on the red cross.
Step 2. Defining Implementation Approach
►top
We will build this web application using OpenRules
Forms by defining 3 Excel-based layouts for every of the above views and
using navigation logic described as processing flow rules. We will
deploy our application on the Tomcat server. As usual, we will create
the following files:
| File |
Directory |
Purpose |
| HelloExternalRulesFromGUI.xls |
./war/rules/main |
Describes the Environment table and the main
method that will be executed during every interaction with a web
client |
| HelloForms.xls |
./war/rules/gui |
Describes all screen layouts and processing
flow rules |
| Dialog.xls |
./war/rules/gui |
The standard OpenRules file borrowed from the
project openrules.forms.lib |
| HelloData.xls |
./war/rules/data |
Rule templates |
| index.jsp |
./ |
The entry point to this JSP-based web
application |
What makes this application special is a need to
reinitialize the rule engine that generates a greeting every time when
the greetings and/or
salutations have been modified. However, we do not have to reinitialize
a rule engine associated with an already opened OpenRulesSession with
all layouts and related rule tables. So, we have to carefully
distributes greeting generation information and GUI information between
two different rule engines making sure that re-initialization of the
first engine dome really quickly.
When we start the application for the first time, we
want to display the default rules (defined in an Excel file) and we also
want to use the default data about a customer (defined in another Excel
file).
In this implementation, we will define a special Java
class HelloManager whose responsibilities will include these and other
data management tasks. The manager will support two rule engines:
- A rule engine that reads the default greeting and
salutation rules from the file war/rules/main/HelloDefaultRules.xls. Only this
engine will deal with greeting rules and rule templates presented in
the file war/rules/logic/HelloTemplates.xls.
- A rule engine associated with the
OpenRulesSession that will handle all GUI problems and will also
read the default data about a customer from the Excel file HelloData.xls.
Thus, the entry point to our web application "index.jsp"
will look as follows:
|
<%@ page import="com.openrules.forms.gui.jsp.*"
%>
<%@ page import="com.openrules.forms.*"
%>
<%@ page import="hello.rules.*"
%>
<%@ page import="com.openrules.ruleengine.*"
%>
<%
String s_attr = "openrules_session";
OpenRulesSession
openrules_session = (OpenRulesSession) session.getAttribute(s_attr);
if (openrules_session ==
null )
{
// Create manager using data from HelloDefaultRules.xls
String xlsMainRules = "file:./webapps/HelloExternaRulesFromGUI/rules/main/HelloDefaultRules.xls";
HelloManager man = new HelloManager(xlsMainRules);
// Create OpenRulesSession using HelloExternaRulesFromGUI.xls
String xlsMainForms = "file:./webapps/HelloExternaRulesFromGUI/rules/main/HelloExternaRulesFromGUI.xls";
openrules_session = new OpenRulesSession(xlsMainForms);
session.setAttribute( s_attr, openrules_session);
System.out.println("NEW SESSION based on " + xlsMainForms);
man.setFormsEngine(openrules_session.getOpenRulesEngine());
// Read default rules and data from Excel files
man.getDefaults();
Dialog dialog = openrules_session.getDialog();
dialog.put("manager",man);
}
%>
<HTML><HEAD><TITLE>OpenRules</TITLE></HEAD>
<body>
<%
System.out.println("PROCESS REQUEST");
openrules_session.processRequest(session, request, out);
%>
</body>
</HTML> |
The first rule engine will be created by the constructor
HelloManager(xlsMainRules), and the second rule engine automatically
created by the OpenRulesSession will be set for the HelloManager by the
statement:
man.setFormsEngine(openrules_session.getOpenRulesEngine());
The Environment table for the first rule engine is located in the file HelloDefaultRules.xls:
| Environment |
| import.java |
hello.rules.* |
| include |
../logic/HelloTemplates.xls |
The Environment table for the second rule engine is located in the file
HelloExternaRulesFromGUI.xls:
| Environment |
| import.static |
com.openrules.tools.Methods |
| import.java |
hello.rules.* |
| include |
../gui/Dialog.xls |
| ../data/HelloData.xls |
| ../gui/HelloForms.xls |
The main execution loop is implemented by the following
method:
| Method TableLayout main(Dialog dialog) |
HelloManager man = (HelloManager) dialog().get("manager");
if (man == null)
return fatalErrorLayout("HelloManager is not defined if index.jsp");
defineNextProcessingStep(man);
if (dialog().errors == 0)
{
processingFlowRules(man);
defineNextProcessingStep(man);
}
return mainLayout(); |
Step 3. Setting Up Rule
Templates
►top
The business logic for producing greetings and
salutations is presented in the Excel file HelloTemplates.xls. The first
template
| Rules void
defineGreeting(App
app, int hour) |
| C1 |
C2 |
A1 |
| min <= hour |
hour <= max |
app.greeting = greeting; |
| int min |
int max |
String greeting |
| Hour From |
Hour To |
Set Greeting |
| |
|
Unknown Greeting |
specifies how to define different greetings (Good
Morning, Good Afternoon, etc.) based on the hour of the day. If the
parameter "hour" belongs to the interval [min;max] defined by a concrete
rule then the attribute "greeting" of the parameter "app" will be set to
the proper greeting. If no rules are satisfied, this multi-hit table
will use the default greeting "Unknown Greeting".
The second template
| Rules void
defineSalutation(App
app, Customer c) |
| C1 |
C2 |
C3 |
A1 |
| c.gender.equals(gender) |
c.maritalStatus.equals(status) |
c.age < age |
app.salutation = salutation; |
| String gender |
String status |
int age |
String salutation |
| Gender |
Marital Status |
Age Less Than |
Set Salutation |
| |
|
|
Unknown Salutation |
specifies how to define different salutations (Mr.,
Mrs., etc.) based on customer attributes Gender, Marital Status, and
Age. If no rules are satisfied, this multi-hit table will use the
default salutation "Unknown Salutation".
Step
4.
Creating Supporting Java Classes ►top
We define a Java package "hello.rules" with the following
classes:
Customer (Customer.java)
 | String name |
 | String gender |
 | String maritalStatus |
 | int age |
App (App.java)
 | Customer customer |
 | String greeting |
 | String salutation |
GreetingRule (GreetingRule.java)
 | int from |
 | int to |
 | String greeting |
These classes are basic Java beans used inside rules and
forms. To demonstrate the use of a more complex rule editor, we will
implement the rule table for salutation rules as an OpenRules
dynamic table.
To do this we will define two classes:
SalutationRule implementes Checkable (SalutationRule.java)
 | String gender |
 | String maritalStatus |
 | String maxAge |
 | String salutation |
 | HelloManager manager |
and the class SalutationRules that extends
DynamicTable (SalutationRules.java)
by defining two methods:
public
String getHeaderLayoutName() {
return "salutationsTableHeader";
}
public
String getRowLayoutName() {
return "salutationsTableRow";
}
And finally the main Java class
is a placeholder for all other objects:
HelloManager (HelloManager.java)
 |
OpenRulesEngine ruleEngine |
 |
OpenRulesEngine formsEngine |
 |
GreetingRule[] greetingRules |
 |
SalutationRule[] defaultSalutationRules |
 |
SalutationRules salutationRules |
 |
App app |
 | ExternalRules externalRules |
The ruleEngine is define is the
constructor. the formsEngine is defined in the
index.jsp. At the application initialization the manager executes the
method "getDefaults":
public void getDefaults() {
greetingRules = (GreetingRule[])ruleEngine.run("getDefaultGreetingRules");
defaultSalutationRules = (SalutationRule[])ruleEngine.run("getDefaultSalutationRules");
salutationRules = new SalutationRules(formsEngine);
for (int i = 0; i < defaultSalutationRules.length; i++) {
SalutationRule rule = defaultSalutationRules[i];
rule.setManager(this);
salutationRules.addNewRow(rule);
}
createExternalRules();
externalRules.setModified(true);
ruleEngine.log("There is " + getExternalRules().getRuleTables().size() + " external tables");
Customer customer = (Customer) formsEngine.run("getDefaultCustomer");
app = new App();
app.setCustomer(customer);
}
|
This method receives the
greetingRules from the file HelloDefaultRules.xls
using the method "getDefaultGreetingRules".
It receives the defaultSalutationRules using the method "getDefaultSalutationRules"
and then creates salutationRules to support the proper dynamic
graphical table. Then it creates an instance of the type ExternalRules using
this method:
public void createExternalRules() {
String[][] greetingGrid = new String[greetingRules.length][3];
for (int i = 0; i < greetingRules.length; i++) {
GreetingRule rule = greetingRules[i];
greetingGrid[i] = new String[] { Integer.toString(rule.from), Integer.toString(rule.to), rule.greeting };
}
String[][] salutationGrid = new String[salutationRules.getRows().size()][4];
for (int i = 0; i < salutationRules.getRows().size(); i++) {
SalutationRule rule = (SalutationRule)salutationRules.getRows().get(i);
salutationGrid[i] = new String[] { rule.gender, rule.maritalStatus, rule.maxAge, rule.salutation };
}
externalRules = new ExternalRules();
externalRules.addRuleTable(
"greetingRules", //table name
"defineGreeting", //template name
greetingGrid);
externalRules.addRuleTable(
"salutationRules", //table name
"defineSalutation", //template name
salutationGrid);
externalRules.setModified(false);
ruleEngine.setExternalRules(externalRules);
}
|
And finally the manager creates the default application
"app" with a customer received from the file HelloData.xls:
| Data Customer customers |
| customer.name |
customer.maritalStatus |
customer.gender |
customer.age |
| Customer Name |
Marital Status |
Gender |
Age |
| Robinson |
Married |
Female |
24 |
| Smith |
Single |
Male |
19 |
|
|
|
|
|
|
|
|
| Method Customer getCustomer() |
|
| return customers[0]; |
|
Step
5. Creating Graphical Layouts in Excel
►top
All GUI realted forms and rules are descibed in the file
HelloForms.xls. The mainLayout specifies a general layout for all
three layout:
| Layout TableLayout mainLayout() |
| properties |
width |
100% |
| cellspacing |
4 |
| cellpadding |
2 |
| border |
1 |
| style |
background-color:lightblue |
| dialog().nextLayout |
| <a href="http://openrules.com"> <font size="1" face="Arial"
color="blue"> OpenRules, Inc. </font></a> |
The layout "GenerateGreeting":
| Layout TableLayout generateGreetingLayout(App app, Customer c) |
| <h3>Generate Customer Greeting </h3> |
| currentTime() |
| "Name:" |
[c.name] |
| "Age:" |
[c.age] |
| "Gender:" |
[c.gender]["Male,Female"] |
| "Marital Status:" |
<F type="radio" >[c.maritalStatus]["Single,Married"] </F> |
| <hr/> |
| actionButton("Generate Greeting"); |
actionButton("Greeting Rules"); |
actionButton("Salutation Rules"); |
| "Generated Greeting:" |
<strong><C> app.result </C></strong> |
There two layouts to support "GreetingRules":
| Layout TableLayout greetingRulesLayout(HelloManager man) |
| <h3>Greeting Rules</h3> |
| <strong>Rules "Define Greeting" </strong> |
| greetingRulesTable(man); |
| actionButton("Save Changes"); |
actionButton("Salutation Rules"); |
actionButton("Generate Greeting"); |
| |
|
|
| Layout TableLayout greetingRulesTable(HelloManager man) |
| <b>Hour From</b> |
<b>Hour To</b> |
<b>Greeting</b> |
| [man.greetingRules[0].from] |
[man.greetingRules[0].to] |
[man.greetingRules[0].greeting][getPossibleGreetings()] |
| [man.greetingRules[1].from] |
[man.greetingRules[1].to] |
[man.greetingRules[1].greeting][getPossibleGreetings()] |
| [man.greetingRules[2].from] |
[man.greetingRules[2].to] |
[man.greetingRules[2].greeting][getPossibleGreetings()] |
| [man.greetingRules[3].from] |
[man.greetingRules[3].to] |
[man.greetingRules[3].greeting][getPossibleGreetings()] |
This form has a fixed number of rules (row), so a user may
change only values of rules attributes.
The layouts "SalutationRules" represent a dynamic table:
| Layout TableLayout salutationRulesLayout(HelloManager man) |
| <h3> Salutation Rules</h3> |
| <strong>Rules "Define Salutation" </strong> |
| man.salutationRules.createTable(); |
| actionHyperlink( "Add Rule"); |
| actionButton("Save Changes"); |
actionButton("Greeting Rules"); |
actionButton("Generate Greeting"); |
| Layout TableLayout salutationsTableHeader() |
| <b>Gender</b> |
<b>Marital Status</b> |
<b>Age Less Than</b> |
<b>Salutation</b> |
<b>Delete</b> |
| Layout TableLayout salutationsTableRow(SalutationRule rule) |
| [rule.gender]["Male,Female"] |
[rule.maritalStatus]["Married,Single"] |
[rule.maxAge] |
[rule.salutation][getPossibleSalutations()] |
deleteRuleButton(rule); |
| Layout TableLayout deleteRuleButton(SalutationRule rule) |
<F type="image" src="../openrules.forms.lib/images/delete.png">
[][] [rule.manager.salutationRules.deleteRow(rule);
dialog().setLastAction("Delete Rule")]
</F> |
Her is the rule table that specifies processing flow:
| Rules void processingFlowRules(HelloManager man) |
IF
Current Step is |
AND
Action is |
THEN
Execute Code |
AND
Go To The Step |
| |
Init |
|
GenerateGreeting |
| GenerateGreeting |
|
{ man.cleanUp(); } |
GenerateGreeting |
| GenerateGreeting |
Generate Greeting |
{ man.generateGreeting(); } |
GenerateGreeting |
| GenerateGreeting |
Greeting Rules |
|
GreetingRules |
| GenerateGreeting |
Salutation Rules |
|
SalutationRules |
| GreetingRules |
Save Changes |
{ man.updateRules(); } |
GreetingRules |
| GreetingRules |
Salutation Rules |
|
SalutationRules |
| GreetingRules |
Generate Greeting |
|
GenerateGreeting |
| SalutationRules |
Save Changes |
{ man.updateRules(); } |
SalutationRules |
| SalutationRules |
Add Rule |
{ man.addSalutationRule(); } |
SalutationRules |
| SalutationRules |
Delete Rule |
|
SalutationRules |
| SalutationRules |
Greeting Rules |
|
GreetingRules |
| SalutationRules |
Generate Greeting |
|
GenerateGreeting |
As you can see, the action "Save Changes" leads to the
execution of the manager's method "updateRules":
public void updateRules() {
createExternalRules();
getExternalRules().setModified(true);
showRules();
}
|
This method will create a new instance of the
external rules (based on the latest changes introduced by rule editors),
will mark external rules as "modified" that will force a rule engine to
reinitialize itself before next run of the method "generateGreeting":
public void generateGreeting() {
ruleEngine.run("greetingRules",app);
ruleEngine.run("salutationRules",app);
}
|
Step 6.
Deploying and Executing the Web Application
To deploy this web application on the Tomcat server
specified in the file build.properties, it is enough to double-click
on deploy.bat. To start the application make sure that your Tomcat
is up and running and double-clock on run.bat.
►top
|