Este contenido no está disponible en el idioma seleccionado.
Chapter 17. Elements and Variables
17.1. Property Access on Java Beans (POJOs) Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Any bean property can be used directly. A bean property is exposed using a standard Java bean getter: a method
getMyProperty() (or isMyProperty() for a primitive boolean) which takes no arguments and return something.
JBoss Rules uses the standard JDK
Introspector class to do this mapping, so it follows the standard Java bean specification.
Warning
Property accessors must not change the state of the object in a way that may effect the rules. The rule engine effectively caches the results of its matching in between invocations to make it faster.
17.2. POJO Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is what the bean property looks like:
Person( age == 50 ) // this is the same as: Person( getAge() == 50 )
Person( age == 50 )
// this is the same as:
Person( getAge() == 50 )
- The age property
- The age property is written as
agein DRL instead of the gettergetAge() - Property accessors
- You can use property access (
age) instead of getters explicitly (getAge()) because of performance enhancements through field indexing.
17.3. Working with POJOs Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Procedure 17.1. Task
- Observe the example below:
public int getAge() { Date now = DateUtil.now(); // Do NOT do this return DateUtil.differenceInYears(now, birthday); }public int getAge() { Date now = DateUtil.now(); // Do NOT do this return DateUtil.differenceInYears(now, birthday); }Copy to Clipboard Copied! Toggle word wrap Toggle overflow - To solve this, insert a fact that wraps the current date into working memory and update that fact between
fireAllRulesas needed.
17.4. POJO Fallbacks Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
When working with POJOs, a fallback method is applied. If the getter of a property cannot be found, the compiler will resort to using the property name as a method name and without arguments. Nested properties are also indexed.
17.5. Fallback Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is what happens when a fallback is implemented:
Person( age == 50 ) // If Person.getAge() does not exists, this falls back to: Person( age() == 50 )
Person( age == 50 )
// If Person.getAge() does not exists, this falls back to:
Person( age() == 50 )
This is what it looks like as a nested property:
Person( address.houseNumber == 50 ) // this is the same as: Person( getAddress().getHouseNumber() == 50 )
Person( address.houseNumber == 50 )
// this is the same as:
Person( getAddress().getHouseNumber() == 50 )
Warning
In a stateful session, care should be taken when using nested accessors as the Working Memory is not aware of any of the nested values and does not know when they change. Consider them immutable while any of their parent references are inserted into the Working Memory. If you wish to modify a nested value you should mark all of the outer facts as updated. In the above example, when the
houseNumber changes, any Person with that Address must be marked as updated.
17.6. Java Expressions Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Capability | Example |
|---|---|
|
You can use any Java expression that returns a
boolean as a constraint inside the parentheses of a pattern. Java expressions can be mixed with other expression enhancements, such as property access.
|
Person( age == 50 )
|
|
You can change the evaluation priority by using parentheses, as in any logic or mathematical expression.
|
Person( age > 100 && ( age % 10 == 0 ) )
|
|
You can reuse Java methods.
|
Person( Math.round( weight / ( height * height ) ) < 25.0 )
|
|
Type coercion is always attempted if the field and the value are of different types; exceptions will be thrown if a bad coercion is attempted.
|
Person( age == "10" ) // "10" is coerced to 10
|
Warning
Methods must not change the state of the object in a way that may affect the rules. Any method executed on a fact in the LHS should be a read only method.
Warning
The state of a fact should not change between rule invocations (unless those facts are marked as updated to the working memory on every change):
Person( System.currentTimeMillis() % 1000 == 0 ) // Do NOT do this
Person( System.currentTimeMillis() % 1000 == 0 ) // Do NOT do this
Important
All operators have normal Java semantics except for
== and !=.
The
== operator has null-safe equals() semantics:
// Similar to: java.util.Objects.equals(person.getFirstName(), "John") // so (because "John" is not null) similar to: // "John".equals(person.getFirstName()) Person( firstName == "John" )
// Similar to: java.util.Objects.equals(person.getFirstName(), "John")
// so (because "John" is not null) similar to:
// "John".equals(person.getFirstName())
Person( firstName == "John" )
The
!= operator has null-safe !equals() semantics:
// Similar to: !java.util.Objects.equals(person.getFirstName(), "John") Person( firstName != "John" )
// Similar to: !java.util.Objects.equals(person.getFirstName(), "John")
Person( firstName != "John" )
17.7. Comma-Separated Operators Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The comma character ('
,') is used to separate constraint groups. It has implicit and connective semantics.
The comma operator is used at the top level constraint as it makes them easier to read and the engine will be able to optimize them.
17.8. Comma-Separated Operator Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The following illustrates comma-separated scenarios in implicit and connective semantics:
// Person is at least 50 and weighs at least 80 kg Person( age > 50, weight > 80 )
// Person is at least 50 and weighs at least 80 kg
Person( age > 50, weight > 80 )
// Person is at least 50, weighs at least 80 kg and is taller than 2 meter. Person( age > 50, weight > 80, height > 2 )
// Person is at least 50, weighs at least 80 kg and is taller than 2 meter.
Person( age > 50, weight > 80, height > 2 )
Note
The comma (
,) operator cannot be embedded in a composite constraint expression, such as parentheses.
17.9. Binding Variables Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
You can bind properties to variables in JBoss Rules. It allows for faster execution and performance.
17.10. Binding Variable Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is an example of a property bound to a variable:
// 2 persons of the same age Person( $firstAge : age ) // binding Person( age == $firstAge ) // constraint expression
// 2 persons of the same age
Person( $firstAge : age ) // binding
Person( age == $firstAge ) // constraint expression
Note
For backwards compatibility reasons, it's allowed (but not recommended) to mix a constraint binding and constraint expressions as such:
// Not recommended Person( $age : age * 2 < 100 )
// Not recommended
Person( $age : age * 2 < 100 )
// Recommended (separates bindings and constraint expressions) Person( age * 2 < 100, $age : age )
// Recommended (separates bindings and constraint expressions)
Person( age * 2 < 100, $age : age )
17.11. Unification Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
You can unify arguments across several properties. While positional arguments are always processed with unification, the unification symbol, ':=', exists for named arguments.
17.12. Unification Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is what unifying two arguments looks like:
Person( $age := age ) Person( $age := age)
Person( $age := age )
Person( $age := age)
17.13. Options and Operators in JBoss Rules Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Option | Description | Example |
|---|---|---|
|
Date literal
|
The date format
dd-mmm-yyyy is supported by default. You can customize this by providing an alternative date format mask as the System property named drools.dateformat. If more control is required, use a restriction.
|
Cheese( bestBefore < "27-Oct-2009" )
|
| List and Map access |
You can directly access a
List value by index.
|
// Same as childList(0).getAge() == 18 Person( childList[0].age == 18 )
|
| Value key |
You can directly access a
Map value by key.
|
// Same as credentialMap.get("jsmith").isValid()
Person( credentialMap["jsmith"].valid )
|
|
Abbreviated combined relation condition
|
This allows you to place more than one restriction on a field using the restriction connectives
&& or ||. Grouping via parentheses is permitted, resulting in a recursive syntax pattern.
|
// Simple abbreviated combined relation condition using a single && Person( age > 30 && < 40 )
// Complex abbreviated combined relation using groupings
Person( age ( (> 30 && < 40) ||
(> 20 && < 25) ) )
// Mixing abbreviated combined relation with constraint connectives Person( age > 30 && < 40 || location == "london" )
|
| Operators |
Operators can be used on properties with natural ordering. For example, for Date fields,
< means before, for String fields, it means alphabetically lower.
|
Person( firstName < $otherFirstName )
Person( birthDate < $otherBirthDate )
|
|
Operator matches
|
Matches a field against any valid Java
regular expression. Typically that regexp is a string literal, but variables that resolve to a valid regexp are also allowed. It only applies on String properties. Using matches against a null value always evaluates to false.
|
Cheese( type matches "(Buffalo)?\\S*Mozarella" )
|
|
Operator not matches
|
The operator returns true if the String does not match the regular expression. The same rules apply as for the
matches operator. It only applies on String properties.
|
Cheese( type not matches "(Buffulo)?\\S*Mozarella" )
|
|
The operator contains
|
CheeseCounter( cheeses contains "stilton" ) // contains with a String literal CheeseCounter( cheeses contains $var ) // contains with a variable
| |
|
The operator not contains
|
The operator
not contains is used to check whether a field that is a Collection or array does not contain the specified value. It only applies on Collection properties.
|
CheeseCounter( cheeses not contains "cheddar" ) // not contains with a String literal CheeseCounter( cheeses not contains $var ) // not contains with a variable
|
|
The operator memberOf
|
The operator
memberOf is used to check whether a field is a member of a collection or array; that collection must be a variable.
|
CheeseCounter( cheese memberOf $matureCheeses )
|
|
The operator not memberOf
|
The operator
not memberOf is used to check whether a field is not a member of a collection or array. That collection must be a variable.
|
CheeseCounter( cheese not memberOf $matureCheeses )
|
|
The operator soundslike
|
This operator is similar to
matches, but it checks whether a word has almost the same sound (using English pronunciation) as the given value.
|
// match cheese "fubar" or "foobar" Cheese( name soundslike 'foobar' )
|
|
The operator str
|
The operator
str is used to check whether a field that is a String starts with or ends with a certain value. It can also be used to check the length of the String.
|
Message( routingValue str[startsWith] "R1" )
Message( routingValue str[endsWith] "R2" )
Message( routingValue str[length] 17 )
|
|
Compound Value Restriction
|
Compound value restriction is used where there is more than one possible value to match. Currently only the
in and not in evaluators support this. The second operand of this operator must be a comma-separated list of values, enclosed in parentheses. Values may be given as variables, literals, return values or qualified identifiers. Both evaluators are actually syntactic sugar, internally rewritten as a list of multiple restrictions using the operators != and ==.
|
Person( $cheese : favouriteCheese ) Cheese( type in ( "stilton", "cheddar", $cheese ) )
|
17.14. Operator Precedence Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Operator type | Operators | Notes |
|---|---|---|
| (nested) property access | . | Not normal Java semantics |
| List/Map access | [ ] | Not normal Java semantics |
| constraint binding | : | Not normal Java semantics |
| multiplicative | * /% | |
| additive | + - | |
| shift | << >>>>> | |
| relational | < ><= >=instanceof | |
| equality | == != | Does not use normal Java (not) same semantics: uses (not) equals semantics instead. |
| non-short circuiting AND | & | |
| non-short circuiting exclusive OR | ^ | |
| non-short circuiting inclusive OR | | | |
| logical AND | && | |
| logical OR | || | |
| ternary | ? : | |
| Comma separated AND | , | Not normal Java semantics |
17.15. Fine Grained Property Change Listeners Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This feature allows the pattern matching to only react to modification of properties actually constrained or bound inside of a given pattern. This helps with performance and recursion and avoid artificial object splitting.
Note
By default this feature is off in order to make the behavior of the rule engine backward compatible with the former releases. When you want to activate it on a specific bean you have to annotate it with @propertyReactive.
17.16. Fine Grained Property Change Listener Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- DRL example
declare Person @propertyReactive firstName : String lastName : String enddeclare Person @propertyReactive firstName : String lastName : String endCopy to Clipboard Copied! Toggle word wrap Toggle overflow - Java class example
@PropertyReactive public static class Person { private String firstName; private String lastName; }@PropertyReactive public static class Person { private String firstName; private String lastName; }Copy to Clipboard Copied! Toggle word wrap Toggle overflow
17.17. Working with Fine Grained Property Change Listeners Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Using these listeners means you do not need to implement the no-loop attribute to avoid an infinite recursion. The engine recognizes that the pattern matching is done on the property while the RHS of the rule modifies other the properties. On Java classes, you can also annotate any method to say that its invocation actually modifies other properties.
17.18. Using Patterns with @watch Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Annotating a pattern with @watch allows you to modify the inferred set of properties for which that pattern will react. The properties named in the @watch annotation are added to the ones automatically inferred. You can explicitly exclude one or more of them by beginning their name with a
! and to make the pattern to listen for all or none of the properties of the type used in the pattern respectively with the wildcards * and !*.
17.19. @watch Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is the @watch annotation in a rule's LHS:
Note
Since doesn't make sense to use this annotation on a pattern using a type not annotated with @PropertyReactive the rule compiler will raise a compilation error if you try to do so. Also the duplicated usage of the same property in @watch (for example like in: @watch( firstName, ! firstName ) ) will end up in a compilation error.
17.20. Using @PropertySpecificOption Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
You can enable @watch by default or completely disallow it using the
on option of the KnowledgeBuilderConfiguration. This new PropertySpecificOption can have one of the following 3 values:
- DISABLED => the feature is turned off and all the other related annotations are just ignored
- ALLOWED => this is the default behavior: types are not property reactive unless they are not annotated with @PropertySpecific
- ALWAYS => all types are property reactive by default
- DISABLED => the feature is turned off and all the other related annotations are just ignored
- ALLOWED => this is the default behavior: types are not property reactive unless they are not annotated with @PropertySpecific
- ALWAYS => all types are property reactive by default
17.21. Basic Conditional Elements Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Name | Description | Example | Additional options |
|---|---|---|---|
|
and
|
The Conditional Element
and is used to group other Conditional Elements into a logical conjunction. JBoss Rules supports both prefix and and infix and. It supports explicit grouping with parentheses. You can also use traditional infix and prefix and.
|
//infixAnd Cheese( cheeseType : type ) and Person( favouriteCheese == cheeseType )
//infixAnd with grouping
( Cheese( cheeseType : type ) and
( Person( favouriteCheese == cheeseType ) or
Person( favouriteCheese == cheeseType ) )
|
Prefix
and is also supported:
(and Cheese( cheeseType : type )
Person( favouriteCheese == cheeseType ) )
The root element of the LHS is an implicit prefix
and and doesn't need to be specified:
when
Cheese( cheeseType : type )
Person( favouriteCheese == cheeseType )
then
...
|
|
or
|
This is a shortcut for generating two or more similar rules. JBoss Rules supports both prefix
or and infix or. You can use traditional infix, prefix and explicit grouping parentheses.
|
//infixOr Cheese( cheeseType : type ) or Person( favouriteCheese == cheeseType )
//infixOr with grouping
( Cheese( cheeseType : type ) or
( Person( favouriteCheese == cheeseType ) and
Person( favouriteCheese == cheeseType ) )
(or Person( sex == "f", age > 60 )
Person( sex == "m", age > 65 )
|
Allows for optional pattern binding. Each pattern must be bound separately, using eponymous variables:
pensioner : ( Person( sex == "f", age > 60 ) or Person( sex == "m", age > 65 ) )
(or pensioner : Person( sex == "f", age > 60 )
pensioner : Person( sex == "m", age > 65 ) )
|
|
not
|
This checks to ensure an object specified as absent is not included in the Working Memory. It may be followed by parentheses around the condition elements it applies to. (In a single pattern you can omit the parentheses.)
|
| |
| exists |
This checks the working memory to see if a specified item exists. The keyword
exists must be followed by parentheses around the CEs that it applies to. (In a single pattern you can omit the parentheses.)
|
| |
Note
The behavior of the Conditional Element
or is different from the connective || for constraints and restrictions in field constraints. The engine cannot interpret the Conditional Element or. Instead, a rule with or is rewritten as a number of subrules. This process ultimately results in a rule that has a single or as the root node and one subrule for each of its CEs. Each subrule can activate and fire like any normal rule; there is no special behavior or interaction between these subrules.
17.22. The Conditional Element Forall Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This element evaluates to true when all facts that match the first pattern match all the remaining patterns. It is a scope delimiter. Therefore, it can use any previously bound variable, but no variable bound inside it will be available for use outside of it.
Forall can be nested inside other CEs. For instance, forall can be used inside a not CE. Only single patterns have optional parentheses, so with a nested forall parentheses must be used.
17.23. Forall Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Evaluating to true
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Single pattern forall
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Multi-pattern forall
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Nested forall
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
17.24. The Conditional Element From Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The Conditional Element
from enables users to specify an arbitrary source for data to be matched by LHS patterns. This allows the engine to reason over data not in the Working Memory. The data source could be a sub-field on a bound variable or the results of a method call. It is a powerful construction that allows out of the box integration with other application components and frameworks. One common example is the integration with data retrieved on-demand from databases using hibernate named queries.
The expression used to define the object source is any expression that follows regular MVEL syntax. Therefore, it allows you to easily use object property navigation, execute method calls and access maps and collections elements.
Important
Using
from with lock-on-active rule attribute can result in rules not being fired.
There are several ways to address this issue:
- Avoid the use of
fromwhen you can assert all facts into working memory or use nested object references in your constraint expressions (shown below). - Place the variable assigned used in the modify block as the last sentence in your condition (LHS).
- Avoid the use of
lock-on-activewhen you can explicitly manage how rules within the same rule-flow group place activations on one another.
17.25. From Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Reasoning and binding on patterns
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Using a graph notation
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Iterating over all objects
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Use with lock-on-active
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
17.26. The Conditional Element Collect Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The Conditional Element
collect allows rules to reason over a collection of objects obtained from the given source or from the working memory. In First Oder Logic terms this is the cardinality quantifier.
The result pattern of
collect can be any concrete class that implements the java.util.Collection interface and provides a default no-arg public constructor. You can use Java collections like ArrayList, LinkedList and HashSet or your own class, as long as it implements the java.util.Collection interface and provide a default no-arg public constructor.
Variables bound before the
collect CE are in the scope of both source and result patterns and therefore you can use them to constrain both your source and result patterns. Any binding made inside collect is not available for use outside of it.
17.27. The Conditional Element Accumulate Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The Conditional Element
accumulate is a more flexible and powerful form of collect, in the sense that it can be used to do what collect does and also achieve results that the CE collect is not capable of doing. It allows a rule to iterate over a collection of objects, executing custom actions for each of the elements. At the end it returns a result object.
Accumulate supports both the use of pre-defined accumulate functions, or the use of inline custom code. Inline custom code should be avoided though, as it is harder for rule authors to maintain, and frequently leads to code duplication. Accumulate functions are easier to test and reuse.
The Accumulate CE also supports multiple different syntaxes. The preferred syntax is the top level accumulate, as noted bellow, but all other syntaxes are supported for backward compatibility.
17.28. Syntax for the Conditional Element Accumulate Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Top level accumulate syntax
accumulate( <source pattern>; <functions> [;<constraints>] )
accumulate( <source pattern>; <functions> [;<constraints>] )Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Syntax example
Copy to Clipboard Copied! Toggle word wrap Toggle overflow In the above example, min, max and average are Accumulate Functions and will calculate the minimum, maximum and average temperature values over all the readings for each sensor.
17.29. Functions of the Conditional Element Accumulate Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- average
- min
- max
- count
- sum
- collectList
- collectSet
These common functions accept any expression as input. For instance, if someone wants to calculate the average profit on all items of an order, a rule could be written using the average function:
17.30. The Conditional Element accumulate and Pluggability Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Accumulate functions are all pluggable. That means that if needed, custom, domain specific functions can easily be added to the engine and rules can start to use them without any restrictions. To implement a new Accumulate Function all one needs to do is to create a Java class that implements the
org.drools.runtime.rule.TypedAccumulateFunction interface and add a line to the configuration file or set a system property to let the engine know about the new function.
17.31. The Conditional Element accumulate and Pluggability Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
As an example of an Accumulate Function implementation, the following is the implementation of the
average function:
17.32. Code for the Conditional Element Accumulate's Functions Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Code for plugging in functions (to be entered into the config file)
jbossrules.accumulate.function.average = org.jbossrules.base.accumulators.AverageAccumulateFunction
jbossrules.accumulate.function.average = org.jbossrules.base.accumulators.AverageAccumulateFunctionCopy to Clipboard Copied! Toggle word wrap Toggle overflow - Alternate Syntax: single function with return type
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - ** item name **
- ** item description **
17.33. Accumulate with Inline Custom Code Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Warning
The use of accumulate with inline custom code is not a good practice for several reasons, including difficulties on maintaining and testing rules that use them, as well as the inability of reusing that code. Implementing your own accumulate functions allows for simpler testing. This form of accumulate is supported for backward compatibility only.
The general syntax of the
accumulate CE with inline custom code is:
<result pattern> from accumulate( <source pattern>,
init( <init code> ),
action( <action code> ),
reverse( <reverse code> ),
result( <result expression> ) )
<result pattern> from accumulate( <source pattern>,
init( <init code> ),
action( <action code> ),
reverse( <reverse code> ),
result( <result expression> ) )
The meaning of each of the elements is the following:
- <source pattern>: the source pattern is a regular pattern that the engine will try to match against each of the source objects.
- <init code>: this is a semantic block of code in the selected dialect that will be executed once for each tuple, before iterating over the source objects.
- <action code>: this is a semantic block of code in the selected dialect that will be executed for each of the source objects.
- <reverse code>: this is an optional semantic block of code in the selected dialect that if present will be executed for each source object that no longer matches the source pattern. The objective of this code block is to undo any calculation done in the <action code> block, so that the engine can do decremental calculation when a source object is modified or retracted, hugely improving performance of these operations.
- <result expression>: this is a semantic expression in the selected dialect that is executed after all source objects are iterated.
- <result pattern>: this is a regular pattern that the engine tries to match against the object returned from the <result expression>. If it matches, the
accumulateconditional element evaluates to true and the engine proceeds with the evaluation of the next CE in the rule. If it does not matches, theaccumulateCE evaluates to false and the engine stops evaluating CEs for that rule.
17.34. Accumulate with Inline Custom Code Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Inline custom code
Copy to Clipboard Copied! Toggle word wrap Toggle overflow In the above example, for eachOrderin the Working Memory, the engine will execute the init code initializing the total variable to zero. Then it will iterate over allOrderItemobjects for that order, executing the action for each one (in the example, it will sum the value of all items into the total variable). After iterating over allOrderItemobjects, it will return the value corresponding to the result expression (in the above example, the value of variabletotal). Finally, the engine will try to match the result with theNumberpattern, and if the double value is greater than 100, the rule will fire.- Instantiating and populating a custom object
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
17.35. Conditional Element Eval Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The conditional element
eval is essentially a catch-all which allows any semantic code (that returns a primitive boolean) to be executed. This code can refer to variables that were bound in the LHS of the rule, and functions in the rule package. Overuse of eval reduces the declarativeness of your rules and can result in a poorly performing engine. While eval can be used anywhere in the patterns, the best practice is to add it as the last conditional element in the LHS of a rule.
Evals cannot be indexed and thus are not as efficient as Field Constraints. However this makes them ideal for being used when functions return values that change over time, which is not allowed within Field Constraints.
17.36. Conditional Element Eval Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
This is what
eval looks like in use:
p1 : Parameter() p2 : Parameter() eval( p1.getList().containsKey( p2.getItem() ) )
p1 : Parameter()
p2 : Parameter()
eval( p1.getList().containsKey( p2.getItem() ) )
p1 : Parameter() p2 : Parameter() // call function isValid in the LHS eval( isValid( p1, p2 ) )
p1 : Parameter()
p2 : Parameter()
// call function isValid in the LHS
eval( isValid( p1, p2 ) )
17.37. The Right Hand Side Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
The Right Hand Side (RHS) is a common name for the consequence or action part of the rule. The main purpose of the RHS is to insert, retractor modify working memory data. It should contain a list of actions to be executed. The RHS part of a rule should also be kept small, thus keeping it declarative and readable.
Note
If you find you need imperative and/or conditional code in the RHS, break the rule down into multiple rules.
17.38. RHS Convenience Methods Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Name | Description |
|---|---|
update(object, handle);
|
Tells the engine that an object has changed (one that has been bound to something on the LHS) and rules that need to be reconsidered.
|
update(object);
|
Using
update(), the Knowledge Helper will look up the facthandle via an identity check for the passed object. (If you provide Property Change Listeners to your Java beans that you are inserting into the engine, you can avoid the need to call update() when the object changes.). After a fact's field values have changed you must call update before changing another fact, or you will cause problems with the indexing within the rule engine. The modify keyword avoids this problem.
|
insert(newobject());
|
Places a new object of your creation into the Working Memory.
|
insertLogical(newobject());
|
Similar to insert, but the object will be automatically retracted when there are no more facts to support the truth of the currently firing rule.
|
retract(handle);
|
Removes an object from Working Memory.
|
17.39. Convenience Methods using the Drools Variable Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- The call
drools.halt()terminates rule execution immediately. This is required for returning control to the point whence the current session was put to work withfireUntilHalt(). - Methods
insert(Object o),update(Object o)andretract(Object o)can be called ondroolsas well, but due to their frequent use they can be called without the object reference. drools.getWorkingMemory()returns theWorkingMemoryobject.drools.setFocus( String s)sets the focus to the specified agenda group.drools.getRule().getName(), called from a rule's RHS, returns the name of the rule.drools.getTuple()returns the Tuple that matches the currently executing rule, anddrools.getActivation()delivers the corresponding Activation. (These calls are useful for logging and debugging purposes.)
17.40. Convenience Methods using the Kcontext Variable Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- The call
kcontext.getKnowledgeRuntime().halt()terminates rule execution immediately. - The accessor
getAgenda()returns a reference to the session'sAgenda, which in turn provides access to the various rule groups: activation groups, agenda groups, and rule flow groups. A fairly common paradigm is the activation of some agenda group, which could be done with the lengthy call:// give focus to the agenda group CleanUp kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();
// give focus to the agenda group CleanUp kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup( "CleanUp" ).setFocus();Copy to Clipboard Copied! Toggle word wrap Toggle overflow (You can achieve the same usingdrools.setFocus( "CleanUp" ).) - To run a query, you call
getQueryResults(String query), whereupon you may process the results. - A set of methods dealing with event management lets you add and remove event listeners for the Working Memory and the Agenda.
- Method
getKnowledgeBase()returns theKnowledgeBaseobject, the backbone of all the Knowledge in your system, and the originator of the current session. - You can manage globals with
setGlobal(...),getGlobal(...)andgetGlobals(). - Method
getEnvironment()returns the runtime'sEnvironment.
17.41. The Modify Statement Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
| Name | Description | Syntax | Example |
|---|---|---|---|
| modify |
This provides a structured approach to fact updates. It combines the update operation with a number of setter calls to change the object's fields.
|
modify ( <fact-expression> ) {
<expression> [ , <expression> ]*
}
The parenthesized <fact-expression> must yield a fact object reference. The expression list in the block should consist of setter calls for the given object, to be written without the usual object reference, which is automatically prepended by the compiler.
| |
17.42. Query Examples Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Note
To return the results use
ksession.getQueryResults("name"), where "name" is the query's name. This returns a list of query results, which allow you to retrieve the objects that matched the query.
- Query for people over the age of 30
query "people over the age of 30" person : Person( age > 30 ) endquery "people over the age of 30" person : Person( age > 30 ) endCopy to Clipboard Copied! Toggle word wrap Toggle overflow - Query for people over the age of X, and who live in Y
query "people over the age of x" (int x, String y) person : Person( age > x, location == y ) endquery "people over the age of x" (int x, String y) person : Person( age > x, location == y ) endCopy to Clipboard Copied! Toggle word wrap Toggle overflow
17.43. QueryResults Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
We iterate over the returned QueryResults using a standard "for" loop. Each element is a QueryResultsRow which we can use to access each of the columns in the tuple. These columns can be accessed by bound declaration name or index position:
17.44. Queries Calling Other Queries Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
Queries can call other queries. This combined with optional query arguments provides derivation query style backward chaining. Positional and named syntax is supported for arguments. It is also possible to mix both positional and named, but positional must come first, separated by a semi colon. Literal expressions can be passed as query arguments, but you cannot mix expressions with variables.
Note
Using the '?' symbol in this process means the query is pull only and once the results are returned you will not receive further results as the underlying data changes.
17.45. Queries Calling Other Queries Example Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
- Query calling another query
Copy to Clipboard Copied! Toggle word wrap Toggle overflow - Using live queries to reactively receive changes over time from query results
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
17.46. Unification for Derivation Queries Copiar enlaceEnlace copiado en el portapapeles!
Copiar enlaceEnlace copiado en el portapapeles!
JBoss Rules supports unification for derivation queries. This means that arguments are optional. It is possible to call queries from Java leaving arguments unspecified using the static field org.drools.runtime.rule.Variable.v. (You must use 'v' and not an alternative instance of Variable.) These are referred to as 'out' arguments.
Note
The query itself does not declare at compile time whether an argument is in or an out. This can be defined purely at runtime on each use.