Deduction rules are at the heart of the deduced framework. They allow developers to link various fields in the application and specify a rule that gets executed when one of those fields changes.
As an example, let's imagine that we create an object representing yourself. Here are the attributes of that object:
In the deduced framework, this would be accomplished by creating a deduction rule that would be configured like this:
return bank+wallet;
Deduction rules are implemented using Java. Each rule represents a method that receives the specified inputs as parameters as well as a context variable representing the deduction rule execution context. The rule method is expected to return the rule output.
In the example above, here is what the code would look like once generated
public class DeducedDynamicClass extends org.deduced.rule.DeductionRuleLibrary { public java.lang.Object analyzeRule( java.lang.Object[] inputs, org.deduced.RuleExecutionContext context, org.deduced.PropertyCollection collection, org.deduced.PropertyCollection rule) { return CalculateTotalRule( (java.lang.Integer)inputs[0], (java.lang.Integer)inputs[1], context); } public java.lang.Object CalculateTotalRule( java.lang.Integer bank, java.lang.Integer wallet, org.deduced.RuleExecutionContext context, org.deduced.PropertyCollection collection, org.deduced.PropertyCollection rule) { // only this part was coded, the rest of the code is generated return bank+wallet; } }
A rule can invoke any java method necessary. However, it is preferable to keep rules simple and well contained. Rules should be implemented so that they are safe to be used in multiple threads.
By default, deduction rules will automatically extends org.deduced.rule.DeductionRuleLibrary. This gives easy access to many utility methods that help in the creation of rules. For instance the rule above might want to use the sum method to ensure the code will handle null inputs gracefully.
return sum(bank,wallet);
The complete list of utility methods can be found in the org.deduced.rule.DeductionRuleLibrary javadoc.
When executed, rules receive the following inputs:
The rule and collection parameter are made available as a convenience.
Rules are allowed to be created, deleted and changed as the application is running. If the rule definition changes, it will automatically be recompiled and executed on all applicable objects. However, it is recommended to disable a rule while it is being modified. Otherwise it becomes easy to introduce compilation or behavior errors that might change the underlying model in a way that isn't desired.
When a new rule is added and enabled, it will automatically be applied to all the objects to which it apply.
When a new rule is deleted or disabled and enabled, it will automatically be removed from the objects that it was applied to. The outputs of the rule will remain as they were when the rule last executed.
The following types of inputs can be used to execute deduction rules:
Instance Reference objects are used to chain a list of property instance that will indicate where the deduction rule should fetch it's values from before execution.
As a simple example, an input might be defined with the name property. This way, when a rule is executed, it will automatically receive the value contained in the name property.
A more complex example would be an object of type custom that would contain an named property collection in a property named child object. In this case, an instance reference could be defined with the following property instances:
Instance References can also reference objects in a list. To do so, the property instances in the instance reference must include the property of the list itself as well as the property of the objects contained within the list.
For instance, an object of type custom that would contain a list of named property collection in a property named child object list. In this case, an instance reference could be defined with the following property instances:
If the child object list is null, then the rule input will be null.
If the child object list is empty, then the rule input will be an empty list.
If some of the name values in the child objects is null, then the rule input will be list that will contain both null and non null values.
The order of the values in an input that returns a list isn't guaranteed. In the example above, if the custom object contains a child object named "Test" and another one named "Ordering", the input received by the deduction rule might be {"Test", "Ordering"} or {"Ordering", "Test"}.
For instance, an object of type custom that would contain a rule that contains a Static Instance Reference defined with :
Unlike Instance References, defining a list of input properties is optional for a Static Instance Reference. If no input property is defined, the rule will use the static reference value as input. This is useful to assign fixed values as rule inputs.
A rule may only contain one output. If many outputs are needed, developers should create different rule for each desired output. Outputs are defined with an Instance Reference object.
Outputs have additional restrictions in the way the instance reference is configured in order to be valid. The main restriction is that all the instances defined in the rule output must be contained by value and not by reference. This is done to simplify the rule execution model and also to guarantee layers in the deduced applications can't override each other.
If a rule doesn't create valid java code, the compilation errors will be stored in the compilation output variable of a rule to help troubleshoot the problem. The rule will also be automatically disabled until it is manually enabled.
When a rule execution yields an exception, that exception is caught by the rule execution engine and not thrown back to avoid breaking the current application. The error message is automatically stored in the last exception field of the deduction rule. Every time a new exception occurs when the rule executes, the last exception field will be replaced by the new error message.
It is recommended to implement deduction rules so they avoid throwing exceptions. A good way to accomplish this is by using the methods defined in : org.deduced.rule.DeductionRuleLibrary. Those methods perform the necessary checks to avoid most of the common exceptions such as null pointer exceptions.
When a property collection type inherits from another one, it automatically inherits the rule defined in the parent type. However, the child type has the option of overriding this rule by creating a rule of it's own that has the same output defined.
It is possible to create a situation where a property collection type inherits a rule that affects the same output form two different parent types. In such a case, only one of the rules will be effective and override the other one. This situation will generate warning messages in the logs.
When a property collection type defines a rule where the output targets a property in one of it's child property collection, that rule will take priority over any rule defined in the child collection that might affect the same output property.
Following that logic, the parent of the parent might also override the same output property. The deeper a parent is in the hierarchy, the more it takes priority when overriding rules.
Deduction rules are normally compiled the first time they are required. This compilation time can be avoided by pre-compiling a deduction rule with your application. To do so, a developer must create a class that implements the interface org.deduced.DeductionRuleAnalyzer and implement the rule logic as required. The arguments will be received as an array of values where the order of the parameter matches the order of the rule inputs.
Once such a rule is implemented, compiled and introduced in the application class path, it can then be used by a deduction rule by replacing the code field of a rule with a java class name. For instance, a developer could create a class named org.deduced.MyCustomRule that implements DeductionRuleAnalyzer. He can then put the value "org.deduced.MyCustomRule" in the code field.
In the base schema org.deduced.Utilities class, there is a property instance named "All Property Values". This instance may be used anywhere within deduction rule inputs.
Using this wild card property instance will tell the deduction rule to fetch all the properties fetched within a collection.