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:
[code language=”xml”]
<!– 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>
[/code]
With the following properties
[code language=”xml”]
<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>
[/code]
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
[code language=”java”]
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);
}
}
[/code]
Create the Response Object
[code language=”java”]
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);
}
}
[/code]
Create the Service Endpoint Interface
[code language=”java”]
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);
}
[/code]
Create the Service Endpoint Implementation
[code language=”java”]
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");
}
}
[/code]
Create the Spring Config File – beans.xml
Create the file beans.xml in src/main/webapp.WEB-INF as follows:
[code language=”xml”]
<?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>
[/code]
Update web.xml to include the Spring Context
add the following entry to web.xml
[code language=”xml”]
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans.xml,/WEB-INF/applicationContext.xml</param-value>
</context-param>
[/code]
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;
[code language=”xml”]
<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>
[/code]
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
[code language=”java”]
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);
}
}
[/code]
Run the RequestClient
Run the RequestClient as a Java application.
You should see the following output:
[code language=”java”]
response : Response [header=Response Header, data=Response from WebService]
[/code]
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:
[code language=”java”]
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;
}
}
[/code]
With that in place, let’s modify our RequestServiceImpl to invoke it – by Injecting the RuleService and then calling it.
[code language=”java”]
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;
}
}
[/code]
next, let’s modify the rules.drl as follows:
[code language=”java”]
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
[/code]
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:
[code language=”java”]
response : Response [header=Rules Executed, data=Woohoo – Rules are running!]
[/code]
Tag:apache cxf, CXF, dependency, Drools, EAP, eip, JBoss, SEDA, servlet, webservice