In this tutorial we will learn how to provide a Web service facade using a Came blueprint project which proxies request to a legacy web service.
This is the second tutorial about Camel and Web services – here you can read the first part: Proxy Web services request with Camel where we have covered this scenario:
The scenario we will discuss in this tutorial is the same, just we will turn the project in a blueprint project and deploy it on JBoss Fuse 6.Here is the blueprint for our project:
<?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camelcxf="http://camel.apache.org/schema/blueprint/cxf" xmlns:cxf="http://cxf.apache.org/blueprint/core" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/blueprint/cxf/camel-cxf.xsd http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd"> <cxf:bus><!-- interceptor per request/response del ws/rest --> <cxf:features> <cxf:logging limit="1024"/> </cxf:features> </cxf:bus> <bean id="beanAdapter" class="com.sample.source.ws.BeanAdapter"/> <!-- WEB SERVICE FACADE --> <camelcxf:cxfEndpoint id="input-cxf" address="http://localhost:9080/example-input-cxf/" serviceClass="com.sample.source.ws.FuseExampleCXF"/> <!-- TARGET WEB SERVICE --> <camelcxf:cxfEndpoint id="SimpleWebSevice" address="http://localhost:8080/webserviceslegacy/LegacyWebServiceImpl" wsdlURL="http://localhost:8080/webserviceslegacy/LegacyWebServiceImpl?wsdl" serviceClass="com.sample.target.ws.LegacyWebService" /> <camelContext id="example-cxf" xmlns="http://camel.apache.org/schema/blueprint"> <route id="input-cxf"> <from uri="cxf:bean:input-cxf"/> <transform> <simple> ${in.body[0]} </simple> </transform> <log message="Message input: ${in.body}"/> <transform> <method bean="beanAdapter" method="transform" /> </transform> <removeHeaders pattern="*"/> <to uri="cxf:bean:SimpleWebSevice" /> </route> </camelContext> </blueprint>
So, the first Web service (input-cxf) is just a Contract exposed through the Camel route. It just contains an interface definition or a WSDL. In our case, it is composed of a Web interface:
package com.sample.source.ws; import com.sample.source.bean.Wrapper; import javax.jws.WebMethod; import javax.jws.WebService; @WebService public interface FuseExampleCXF { @WebMethod int count(Wrapper wrapper); }
This Web service has the count method which receives as input a Wrapper Object. The use case is providing a compatibility facade to Web service clients that use this interface and adapt the parameter using a Bean Transformation. The class which is in charge to perform the transformation is the com.sample.source.ws.BeanAdapter class which follows here:
package com.sample.source.ws; import com.sample.target.bean.Struct; import com.sample.source.bean.Wrapper; import org.apache.camel.Exchange; public class BeanAdapter { public Struct transform(Wrapper input) { Struct struct = new Struct(); struct.setX(input.getA()); struct.setY(input.getB()); return struct; } }
This class will be in charge to transform the Wrapper class from the incoming Web service into the Struct class which is expected by the target Web service:
package com.sample.target.ws; import com.sample.target.bean.Struct; import javax.jws.*; @WebService public interface LegacyWebService { @WebMethod public int callStruct(@WebParam( name = "total")Struct s); }
The Web service is deployed on an external middleware, such as JBoss EAP with the following implementation:
package com.sample.target.ws; import com.sample.target.bean.Struct; import javax.jws.WebService; import javax.jws.WebMethod; import javax.jws.WebParam; @WebService public class LegacyWebServiceImpl implements LegacyWebService { @WebMethod public int callStruct(@WebParam( name = "struct")Struct s) { System.out.println("Invoked Web service with "+s.getX() + " and "+s.getY()); return s.getX() + s.getY(); } }
In order to build the OSGI bundle you can use the following pom.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>it.fuse.demo</groupId> <artifactId>fuse-demo</artifactId> <packaging>bundle</packaging> <name>Fuse :: Demo</name> <version>0.0.3-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.target>1.7</maven.compiler.target> <maven.compiler.source>1.7</maven.compiler.source> <camel.version>2.15.1.redhat-620133</camel.version> <fabric8.version>1.2.0.redhat-133</fabric8.version> <karaf.enterprise.version>2.4.0.redhat-620133</karaf.enterprise.version> <jboss.fuse.bom.version>6.2.0.redhat-133</jboss.fuse.bom.version> <maven.bundle.plugin.version>2.5.3</maven.bundle.plugin.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.fuse.bom</groupId> <artifactId>jboss-fuse-parent</artifactId> <version>${jboss.fuse.bom.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-blueprint</artifactId> </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-cxf</artifactId> </dependency> <dependency> <groupId>org.apache.servicemix.specs</groupId> <artifactId>org.apache.servicemix.specs.jaxws-api-2.2</artifactId> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> </plugin> </plugins> </build> <repositories> <repository> <id>fuse-public-repository</id> <name>FuseSource Community Release Repository</name> <url>https://repo.fusesource.com/nexus/content/groups/public</url> <snapshots> <enabled>false</enabled> </snapshots> <releases> <enabled>true</enabled> <updatePolicy>never</updatePolicy> </releases> </repository> </repositories> </project>
Now from the Karaf command line, install at first the features required to provision the bundle:
JBossFuse:karaf@root> features:install cxf JBossFuse:karaf@root> features:install camel-jaxb JBossFuse:karaf@root> features:install camel-blueprint JBossFuse:karaf@root> features:install camel-cxf
Next, install the bundle on JBoss Fuse with:
JBossFuse:karaf@root> osgi:install -s mvn:org.apache.camel/fuse-demo/0.0.3-SNAPSHOT
That’s all. Verify with any Web service client that the Web service available on http://localhost:9080/example-input-cxf/ correctly responds and the route camel forwards the call to the target Web service.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.source.sample.com/"> <soapenv:Header/> <soapenv:Body> <ws:count> <!--Optional:--> <arg0> <a>1</a> <b>2</b> </arg0> </ws:count> </soapenv:Body> </soapenv:Envelope>
You should expect as return a response with the sum of the two parameters of the Wrapper object:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:countResponse xmlns:ns2="http://ws.source.sample.com/"> <return>3</return> </ns2:countResponse> </soap:Body> </soap:Envelope>