IBM BPM, V8.0.1, All platforms > Programming IBM BPM > Business rule management programming > Examples

Example 13: Add a condition value and actions to a decision table

In this example, a condition value and action are added to a decision table. Condition values can be added to a decision table through the use of a template.

When adding a condition value to a condition node, you are adding a case edge. The new case edge is added at the end of the list of case edges. For the condition value, you must specify a template instance expression that has the appropriate parameter values set. In order to specify the template instance expression you will have to use a specific template. It is recommended to give the template names at each condition node level unique names in order to retrieve the correct templates for that type of condition.

If a single template definition is used, it may make it difficult to determine at which level the condition is being added.

When setting the condition value in a condition node, this will add the condition value with the same template instance to all condition nodes at the same level. This is done as the decision table is balanced. Also as part of the adding a new condition value, new action nodes will be added. These action nodes have tree actions that have null values specified for the user presentation and template instance expression. Because the condition value can be added to a condition node that does not have an action node as a child node, the addition of a condition node may result in a large number of action nodes. The number of action nodes is based upon the level the condition node is added and the number of condition nodes at that level and the number of condition nodes at each child level.

In order to find the action nodes that have been created, a search of action nodes with tree actions that have null user presentation and template instance expression may be performed. A TreeActionValueTemplate can be used to create an expression that can be set into the TreeAction. This pattern would need to be repeated for all new action nodes.

For this example two methods were provided to assist in setting up the new tree actions. getEmptyActionNode recursively looks for an empty action node from the current condition node and getParameterValue returns the value of a parameter that was specified by name.

package com.ibm.websphere.sample.brules.mgmt;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.ibm.wbiserver.brules.mgmt.BusinessRule;
import com.ibm.wbiserver.brules.mgmt.BusinessRuleGroup;
import com.ibm.wbiserver.brules.mgmt.BusinessRuleManagementException;
import com.ibm.wbiserver.brules.mgmt.BusinessRuleManager;
import com.ibm.wbiserver.brules.mgmt.Operation;
import com.ibm.wbiserver.brules.mgmt.Parameter;
import com.ibm.wbiserver.brules.mgmt.ParameterValue;
import com.ibm.wbiserver.brules.mgmt.Template;
import com.ibm.wbiserver.brules.mgmt.ValidationException;
import com.ibm.wbiserver.brules.mgmt.dtable.ActionNode;
import com.ibm.wbiserver.brules.mgmt.dtable.CaseEdge;
import com.ibm.wbiserver.brules.mgmt.dtable.ConditionNode;
import com.ibm.wbiserver.brules.mgmt.dtable.DecisionTable;
import com.ibm.wbiserver.brules.mgmt.dtable.TemplateInstanceExpression;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeAction;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeActionTermDefinition;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeActionValueTemplate;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeBlock;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeConditionValueTemplate;
import com.ibm.wbiserver.brules.mgmt.dtable.TreeNode;
import com.ibm.wbiserver.brules.mgmt.problem.Problem;
import com.ibm.wbiserver.brules.mgmt.query.QueryOperator;

public class Example13
{
	static Formatter out = new Formatter();

