JBoss.orgCommunity Documentation

Drools Integration User Guide

Version 6.0.0.CR3


Camel provides a light weight bus framework for getting information into and out of Drools.

Drools introduces two elements to make easy integration.

Drools can be configured like any normal camel component, but notice the policy that wraps the drools related segments. This will route all payloads to ksession1


It is possible to not specify the session in the drools endpoint uri, and instead "multiplex" based on an attribute or header. In this example the policy will check either the header field "DroolsLookup" for the named session to execute and if that isn't specified it'll check the "lookup" attribute on the incoming payload. It then attempts to "lookup" the session from the execution-node context and execute against it.



The following urls show sample script examples for jaxb, xstream and json marshalling using:

  • http://fisheye.jboss.org/browse/JBossRules/trunk/drools-camel/src/test/resources/org/drools/camel/component/jaxb.mvt?r=HEAD

  • http://fisheye.jboss.org/browse/JBossRules/trunk/drools-camel/src/test/resources/org/drools/camel/component/jaxb.mvt?r=HEAD

  • http://fisheye.jboss.org/browse/JBossRules/trunk/drools-camel/src/test/resources/org/drools/camel/component/xstream.mvt?r=HEAD

In this section we will explain the drools namespace.

Execution nodes are a context to register ksessions and kbases against for lookup.

A Knowledge Base has a 0..n resources. Has two nested elements, resources and configurations. Those resources can be inner elements or references, using the "ref" attribute.








Drools supports adding 3 types of listeners to KnowledgeSessions - AgendaListener, WorkingMemoryListener, ProcessEventListener

The drools-spring module allows you to configure these listeners to KnowledgeSessions using XML tags. These tags have identical names as the actual listener interfaces i.e., <drools:agendaEventListener....>, <drools:workingMemoryEventListener....> and <drools:processEventListener....>.

drools-spring provides features to define the listeners as standalone (individual) listeners and also to define them as a group.

drools-spring allows for grouping of listeners. This is particularly useful when you define a set of listeners and want to attach them to multiple sessions. The grouping feature is also very useful, when we define a set of listeners for 'testing' and then want to switch them for 'production' use.

This chapter describes the infrastructure used when configuring a human task server with Spring as well as a little bit about the infrastructure used when doing this.

The jBPM human task server can be configured to use Spring persistence. Example 2.11, “Configuring Human Task with Spring” is an example of this which uses local transactions and Spring's thread-safe EntityManager proxy.

The following diagram shows the dependency graph used in Example 2.11, “Configuring Human Task with Spring”.


A TaskService instance is dependent on two other bean types: a drools SystemEventListener bean as well as a TaskSessionSpringFactoryImpl bean. The TaskSessionSpringFactoryImpl bean is howerver not injected into the TaskService bean because this would cause a circular dependency. To solve this problem, when the TaskService bean is injected into the TaskSessionSpringFactoryImpl bean, the setter method used secretly injects the TaskSessionSpringFactoryImpl instance back into the TaskService bean and initializes the TaskService bean as well.

The TaskSessionSpringFactoryImpl bean is responsible for creating all the internal instances in human task that deal with transactions and persistence context management. Besides a TaskService instance, this bean also requires a transaction manager and a persistence context to be injected. Specifically, it requires an instance of a HumanTaskSpringTransactionManager bean (as a transaction manager) and an instance of a SharedEntityManagerBean bean (as a persistence context instance).

We also use some of the standard Spring beans in order to configure persistence: there's a bean to hold the EntityManagerFactory instance as well as the SharedEntityManagerBean instance. The SharedEntityManagerBean provides a shared, thread-safe proxy for the actual EntityManager.

The HumanTaskSpringTransactionManager bean serves as a wrapper around the Spring transaction manager, in this case the JpaTransactionManager. An instance of a JpaTransactionManager bean is also instantiated because of this.

Example 2.11. Configuring Human Task with Spring


