Monthly Archives: May 2010

Drools Server Configuration Using Spring

Now we can forget the profiles.xml configuration file, that I introduce on my previous post, and configure the service using Spring. If you have used the drools-spring module you know what I’m talking about. Or you can check this here

Don’t get crazy, but now we have 4 xml configuration files. Let’s talk a little about them.

configuration.xml: It is the main xml file, but only is used to import the next three files. So, you don’t need to modify this file.

core.xml
: As the previous file, you don’t need to modify this one either. This file only contains the REST/SOAP services configuration.

sessions.xml: In this file you can configure the knowledge base and knowledge sessions that are going to be used on the service definition. The configuration is the same as previously used on the drools-spring module, but now the drools:kbase can have a XSD model definition file using the tag <drools:model/>

<?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:context="http://www.springframework.org/schema/context"
    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.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
		http://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd"
    default-autowire="byName">

    <drools:connection id="connection1" type="local" />

    <drools:execution-node id="node1" connection="connection1" />

    <drools:kbase id="kbase1" node="node1">
	<drools:resource source="classpath:changesets/change-set-1.xml" type="CHANGE_SET" />
        <drools:model source="classpath:model/person.xsd" />
    </drools:kbase>

    <drools:kbase id="kbase2" node="node1">
        <drools:resource source="classpath:changesets/change-set-2.xml" type="CHANGE_SET" />
    </drools:kbase>

    <drools:ksession id="ksession1" type="stateful"  kbase="kbase1" node="node1"/>

    <drools:ksession id="ksession2" type="stateless" kbase="kbase2" node="node1"/>

</beans>

services.xml: In this file you can configure the drools server service, and contains the new definitions added to the drools-spring service.

The first thing that you should know is that there’s a new xml namespace for this, named drools-service. The configuration files shipped with the drools-service.war already have this definition, so you shouldn’t take care about this.

Here’s a full configuration example.


<?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:context="http://www.springframework.org/schema/context"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:drools-service="http://drools.org/schema/drools-service-spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
		http://drools.org/schema/drools-service-spring http://drools.org/schema/drools-service-spring.xsd
		http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"
    default-autowire="byName">

	<!-- Only needed to deploy on JBoss AS 5.X -->
    <bean id="jbossResolver" class="org.apache.camel.jboss.JBossPackageScanClassResolver"/>

    <!-- This camel context bean is required -->
	<camelContext id="executionContext" xmlns="http://camel.apache.org/schema/spring" />

	<drools-service:configuration id="service-conf-2" marshaller="XSTREAM" session="ksession2" />

	<drools-service:definition id="service" smId="sm1" camelContext="executionContext">
		<drools-service:configuration marshaller="JAXB" session="ksession1">
			<drools-service:class>org.drools.model.Person</drools-service:class>
			<drools-service:startup-command>
				<![CDATA[
				<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
				<batch-execution lookup="ksession1" xmlns:ns2="http://drools.org/model">
				    <insert out-identifier="santa">
				        <object xsi:type="ns2:person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
				            <ns2:name>santa</ns2:name>
				            <ns2:age>99</ns2:age>
				        </object>
				    </insert>
				</batch-execution>
	  	   		]]>
			</drools-service:startup-command>
		</drools-service:configuration>
		<drools-service:configuration-ref id="service-conf-2" />
	</drools-service:definition>

</beans>

There are a lot of new definitions, so let’s go step by step.

The next bean definition is only needed when the war file is deployed on a JBoss AS 5, to solve Apache Camel issues with the new AS classloader.

<bean id="jbossResolver" class="org.apache.camel.jboss.JBossPackageScanClassResolver"/>

Here we configure the Apache Camel Context bean instance.

<camelContext id="executionContext" xmlns="http://camel.apache.org/schema/spring" />

We can define an external drools service configuration, in this example we define a configuration that will use the Stateless Knowledge Session with id ksession2 and with XStream as the command marshaller.

<drools-service:configuration id="service-conf-2" marshaller="XSTREAM" session="ksession2" />

And next is the drools service definition, named by default as service (note: if you want to change the drools service definition id you must also change the bean reference on core.xml file). Also this definition must reference to the serviceManager used in the Knowledge Sessions creation and the Camel Context bean defined previously.

