Drools Integration Modules: Spring Framework and Apache Camel

Exclusive offer: get 50% off this eBook here
Drools Developer’s Cookbook

Drools Developer’s Cookbook — Save 50%

Over 40 recipes for creating a robust business rules implementation by using JBoss Drools rules with this book and ebook

$26.99    $13.50
by Lucas Amador | January 2012 | Cookbooks Open Source

Integration with other systems is always one of the most critical steps in development and it should be on our mind during the planning phase. In this article, the Drools integration modules, Spring Framework and Apache Camel, will be covered explaining how they can be used independently of the Drools Server but, of course, integrated with Drools.

In this article by Lucas Amador, author of Drools Developer's Cookbook, we will cover the following concepts:

  • Setting up Drools using Spring Framework
  • Configuring JPA to persist our knowledge with Spring Framework
  • Integrating Apache Camel in your project

(For more resources on Drools, see here.)

Setting up Drools using Spring Framework

In this recipe, you will see how to configure the Drools business rules engine using the Spring framework, using the integration module specially created to configure the Drools beans with XML.

How to do it...

Carry out the following steps in order to configure a Drools project using the Spring Framework integration:

  1. Add the following dependency in your Maven project by adding this XML code snippet in the pom.xml file:

    <dependency> <groupId>org.drools</groupId> <artifactId>drools-spring</artifactId> <version>5.2.0.Final</version> </dependency>

  2. Once the drools-spring module and the Spring Framework dependencies are added into your project, it's time to write the rules that are going to be included in the knowledge base:

    package drools.cookbook.chapter07 import drools.cookbook.chapter07.model.Server import drools.cookbook.chapter07.model.Virtualization rule "check minimum server configuration" dialect "mvel" when $server : Server(processors < 2 || memory<=1024 || diskSpace<=250) then System.out.println("Server \"" + $server.name + "\" was rejected by don't apply the minimum configuration."); retract($server); end rule "check available server for a new virtualization" dialect "mvel" when $virtualization : Virtualization($virtMemory : memory, $virtDiskSpace : diskSpace) $server : Server($memory : memory, $diskSpace : diskSpace, virtualizations !=null) Number((intValue + $virtMemory) < $memory) from accumulate (Virtualization($vmemory : memory) from $server.virtualizations, sum($vmemory)) Number((intValue + $virtDiskSpace) < $diskSpace) from accumulate(Virtualization($vdiskSpace : diskSpace) from $server.virtualizations, sum($vdiskSpace)) then $server.addVirtualization($virtualization); retract($virtualization); end

  3. Then a Spring Application Context XML file has to be created to configure the Drools beans with the following code

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="<code>http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://drools.org/schema/drools-spring org/drools/container/spring/drools-spring-1.2.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <drools:grid-node id="node1" /> <drools:resource id="resource1" type="DRL" source="classpath:drools/cookbook/chapter07/rules.drl" /> <drools:kbase id="kbase1" node="node1"> <drools:resources> <drools:resource ref="resource1" /> </drools:resources> </drools:kbase> <drools:ksession id="ksession1" type="stateful" kbase="kbase1" node="node1" /> <drools:ksession id="ksession2" type="stateless" kbase="kbase1" node="node1" /> </beans>

  4. After all these three steps, you are ready to load the XML file using the Spring Framework API and obtain the instantiated beans to interact with the knowledge sessions:

    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); applicationContext.start(); StatefulKnowledgeSession ksession1= (StatefulKnowledgeSession)applicationContext .getBean("ksession1"); Server debianServer = new Server("debian-1", 4, 2048, 250, 0); ksession1.insert(debianServer); ksession1.fireAllRules(); applicationContext.stop();>

  5. In your Maven project, add the following dependencies in the pom.xml file to use JPA persistence using the Spring Framework:

    public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPath mlApplicationContext("applicationContext.xml"); applicationContext.start(); StatefulKnowledgeSession ksession1 = (StatefulKnowledgeSession) applicationContext.getBean("ksession1"); Server debianServer = new Server("debian-1", 4, 2048, 250, 0); ksession1.insert(debianServer); ksession1.fireAllRules(); applicationContext.stop(); }

  6. Implement the java.io.Serializable interface to the objects of your domain model that will be persisted.
  7. Create a persistence.xml file inside the resources/META-INF folder to configure the persistence unit. In this recipe, we will use an embedded H2 database for testing purposes, but you can configure it for any relational database engine:

    <?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/ persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/ orm"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http: java.sun.com/xml/ns/persistence/persistence_1_0.xsd http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/ xml/ns/persistence/orm_1_0.xsd"> <persistence-unit name="drools.cookbook.spring.jpa" transaction- type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>org.drools.persistence.info.SessionInfo</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.max_fetch_depth" value="3" /> <property name="hibernate.hbm2ddl.auto" value="create" /> <property name="hibernate.show_sql" value="false" /> </properties> </persistence-unit> </persistence>

  8. Now, we have to create an XML file named applicationContext.xml in the resources folder, in which we are going to define the beans needed to configure the JPA persistence and the Drools beans:

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/ beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance"xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation="http://www.springframework.org/schema/ beans http://www.springframework.org/schema/beans/spring- beans-2.0.xsdhttp://drools.org/schema/drools-spring org/drools/ container/spring/drools-spring-1.2.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/ schema/spring/camel-spring.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource. DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:tcp://localhost/Drools" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm. jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="persistenceUnitName" value="drools.cookbook. spring.jpa" /> </bean> <bean id="txManager" class="org.springframework.orm.jpa. JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <drools:grid-node id="node1" /> <drools:kstore id="kstore1" /> <drools:resource id="resource1" type="DRL" source="classpath:drools/cookbook/chapter07/rules.drl" /> <drools:kbase id="kbase1" node="node1"> <drools:resources> <drools:resource ref="resource1" /> </drools:resources> </drools:kbase> <drools:ksession id="ksession1" type="stateful" kbase="kbase1" node="node1"> <drools:configuration> <drools:jpa-persistence> <drools:transaction-manager ref="txManager" /> <drools:entity-manager-factory ref="entityManagerFactory" /> </drools:jpa-persistence> </drools:configuration> </drools:ksession> </beans>

  9. Finally, we have to write the following code in a new Java class file, or in an existing one, in order to interact with the Stateful knowledge session and persist this state into the H2 database without further actions:

    public void startApplicationContext() { ClassPathXmlApplicationContext applicationContext =newClassPathXmlApplicationContext("/applicationContext.xml"); applicationContext.start(); StatefulKnowledgeSession ksession1 = (StatefulKnowledgeSession) applicationContext.getBean("ksession1"); int sessionId = ksession1.getId(); Server debianServer = new Server("debianServer", 4, 2048, 1222, 0); ksession1.insert(debianServer); ksession1.fireAllRules(); ksession1.dispose(); Environment env = KnowledgeBaseFactory.newEnvironment(); env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, applicationContext.getBean("entityManagerFactory")); env.set(EnvironmentName.TRANSACTION_MANAGER, applicationContext.getBean("txManager")); Virtualization virtualization = new Virtualization( "dev","debian", 512, 30); KnowledgeStoreService kstore = (KnowledgeStoreService) applicationContext.getBean("kstore1"); KnowledgeBase kbase1 = (KnowledgeBase)applicationContext. getBean("kbase1"); ksession1 = kstore .loadStatefulKnowledgeSession(sessionId, kbase1, null, env); ksession1.insert(virtualization); ksession1.fireAllRules(); applicationContext.stop(); }

