Apache Camel

Apache Camel CXF Example

In this article, I am going to show you an example of Apache Camel CXF. We will explore Camel’s capabilities for interacting with SOAP web services, which are commonly used in integration technology. The CXF component provides integration with Apache CXF for connecting to Java XML Web Services (JAX-WS) hosted in CXF and what is Apache CXF? Apache CXF is an open-source, fully featured Web services framework. And where does the name CXF comes from? It originated as the combination of two open-source projects: Celtix and XFire so CXF was derived by combining “Celtix” and “XFire”.

In this example, we will use CXF to create Camel routes that request external web services. We will also use CXF to act as a web service listener.

Before we start with our example, Let’s look into the setup details.

This example uses the following frameworks:

  1. Maven 3.2.3
  2. Apache Camel 2.15.1
  3. Apache CXF 3.0.4
  4. Spring 4.1.5.RELEASE
  5. Eclipse  as the IDE, version Luna 4.4.1.

1. Dependencies

You need following dependencies:

  1. camel-core – basic module of apache camel.
  2. camel-cxf – We want to use Apache CXF for the webservice stuff.
  3. cxf-rt-transports-http-jetty – We want Apache CXF to also act as webservice listener.
  4. spring-context and camel-spring – Since we be configuring our camel context in spring.

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>com.javacodegeeks.camel</groupId>
	<artifactId>camelHelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-core</artifactId>
			<version>2.15.1</version>
		</dependency>		
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.1.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-spring</artifactId>
			<version>2.15.1</version>
		</dependency>	
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-cxf</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>3.0.4</version>
		</dependency>		
	</dependencies>
</project>

2. Developing Webservice

Our webservice consists of a product service. Given a product ID, it will provide us with product details. Product details consists of product ID, product name and its price.

We will define a contract for the service through a WSDL file.

productService.wsdl:

<?xml version="1.0" encoding="UTF-8"?>

<wsdl:definitions name="wsdl-first"
	xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://ws.javacodegeeks.com/product-service"
	xmlns:typens="http://ws.javacodegeeks.com/product-service/types"
	targetNamespace="http://ws.javacodegeeks.com/product-service">

	<wsdl:types>
		<xsd:schema targetNamespace="http://ws.javacodegeeks.com/product-service/types"
			elementFormDeerror="qualified">
			<xsd:element name="productRequest">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element name="id" type="xsd:string" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
			<xsd:element name="productResponse">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element name="id" type="xsd:string" />
						<xsd:element name="description" type="xsd:string" />
						<xsd:element name="price" type="xsd:int" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
			<xsd:element name="error">
				<xsd:complexType>
					<xsd:sequence>
						<xsd:element minOccurs="0" name="reason" type="xsd:string" />
					</xsd:sequence>
				</xsd:complexType>
			</xsd:element>
		</xsd:schema>
	</wsdl:types>

	<wsdl:message name="ProductRequest">
		<wsdl:part name="request" element="typens:productRequest" />
	</wsdl:message>

	<wsdl:message name="ProductResponse">
		<wsdl:part name="response" element="typens:productResponse" />
	</wsdl:message>

	<wsdl:message name="ErrorMessage">
		<wsdl:part name="error" element="typens:error" />
	</wsdl:message>

	<wsdl:portType name="Product">
		<wsdl:operation name="getProductDetails">
			<wsdl:input message="tns:ProductRequest" />
			<wsdl:output message="tns:ProductResponse" />
			<wsdl:fault name="error" message="tns:ErrorMessage" />
		</wsdl:operation>
	</wsdl:portType>

	<wsdl:binding name="ProductSOAPBinding" type="tns:Product">
		<soap:binding style="document"
			transport="http://schemas.xmlsoap.org/soap/http" />
		<wsdl:operation name="getProductDetails">
			<wsdl:input>
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output>
				<soap:body use="literal" />
			</wsdl:output>
			<wsdl:fault name="error">
				<soap:fault name="error" use="literal" />
			</wsdl:fault>
		</wsdl:operation>
	</wsdl:binding>

	<wsdl:service name="ProductService">
		<wsdl:port binding="tns:ProductSOAPBinding" name="ProductPort">
			<soap:address location="http://localhost:9090/productService" />
		</wsdl:port>
	</wsdl:service>

</wsdl:definitions>

3. CXF wsdl2java

We need to generate JAX-WS and JAXB (Java Architecture for XML Binding) annotated Java classes and interfaces from the above WSDL.

