This is the final part of a three-part series on using Drools Expert with Apache Camel. Part one provides an overview of Drools Expert and part two covers Apache Camel. Today’s blog details a working example utilizing both technologies.
The following examples of using Drools as a Content Based Router have been adapted from a JBoss Fuse example and modified for the purposes of this blog. The modified code shown here can be downloaded from GitHub. These code samples use the latest Drools 6 “KIE” API (Knowledge is Everything), which removes several XML elements commonly seen in Drools 5 Camel routes (as detailed in the Drools 6 documentation).
Knowledge Session Declaration
All knowledge sessions are stored in a KieModule, which can be configured using XML or through manual Java invocations. The recommended way to configure a KieModule is to place a kmodule.xml file in your Java project’s META-INF folder. An alternative approach to manually instantiate a KieModule without XML can be found in section 18.104.22.168 in the KIE documentation.
Code sample from kmodule.xml
The KieModule can contain many knowledge bases, which act as groupings of facts. The packages attribute on the kbase element specifies which packages under the project’s resources folder should be scanned for DRL files. If the packages element is not included, all DRL files within the resources folder will be used. Each knowledge base can contain many knowledge sessions, each of which will contain all of the rules that the base’s DRL files declare.
Using a Knowledge Session
Camel configuration files can reference the knowledge session beans declared in kmodule.xml within routes by using the kie:session-ref element, which instantiates the knowledge session as a bean that routes can reference. The kie:session-ref element’s ID must reference a knowledge session defined in kmodule.xml. This element can also be used to instantiate global variables within the session that act as POJOs accessible within rules that do not originate from facts. (An example of global variable instantiation can be seen in a more complex version of the sample shown below at camel-context.xml.)
Code sample from blog-camel-context-simple.xml
Executable from the JUnit test at CamelContextSimpleTest.java
The critical part of this route example is the following element:
This “to” element specifies that the ksession1 knowledge session should fire all of its rules on the POJO that was output by the previous Processor in the route (which is a Person object in this instance). Different actions can be used instead of insertBody (e.g. passing in the Exchange object itself, or passing the Exchange’s “in” Message object which contains the Person POJO body used by the example above). The outgoing result of the execution of this “to” element is a modified version of the Person object with its canDrink variable set to true or false, which influences the following conditional element.
The DRL file that composes ksession1’s business logic contains one rule that determines whether or not the given Person is eligible to drink. As business requirements change, additional DRL files can be added to ksession1 via kmodule.xml or the contents of this DRL can be modified to affect the Person’s drinking eligibility without directly modifying any Java files or Camel routes.
Code sample from can-drink-rule.drl
How Could This Work Without Drools?
The Drools components in this example could have been replaced with a Processor implemented using the following Java class to achieve the same result. The element in the route that references the knowledge session could be replaced with the following line to implement the Processor below.
<bean method="fireAllRules" ref="drlEquivalentProcessor"/>
Code sample from blog-camel-context-no-drools.xml
Code sample from DrlEquivalentProcessor.java
Executable from the JUnit test at CamelContextNoDroolsTest.java
To further illustrate how Drools processes rules, this processor reflects the general logical flow of a rules engine in a very simplified fashion instead of taking the most efficient path to implement the rule. The simplest possible Processor implementation can be found at DrlEquivalentProcessorSimple.java (as implemented by the Camel route at blog-camel-context-no-drools-simple.xml and executable from the JUnit test at CamelContextNoDroolsSimpleTest.java). A slightly more complex version that better models the flow of rules engine logic can be found at DrlEquivalentProcessorExchange.java (as implemented by the Camel route at blog-camel-context-no-drools-exchange.xml and executable from the JUnit test at CamelContextNoDroolsExchangeTest.java). The Drools Expert rules engine is actually implemented using the Rete Algorithm which is much more complex than any of these Java examples, but the general data flow is similar.
When Drools Is Appropriate
Drools Expert should not be used to implement a single simple rule as shown in the examples above, as shown by the simplicity of the equivalent Java samples. However, when a decision is composed of dozens of loosely coupled rules, it may make sense to externalize the logic into a series of DRL files to take advantage of their easily readable rule-oriented syntax, DRL visualization solutions, and the ability for domain experts to understand and modify DRL files without changing application source code.
Some caveats to remember when using Drools are that it scales best when a large number of rules are executed against a small number of facts. It also makes more sense to use Drools when the rules are loosely coupled; if many rules depend on each other in a chain, it may make more sense to write an if statement decision tree in Java code instead of presenting the logic as a series of individual rules spread throughout one or more DRL files.
If you have any questions over this introduction to using Drools Expert with Apache Camel, feel free to use the comments section below or contact us at firstname.lastname@example.org. You can also follow us on Twitter at @CrederaOpen and connect with us on LinkedIn for additional Open Technologies insights.