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!]