Inside the definition we can add multiple configurations, defined internally or externally. In this example we are adding to configurations: one externally referenced as “service-conf-2” and another internally.
The internal definition is using the JAXB marshaller and associated to the Stateful Knowledge Session with id ksession1. Also it is making a reference to the class called org.drools.model.Person, which was defined on the XSD file used in the creation of the KnowledgeBase with id kbase1, to be included on the JAXB Context that is going to be used on the marshalling/unmarshalling of the commands with JAXB format.

And finally, there is a tag named to specify commands that are going to be executed when the .war file is deployed. You don’t need to include this startup commands, it’s just only in case that you need something to initialize your Knowledge Session. Remember that you must use the tags, that allows us to include xml snippets without the need of escaping all the xml tags, when you add one xml command.

<drools-service:definition id="service" smId="sm1" camelContext="executionContext">
		<drools-service:configuration marshaller="JAXB" session="ksession1">
			<drools-service:class>org.drools.model.Person</drools-service:class>
			<drools-service:startup-command>
				<![CDATA[
				<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
				<batch-execution lookup="ksession1" xmlns:ns2="http://drools.org/model">
				    <insert out-identifier="santa">
				        <object xsi:type="ns2:person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
				            <ns2:name>santa</ns2:name>
				            <ns2:age>99</ns2:age>
				        </object>
				    </insert>
				</batch-execution>
	  	   		]]>
			</drools-service:startup-command>
		</drools-service:configuration>
		<drools-service:configuration-ref id="service-conf-2" />
	</drools-service:definition>

How to use drools-server

On this new version we are using the Drools Commands API in XML form. Take a look at the following example:

BatchExecutionCommand executionCommand = new BatchExecutionCommand();

InsertObjectCommand insertCommand = new InsertObjectCommand();
insertCommand.setObject(new Person("lucaz"));
insertCommand.setOutIdentifier("person1");

executionCommand.setLookup("ksession1");
executionCommand.getCommands().add(insertCommand);

String xml = BatchExecutionHelper.newXStreamMarshaller().toXML(executionCommand);

With this lines you will get the xml command representation, using xstream marshaller, that you can use to interact with the drools execution server:

<batch-execution lookup="ksession1">
  <insert out-identifier="person1" return-object="true">
    <org.drools.pipeline.camel.Person>
      <name>lucaz</name>
    </org.drools.pipeline.camel.Person>
  </insert>
</batch-execution>

RestWS integration

Let’s test the RestWS service by following this steps:

1) Create an Apache HttpClient instance and configure it with the drools-server ip address and port:

HttpClient httpClient = new HttpClient();
httpClient.getHostConfiguration().setHost("127.0.0.1", 8080);

2) Create a PosthMethod and send the xml command to the URI /drools-server/services/rest/execute

PostMethod postMethod = new PostMethod("/drools-server/services/rest/execute");
postMethod.addParameter("command", xmlCommand);

3) Execute the method. If the execution was succesfull you will got a HTTP Response Code OK (200) otherwise a BAD_REQUEST (400) response code will be thrown to the client.

httpClient.executeMethod(postMethod);
assertEquals(200, postMethod.getStatusCode());

4) And finally, get the execution response

String response = postMethod.getResponseBodyAsString();

SOAP integration

Here’s one way to use the SOAP interface with Apache CXF:

1) Create a JaxWsProxyFactoryBean, set the KnowledgeServiceSoap (that could be generated with the WSDL exposed at http://127.0.0.1:8080/drools-server/services/soap?wsdl ) as the Service Class and the URL

JaxWsProxyFactoryBean clientFactory = new JaxWsProxyFactoryBean();
clientFactory.setServiceClass(KnowledgeServiceSoap.class);
clientFactory.setAddress("http://127.0.0.1:8080/drools-server/services/soap");

2) Create the KnowledgeServiceSoap client and execute the xml command

<span style="font-size: x-small;">KnowledgeServiceSoap client = (KnowledgeServiceSoap) clientFactory.create();
String response = client.execute(xmlCommand);</span>

That’s all, not too much more magic. Now, with these features, we have a more unified service definition using the drools-spring module. If you want to see this running, you can download a client project and the compiled drools-server.war from this link

Feedback is always appreciated.

Advertisements