How it works...

In order to use the Spring Framework integration in your project, First you have to add the drools-spring module to it. In a Maven project, you can do it by adding the following code snippet in your pom.xml file:

<dependency> <artifactId>org.drools</artifactId> <groupId>drools-spring</groupId> <version>5.2.0.Final</version> </dependency>

This dependency will transitively include the required Spring Framework libraries in the Maven dependencies. Currently, the integration is done using the 2.5.6 version, but it should work with the newest version as well.

Now, we are going to skip the rule authoring step because it's a very common task and you really should know how to do it at this point, and we are going to move forward to the beans configuration.

As you know, the Spring Framework configuration is done through an XML file where the beans are defined and injected between them, and to make Drools declaration easy the integration module provides a schema and custom parsers. Before starting the bean configuration, the schema must be added into the XML namespace declaration, otherwise the Spring XML Bean Definition Reader is not going to recognize the Drools tags and some exceptions will be thrown. In the following code lines, you can see the namespace declarations that are needed before you start writing the bean definitions:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://drools.org/schema/drools-spring org/drools/container/spring/drools-spring-1.2.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <!—- define your beans here --> </beans>

After this, the drools beans can be added inside the XML configuration file using the friendly tags:

<drools: /> tags: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://drools.org/schema/drools-spring org/drools/container/spring/drools-spring-1.2.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <drools:grid-node id="node1" /> <drools:resource id="resource1" type="DRL" source="classpath:drools/cookbook/chapter07/rules.drl" /> <drools:kbase id="kbase1" node="node1"> <drools:resources> <drools:resource ref="resource1" /> </drools:resources> </drools:kbase> <drools:ksession id="ksession1" type="stateful" kbase="kbase1" node="node1" /> </beans>

