5.4.0.Final will be the last release to keep API compatability for classes outside of knowledge-api. This means that the classes inside of core and compiler will change in the future.
Currently, when you in a RHS you call modify() on a given fact it triggers a revaluation of all Patterns of the matching object type in the knowledeg base. As some have found this can be a problem, forcing you to split up your objects into smaller 1 to 1 objects, to avoid unwanted evaluation of objects like recursion or excessive evaluation issues. This new feature allows a pattern to react (and then be re-eavluated) only to modifications made on fields constrained or bound inside the pattern itself.
The implementation is bit mask based, so very efficient. When the engine executes a modify statement it uses a bit mask of fields being changed, the pattern will only respond if it has an overlapping bit mask. This does not work for update(), and is one of the reason why we promote modify() as it encapsulates the field changes within the statement.
feature is off by default in order to make the behavior of the rule engine backward compatible with the former releases. If you want to activate it on a specific bean you have to annotate it with @propertySpecific. This annotation works both on drl type declarations:
declare Person @propertySpecific firstName : String lastName : String end
and on Java classes:
@PropertySpecific public static class Person { private String firstName; private String lastName; }
Given this simple type declaration, the most evident advantage of this new Property Specific feature, will be, for instance, that the following rule:
rule "Modify last name" when Person( firstName == "Mario" ) then modify($person) { setLastName("Fusco") } end
will no longer end up in an infinite loop.
Moreover on Java classes you can also annotate any method to say that its invocation actually modifies other properties. For instance in the former Person class you could have a method like:
@Modifies( { "firstName", "lastName" } ) public void setName(String name) { String[] names = name.split("\\s"); this.firstName = names[0]; this.lastName = names[1]; }
That means that if a rule has a RHS like the following:
modify($person) { setName("Mario Fusco") }
it will correctly recognize that both the firstName and lastName have been modified and act accordingly. Of course the @Modifies annotation on a method has no effect if the declaring class isn't annotated with @PropertySpecific.
The third newly introduced annotation is on patterns and allows you to modify the inferred set of properties "listened" by it. So, for example, you can annotate a pattern in the LHS of a rule like:
Person( firstName == $expectedFirstName ) @watch( lastName ) // --> listens for changes on both firstName (inferred) and lastName Person( firstName == $expectedFirstName ) @watch( * ) // --> listens for all the properties of the Person bean Person( firstName == $expectedFirstName ) @watch( lastName, !firstName ) // --> listens for changes on lastName and explicitly exclude firstName Person( firstName == $expectedFirstName ) @watch( *, !age ) // --> listens for changes on all the properties except the age one
The usage of @watch on a type not annotated as @PropertySpecific will raise a compilation error. The same will happen if you mention an unknown property name inside @watch or use the same name more than once like for example in: @watch( lastName, !lastName )
A new RuleSet property has been added called "Declare".
This provides a slot in the RuleSet definition to define declared types.
In essence the slot provides a descrete location to add type declarations where, previously, they may have been added to a Queries or Functions definition.
A working version of Wumpus World, an AI example covered in in the book "Artificial Intelligence : A Modern Approach", is now available among the other examples. A more detailed overview of Wumpus World can be found here
The engine now supports the declaration of entry-points. This allow tools and the application to inspect, select and restrict the use of entry-points in rules.
The simplified EBNF to declare an entry-point is:
entryPointDeclaration := DECLARE ENTRY-POINT epName annotation* END epName := stringId
Example:
declare entry-point STStream @doc("A stream of StockTicks") end
The engine now supports the declaration of Windows. This promotes a clear separation between what are the filters applied to the window and what are the constraints applied to the result of window. It also allows easy reuse of windows among multiple rules.
Another benefit is a new implementation of the basic window support in the engine, increasing the overall performance of the rules that use sliding windows.
The simplified EBNF to declare a window is:
windowDeclaration := DECLARE WINDOW ID annotation* lhsPatternBind END
Example:
declare window Ticks @doc("last 10 stock ticks") StockTick( source == "NYSE" ) over window:length( 10 ) from entry-point STStream end
Rules can then use the declared window by referencing using a FROM CE. Example:
rule "RHT ticks in the window" when accumulate( StockTick( symbol == "RHT" ) from window Ticks, $cnt : count(1) ) then // there has been $cnt RHT ticks over the last 10 ticks end
Guvnor 5.4.x requires at least Java 6 to run. The Drools and jBPM will still run on Java 5. Guvnor 5.3.x hotfixes will still run on Java 5 too.
Any custom configuration in the guvnor war in WEB-INF/components.xml
must
now happen in
WEB-INF/beans.xml
.
On the bottom of Web decision tables, the button Analyze... that checks for issues in your decision table, now also checks for 2 new detections:
A duplicate match are 2 rows in a decision table that can both match but have the same actions.
For example: a person between 20 and 40 has to pay a fee of 400 and a person between 30 and 50 has to pay a fee of 400 too. These 2 rows duplicate each other. If the fee would be different between them, then they would conflict each other.
A multiple values for one action match is 1 row in a decision table who's actions contradict itself. This is a common problem in limited entry tables, but rare in non-limited entry tables.
For example: a person below 40 has to pay the standard fee (400) and also has to pay the youngster fee (200). Since fee can only be set once, that's a problem.
BRL fragments can now be used for Condition and/or Action columns.
A BRL fragment is a section of a rule created using Guvnor's (BRL) Guided Rule Editor: Condition columns permit the definition of "WHEN" sections and Action columns the definition of "THEN" sections. Fields defined therein as "Template Keys" become columns in the decision table.
Consequently any rule that could be defined with the (BRL) Guided Rule Editor can now be defined with a decision table; including free-format DRL and DSL Sentences.
BRL fragments are fully integrated with other columns in the decision table, so that a Pattern or field defined in a regular column can be referenced in the BRL fragments and vice-versa.
You can now copy and paste rows in both the guided Decision Table and Template Data editors.
Simply right-click a row in the tables' left hand-side selector column and choose the appropriate operation.
When creating new constraints or actions in the BRL guided (rule) editor it is simple to define a value as literal, or formula or expression. However, up until now, changing the value type required deletion of the whole constraint or action. This release brings the ability to remove the value definition thus enabling you to change a literal value to a formula etc without needing to delete the whole constraint or action.
A new Editor to create Change-Sets was added in Guvnor. Using this new editor you can create change-sets referencing packages, snapshots and even particular assets inside a package and expose them to external applications. For further information refer to the documentation.
Custom Forms is a feature that exists in Guvnor since 5.1.1. It basically allows you to define external applications that will be invoked by Rule Editor when a particular field of a particular Fact Type is being used in a rule.
This feature is now also available to be used in DSL sentences. When defining a variable in a sentence you can now use this syntax for variable's definition:
{<varName>:CF:<factType.fieldName>}
If you have an active Working-Set defining a Custom Form configuration for factType.fieldName, the Custom Form will be invoked by Rule Editor while setting the value of that variable.