Skip to content

Latest commit

 

History

History
369 lines (245 loc) · 32.8 KB

jboss-brms-6-workshop.adoc

File metadata and controls

369 lines (245 loc) · 32.8 KB

JBoss BRMS 6.0 Workshop

Rules Engine

A business rules engine is a software system that executes one or more business rules in a runtime production environment.

KIE and Drools API

In version 6.x of JBoss BRMS and BPMSuite, the Drools API has changed quite drastically. Common knowledge concepts and APIs have been centralized in the KIE API, where KIE stands for Knowledge Is Everything.

Furthermore, the platform has focussed on utilizing standards and defacto standards for storage and build management. For example, the new KIE, Drools and jBPM platform heavily utilize Maven as the build and deployment management platform and the BRMS and BPMSuite platforms use Git as the source code management system.

The KIE API

This paragraph discusses the main KIE API classes. The JavaDoc for the API can be found here.

KieServices

Interface into the KIE API and runtime. Built by the KieServices.Factory: 'KieServices.Factory.get();'

KieContainer

Container for KieBases and KieSessions. Provides the API to build new Stateless and Stateful KieSessions.

KieSession

A Drools/KIE session in which facts and/or events can be inserted and in which rules are executed. A session can be either Stateful or Stateless

Stateful KieSession

A KieSession is by default stateful. This implies that the session retains state until it is expicitly disposed by calling the 'KieSession.dispose()' method. This implies that a system can continuously insert facts and fire rules until the session is explicitly disposed.

Stateless KieSession

A stateless KieSession is basically a wrapper around a stateful KieSession. The differences is that one cannot interact with the session. The session’s 'execute' method can be called only once, after which the session is automatically disposed. Interaction with the session is done by passing Drools 'Command' objects to the session. The session is automically disposed after the commands have been executed.

EventListeners

Drools provides a pluggable EventListener system based on the standard Java EventListener interface. The system provides 3 interfaces:

AgendaEventListener

Provides listener functionality for Agenda events, e.g. matchCreated, beforeMatchFired, afterMatchFired, beforeRuleFlowGroupActivated, etc. This allows one to, for example. implement loggers, auditing functionality (which rules have fired) and debugging functionality. In a recent Red Hat Services engagement, this feature was used to implement a framework to verify how many rules are covered during a JUnit test run.

RuleRuntimeEventListener

Provides listener functionality for WorkingMemory events. These events are fired when objects (facts, events) are inserted in, updated in or removed from the session’s WorkingMemory.

ProcessEventListener

Listens to process events like beforeProcessStarted, afterProcessStarted, beforeNodeTriggered, etc. This interface is for example iplemented by the JPAWorkingMemoryDbLogger which is responsible for logging jBPM process data to database for, for example, BAM purposes.

AgendaFilter

The AgendeFilter interface provides a means to control whether a rule should be fired or not. By implementing the 'boolean accept(Match match)' method, one can control whether the rule firing is accepted for a given Match or not. This can for example be based on the name of the rule, the facts that caused the rule to match, etc. This interface can for example be used in JUnit tests to only allow the rule under test to fire.

Drools Resources

A rulebase can be created from various sources. Drools supports the following resources out of the box:

DRL

The Drools Rule Language. This the main Drools language. Every rules resource is essentially translated into DRL by the Drools compilers.

DRL Rules

DTABLE

Decision Table implement in Microsoft Excel

DTABLE Rules

DSL and DSLR

Domain Specific Language. This allows one to write rules in a custom (Domain Specific) rules language. The Drool compiler will translate these rules into DRL. This feature can, for example, be used to write rules in a native language. E.g. it has been used in a customer project where rules were written by business people in French.

DSL Rules
DSLR Rules

RDSLR

Guided rule with DSL. This is a filetype that’s created by the JBoss BRMS web-based rule-editors in the KIE WorkBench.

BPMN2

Business Process Modeling and Notation, a language in which to define business processes. Can be used in BRMS 6 to define so called RuleFlows (which is a supported feature) and in BPMSuite 6 to define jBPM6 business processes.

BPMN2 RuleFlow

Drools Rule Language: Rule Layout and keywords

A Drools rule basically contains of 3 parts:

Left Hand Side (LHS)

the rule constraints. This is the conditional part of the rule. It consists of zero or more conditional elements. Facts are matched with the conditional elements, and if all elements match, the rule is activated.

Right Hand Sice (RHS)

the rule consequence. This defines the action performed when the rule is fired.