	static public String executeExample13()
	{
		try
		{
			out.clear();

			// Retrieve a business rule group by target namespace 			// and name 			List<BusinessRuleGroup> brgList = BusinessRuleManager
				.getBRGsByTNSAndName(
			"http://BRSamples/com/ibm/websphere/sample/brules", 					QueryOperator.EQUAL,"ConfigurationValues", 					QueryOperator.EQUAL, 0, 0);

			if (brgList.size() > 0)
				{
					// Get the first business rule group from the 					// list. This should be the only business 					// rule group in the list as the combination
					// of target namespace and name are unique 					BusinessRuleGroup brg = brgList.get(0);

					// Get the operation of the business rule
					// group that has the business rule that will 					// be modified as the business rules are 					// associated with a specific operation 					Operation op = brg.getOperation("getMessages");

					// Get all business rules available for 					// this operation 					List<BusinessRule> ruleList =
						op.getAvailableTargets();

					// For this operation there is only 1 business 					// rule and it is the business that we want 					// to update

					DecisionTable decisionTable = (DecisionTable)
						ruleList.get(0);
						out.printlnBold("Decision table before 						publish:");
						out.print(RuleArtifactUtility
						.printDecisionTable(decisionTable));

The level at which the condition value is going to be added needs to be located. This is typically passed as parameter as the user interface or application using the classes knows where to add the condition.

					// Get the tree block that contains all of 					// the conditions and actions for the decision
					// table
					TreeBlock treeBlock =
						decisionTable.getTreeBlock();

					// From the tree block, get the tree node which 					// is the starting point for navigating through 					// the decision table
					ConditionNode conditionNode = (ConditionNode)
						treeBlock.getRootNode();

					// Get the case edges for this node which is 					// the first level of conditions
					List<CaseEdge> caseEdges =
						conditionNode.getCaseEdges();

					// Get the case edge which will have the new
					// condition added
					CaseEdge caseEdge = caseEdges.get(0);

					// For the case edge get the condition node in 					// order to retrieve the templates for the 					// condition
					conditionNode = (ConditionNode)
									caseEdge.getChildNode();

					// Get the templates for the condition
					List<TreeConditionValueTemplate>
						treeValueConditionTemplates = conditionNode
						.getAvailableValueTemplates();

					Iterator<TreeConditionValueTemplate>
						treeValueConditionTemplateIterator =
						treeValueConditionTemplates.iterator();

					TreeConditionValueTemplate conditionTemplate =
						null;

By using unique template names at each condition node level in the decision table, you can more easily ensure the condition value is being added at the correct condition node value.

					// Find the template that should be used 						while
					(treeValueConditionTemplateIterator.hasNext())
					{
						conditionTemplate =
							treeValueConditionTemplateIterator
								.next();
						if (conditionTemplate.getName().equals(
							"Condition Value Template
							2.1"))
							{
								// Template found
								break;
							} 							conditionTemplate = null;
					} 					if (conditionTemplate != null)
					{

With the correct template found, an instance can be created and the appropriate parameter value set before it is added to the condition node.

					// Get the parameter definition from the 					// template 					Parameter conditionParameter =
					conditionTemplate.getParameter("param0");

					// Create a parameter value instance to 					// be used in a new condition template 					// instance 					ParameterValue conditionParameterValue =
							conditionParameter
							.createParameterValue("fatal");

					List<ParameterValue>
							conditionParameterValues = new
							ArrayList<ParameterValue>();

					// Add the parameter value to a list

					conditionParameterValues
						.add(conditionParameterValue);

					// Create a new condition template 					// instance with the parameter value 					TemplateInstanceExpression
						newConditionValue =
						conditionTemplate
							.createTemplateInstanceExpression(c
						onditionParameterValues);
					// Add the condition template instance to 					// this condition node 					conditionNode

					.addConditionValueToThisLevel(newConditionValue);
					// When a condition node is added there 					// are new action nodes that are created 					// and empty. These must be filled with 					// action template instances. By
					// searching for each empty action
					// node from the parent level, all of the 					// new empty action nodes can be found.
					conditionNode = (ConditionNode)
					conditionNode.getParentNode();

With the condition value added to the condition node, the tree actions in the new action nodes must be set with a TreeActionValueTemplate. First locate the empty action node for the case edges. Use the parent condition node to ensure that as you iterate through the condition nodes, you will pick up all action nodes.

					// Get the case edges for the parent node 					caseEdges = conditionNode.getCaseEdges();

					Iterator<CaseEdge> caseEdgesIterator =
					caseEdges.iterator();

					while (caseEdgesIterator.hasNext())
					{
						// For each case edge, retrieve an 						// empty action node if it exists
						ActionNode actionNode =
						getEmptyActionNode(caseEdgesIterator
						.next());

						// Check if all actions are filled
						if (actionNode != null)
						{

When an action node is found with empty tree actions, the tree action must be set with a TreeActionValueTemplate. First locate the template and then specify the parameters before creating a template instance. With the template instance created, the tree action can be updated. For this example the parameter was set with a value from another tree action in another action node under the same condition node. For other decision tables where another tree action might not have a value that may be used to create the new parameter values, the value will have to be passed as a parameter from the application.

							// Get the list of tree
							// actions. These 							// are not the actual
							// actions, but the 							// placeholders for the 							// actions
							List<TreeAction>
							treeActionList = actionNode
								.getTreeActions();

							List<TreeActionTermDefinition>
							treeActionTermDefinitions =
								treeBlock
							.getTreeActionTermDefinitions();

							List<TreeActionValueTemplate>
								treeActionValueTemplates =
								treeActionTermDefinitions
								.get(0).getValueTemplates();

							TreeActionValueTemplate
								actionTemplate = null;

							for (TreeActionValueTemplate
									tempActionTemplate :
									treeActionValueTemplates)
									{

									if
									(tempActionTemplate.get
										Name().equals(
										"Action Value
										Template 1"))
										{
											actionTemplate =
											tempActionTemplate;
											break;
										} 									} 
									if (actionTemplate != null)
									{
										// Get another action
										// that is under
										// the parent condition
										// node in order
										// to use the value as 										// the basis for 										// the error message in 										// the new
										// action node. Move up
										// to the 										// parent condition
										// node first 										ConditionNode
										parentNode =
										(ConditionNode)
										actionNode
											.getParentNode();

										// Get the first case
										// edge of the 										// parent node as this 										// action will 										// always be filled in 										// as new actions
										// are added to the end
										// of the case
										// edge list.
										CaseEdge caseE =
											parentNode.getCas
											eEdges().get(
											0);

										// The child node is an 										// action node 										// and at the same 										// level as the new
										// action node.
										ActionNode aNode =
										(ActionNode) caseE
											.getChildNode();

										// Get the list of tree
										// actions
										TreeAction
											existingTreeAction =
											aNode
											.getTreeActions()
											.get(0);

										// Get the template 										// instance 										// expression for the 										// tree action
										// from which you can 										// retrieve the 										// parameter 
										TemplateInstanceExpression
										existingExpression =
											existingTreeAction
											.getValueTemplateInstance();

										ParameterValue
										existingParameterValue =
										getParameterValue(
												"param0", 										existingExpression);

										String actionValue =
										existingParameterValue
											.getValue();

										// Create the new
										// message from the 										// message of the 										// existing 										// tree action
										actionValue = "Fatal"
												+
										actionValue.substring(actionValue
											.indexOf(":"), actionValue
											.length());
											Parameter
											actionParameter =
											actionTemplate
											.getParameter("param0");

											// Get the parameter 											// from the template 											ParameterValue
											actionParameterValue =
												actionParameter
											.createParameterValue(actionValue);

											// Add the parameter to 											// a list of templates
											List<ParameterValue>
											actionParameterValues = new
											ArrayList<ParameterValue>();

									actionParameterValues.add(actionParameterValue);

											// Create a new tree
											// action instance 
										TemplateInstanceExpression
											treeAction = actionTemplate
					.createTemplateInstanceExpression(actionParameterValues);

										// Set the tree action
										// in the action node 										// by setting it in the 										// tree action list

Here the tree action in the action node is updated.

										treeActionList.get(0)
										.setValueTemplateInstance(
										treeAction);
										} 									} 							} 				} 				// With the condition value and actions
				// updated, the business rule group can be 				// published.
				// Use the original list or create a new list
				// of business rule groups 					List<BusinessRuleGroup> publishList = new
						ArrayList<BusinessRuleGroup>();

				// Add the changed business rule group to the 				// list
					publishList.add(brg);

				// Publish the list with the updated business 				// rule group 
				BusinessRuleManager.publish(publishList, true);

				brgList =
					BusinessRuleManager.getBRGsByTNSAndName(
					"http://BRSamples/com/ibm/websphere/sample/brules", 					QueryOperator.EQUAL, “ConfigurationValues", 					QueryOperator.EQUAL, 0, 0);
					brg = brgList.get(0);
					op = brg.getOperation("getMessages");
					ruleList = op.getAvailableTargets();
					decisionTable = (DecisionTable)
						ruleList.get(0);
					out.printlnBold("Decision table after 						publish:");
					out
						.print(RuleArtifactUtility
							.printDecisionTable(decisionTable));
				} 		} catch (ValidationException e)
		{
			List<Problem> problems = e.getProblems();

			out.println("Problem = " +
			problems.get(0).getErrorType().name());

			e.printStackTrace();
			out.println(e.getMessage());
		} catch (BusinessRuleManagementException e)
		{
			e.printStackTrace();
			out.println(e.getMessage());
		} 		return out.toString();
	} 
	/*
	* This method searches from the current case edge for any
	* action nodes that have empty tree actions. An empty
	* action node is found by looking at the end of the list
	* of case edges and checking if the action node has tree
	* actions that have both a null user presentation and 	* TemplateInstanceExpression.
	*/
	private static ActionNode getEmptyActionNode(CaseEdge next)
	{
		ActionNode actionNode = null;
		TreeNode treeNode = next.getChildNode();

	if (treeNode instanceof ConditionNode)
	{
		List<CaseEdge> caseEdges = ((ConditionNode) treeNode)
			.getCaseEdges();

		if (caseEdges.size() > 1)
		{
			// Get right-most case-edge as the new
			// condition and thus empty actions are at the 			// right-end of the case edges
			actionNode = getEmptyActionNode(caseEdges
				.get(caseEdges.size() - 1));

			if (actionNode != null)
			{
				return actionNode;
			} 	} 	} else
	{
		actionNode = (ActionNode) treeNode;

		List<TreeAction> treeActions =
		actionNode.getTreeActions();

		if (!treeActions.isEmpty())
		{
		if
		((treeActions.get(0).getValueUserPresentation() == null)
			&&
		(treeActions.get(0).getValueTemplateInstance() == null))
			{
				return actionNode;
			} 		}	
			`actionNode = null;
		} 		return actionNode;
	} 	/*
	* This method will check the different parameter values for an 	* expression and if the correct one is found, return that 	* parameter value.
	*/
	private static ParameterValue getParameterValue(String pName, 			TemplateInstanceExpression expression)
	{
		ParameterValue parameterValue = null;

		// Check that the expression is not null as null would 		// indicate that the expression that was passed in was
		// probably not defined with a template and does not have 		// any parameters to check.
		if (expression != null)
		{
			// Get the parameter vlues for the expression
			List<ParameterValue> parameterValues = expression
				.getParameterValues();
			Iterator<ParameterValue> parameterIterator =
				parameterValues
				.iterator();

			// For the different parameters, check that it 			// matches the parameter value sought
			while (parameterIterator.hasNext())
			{
				parameterValue = parameterIterator.next();

				if
				(parameterValue.getParameter().getName().equals(pName))
				{
				// Return the parameter value that 				// matched
				return parameterValue;
				} 		} 	} 	return parameterValue;} }


Example

Web browser output for example 13.

Executing example13

Decision table before publish:
Decision Table
Name: getMessages
Namespace: http://BRSamples/com/ibm/websphere/sample/brules

Decision table after publish:
Decision Table
Name: getMessages
Namespace: http://BRSamples/com/ibm/websphere/sample/brules

Examples