<?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:jbpm="http://drools.org/schema/drools-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://drools.org/schema/drools-spring org/drools/container/spring/drools-spring-1.2.0.xsd">

  <!-- persistence & transactions-->
  <bean id="htEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="org.jbpm.task" />
  </bean>

  <bean id="htEm" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="htEmf"/>
  </bean>

  <bean id="jpaTxMgr" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="htEmf" />
    <!-- this must be true if using the SharedEntityManagerBean, and false otherwise -->
    <property name="nestedTransactionAllowed" value="true"/>
  </bean>

  <bean id="htTxMgr" class="org.drools.container.spring.beans.persistence.HumanTaskSpringTransactionManager">
    <constructor-arg ref="jpaTxMgr" />
  </bean>

  <!-- human-task beans -->

  <bean id="systemEventListener" class="org.drools.SystemEventListenerFactory" factory-method="getSystemEventListener" />

  <bean id="taskService" class="org.jbpm.task.service.TaskService" >
    <property name="systemEventListener" ref="systemEventListener" />
  </bean>

  <bean id="springTaskSessionFactory" class="org.jbpm.task.service.persistence.TaskSessionSpringFactoryImpl"
        init-method="initialize" depends-on="taskService" >
    <!-- if using the SharedEntityManagerBean, make sure to enable nested transactions -->
    <property name="entityManager" ref="htEm" />
    <property name="transactionManager" ref="htTxMgr" />
    <property name="useJTA" value="false" />
    <property name="taskService" ref="taskService" />
  </bean>

</beans>

When using the SharedEntityManagerBean instance, it's important to configure the Spring transaction manager to use nested transactions. This is because the SharedEntityManagerBean is a transactional persistence context and will close the persistence context after every operation. However, the human task server needs to be able to access (persisted) entities after operations. Nested transactions allow us to still have access to entities that otherwise would have been detached and are no longer accessible, especially when using an ORM framework that uses lazy-initialization of entities.

Also, while the TaskSessionSpringFactoryImpl bean takes an “useJTA” parameter, at the moment, JTA transactions with Spring have not yet been fully tested.

Inside the war file you will find a few XML configuration files.

The next step is configure the services that are going to be exposed through drools-server. You can modify this configuration in camel-server.xml file.


<?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:cxf="http://camel.apache.org/schema/cxf"
  xmlns:jaxrs="http://cxf.apache.org/jaxrs"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
  http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
  http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/> 
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

  <!--
   !   If you are running on JBoss you will need to copy a camel-jboss.jar into the lib and set this ClassLoader configuration
   !  http://camel.apache.org/camel-jboss.html
   !   <bean id="jbossResolver" class="org.apache.camel.jboss.JBossPackageScanClassResolver"/>
   -->

  <!--
   !   Define the server end point.
   !   Copy and paste this element, changing id and the address, to expose services on different urls.
   !   Different Camel routes can handle different end point paths.
   -->
  <cxf:rsServer id="rsServer"  
                address="/kservice/rest"
                serviceClass="org.drools.jax.rs.CommandExecutorImpl">
    <cxf:providers>
      <bean class="org.drools.jax.rs.CommandMessageBodyReader"/>
    </cxf:providers>
  </cxf:rsServer>  

  <!-- Leave this, as it's needed to make Camel "drools" aware -->
  <bean id="droolsPolicy" class="org.drools.camel.component.DroolsPolicy" />  

  <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">    
    <!-- 
     ! Routes incoming messages from end point id="rsServer".
     ! Example route unmarshals the messages with xstream and executes against ksession1.
     ! Copy and paste this element, changing marshallers and the 'to' uri, to target different sessions, as needed.
     !-->
     
    <route>
      <from uri="cxfrs://bean://rsServer"/>
        <policy ref="droolsPolicy">
          <unmarshal ref="xstream" />       
          <to uri="drools:node1/ksession1" />
          <marshal ref="xstream" />
        </policy>
    </route>    
        
  </camelContext>
  
</beans> 

DroolsPolicy is used to add Drools support in Camel, basically what it does is to add interceptors into the camel route to create Camel Processors on the fly and modify the internal navigation route. If you want to have SOAP support you need to create your custom Drools Policy, but it's going to be added in the next release.

But you don’t need to know more internal details, only instantiate this bean:


<bean id="droolsPolicy" class="org.drools.camel.component.DroolsPolicy" />

The next is create the camel route that will have the responsibility to execute the commands sent through JAX-RS. Basically we create a route definition associated with the JAX-RS definition as the data input, the camel policy to be used and inside the “execution route” or ProcessorDefinitions. As you can see, we set XStream as the marshaller/unmarshaller and the drools execution route definition


<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
  <route>
    <from uri="cxfrs://bean://rsServer"/>
    <policy ref="droolsPolicy">
      <unmarshal ref="xstream" />
      <to uri="drools:node1/ksession1" />
      <marshal ref="xstream" />
    </policy>
  </route>
</camelContext>

