JBoss.orgCommunity Documentation

Chapter 13. Drools Camel Server

13.1. Introduction
13.2. Deployment
13.3. Configuration
13.3.1. REST/Camel Services configuration

The drools camel server (drools-camel-server) module is a war which you can deploy to execute KnowledgeBases remotely for any sort of client application. This is not limited to JVM application clients, but any technology that can use HTTP, through a REST interface. This version of the execution server supports stateless and stateful sessions in a native way.

Drools Camel Server is a war file, which can be deployed in a application server (such as JBoss AS). As the service is stateless, it is possible to have have as many of these services deployed as you need to serve the client load. Deploy on JBoss AS 4.x / Tomcat 6.x works out-of-the-box, instead some external dependencies must be added and the configuration must be changed to be deployed in JBoss AS 5

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="/rest"
                serviceClass="org.kie.jax.rs.CommandExecutorImpl">
       <cxf:providers>
           <bean class="org.kie.jax.rs.CommandMessageBodyReader"/>
       </cxf:providers>
  </cxf:rsServer>  
  
  <cxf:cxfEndpoint id="soapServer"
            address="/soap"
             serviceName="ns:CommandExecutor"
             endpointName="ns:CommandExecutorPort"
          wsdlURL="soap.wsdl"
          xmlns:ns="http://soap.jax.drools.org/" >
    <cxf:properties>
      <entry key="dataFormat" value="MESSAGE"/>
      <entry key="defaultOperationName" value="execute"/>
    </cxf:properties>
  </cxf:cxfEndpoint>

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

  <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="kiePolicy">
         <unmarshal ref="xstream" />
         <to uri="kie:ksession1" />
         <marshal ref="xstream" />
       </policy>
    </route>    

    <route>
      <from uri="cxf://bean://soapServer"/>
      <policy ref="kiePolicy">
        <unmarshal ref="xstream" />       
        <to uri="kie:ksession1" />
        <marshal ref="xstream" />
      </policy>
    </route>
        
  </camelContext>
  
</beans> 

KiePolicy 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="kiePolicy" class="org.kie.camel.component.KiePolicy" />

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="kiePolicy">
        <unmarshal ref="xstream" />
        <to uri="kie:ksession1" />
        <marshal ref="xstream" />
      </policy>
   </route>    
   <route>
     <from uri="cxf://bean://soapServer"/>
     <policy ref="kiePolicy">
       <unmarshal ref="xstream" />       
       <to uri="kie: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;kie:{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:


<!-- Leave this, as it's needed to make Camel "drools" aware -->
<bean id="kiePolicy" class="org.kie.camel.component.KiePolicy" />
  
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
  <route>
     <from uri="direct://kservice/rest"/>
     <policy ref="kiePolicy">
       <to uri="cxfrs://http://localhost:8080/drools-server/kservice/rest"/>
     </policy>
  </route>
  <route>
    <from uri="direct://kservice/soap"/>
    <policy ref="kiePolicy">
      <to uri="cxfrs://http://localhost:8080/drools-server/kservice/soap"/>
    </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 DataFormats to do the marshalling. The KiePolicy 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