As you can see, there is only one stateful knowledge session bean configured by using the tag with a ksession1 ID. This ksession1 bean was injected with a knowledge base and a grid node so that the Drools Spring beans factories, which are provided by the integration module, can instantiate it.

Once the drools beans are configured, it's time to instantiate them using the Spring Framework API, as you usually do:

public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPath mlApplicationContext("applicationContext.xml"); applicationContext.start(); StatefulKnowledgeSession ksession1 = (StatefulKnowledgeSession) applicationContext.getBean("ksession1"); Server debianServer = new Server("debian-1", 4, 2048, 250, 0); ksession1.insert(debianServer); ksession1.fireAllRules(); applicationContext.stop(); }

In the Java main method, a ClassPathXmlApplicationContext object instance is used to load the bean definitions, and once they are successfully instantiated they are available to be obtained using the getBean(beanId) method . At this point, the Drools beans are instantiated and you can start interacting with them as usual by just obtaining their references.

As you saw in this recipe, the Spring framework integration provided by Drools is pretty straightforward and allows the creation of a complete integration, thanks to its custom tags and simple configuration.

See also

For more information about the Drools bean definitions, read the Spring Integration in the official documentation available at http://www.jboss.org/drools/documentation.

Configuring JPA to persist our knowledge with Spring Framework

How to do it...

Carry out the following steps in order to configure the Drools JPA persistence using the Spring module integration:

How it works...

Before we start declaring the beans that are needed to persist the knowledge using JPA, we have to add some dependencies into our project configuration, especially the ones used by the Spring Framework. These dependencies were already described in the first step of the previous section, so we can safely continue with the remaining steps.

Once the dependencies are added into the project, we have to implement the java.io.Serializable interface in the classes of our domain model that will be persisted.

After this, we have to create a persistence unit configuration by using the default persistence.xml file located in the resources/META-INF directory of our project. This persistence unit is named drools.cookbook.spring.jpa and uses the Hibernate JPA implementation. Also, it is configured to use an H2 Java database, but in your real environment, you should supply the appropriate configuration. Next, you will see the persistence unit example, with the annotated SessionInfo entity that will be used to store the session data, which is ready to be used with Drools:

<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/ persistence" xmlns:orm="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http:// java.sun.com/xml/ns/persistence/persistence_1_0.xsd http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/ persistence/orm_1_0.xsd"> <persistence-unit name="drools.cookbook.spring.jpa" transaction- type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <class>org.drools.persistence.info.SessionInfo</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.max_fetch_depth" value="3" /> <property name="hibernate.hbm2ddl.auto" value="create" /> <property name="hibernate.show_sql" value="false" /> </properties> </persistence-unit> </persistence>