The drools endpoint creation has the next arguments

<!-- XML : generated by JHighlight v1.0 (http://jhighlight.dev.java.net) -->
<span class="xml_tag_symbols">&lt;</span><span class="xml_tag_name">to</span><span class="xml_plain">&nbsp;</span><span class="xml_attribute_name">uri</span><span class="xml_tag_symbols">=</span><span class="xml_attribute_value">&quot;drools:{1}/{2}&quot;</span><span class="xml_plain">&nbsp;</span><span class="xml_tag_symbols">/&gt;</span><span class="xml_plain"></span><br />

Both parameters are configured in knowledge-services.xml file.

With drools-server war unzipped you should be able to see a test.jsp and run it. This example just executes a simple "echo" type application. It sends a message to the rule server that pre-appends the word "echo" to the front and sends it back. By default the message is "Hello World", different messages can be passed using the url parameter msg - test.jsp?msg="My Custom Message".

Under the hood the jsp invokes the Test.java class, this then calls out to Camel which is where the meet happens. The camel-client.xml defines the client with just a few lines of xml:


<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
   <route>
      <from uri="direct://kservice"/>
      <policy ref="droolsPolicy">
         <to uri="cxfrs://http://localhost:8080/drools-server-app/kservice/rest"/>
      </policy>
   </route>         
 </camelContext>

"direct://kservice" is just a named hook, allowing java to grab a reference and push data into it. In this example the data is already in xml, so we don't need to add any DataFormat's to do the marshalling. The DroolsPolicy adds some smarts to the route and you'll see it used on the server side too. If JAXB or XStream were used, it would inject custom paths and converters, it can also set the ClassLoader too on the server side, on the client side it automatically unwraps the Response object.

The rule itself can be found here: test.drl. Notice the type Message is declared part of the drl and is thus not present on the Classpath.

declare Message
   text : String
end
    
  
rule "echo" dialect "mvel"
when
   $m : Message();
then
   $m.text = "echo:" + $m.text;
end

XML marshalling/unmarshalling of the Drools Commands requires the use of special classes, which are going to be described in the following sections.

The following urls show sample script examples for jaxb, xstream and json marshalling using:

There are two options for using JAXB, you can define your model in an XSD file or you can have a POJO model. In both cases you have to declare your model inside JAXBContext, and in order to do that you need to use Drools Helper classes. Once you have the JAXBContext you need to create the Unmarshaller/Marshaller as needed.

Currently, the following commands are supported:

OSGi is a dynamic module system for declarative services. So what does that mean? Each jar in OSGi is called a bundle and has it's own ClassLoader. Each bundle specifies the packages it exports (makes publicly available) and which packages it imports (external dependencies). OSGi will use this information to wire the ClassLoaders of different bundles together; the key distinction is you don't specify what bundle you depend on, or have a single monolithic classpath, instead you specify your package import and version and OSGi attempts to satisfy this from available bundles.

It also supports side by side versioning, so you can have multiple versions of a bundle installed and it'll wire up the correct one. Further to this Bundles can register services for other bundles to use. These services need initialisation, which can cause ordering problems - how do you make sure you don't consume a service before its registered? OSGi has a number of features to help with service composition and ordering. The two main ones are the programmatic ServiceTracker and the xml based Declarative Services. There are also other projects that help with this; Spring DM, iPOJO, Gravity.

Each of the Drools factories is now also available as a FactoryService interface. You can either have OSGi inject those into a pojo, or retrieve them yourself from OSGi.

The following modules should work with OSGi;

The following Services can be located as OSGi Bundles

I'll cover injection here. The below example injects the KnowledgeBuilderFactoryService, KnowledgeBaseFactoryService and ResourceFactoryService into the TestComponent pojo.


The TestComponent will only be activated when all of the referenced services are available and injected into the pojo. You'll also notice the "target" attribute for the KnowledgeBuilderFactoryService. The reason for this is that OSGi DS has no built in way to declaratively say which optional services must be present to satisfy your component. As a work around I made any Drools service that has optional services set a property if/when the optional service is available. Filters can then be applied, via the target attribute, to make sure the Service is in a desired state before consuming it. And that is pretty much it :)



The Drools engine supports runtime monitoring through JMX standard MBeans. These MBeans expose configuration and metrics data, from live knowledge bases and sessions, to internal details like rule execution times. Any JMX compatible console can be used to access that data. This chapter details how to use RHQ/JON to do it, but similar steps can be used for any other console.