Callables are hold by an ICallableRepository, which is implemented by the RuleSet.
Finally, an Addon implementation is dedicated to perform the call. For the moment, one implementation is provided, named Call. It allows to invoke a function by its name and to provide parameters. It returns eventually a value, which can be used as an input to following rules or to set an output data.
An example is often better than long texts. So we’ll show here how to build a very simple rule set using a function.
Let’s take here the following case : A Rule Set will call a Function, with a parameter which has the value “0”. The function will increment by one the parameter, and recursively call itself.
When the parameter is equal to the input value provided to the rule set, the value is returned. Then the rule set returns the value returned by the function.
We’ll assert that the value retrieved by the Java program is the provided value.
Let’s analyse the following rules which achieve this goal:
<?xml version="1.0" encoding="UTF-8"?> <rules implem="RULEEXECUTIONSET" name="test_function"> <contextFactory implem="CONTEXT" classIn="Integer"/> <callable implem="FUNCTION" name="myFunction"> <executable implem="RULE"> <condition implem="EVAL" source="$parameter" operator="GTE" reference="#READBASE" /> <then implem="RETURN" value="$parameter"/> </executable> <executable implem="RETURN"> <value implem="CALL" callable="myFunction"> <argument name="parameter"> <value implem="SUM"> <value implem="PROPERTY" property="$parameter" /> <value implem="VALUE" value="1" /> </value> </argument> </value> </executable> </callable> <executable implem="FLOWCONTROL" command="STOP"> <returnValue implem="CALL" callable="myFunction" parameter="0" /> </executable> </rules>
First, we declare the context factory and the input type, which is simply Integer.
Then we declare the function, which evaluate if the “parameter” is greater than or equal to the read base (i.e. the Integer value provided to the rule set). If so, we return the value. If not, the function performs a recursive call, incrementing by one its parameter.
Finally, the only rule of the rule set is to call the function and return the value, which is performed by launching a flow control command “STOP” with a “returnValue”.
This rules set might be tested with the following JUnit code:
final InputStream xml = ResourceLoader.getResourceAsStream("function_test.xml"); final TestingRichXmlFactory factory = this.getFactory(); final IMruleExecutionSet eng = factory.read(xml); final MExecutionContext<Integer> ctxt = new MExecutionContext<Integer>(eng); ctxt.setInput(10); IExecutionResult result = ctxt.execute(); Assert.assertEquals(Integer.valueOf(10), ConvertUtils.getDefaultInstance().cast(Integer.class,result.getReturnedValue()));
Note the “cast” to Integer of the returned value, as MRules internally works on BigDecimal for operations on Numbers.
In this section, you have learned how to use functions. To see more advanced usage, you can download and execute the Sudoku demo, which is based on functions and recursive calls to solve grids.
To go further, future versions of MRules will provide new callable implementations, in order to be able to execute external rule sets and chain their executions.