Let’s add Maven plugin cxf-codegen-plugin to automate the build-time generation of JAX-WS artifacts from the WSDL document. Plugin cxf-codegen-plugin is provided by the Apache CXF project.

We will integrate CXF wsdl2java generator in the pom.xml so we have CXF generate the needed POJO classes for our webservice contract.

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>com.javacodegeeks.camel</groupId>
	<artifactId>camelHelloWorld</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-core</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.1.5.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-spring</artifactId>
			<version>2.15.1</version>
		</dependency>	
		<dependency>
			<groupId>org.apache.camel</groupId>
			<artifactId>camel-cxf</artifactId>
			<version>2.15.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.cxf</groupId>
			<artifactId>cxf-rt-transports-http-jetty</artifactId>
			<version>3.0.4</version>
		</dependency>		
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.cxf</groupId>
				<artifactId>cxf-codegen-plugin</artifactId>
				<version>2.7.0</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<configuration>
							<sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
							<wsdlOptions>
								<wsdlOption>
									<wsdl>${basedir}/src/main/resources/productService.wsdl</wsdl>
								</wsdlOption>
							</wsdlOptions>
						</configuration>
						<goals>
							<goal>wsdl2java</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

4. Implementing a web service using Camel CXF

In this example, we will use Camel CXF Component to act as a SOAP web service listener.

First, configure the Camel CXF endpoint.

applicationContext.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:cxf="http://camel.apache.org/schema/cxf"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
       ">

	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

	<cxf:cxfEndpoint id="productServiceEndpoint"
		address="http://localhost:${port1}/productService" serviceClass="com.javacodegeeks.ws.product_service.Product" />

</beans>

Next, create a POJO that will accept the the web service request, process it and return a response.

ProductServiceImpl:

package com.javacodegeeks.camel;

import java.util.HashMap;
import java.util.Map;

import com.javacodegeeks.ws.product_service.types.ProductResponse;

public class ProductServiceImpl {
    public ProductResponse getProductDetails(com.javacodegeeks.ws.product_service.types.ProductRequest request) {
    	Product product = PRODUCT_DETAILS.get(request.getId());
        if (product == null) {
            throw new ProductNotFoundException(request.getId());
        }

        ProductResponse response = new ProductResponse();
        response.setId(product.id);
        response.setDescription(product.description);
        response.setPrice(product.price);
        return response;
    }
    
    private static Map<String, Product> PRODUCT_DETAILS = new HashMap<String, Product>();
    
    private static class Product {
    	private String id;
    	private String description;
    	private int price;
    	
    	Product(String id, String desc, int price) {
    		this.id = id;
    		this.description = desc;
    		this.price = price;
    	}
    }
    
    static {
    	PRODUCT_DETAILS.put("P01", new Product("P01", "Laptop", 40000));
    	PRODUCT_DETAILS.put("P02", new Product("P02", "Mobile", 14000));
    	PRODUCT_DETAILS.put("P03", new Product("P03", "Tablet", 30000));
    }
}

If product is not found, we will throw ProductNotFoundException.

ProductNotFoundException:

package com.javacodegeeks.camel;

public class ProductNotFoundException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	private String productId;
	public ProductNotFoundException(String id) {
		this.productId = id;
	}
	
	public String toString() {
		return "Product " + productId + " not found exception"; 
	}
}

Finally, we need to build the route to consume the request, delegate it to route built, our above POJO will handle the request and return the response. The CXF endpoint configured will become the Camel consumer. It will create an HTTP listener to receive the SOAP messages and feed the messages into the Camel route.

Our route would look like:

applicationContext.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:cxf="http://camel.apache.org/schema/cxf"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
       ">

	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route id="wsRoute">
			<from uri="cxf:bean:productServiceEndpoint" />
			<bean ref="productServiceImpl" />
		</route>
	</camelContext>

	<bean id="productServiceImpl" class="com.javacodegeeks.camel.ProductServiceImpl"/>

	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

	<cxf:cxfEndpoint id="productServiceEndpoint"
		address="http://localhost:${port1}/productService" serviceClass="com.javacodegeeks.ws.product_service.Product" />

</beans>

5. Invoking a web service using Camel CXF

Our route consists of from(“direct:start”) which is the consumer that will kick-start our routing flow. It will wait for messages to arrive on the direct queue and then dispatch the message to invoke the CXF endpoint using the cxf:bean: prefix with the operation name that you want to trigger.