Now, we are ready to declare the beans that are needed to enable the JPA persistence with an XML file, where the most important section is the declaration of the Spring DriverManagerDataSource and LocalContainerEntityManagerFactoryBean beans , which are very descriptive and can be configured with the parameters of your data engine. Also, one of the most important declarations is the KnowledgeStoreService bean, using the tag, that will be primarily used to load the persistence knowledge session:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/ beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://drools.org/schema/drools-spring org/drools/container/spring/ drools-spring-1.2.0.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/ spring/camel-spring.xsd"> <bean id="dataSource" class="org.springframework.jdbc.datasource. DriverManagerDataSource"> <property name="driverClassName"value="org.h2.Driver" /> <property name="url"value="jdbc:h2:tcp://localhost/Drools" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa. LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="persistenceUnitName" value="drools.cookbook.spring.jpa" /> </bean> <bean id="txManager" class="org.springframework.orm.jpa. JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <drools:grid-node id="node1" /> <drools:kstore id="kstore1" /> <drools:resource id="resource1" type="DRL" source="classpath:drools/ cookbook/chapter07/rules.drl" /> <drools:kbase id="kbase1" node="node1"> <drools:resources> <drools:resource ref="resource1" /> </drools:resources> </drools:kbase> <drools:ksession id="ksession1" type="stateful" kbase="kbase1" node="node1"> <drools:configuration> <drools:jpa-persistence> <drools:transaction-manager ref="txManager" /> <drools:entity-manager-factory ref="entityManagerFactory" /> </drools:jpa-persistence> </drools:configuration> </drools:ksession> </beans>

After the bean definitions, we can start writing the Java code needed to initialize the Spring Framework application context and interact with the defined beans. After loading the application context by using a ClassPathXmlApplicationContext object, we have to obtain the stateful knowledge session to insert the facts into the working memory, and also obtain the ID of the knowledge session to recover it later:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml"); applicationContext.start(); StatefulKnowledgeSession ksession1 = (StatefulKnowledgeSession) applicationContext.getBean("ksession1"); int sessionId = ksession1.getId(); Server debianServer = new Server("debianServer", 4, 2048, 1222, 0); ksession1.insert(debianServer); ksession1.fireAllRules(); ksession1.dispose();

Once we are done interacting with the knowledge session and inserting facts, firing the rules, and so on, these can be disposed. They can be restored later using the KnowledgeStoreService bean , but we have to create a new org.drools.runtime.Environment object to set the EntityManager and TransactionManager used in the persistence process before trying to load the persisted knowledge session. The org.drools.runtime.Environment object can be created as follows:

Environment env = KnowledgeBaseFactory.newEnvironment(); env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, applicationContext.getBean("entityManagerFactory")); env.set(EnvironmentName.TRANSACTION_MANAGER, applicationContext.getBean("txManager")); Virtualization virtualization = new Virtualization("dev", "debian", 512, 30);

Finally, with the Environment object created, we can obtain the KnowledgeStoreService bean together with the KnowledgeSession bean and the StatefulKnowledgeSession ID to load the stored state and start to interact with it as we do usually:

KnowledgeStoreService kstore = (KnowledgeStoreService) applicationContext.getBean("kstore1"); KnowledgeBase kbase1 = (KnowledgeBase) applicationContext. getBean("kbase1"); ksession1 = kstore.loadStatefulKnowledgeSession(sessionId, kbase1, null, env); ksession1.insert(virtualization); ksession1.fireAllRules(); applicationContext.stop();

As you saw in this recipe, the knowledge session persistence is totally transparent to the user and automatic without any extra steps to save the state. By following these steps you can easily integrate JPA persistence using Hibernate, or any other vendor's JPA implementation, in order to save the current state of the knowledge session using the Spring Framework Integration.

Drools Developer’s Cookbook Over 40 recipes for creating a robust business rules implementation by using JBoss Drools rules with this book and ebook
Published: January 2012
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

(For more resources on Drools, see here.)

Integrating Apache Camel in your project

