The Camel CXF Component allows a Camel route to act as a SOAP (or REST) web service listener. This allows you to create web service frontends for other systems, including acting as a web service proxy—something that is discussed in-depth in the Web service proxying recipe.
This recipe will show you the basic steps of exposing a Camel route as a web service consumer/listener.
This recipe assumes that you have a project with JAX-WS artifacts created as shown in the Generating the service stubs from a WSDL recipe. To use the generated API, you need to include a dependency to that project in your build:
<dependency> <groupId>org.camelcookbook.examples</groupId> <artifactId>ws-payments-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
This recipe's example is based on paymentService.wsdl
, whose interface has one operation, transferFunds
.
<wsdl:portType name="Payment"> <wsdl:operation name="transferFunds"> <wsdl:input message="tns:TransferRequest"/> <wsdl:output message="tns:TransferResponse"/> <wsdl:fault name="fault" message="tns:FaultMessage"/> </wsdl:operation> </wsdl:portType>
All source files for this recipe are located in the ws-camel-routes
project in the camel-cookbook-web-services
module. The Java code for this recipe is located in the org.camelcookbook.ws.service
package. The Spring XML files are located under src/main/resources/META-INF/spring
and prefixed with service
.
There are three primary steps to expose a web service listener (consumer) using Camel:
The preceding steps are performed as follows:
In the XML DSL, you will want to use the cxfEndpoint
defined in the Camel CXF schema. This makes it possible for your IDE to autocomplete and validate the endpoint's parameters.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:cxf="http://camel.apache.org/schema/cxf" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <cxf:cxfEndpoint id="paymentServiceEndpoint" address="http://localhost:1234/paymentService" serviceClass="org.camelcookbook.ws.payment_service.Payment"/> <!-- other stuff --> </beans>
In the Java DSL, since we cannot use Spring namespace handlers (that is, cxfEndpoint
), we will just create an endpoint URI String:
final String cxfUri = "cxf:http://localhost:1234/paymentService?" + "serviceClass=" + Payment.class.getCanonicalName();
import org.camelcookbook.ws.payment_service.types.TransferRequest; import org.camelcookbook.ws.payment_service.types.TransferResponse; public class PaymentServiceImpl { public TransferResponse transfer(TransferRequest request) { TransferResponse response = new TransferResponse(); response.setReply("OK"); return response; } }
InOut
, as in this example.In the XML DSL, you reference the endpoint you configured in step one using cxf:bean
. The endpoint must be referenced within the from
statement for it to be a Camel consumer, that is, in order for it to create an HTTP listener to receive the SOAP messages and feed messages into the Camel route:
<route id="wsRoute">
<from uri="cxf:bean:paymentServiceEndpoint"/>
<transform>
<simple>${in.body[0]}</simple>
</transform>
<log message="request = ${body}"/>
<bean ref="paymentServiceImpl"/>
<log message="response = ${body}"/>
</route>
In the Java DSL, we concatenate any additional options to our endpoint URI as we saw in step 1:
from(cxfUri)
.id("wsRoute")
.transform(simple("${in.body[0]}"))
.log("request = ${body}")
.bean(PaymentServiceImpl.class)
.log("response = ${body}");
The Camel CXF Component, when acting as an endpoint consumer, will put an array of objects into the Camel message—specifically an array of the request parameters. For Document-style web services, there will only be a single parameter. The transform(simple("${in.body[0]}"))
step will extract that single POJO request object and place it into the Camel message body for processing by the rest of the route.
The Camel CXF Component, when used as a consumer endpoint (in the from
part of the route), will start an HTTP listener internally that will receive SOAP messages when the Camel route is started. The endpoint will receive and parse SOAP messages it receives, and map them into the route as Camel exchanges.
The mapping is based on the dataFormat
option of the Camel CXF Component that defaults to POJO
, which will map the SOAP headers and other related connection information into exchange headers. The SOAP body will be transformed into a POJO according to the JAX-WS bindings, and placed into the message body of the exchange.
When using the POJO
data format, the Camel CXF endpoint consumer will create a MessageContentList
, which is an array of the request parameters. This is what is placed into the exchange message body. Be aware that you will need to access the request parameters from an array, even if your web service is Document-Literal style, that is, it only contains a single parameter. This is a common source of confusion when using the Camel CXF Component.
The Java bean that processes the request could implement the generated JAX-WS web service Java interface org.camelcookbook.ws.payment_service.Payment
. This would provide stronger typing to the WSDL, but it also forces you to implement all of the web service operations within a single Java class, which you may not want to do. In general, it is easier to just use the generated request and response types in your method arguments to achieve strong typing.
The operation name of the invoked web service will be placed into an exchange header called operationName
. You can use this header to correctly route and process the request. We will see an example of this in the Providing multiple web service operations within a single route recipe.
18.119.106.237