applicationContext.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:cxf="http://camel.apache.org/schema/cxf"
	xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
        http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
       ">

	<camelContext xmlns="http://camel.apache.org/schema/spring">
		<route id="wsRoute">
			<from uri="cxf:bean:productServiceEndpoint" />
			<bean ref="productServiceImpl" />
		</route>
		<route id="wsClient">
			<from uri="direct:start" />
			<to
				uri="cxf:bean:productServiceEndpoint?defaultOperationName=getProductDetails" />
		</route>
	</camelContext>

	<bean id="productServiceImpl" class="com.javacodegeeks.camel.ProductServiceImpl"/>

	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />

	<cxf:cxfEndpoint id="productServiceEndpoint"
		address="http://localhost:${port1}/productService" serviceClass="com.javacodegeeks.ws.product_service.Product" />

</beans>

6. Camel CXF Example Main Class

Let’s analyse our main class CamelCxfExample.

  1. Since CamelContext is defined in applicationContext.xml, we will first create the ApplicationContext object.
  2. Next, we will call SpringCamelContext.springCamelContext to return us the CamelContext.
  3. Start the camel context.
  4. We will use a ProducerTemplate to send messages to the direct:start endpoint to initiate the webservice request.
  5. Finally, we print the product details response.

CamelCxfExample:

package com.javacodegeeks.camel;

import org.apache.camel.CamelContext;
import org.apache.camel.CamelExecutionException;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.spring.SpringCamelContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.javacodegeeks.ws.product_service.types.ProductRequest;
import com.javacodegeeks.ws.product_service.types.ProductResponse;

public class CamelCxfExample {
	private static ProducerTemplate template;

	public static void main(String[] args) throws Exception {
		System.setProperty("port1", "9000");
		ApplicationContext appContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml");
		CamelContext camelContext = SpringCamelContext.springCamelContext(
				appContext, false);
		try {
			template = camelContext.createProducerTemplate();
			System.out.println("Start camel context");
			camelContext.start();
			printProductDetails("P01");
			printProductDetails("P02");
			printProductDetails("Uknown");
		} finally {
			System.out.println("Stop camel context");
			camelContext.stop();
		}
	}

	private static void printProductDetails(String id) {
		try {
			System.out.println("Request: Get " + id + " details ");
			ProductRequest request = new ProductRequest();
			request.setId(id);
			ProductResponse response = template.requestBody("direct:start",
					request, ProductResponse.class);
			System.out.println("Response: Id: " + response.getId() + ", Product: "
					+ response.getDescription() + ", Price: " + response.getPrice());
		} catch (CamelExecutionException p) {
			System.out.println(p.getCause());
		}
	}
}

After the first two successful requests, we deliberately request for an unknown product to make sure an exception is thrown.

Output:

INFO: Creating Service {http://ws.javacodegeeks.com/product-service}ProductService from class com.javacodegeeks.ws.product_service.Product
Apr 20, 2015 10:17:03 PM org.apache.cxf.endpoint.ServerImpl initDestination
INFO: Setting the server's publish address to be http://localhost:9000/productService
Apr 20, 2015 10:17:03 PM org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
INFO: Creating Service {http://ws.javacodegeeks.com/product-service}ProductService from class com.javacodegeeks.ws.product_service.Product
Start camel context
Request: Get P01 details 
Response: Id: P01, Product: Laptop, Price: 40000
Request: Get P02 details 
Response: Id: P02, Product: Mobile, Price: 14000
Request: Get Uknown details 
Apr 20, 2015 10:17:04 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Application {http://ws.javacodegeeks.com/product-service}ProductService#{http://ws.javacodegeeks.com/product-service}getProductDetails has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: ProductNotFoundException
Stop camel context

7. Download the Eclipse Project

This was an example about Camel CXF.

Download
You can download the full source code of this example here: camelCxfExample.zip

Ram Mokkapaty

Ram holds a master's degree in Machine Design from IT B.H.U. His expertise lies in test driven development and re-factoring. He is passionate about open source technologies and actively blogs on various java and open-source technologies like spring. He works as a principal Engineer in the logistics domain.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
San
San
5 years ago

Hello,
Could you show how to write camel cxfProducer, which send request to external soap service.

Thank you.
Sanjeev

John
John
5 years ago

Doesn’t work, please provide update.

Guest
Guest
4 years ago

Not working

Back to top button