This recipe will explain how to programmatically integrate Drools with the Apache Camel Framework to define execution routes, which will consume and execute Drools commands. The advantage of this integration is that Apache Camel makes possible the implementation of more advanced enterprise integration patterns. As you may already know from the previous recipes, the interaction with knowledge sessions is done by sending command objects or their XML representation to defined routes. However, for further details you can read this recipe.

How to do it...

In the following steps, you will see how easily the Apache Camel Framework can be integrated with JBoss Drools:

  1. n order to use the Apache Camel integration, you have to add the drools-camel module to your project. If your project is managed using Apache Maven, as is recommended, then you can add the required dependencies by adding the following snippet code in the pom.xml file:

    <dependency> <groupId>org.drools</groupId> <artifactId>drools-camel</artifactId> <version>5.2.0.Final</version> </dependency>

  2. As usual, you need to create a DRL file to add rules and create the knowledge session. However, we are going to use the same rules created in the first recipe (Setting up Drools using Spring Framework), and we can continue moving forward.
  3. After this, you are ready to start implementing the integration, firstly, by creating a Stateful knowledge session with the previously defined rules. Create a CamelIntegration class and get ready to write the code, as follows:

    private StatefulKnowledgeSession createKnowledgeSession() { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory .newKnowledgeBuilder(); kbuilder.add(new ClassPathResource("rules.drl", getClass()), ResourceType.DRL); if (kbuilder.hasErrors()) { if (kbuilder.getErrors().size() > 0) { for (KnowledgeBuilderError kerror : kbuilder.getErrors()) { System.err.println(kerror); } } } KnowledgeBase kbase = kbuilder.newKnowledgeBase(); return kbase.newStatefulKnowledgeSession(); }

  4. In this step, you have to create an org.drools.grid.GridNode object and assign it to a JNDI context, which will be used in the next step to create a Camelcontext object :

    private Context createContext(StatefulKnowledgeSession ksession) { GridImpl grid = new GridImpl(); grid.addService(WhitePages.class, new WhitePagesImpl()); GridNode node = grid.createGridNode("node"); Context context = new JndiContext(); context.bind("node", node); node.set("ksession1", ksession); return context; }

  5. At this point, you are ready to create an org.apache.camel.CamelContext object and define the route that will be used to consume the Drools commands:

    private CamelContextCamelContext createCamelContext(Context context) { CamelContext camelContext = new DefaultCamelContext(context); RouteBuilder rb = new RouteBuilder() { public void configure() throws Exception { from("direct:test-with-session") .to("drools://node/ksession1"); } }; camelContext.addRoutes(rb); }

  6. Finally, after the routes are created the CamelContext is ready to consume the Drools commands to interact with the routes defined:

    Server debianServer = new Server("debian", 2, 2048, 2048, 0); Server winServer = new Server("win", 2, 1024, 250, 0); Virtualization virtualization = new Virtualization("dev", "debian", 512, 30); InsertObjectCommand insertServerCommand = (InsertObjectCommand) CommandFactory.newInsert(debianServer, "debian-server"); InsertObjectCommand insertBadServerCommand = (InsertObjectCommand) CommandFactory.newInsert(winServer, "win-server"); InsertObjectCommand insertVirtualizationCommand = (InsertObjectCommand) CommandFactory .newInsert(virtualization, "dev-virtualization"); FireAllRulesCommand fireAllRulesCommand = (FireAllRulesCommand) CommandFactory.newFireAllRules("executed-rules"); List<Command> commands = new ArrayList<Command>(); commands.add(insertServerCommand); commands.add(insertBadServerCommand); commands.add(insertVirtualizationCommand); commands.add(fireAllRulesCommand); BatchExecutionCommand batchExecutionCommand = CommandFactory.newBatchExecution(commands, "ksession1"); StatefulKnowledgeSession ksession = createKnowledgeSession(); Context context = createContext(ksession); CamelContext camelContext = createCamelContext(context); camelContext.start(); ProducerTemplate template = camelContext .createProducerTemplate(); ExecutionResults response = (ExecutionResults) template. requestBody("direct:test-with-session", batchExecutionCommand); DefaultFactHandle handle = (DefaultFactHandle) response.getFactHandle("debian-server")); Long executedRules = response.getValue("executed-rules"); camelContext.stop();