Rule attributes and meta-data

additional rule attributes that can influence rule odering rule exection, etc.

DRL Rule Layout

Drools defines a vast amount of keywords that can be used in the LHS and RHS of the rules. In this section we will discuss a number of these keywords that we will cover in this workshop. For a complete overview of keywords, please consult the Drools documentation: http://docs.jboss.org/drools/release/6.1.0.Final/drools-docs/html_single/index.html#d0e5393

Rule file keywords

  • package: defines the package-name of the rulebase (just like a Java package).

  • import: import of Java classes to be used in the rules.

  • function: this keyword allows us to define a function inside the rulebase.

  • declare: allows us to declare fact types directly inside the rulebase definition file instead of in Java. Also allows to add annotations to existing Java classes, for example to mark an existing class as a Drools Event (used in Complex Event Processing).

  • global: declare a global variable. This is not a fact inside the workingmemory, so the engine will not reason over globals. A global can be used, for example, to store the result of the rule firing (e.g. warnings, errors, filtered tickets, discounts, etc.).

attributes

  • salience: Defines the order of rule execution. Rules with a higher salience will execute first.

  • agenda-group: The name of the agenda-group to which this rule belongs. The rule will only fire if the agenda-group is active.

  • ruleflow-group: The name of the ruleflow-group. The rule will only fire when the ruleflow-group is active. In Drools 6, a ruleflow-group is implemented as an agende-group, and the ruleflow BPMN2 model defines the agenda-group stack.

  • no-loop: Prevents a rule from re-activating itself.

  • lock-on-active: inhibits additional activations of rules in the same agenda-group or ruleflow-group.

  • enabled: if set to 'false' disables the rule.

  • auto-focus: if set to 'true' the rule will give focus to the agenda-group to which it belongs when the rule matches.

conditional elements

  • or: is used to group other Conditional Elements into a logical disjunction. Drools supports both prefix or and infix or.

  • from: Loads data into the engine from an arbritrary source to be matched by the LHS

  • exists: Matches when on one or more instances of a certain type.

  • not: Matches when there are no facts within the workingmemory that match the constraint.

  • eval: The conditional element eval is essentially a catch-all which allows any semantic code (that returns a primitive boolean) to be executed.

  • accumulate: Accumulate allows a rule to iterate over a collection of objects, executing custom actions for each of the elements, and at the end, it returns a result object. It supports both pre-defined accumulate functions, as well as inline custom code.

The Rule Network

The rule network (or graph) defines the reasoning network through which our facts flow. It defines an efficient discrimination network through which data flows. The nodes at the top of the network would have many matches, and as we go down the network, there would be fewer matches. At the very bottom of the network are the terminal nodes. In this paragraph we will give a brief introduction to the network and Rete algorithm. For a more in-depth explanation please consult the Drools Manual.

A network consists of various types of nodes.

Rule Network Nodes

  • ObjectTypeNode: Matches on Objects and can propagate to AlphaNodes, LeftInputAdapterNodes and BetaNodes. AlphaNodes are used to evaluate literal

  • AlphaNode: Used to evaluate literal conditions.

  • LeftInputAdapterNode: This takes an Object as an input and propagates a single Object Tuple, which can be then fed into a BetaNode.

  • BetaNode: Evaluates constraints on two or more facts. The let input is for tuples, the right input is for facts.

    • JoinNode (BetaNode): Joins a tuple with a fact, creating a new tuple.

    • NotNode (BetaNode): represents the 'not' construct.

    • AccumulateNode (BetaNode): represents the 'accumulate' construct.

    • ExistsNode(BetaNode): represents the 'exists' construct.

    • EvalNode (BetaNode): represents the 'eval' construct.

    • TerminalNode: Terminal nodes are used to indicate a single rule having matched all its conditions; at this point we say the rule has a full match.

Here is an example of 2 rules written in DRL and the network/graph it produces:

Rule Network DRL

Rule Network Tree

ReteOO and PHREAK

