Drools EIP – From the Ground Up – Part 2 :: WebService


In Part 1 we created and deployed a Web Servlet that invoked the Rule Engine to fire the rules.

In Part 2 we will create a Web Service that will pass a Request to the Rule Engine and return a Response.  Each event will in turn encapsulate any data that is to be returned.

The Steps – Part 1 – Build The Web Service

Add the CXF dependencies

We need to modify our pom.xml from the previous example to add the Apache CXF Depdendencies:

<!-- apache cxf -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>

<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>

With the following properties

<properties>
<drools.version>5.6.0.Final</drools.version>
<cxf.version>2.5.0</cxf.version>
<commons-version>1.1.3</commons-version>
<junit.version>4.11</junit.version>
</properties>

Note that adding the CFX dependencies will also pull down a number of Spring jars that we will be making use of.

Create the Request Object

package com.skills421.model;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Request")
public class Request implements Serializable
{
private static final long serialVersionUID = 1L;

private String header;
private Object data;

public Request()
{

}

public Request(String header, Serializable data)
{
super();
this.header = header;
this.data = data;
}

public String getHeader()
{
return header;
}

public void setHeader(String header)
{
this.header = header;
}

public Object getData()
{
return data;
}

public void setData(Object data)
{
this.data = data;
}

@Override
public String toString()
{
return String.format("Request [header=%s, data=%s]", header, data);
}
}

Create the Response Object

package com.skills421.model;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Response")
public class Response implements Serializable
{
private static final long serialVersionUID = 1L;

private String header;
private Object data;

public Response()
{

}

public Response(String header, Serializable data)
{
super();
this.header = header;
this.data = data;
}

public String getHeader()
{
return header;
}

public void setHeader(String header)
{
this.header = header;
}

public Object getData()
{
return data;
}

public void setData(Object data)
{
this.data = data;
}

@Override
public String toString()
{
return String.format("Response [header=%s, data=%s]", header, data);
}
}

Create the Service Endpoint Interface

package com.skills421.services;

import javax.jws.WebMethod;
import javax.jws.WebService;

import com.skills421.model.Request;
import com.skills421.model.Response;

@WebService
public interface RequestService
{
@WebMethod
public Response sendRequest(Request request);
}

Create the Service Endpoint Implementation

package com.skills421.services;

import javax.jws.WebService;

import com.skills421.model.Request;
import com.skills421.model.Response;

@WebService(endpointInterface="com.skills421.services.RequestService",serviceName="requestService")
public class RequestServiceImpl implements RequestService
{
public Response sendRequest(Request request)
{
return new Response("Response Header","Response from WebService");
}
}

 Create the Spring Config File – beans.xml

Create the file beans.xml in src/main/webapp.WEB-INF as follows:

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

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

</beans>

 Update web.xml to include the Spring Context

add the following entry to web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml,/WEB-INF/applicationContext.xml</param-value>
</context-param>

The Steps – Part 2 – Test The Web Service

Compile the Project

Compile your project and run it on the server.

View the WSDL

Now navigate to the following url and you should be able to see the whole wsdl : http://localhost:8080/ServletExample/requestService?wsdl

The Steps – Part 3 – Create a Client Project

Create a new Maven Project called WSClient

  • New -> Other -> Maven -> MavenProject
  • next
  • create a simple project
  • Group Id: com.skills421.examples
  • Artifact Id: WSClient

Add the Apache CXF Dependencies and set the Java Version to 1.6

Edit the pom.xml as follows;

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.skills421.examples</groupId>
<artifactId>WSClient</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<camel-version>2.13.1</camel-version>
</properties>

<dependencies>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
</dependencies>

<build>
<finalName>WSExample</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

Copy the Request and Response code from the Server

This is easier than using the wsdl for now

Copy the RequestService interface from the Server

Again, this is easier than using the wsdl for now

Write the RequestClient as follows

package com.skills421;

import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

import com.skills421.model.Request;
import com.skills421.model.Response;
import com.skills421.services.RequestService;

public class RequestClient
{
public static void main(String[] args)
{
String serviceUrl = "http://localhost:8080/ServletExample/requestService";

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(RequestService.class);
factory.setAddress(serviceUrl);

RequestService requestService = (RequestService) factory.create();

Request request = new Request("Request header", "Request data");

Response reponse = requestService.sendRequest(request);

System.out.println("response : " + reponse);
}
}

Run the RequestClient

Run the RequestClient as a Java application.
You should see the following output:

response : Response [header=Response Header, data=Response from WebService]

The Steps – Part 4 – Hook up the Rules

Okay, we have got this far.  Now let’s hook up the rules.  To do this we will create a @Service as follows:

package com.skills421.beans;

import org.drools.KnowledgeBase;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.impl.ClassPathResource;
import org.drools.runtime.StatefulKnowledgeSession;
import org.springframework.stereotype.Service;

import com.skills421.model.Request;
import com.skills421.model.Response;

@Service
public class RuleService
{

public RuleService()
{
// TODO Auto-generated constructor stub
}

public Response runRules(Request request)
{
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(new ClassPathResource("rules/skills421/examples/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();

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

Response response = new Response();

ksession.setGlobal("RESPONSE", response);

ksession.fireAllRules();

return response;
}
}

With that in place, let’s modify our RequestServiceImpl to invoke it – by Injecting the RuleService and then calling it.

package com.skills421.services;

import javax.inject.Inject;
import javax.jws.WebService;

import com.skills421.beans.RuleService;
import com.skills421.model.Request;
import com.skills421.model.Response;

@WebService(endpointInterface="com.skills421.services.RequestService",serviceName="requestService")
public class RequestServiceImpl implements RequestService
{
@Inject
private RuleService ruleService;

public Response sendRequest(Request request)
{
Response response = ruleService.runRules(request);
return response;
}
}

next, let’s modify the rules.drl as follows:

package rules.skills421.examples

import com.skills421.model.Response;

global Response RESPONSE;

rule "always true"
dialect "mvel"
when
then
RESPONSE.header = "Rules Executed";
RESPONSE.data = "Woohoo - Rules are running!";
end

Test our Rules WebService

Now let’s start the Server with our new code.

Finally, let’s run our RequestClient.

And here’s the output:

response : Response [header=Rules Executed, data=Woohoo - Rules are running!]
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s