How it works...

The Apache Camel integration allows us to interact with a Drools stateless or stateful knowledge session through a pipeline, transforming the XML commands into executable commands, and executing each of them. It is the evolution of the old drools-pipeline module that is not available anymore. The advantage of this integration is that now it is possible to implement most of the available Enterprise Integration Patterns to solve a specific design problem with an elegant solution.

A list of the Enterprise Integration Patterns supported by Apache Camel is available at http://camel.apache.org/enterprise-integration-patterns.html.

With this integration, you can also use any of the available Apache Camel Components in the endpoints declaration to create declarative services. You can find these Camel Components athttp://camel.apache.org/component.html. For example, you can consume messages from a JMS Queue/Topic, send them to the Drools Component to execute them, and then send the execution results to another system using Apache MINA. As you can see, this brings a more powerful interoperability mechanism to integrate Drools with other systems. After this introduction, we can go forward through the recipe steps.

First, you have to add the drools-camel library to your project. We recommend the use of Apache Maven to manage the projects. If you are following this advice then you can modify the pom.xml file and add the following dependency in the dependencies declaration section:

<dependency> <groupId>org.drools</groupId> <artifactId>drools-camel</artifactId> <version>5.2.0.Final</version> </dependency>

This dependency will include the 2.4.0 version of Apache Camel, among other dependencies, which was optimized by the Apache Camel developers to provide a complete integration.

At this point, we can skip the rules authoring and the knowledge session creation steps, and move on to the most important ones.

The integration is coupled with another Drools module called drools-grid that allows an interaction with Drools knowledge sessions, independent of the JVM location. In this case, it is primarily used to execute the commands locally. This module is a transitive dependency of the drools-camel module, so you don't have to worry about this dependency.

At this point, you have to create an org.drools.grid.impl.GridImpl object instance and add to it a WhitePages service , which is a directory used to register all the available services. Using this GridImpl object , you have to create a GridNode that will have the responsibility to find the registered knowledge sessions and execute the commands on it with the previous registration of the knowledge session in the GridNode. The only step remaining is the creation of a JndiContext object that will be used later, and the binding of the GridNode on it:

GridImpl grid = new GridImpl(); grid.addService(WhitePages.class, new WhitePagesImpl()); GridNode node = grid.createGridNode("node"); Context context = new JndiContext(); context.bind("node", node); node.set("ksession1", ksession);

Now, we can create a CamelContext object using the previously created JndiContext. As we are programmatically configuring Apache Camel, a DefaultCamelContext is going to be used, but if you wish to use Spring Framework or OSGi, then there are appropriate CamelContext implementations provided by Camel for these.

ow, this is the part where you can define the routes, which is one of the most powerful features of this integration because of its very large library of components provided by Apache Camel to build pipelines. The routes are created by using a RouteBuilder object and adding the route definition using the Camel Java DSL from() and to() definitions. Once the routes are defined they must be added in the CamelContext object instance and the CamelContext must be started, otherwise the routes aren't going to be available. The following code snippet shows how to declare a simple route using a RouteBuilder object and add it to the CamelContext before getting started:

CamelContext camelContext = new DefaultCamelContext(context); RouteBuilder rb = new RouteBuilder() { public void configure() throws Exception { from("direct:test-with-session") .to("drools://node/ksession1"); } }; camelContext.addRoutes(rb); camelContext.start();

In the previous route definition, we were consuming messages from a direct endpoint and sending them to a Drools endpoint, which has the following syntax:

drools://{1}/{2}

where the parameters are as follows:

  • {1}: The Grid Node identifier that was registered in the CamelContext
  • {2}: The identifier of the knowledge session registered in the Grid node with identifier {1}

The knowledge session identifier is optional if it is supplied in the BatchExecutionCommand message. When this identifier is not configured the Grid node will obtain the knowledge session using its internal directory.