Drools was based on the RETE (pronounced: ReeTee), a pattern matching algorithm for implementing production rule systems (http://en.wikipedia.org/wiki/Rete_algorithm). The implementation in Drools is called ReteOO, a Java-based RETE algorithm with enhancements. This algorithm is eager in nature, which can lead to much wasted work (where wasted work is classified as matching efforts that don’t result in rule-firing). This is demonstrated by the fact that most of the work in Drools 5 is done during the insert, update and delete actions. I.e. the rules in Drools 5 are not evaluated when calling fireAllRules, but when facts are inserted in, updated in and deleted from the WorkingMemory. Only the Right-Hand-Side of the rules is executed during a 'fireAllRules()' call.

In Drools vesion 6, the ReteOO algorithm was replaced by the PHREAK algorithm, a word-play on Hybrid Reasoning. PHREAK is a lazy evalutation algorithm in which the rule evaluation is done in the 'fireAllRules()' phase rather than the insert/update/delete phase. This is done through a goal-oriented, heuristics-based, algorithm: To learn more about PHREAK, please consult the following blog-post by the Drools project lead Mark Proctor: http://blog.athico.com/2013/11/rip-rete-time-to-get-phreaky.html

Drools and Maven: The KJAR

Up to version 5 of Drools, rules were added to a rulebase via a programming API. The idea was to create a so called KnowledgeBuilder to which various resources were added. Next, this builder was used to create a Drools KnowlegdeBase to create a KnowledgeSession (either Stateful or Stateless). When creating rule packages via the Drools Guvnor web-interface, rules were compiled into .pkg files, a proprietary packaging format.

In version 6, the concept of convention over configuration has been adopted. Proprietary ways of packaging (.pkg) has been replaced with a Maven-based packaging approach. In Drools 6, the rule definitions are packaged in so called KJARs, or Knowledge JARs. A KJAR is nothing more than a standard JAR file with a kmodule.xml descriptor in its META-INF directory.

A kmodule.xml allows one to define and configure (named) KieBases and KieSessions. For example, we can define which packages in a KJAR are added to a KieBase. This allows us to add different rule defintions to a KJAR and define a separate KieBase per rule resource or per set of rule resources. Furthermore, we can configure the session’s event-mode, cloud or stream (for Complex Event Processing scenarios). We can configure which clock is used by the session (realtime or pseudo), and we can define which WorkItemHandlers are configured on a session (which is used in jBPM6 environments) and which listeners we want to attach to a KieSession.

KModule.xml

KModule.xml

BRMS Design Patterns

BRMS/Drools is a lightweight and flexible rules-engine which can be use in various different environments in different ways. In this section we will discuss a number of KieSession and deployment patterns.

We will first look at rule execution. As we have seen earlier, rules can be executed in either a stateless or a stateful session. Second the rules-engine itself can be either deployed "in-process" with the actual application (or service) or as a remote rule execution service. When we combine these 2 parameters, we come to the following 4 options of executing rules.

Option Description Pros Cons

Embedded Stateless

The rules-engine runs stateless sessions embedded within the application. The Drools libraries (note, not necessarily the rule definitions) are packaged with the application and embedded into a Java Archive (WAR/EAR), or are referenced as an OSGi bundle. The application integrates with the rules-engine through its Java API. The rules run in a stateless session, which is disposed after the rules have been fired.

Simple API-based integration between application and rules-engine.

Performant (no remoting)

Expensive to scale (BRMS subscription needed on every core that serves the application).

Upgrading BRMS implies that the application needs to be upgraded.

Remote Stateless

The rules-engine and rules are exposed through a remote service. The application interacts with the remote service via the RESTful or JMS API (out-of-the-box in the kie-execution-server), or via a custom API. The rules sessions is able to serve only a single request. For each request a new session is created.

Flexible

Potentially more cost-effective (centralized BRMS execution, potentially requiring less subscriptions

Less performant (marshalling/serialization and network overhead).

More difficult integration (JSON, XML) in comparison with Java API integration.

Embedded Stateful

Like Embedded Stateless, but with long-running sessions. This architecture is usually used in Complex Event Processin scenario’s where sessions consume a constant stream of events and/or facts on which they need to operate. The session is kept alive until the application calls the session’s dispose method.

Allows for multiple rule firings on a single session, giving the ability to serve fact/event streams.

Complex Event Processing

Increases application complexity.

Expensive to scale (BRMS subscription needed on every core that serves the application).

Upgrading BRMS implies that the application needs to be upgraded.

Remote Stateful

Not (yet) supported by the BRMS KIE-Execution-Server. Can be designed and implemented as a stateful service, for example via Remote Stateful Session Beans (SFSB) EJBs.

Complex

HA concerns

Less performant (marshalling/serialization and network overhead).

We will now look at the various options/patterns of rule deployment. As we have seen, Drools rules are packaged in Knowledge JARs, or KJARs, and there are multiple options to reference the rules from the rules engine.

Option Description Pros Cons

Push (Remote/KIE Server)

The rule deployment is pushed to the KIE-Execution Server via the KIE Server Controller (in managed-mode) or via the KIE-Execution Server RESTful API (unmanaged). Although the deployment GAV (GroupId, ArtifactId, Version) is pushed to the server, the actual KJAR artifact is still fetched from the Maven repository by the execution server.

Flexible

Rules LCM outside of application

Requires operationalization of the rules deployment interface outside normal application deployments

Static (Embedded)

The KJAR is packaged and deployed with the application. The KieContainer is loaded as a KieClasspathContainer.

Simple

Uses existing application deployment process

To upgrade rules, the application needs to be upgraded (and deployed).

Polling/Scanning (Embedded)

The KJAR is dynamically fetched from the KieRepository at runtime using a given ReleaseId (Maven GAV). A KieScanner is configured on the KieContainer to scan for updates of the given KJAR at runtime and to dynamically update the KieBases in the KieContainer and any active KieSessions.

Allows for update of rules at runtime without application restarts.

Dynamically updating rules at runtime can be dangerous when rules have not been properly tested.

Rules LCM has to be managed outside of the application.

Example API usage

As mentioned in the previous section, prior to Drools 6, one required quite a bit of code to build KnowledgeBase and KnowlegdeSession, as is shown below:

Drools 5 KnowledgeBase resources

Drools 5 KnowledgeBase resource

Drools 5 session

The next example shows how we can load the same rule-base in Drools 6. Due to the use of convention over configuration, the rule-base is automatically created using the configuration in the kmodule.xml descriptor file. A KieServices implementation is retrieved from the KieServices.Factory from which a new KieContainer is constructed. The KieSession is created by the KieContainer, facts are inserted and the rules are fired. After the rule-firing, the KieSession is disposed, releasing the resources.

Drools 6 KieContainer

Drools 6 KieSession

And another small example:

KieServices kieServices = KieServices.Factory.get();
KieContainer kContainer = kieServices.getKieClasspathContainer();
KieSession kSession = kContainer.newKieSession();
for( Object fact : facts ) {
     kSession.insert( fact );
}
kSession.fireAllRules();
kSession.dispose();

Dynamically loading rules at runtime

An ofter heared requirement is the ability to dynamically load and/or re-load rules at runtime. A use-case for this is to be able to update rules at runtime without having to restart the application that uses the engine. In previous versions of Drools this was accomplished by the KnowledgeAgent, that would scan a ChangeSet.xml file for changes in the ruleset.

In Drools 6, this is implemented via the KieScanner. This scanner periodically scans the Maven repository, from which the KJAR was retrieved (using, for example, an @ReleaseId reference), for changes. When a change in the KJAR is detected, the KJAR is retrieved from the repository, compiled and configured on the KieContainer. When a new session is retrieved from the KieContainer, it will use the new KieBase with the new rules.

Note
KieScanner and existing KieSessions
When the KieScanner finds a new KJAR and the KieContainer is updated, only newly created KieSessions will use the new rules. Existing KieSessions will continue to use the old rule-base.

The Brms6WorkshopKieScannerApp example shows the KieScanner functionality. This is an excerpt of the code of that sample application which demonstrates the scanner API:

KieScanner

To run the demo, do the following:

  1. run mvn clean install on the Brms6WorkshopKieScannerRules project to install the KJAR in your local .m2 repository.

  2. run mvn clean install exec:java on the Brms6WorkshopKieScannerApp project to start the application. If the app has been started correctly, it will print the line Found person: Duncan every 5 seconds.

  3. alter the rule in the rules.drl file in the Brms6WorkshopKieScannerRules project. For example, change the text in the System.out.println in the RHS of the rule. Run mvn clean install. This will install a new version of the KJAR in your local .m2 repository.

  4. Check the output if the Brms6WorkshopKieScannerApp that is still running. If everything has been done correctly, the KieScanner should automatically pick-up the new KJAR and start processing the data with the new rules.

Playtime

Now that we’ve seen some of the Drools APIs, and some of the capabilities, let’s start playing with some code and rules. The Brms6WorkshopRules project contains a Main class which demonstrates how to use the KIE API to load a simple rulebase and create a KieSession. It demonstrates how facts can be inserted into the session, rules can be fired and how results can be retrieved.

Rules are implemented in 3 different ways:

  1. DRL

  2. DTABLE / Microsoft Excel

  3. DSL and DSLR

We’ll go through these concepts one-by-one in order to get a feel of how the engine works. Feel free to add new rules to the rule definitions and to experiment with the API.

Drools Expert Labs

These Drools Expert labs aim to build-up a small rulebase for a ticket ordering system. The lab starts with a small, pre-defined fact-model and a simple rule-base. The idea is to gradually expand the rule-base and add new features using more sophisticated Drools concepts, effectively building new and more sophisticated functionality.

Fact Model

The fact model contains the classes that define the facts over which the rules will reason. We will create objects from these classes and inject them into the Drools WorkingMemory (session).

The examples are modelled around an online ticketing system. The rules are responsible for filtering out tickets that are not available to a certain person (e.g. under age) and applying initial discount to the ticket prices (e.g. the person has a discount pass, the person is under age, etc.). To do this, we insert 3 types of facts into the session:

  1. Ticket

  2. Person

  3. EventPass

The result, which is a list of TicketOffer`s with the tickets available for this `Person, including calculated discount. This is passed into the global `TicketOffer`s.

The implementation

The main logic in these labs is defined in the Brms6WorkshopTicketsUseCaseRulesMain project. It contains the logic to build a KieContainer and KieSession, creates the fact objects, inserts them into the KieSession and fires the rules. The various other projects define the ruleset(s) that are used at runtime. We will start with a very simple rulebase with just 2 rules, and gradually build up a more complex set of rules.

Lab 1 - Order of Execution

We start with 2 simple rules in Brms6WorkshopTicketsUseCaseRules1, one that creates the TicketOffer`s, and one that filters out the tickets for people below the age of 18. Execute the application by running the `Main class. Observe the output. What is wrong with our rulebase? Can you fix it? How?

A possible solution is implemented in Brms6WorkshopTicketsUseCaseRules2.

Lab 2 - Rule Implementation

Start with the Brms6WorkshopTicketsUseCaseRules2 project. We will now implement a rule filters out all tickets out all tickets with 'TICKET_CLASS.GOLD' if our Person does not have an EventPass. I.e. we only allow people with a special event-pass to purchase these tickets.

A possible solution is implemented in Brms6WorkshopTicketsUseCaseRules3.

Lab 3 - Looping 2

Start with the Brms6WorkshopTicketsUseCaseRules3 project. In this lab implement 2 discount rules. The first rule gives a 25% discount for on all tickets for non-adults (people below the age of 18) and the second rule applies a 10% discount on all tickets for people with an EventPass.

First try to implement a single rule and observe what happens. If you encounter an issue, try to solve this issue first. Then implement the second discount rule. Again, if any problems occur, try to solve them. Feel free to share anything you encounter with the group. We’re here to learn :-)

Again, a possible solution is implemented in Brms6WorkshopTicketsUseCaseRules4.

Lab 4 - Inference

Start with the Brms6WorkshopTicketsUseCaseRules4 project. If all is well, we have now got 2 rules in our ruleset that check on the same constraint, namely if a Person is under the age of 18. One of the powers of Drools is the possibility to infer new data (facts) in rules, and add this new inferred data as a constraint to other rules. We’re going to apply this technique in this lab.

In our fact model, we have a class called IsAdult. Create a new rule that infers this fact from the facts entered into working memory, and inserts this new fact into the engine. Next, use this new fact in the constraint of the rules that check if a person is underage.

A possible solution is implemented in Brms6WorkshopTicketsUseCaseRules5.

Lab 5 - Agenda-Group

Start with the Brms6WorkshopTicketsUseCaseRules5 project. We’ve heavily used the 'salience' keyword in our rules to define rule execution ordering. Using 'salience' is however very error-prone. A better solution is to group rules into various 'agenda-groups', and control the order of execution of the rules by setting the focus on the correct agenda-group.

Group the rules in 4 different 'agenda-groups': init, filter, create-offers and discount. Next, create a rule that fires first (in the init 'agenda-group') and set the focus of the agende-groups in the RHS (consuquence) of the rule. The code to set the focus of an 'agenda-group' in the RHS of a rule is: kcontext.getKnowledgeRuntime().getAgenda().getAgendaGroup("init").setFocus();

Note that the 'agenda-group' is a stack-based system on which we push and from which we pop agenda-groups.

A possible solutions is implemented in Brms6WorkshopTicketsUseCaseRules6.

Lab 6 - RuleFlow-Group

Start with the Brms6WorkshopTicketsUseCaseRules6 project. Instead of 'agenda-group', we will now define the ordering of the rule execution with a BPMN2 RuleFlow. Change the implementation into one that use a RuleFlow and ruleflow-group.

A solution is implemented in the Brms6WorkshopTicketsUseCaseRules7 project.

Lab 7 - From

Start with the Brms6WorkshopTicketsUseCaseRules7 project. In the current rulebase, the discount values are statically defined. We however want to retrieve these discounts from a Service. Therefore, we’ve added the DiscountService Java class to our project. Use this class to retrieve the discount values for 2 discount rules. Hint: Use the from keyword.

A solution is implemented in the Brms6WorkshopTicketsUseCaseRules8 project.

Lab 8 - Logical Inserts

Start with the Brms6WorkshopTicketsUseCaseRules8 project. This is actually the same starting point as Lab 6, hence, the rules use Agenda-Groups instead of BPMN2 RuleFlow-Groups.

In this lab we will work with the Drools Truth Maintenance System (TMS). TMS works around the concept of Logical Inserts. When a fact is inserted into the session in the standard/normal way, the fact is only removed from the session when it is explicitly removed by Java code or by (another) rule. When you logically insert a fact into the session, the fact is automatically removed when the conditions that logically inserted the fact are no longer true.

One can logically insert a fact into the session by using the insertLogical keyword.

Using this mechanism, we can rewrite the rules in such a way that the order of execution of the rules (especially the filter rules) is no longer important. Remove the "Agenda-Group setup" rule from the DRL. Remove the agenda-group definitions from the rules, and rewrite the rules in such a way that it produces the same output as when using the Agenda Groups.

Note
Using TMS can have some performance impact, so the implementation of Lab 8, using logical inserts, is not necessarily a better implementation than the implementation using agenda-groups. The lab has been constructed to explain the concept of logical inserts, not to implement the best performing rule-base.

Lab 9 - Unit Tests

To build-in quality in your rules-system, it is extremely import to test your rules. No one wants to be responsible for an un-tested, rule in production that, due to an error, costs your company milliosn of euros/dollars/your currency of choice.

Testing rules can be hard, especially when we have a large rule-base (KieBase). How do you test a KieBase containing 1000 rules? What we would like to do is to test rules individually, or in groups. Group-testing of rules can be done by utilizing construtcs that have seen in previous labs: agenda-group and ruleflow-group. I.e. when we want to just test the rules of a certain group, the only thing we need to do is make sure that only that group gets activated (i.e. gets the focus).

There is however also a mechanism to test individual rules. To test individual rules, we can pass a, so called, AgendaFilter to the KieSession.fireAllRules method. The AgendaFilter allows us to control whic rule matches get accepted and will be placed on the Drools agenda for execution. Using this approach we can filter which rules get fired when we call the fireAllRules method, which allows us to test individual rule execution in, for example, unit-tests.

Start with the Brms6WorkshopTicketsUseCaseRules9 project. This is actually the same starting point as Lab 6, hence, the rules use Agenda-Groups instead of BPMN2 RuleFlow-Groups.

The project contains a unit-test class, RulesTest, with one unit-test, testDiscountForNonAdultsRule. This unit-test is annotated with the JUnit @Ignore annotation. The reason for this is that the unit-test, in its current state will fail, and would therefore fail the build of the labs. The exercise of this lab is:

  1. Remove the @Ignore annotation from the unit-test and run the test. This will throw an NPE.

  2. Change the unit-test in such a way that it will only test the "25% discount for non-adults" rule.

Lab 10 - Property Reactive

In previous labs we’ve seen how we could stop rules from looping by using the no-loop and lock-on-active Drools constructs. There is however another option to prevent a modification of a fact to re-trigger rule evaluations (and potentially execution): @PropertyReactive.

Property Reactive allows the Drools pattern matching algorithm to only react to modification of properties actually constrained or bound inside of a given pattern. This implies that when one modifies a property of a given fact in the RHS of a rule in a modify block, and there are no rules that have a LHS constraint on that property, the rules will not be re-evaluated and will not re-fire.

To show this in action, we have created the Brms6WorkshopTicketsUseCaseRules10 project, based on the Lab 6 project. However, we have removed the lock-on-active keyword from the rules in the discount agenda-group. As these rules modify the TicketOffer fact by adding a discount, these rules will start looping. Note however that there is no LHS constraint on the TicketOffer 's discount property in the LHS of the rules. Hence, by using the @PropertyReactive feature of Drools, we can prevent these rules from being re-evaluated.

Fix the looping of rules in Lab 10 by using the @PropertyReactive feature of Drools.