This route is very simple, but routes can be made more complex by adding Enterprise Integration Patterns (EIP) , such as Message Filter or Content Based Router, which can be implemented using filter() and choice() predicates.

  • Message Filter example:

    RouteBuilder messageFilter = new RouteBuilder() { public void configure() throws Exception { from("direct:test-with-session") .filter(header("priority").isNotEqualsTo("high")) .to("drools://node/ksession1"); } };

  • Content Based Router example:

    RouteBuilder contentBasedRouter = new RouteBuilder() { public void configure() throws Exception { from("direct:test-with-session") .choice() When(or(header("priority").isEqualsTo("low"), header("priority").isEqualsTo("medium"))) .to("drools://node/ksession1"); when(header("priority").isEqualsTo("high")) .to("drools://node/ksession2"); } };

Take a look at http://camel.apache.org/routes.html to learn how to create more complex routes. Also, to know more about the available predicates, you can find useful information at http://camel.apache.org/predicate.html.

Now, that the routes are started, you are ready to create the Drools commands and send them to CamelContext object:

List<Command> commands = new ArrayList<Command>(); commands.add(insertServerCommand); commands.add(insertBadServerCommand); commands.add(insertVirtualizationCommand); commands.add(fireAllRulesCommand); BatchExecutionCommand batchExecutionCommand = CommandFactory .newBatchExecution(commands, "ksession1");

The interaction with CamelContext object is realized by obtaining a ProducerTemplate object instance from it and sending the BatchExecutionCommand to the input endpoint by using the requestBody() method , as shown in the following code:

ProducerTemplate template = camelContext .createProducerTemplate(); ExecutionResults response = (ExecutionResults) template .requestBody("direct:test-with-session", batchExecutionCommand);

The BatchExecutionCommand instance will be delivered from the direct endpoint to the Drools endpoint by Apache Camel, where the registered GridNode will unmarshall/marshall the message if necessary, execute it, and return the results in an ExecutionResults object. With this object, you can access the different types of returned results, which will depend on the commands sent. You can see this in the following code snippet:

DefaultFactHandle handle = (DefaultFactHandle)response .getFactHandle("debian-server")); Long executedRules = response.getValue("executed-rules");

Summary

In this article, in the fisrt recipe we saw that the Spring framework integration provided by Drools is pretty straightforward and simple, and allows the creation of a complete integration with other modules. In the second recipe, we saw how easily we can integrate JPA persistence using Hibernate, or any other JPA implementation, in order to save the current state of the knowledge session using the Spring Framework Integration. In the last recipe, we saw how to create a complete integration of Drools with Apache Camel with its most used features.



Drools Developer’s Cookbook Over 40 recipes for creating a robust business rules implementation by using JBoss Drools rules with this book and ebook
Published: January 2012
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Lucas Amador

Lucas Amador is a Software Developer born and raised in Buenos Aires, Argentina. His Open Source interest started since young. However, he finally got fully involved in 2008 while working with a JBoss partner and providing consultancy and developing software using the JBoss middleware platform for telco, financial and other such companies. At this time he obtained the Sun Java Developer and JBoss Advanced Developer certifications.

He started getting involved in the JBoss Drools community through the Google Summer of Code 2009 program by implementing a refactoring module for the Eclipse Drools Plugin, and since then he is a jBPM5/Drools committer where spend his time implementing new features and fixing bugs. Lucas works as a freelance developer and is always looking something interesting to work in.

Books From Packt


Spring Security 3
Spring Security 3

Spring Roo 1.1 Cookbook
Spring Roo 1.1 Cookbook

Apache Maven 3 Cookbook
Apache Maven 3 Cookbook

JBoss Tools 3 Developers Guide
JBoss Tools 3 Developers Guide

NHibernate 3 Beginner's Guide
NHibernate 3 Beginner's Guide

NHibernate 3.0 Cookbook
NHibernate 3.0 Cookbook

JBoss AS 5 Development
JBoss AS 5 Development

Spring Persistence with Hibernate
Spring Persistence with Hibernate


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
S
3
K
d
Z
6
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software