Fuse_ESB_Enterprise-7.0-Web_Services_and_Routing_with_Camel_CXF-en-US
Fuse_ESB_Enterprise-7.0-Web_Services_and_Routing_with_Camel_CXF-en-US
Integration Everywhere
Web Services and Routing with Camel/CXF
Version 7.0
Trademark Disclaimer
These materials and all Progress® software products are copyrighted and all rights are reserved by Progress Software Corporation.
The information in these materials is subject to change without notice, and Progress Software Corporation assumes no responsibility
for any errors that may appear therein. The references in these materials to specific platforms supported are subject to change.
Fuse, FuseSource, Fuse ESB, Fuse ESB Enterprise, Fuse MQ Enterprise, Fuse Mediation Router, Fuse Message Broker, Fuse
Services Framework, Fuse IDE, Fuse HQ, Fuse Management Console, and Integration Everywhere are trademarks or registered
trademarks of FuseSource Corp. or its parent corporation, Progress Software Corporation, or one of their subsidiaries or affiliates
in the United States. Apache, ServiceMix, Camel, CXF, and ActiveMQ are trademarks of Apache Software Foundation. Any other
names contained herein may be trademarks of their respective owners.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
conditions are met:
• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
• Neither the name of JLine nor the names of its contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
• Stax2 API (http://woodstox.codehaus.org/StAX2) org.codehaus.woodstox:stax2-api:jar:3.1.1
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
conditions are met:
• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
conditions are met:
• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
• Neither the name of JiBX nor the names of its contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 7
Generating Responses Using Templates ............................................................................. 117
TypeConverter for SAXSource .......................................................................................... 120
Deploy to OSGi ............................................................................................................ 121
8. Proxying a Web Service ..................................................................................................... 125
Proxying with HTTP ...................................................................................................... 126
Proxying with POJO Format ............................................................................................ 129
Proxying with PAYLOAD Format ....................................................................................... 131
Handling HTTP Headers ................................................................................................ 134
9. Filtering SOAP Message Headers ......................................................................................... 137
Basic Configuration ...................................................................................................... 138
Header Filtering ........................................................................................................... 141
Implementing a Custom Filter ......................................................................................... 143
Installing Filters ........................................................................................................... 146
8 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
List of Figures
2.1. Building a Java-First Web Service ......................................................................................... 19
3.1. Building a WSDL-First Web Service ....................................................................................... 37
4.1. Building a WS Client ......................................................................................................... 53
5.1. Sample POJO Route .......................................................................................................... 68
6.1. Sample PAYLOAD Route .................................................................................................... 88
6.2. SOAP/HTTP-to-JMS Bridge ................................................................................................. 93
6.3. Response Generated by Velocity ........................................................................................... 97
7.1. Sample Provider-Based Route ............................................................................................ 108
7.2. SOAP/HTTP-to-JMS Bridge ............................................................................................... 113
7.3. Response Generated by Velocity ......................................................................................... 117
8.1. Proxy Route with Message in HTTP Format ........................................................................... 126
8.2. Proxy Route with Message in POJO Format ........................................................................... 129
8.3. Proxy Route with Message in PAYLOAD Format ...................................................................... 131
9.1. Filter Map ..................................................................................................................... 141
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 9
List of Examples
9.1. Sample Binding Namespaces ............................................................................................ 144
9.2. Sample Header Filter Implementation .................................................................................. 145
10 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 1. Demonstration Code for
Camel/CXF
This chapter explains how to install, build, and run the demonstrations that accompany this guide.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 11
Chapter 1. Demonstration Code for Camel/CXF
Important
The demonstrations accompanying this guide are available to
subscription customers only.
Prerequisites For building and running the demonstration code, you must have the following
prerequisites installed:
1
• Java platform—the demonstrations must run on the Java 6 platform from
Oracle.
• Apache Maven build tool—to build the demonstration, you require Apache
2
Maven 3.0.x (or Maven 2.2.1).
• Fuse ESB Enterprise—the demonstrations are deployed into the Fuse ESB
3
Enterprise container, which can be downloaded from the FuseSource site.
Downloading the demonstration The source code for the demonstrations is packaged as a Zip file,
package cxf-webinars-assembly-1.1.1-src.zip, and is available from the
following location:
http://repo.fusesource.com/nexus/content/repositories/subscriber/org/fusesource/sparks/fuse-
webinars/cxf-webinars-assembly/1.1.1/
1
http://www.oracle.com/technetwork/java/javase/downloads/index.html
2
http://maven.apache.org/download.html
3
http://fusesource.com/products/enterprise-servicemix/
12 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Downloading and Installing the Demonstrations
When you try to navigate to this location with your browser, you will be
prompted for a username and password. Enter your subscription login
credentials to gain access to this directory and click on
cxf-webinars-assembly-1.1.1-src.zip to start downloading.
Installing the package To install the package, simply extract the Zip archive into any convenient
location on your file system.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 13
Chapter 1. Demonstration Code for Camel/CXF
Starting and configuring the Fuse Start and configure the Fuse ESB Enterprise container as follows:
ESB Enterprise container
1. (Optional) If your local Maven repository is in a non-standard location,
you might need to edit the Fuse ESB Enterprise configuration to specify
your custom location. Edit the
FuseEsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file and set
the org.ops4j.pax.url.mvn.localRepository property to the
location of your local Maven repository:
#
# Path to the local maven repository which is used to
avoid downloading
# artifacts when they already exist locally.
# The value of this property will be extracted from the
settings.xml file
# above, or defaulted to:
# System.getProperty( "user.home" ) + "/.m2/repository"
#
#org.ops4j.pax.url.mvn.localRepository=
org.ops4j.pax.url.mvn.localRepository=file:E:/Data/.m2/re
pository
14 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Running the Demonstrations
Demonstration features The following features are now available from the Fuse ESB Enterprise console
(where you can enter the command, features:list | grep customer to
check the status of these features):
customer-ws
customer-ws-client
customer-ws-cxf-payload
customer-ws-cxf-pojo
customer-ws-cxf-provider
Running the It is now a relatively straightforward task to run each of the demonstrations
customer-ws-osgi-bundle by installing the relevant features.
demonstration
For example, to start up the WSDL-first Web service (discussed in WSDL-First
Service Implementation on page 35), enter the following console command:
karaf@root> features:install customer-ws
To see the Web service in action, start up the sample Web service client
(discussed in Implementing a WS Client on page 51), by entering the following
console command:
karaf@root> features:install customer-ws-client
The bundle creates a thread that invokes the Web service once a second and
logs the response. View the log by entering the following console command:
karaf@root> log:tail -n 4
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 15
Chapter 1. Demonstration Code for Camel/CXF
To stop viewing the log, type the interrupt character (usually Ctrl-C).
To stop the client, first discover the client's bundle ID using the osgi:list
console command. For example:
karaf@root> list | grep customer-ws-client
[ 219] [Active ] [ ] [Started] [ 60] customer-
ws-client (1.1.1)
You can then stop the client using the osgi:stop console command. For
example:
karaf@root> stop 219
To shut down the container completely, enter the following console command:
karaf@root> shutdown -f
16 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 2. Java-First Service
Implementation
Java-First Overview ................................................................................................................ 18
Define SEI and Related Classes ................................................................................................. 20
Annotate SEI for JAX-WS ......................................................................................................... 24
Instantiate the WS Endpoint ..................................................................................................... 28
Java-to-WSDL Maven Plug-In ................................................................................................... 31
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 17
Chapter 2. Java-First Service Implementation
Java-First Overview
Overview The Java-first approach is a convenient way to get started with Web services,
if you are unfamiliar with WSDL syntax. Using this approach, you can define
the Web service interface using an ordinary Java interface and then use the
provided Apache CXF utilities to generate the corresponding WSDL contract
from the Java interface.
Note
There is no demonstration code to accompany this example.
Service Endpoint Interface (SEI) An SEI is an ordinary Java interface. In order to use the standard JAX-WS
1
frontend, the SEI must be annotated with the @WebService annotation.
In the Java-first approach, the SEI is the starting point for implementing the
Web service and it plays a central role in the development of the Web service
implementation. The SEI is used in the following ways:
• Proxy type (client side)—on the client side, you use the SEI to invoke
operations on the client proxy object.
• Basis for generating the WSDL contract—in the Java-first approach, you
generate the WSDL contract by converting the SEI to WSDL.
1
If the SEI is left without annotations, Apache CXF defaults to using the simple frontend [http://cxf.apache.org/docs/simple-frontend.html]. This
is a non-standard frontend, which is not recommended for most applications.
18 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Java-First Overview
well-known location. The WSDL contract contains all of the metadata required
by WS clients.
The CustomerService Figure 2.1 on page 19 shows an overview of the files required to implement
demonstration and build the CustomerService Web service using the Java-first approach.
Implementing and building the To implement and build the Java-first example shown in
service Figure 2.1 on page 19, you would perform the following steps:
1. Implement the SEI, which constitutes the basic definition of the Web
service's interface.
2. Annotate the SEI (you can use the annotations to influence the ultimate
form of the generated WSDL contract).
• Any data types referenced by the SEI—for example, the Customer class.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 19
Chapter 2. Java-First Service Implementation
The CustomerService SEI A JAX-WS service endpoint interface (SEI) is essentially an ordinary Java
interface, augmented by certain annotations (which are discussed in the next
section). For example, consider the following CustomerService interface,
which defines methods for accessing the Customer data type:
// Java
package com.fusesource.demo.wsdl.customerservice;
javax.xml.ws.Holder<?> types The getCustomerStatus method from the CustomerService interface has
parameters declared to be of javax.xml.ws.Holder<String> type. These
so-called holder types are needed in order to declare the OUT or INOUT
parameters of a WSDL operation.
20 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Define SEI and Related Classes
The syntax of WSDL operations allows you to define any number of OUT or
INOUT parameters, which means that the parameters are used to return a
value to the caller. This kind of parameter passing is not natively supported
by the Java language. Normally, the only way that Java allows you to return
a value is by declaring it as the return value of a method. You can work around
this language limitation, however, by declaring parameters to be holder types.
The caller can access the value of the returned rightWay string as
rightWay.value. For example:
// Java
String wrongWay = "This string never changes";
javax.xml.ws.Holder<String> rightWay.value = "This value
*can* change.";
sampleObject.getStringValues(wrongWay, rightWay);
Related classes When you run the Java-to-WSDL compiler on the SEI, it converts not only
the SEI, but also the classes referenced as parameters or return values. The
parameter types must be convertible to XML, otherwise it would not be
possible for WSDL operations to send or to receive those data types. In fact,
when you run the Java-to-WSDL compiler, it is typically necessary to convert
an entire tree of related classes to XML using the standard JAX-B encoding.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 21
Chapter 2. Java-First Service Implementation
Normally, as long as the related classes do not require any exotic language
features, the JAX-B encoding should be quite straightforward.
Default constructor for related There is one simple rule, however, that you need to keep in mind when
classes implementing related classes: each related class must have a default
constructor (that is, a constructor without arguments). If you do not define
any constructor for a class, the Java language automatically adds a default
constructor. But if you define a class's constructors explicitly, you must ensure
that one of them is a default constructor.
The Customer class For example, the Customer class appears as a related class in the definition
of the CustomerService SEI ( "The CustomerService SEI" on page 20). The
Customer class consists of a collection of String fields and the only special
condition it needs to satisfy is that it includes a default constructor:
// Java
package com.fusesource.demo.customer;
22 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Define SEI and Related Classes
return lastName;
}
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 23
Chapter 2. Java-First Service Implementation
Note
It sometimes makes sense also to annotate the service
implementation class (the class that implements the SEI)—for
example, if you want to associate an implementation class with a
specific WSDL serviceName and portName (there can be more than
one implementation of a given SEI).
Minimal annotation The minimal annotation required for an SEI using the JAX-WS frontend is to
prefix the interface declaration with @WebService. For example, the
CustomerService SEI could be minimally annotated as follows:
// Java
package com.fusesource.demo.wsdl.customerservice;
import javax.jws.WebService;
@WebService
public interface CustomerService {
...
}
If you run the Java-to-WSDL utility on this interface, it will generate a complete
WSDL contract using the standard default style of code conversion.
@WebService annotation Although it is sufficient to specify the @WebService annotation without any
attributes, it is usually better to specify some attributes to provide a more
descriptive WSDL service name and WSDL port name. You will also usually
want to specify the XML target namespace. For this, you can specify the
following optional attributes of the @WebService annotation:
24 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Annotate SEI for JAX-WS
name
Specifies the name of the WSDL contract (appearing in the
wsdl:definitions element).
serviceName
Specifies the name of the WSDL service (a SOAP service is defined by
default in the generated contract).
portName
Specifies the name of the WSDL port (a SOAP/HTTP port is defined by
default in the generated contract).
targetNamespace
The XML schema namespace that is used, by default, to qualify the
elements and types defined in the contract.
@WebParam annotation You can add the @WebParam annotation to method arguments in the SEI. The
@WebParam annotation is optional, but there are a couple of good reasons for
adding it:
name
Specifies the mapped name of the parameter.
targetNamespace
Specifies the namespace of the mapped parameter. Set this to a blank
string for a more compact XML encoding.
mode
Can have one of the following values:
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 25
Chapter 2. Java-First Service Implementation
OUT and INOUT parameters In WSDL, OUT and INOUT parameters represent values that can be sent from
the service back to the client (where the INOUT parameter is sent in both
directions).
In Java syntax, the only value that can ordinarily be returned from a method
is the method's return value. In order to support OUT or INOUT parameters
in Java (which are effectively like additional return values), you must:
Annotated CustomerService SEI The following example shows the CustomerService SEI after it has been
annotated. Many other annotations are possible, but this level of annotation
is usually adequate for a WSDL-first project.
// Java
package com.fusesource.demo.wsdl.customerservice;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService(
targetNamespace = "http://demo.fusesource.com/wsdl/CustomerService/",
name = "CustomerService",
serviceName = "CustomerService",
portName = "SOAPOverHTTP"
)
public interface CustomerService {
26 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Annotate SEI for JAX-WS
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 27
Chapter 2. Java-First Service Implementation
1. Create an instance of the implementor class, using the Spring bean element.
The jaxws:endpoint element You can instantiate a WS endpoint using the jaxws:endpoint element in a
Spring file, where the jaxws: prefix is associated with the
http://cxf.apache.org/jaxws namespace.
Note
Take care not to confuse the jaxws:endpoint element with the
cxf:cxfEndpoint element, which you meet later in this guide: the
jaxws:endpoint element is used to integrate a WS endpoint with
a Java implementation class; whereas the cxf:cxfEndpoint is used
to integrate a WS endpoint with a Camel route.
Define JAX-WS endpoint in XML The following sample Spring file shows how to define a JAX-WS endpoint in
XML, using the jaxws:endpoint element.
<?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:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframe
work.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
28 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint
xmlns:customer="http://demo.fusesource.com/wsdl/CustomerService/"
id="customerService"
address="http://0.0.0.0:9191/Customer"
serviceName="customer:CustomerService"
endpointName="customer:SOAPOverHTTP"
implementor="#customerServiceImpl">
</jaxws:endpoint>
<bean id="customerServiceImpl"
class="com.fusesource.customer.ws.CustomerServiceImpl"/>
</beans>
Address for the Jetty container To instantiate a custom Jetty container for the endpoint, specify a complete
HTTP URL, including the host and IP port (the value of the IP port effectively
identifies the target Jetty container). Typically, for a Jetty container, you
specify the host as 0.0.0.0, which is interpreted as a wildcard that matches
every IP network interface on the local machine (that is, if deployed on a
multi-homed host, Jetty opens a listening port on every network card).
Referencing the service The implementor attribute of the jaxws:endpoint element references the
implementation implementation of the WS service. The value of this attribute can either be
the name of the implementation class or (as in this example) a bean reference
in the format, #BeanID, where the # character indicates that the following
identifier is the name of a bean in the bean registry.
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. Depending
on which version of Apache CXF you use, it might not be necessary to include
all of these import tags.
META-INF/cxf/cxf.xml
Required for all Apache CXF versions (creates the default bus instance).
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 29
Chapter 2. Java-First Service Implementation
META-INF/cxf/cxf-extension-soap.xml
Needed only for versions prior to Apache CXF 2.4.
META-INF/cxf/cxf-extension-http.xml
Needed only for versions prior to Apache CXF 2.4.
META-INF/cxf/osgi/cxf-extension-osgi.xml
Needed only for versions prior to Apache CXF 2.4.3.
30 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Java-to-WSDL Maven Plug-In
Configure the Java-to-WSDL Configuring the Java-to-WSDL Maven plug-in is relatively easy, because most
Maven plug-in of the default configuration settings can be left as they are. After copying and
pasting the sample plugin element into your project's POM file, there are
just a few basic settings that need to be customized, as follows:
• CXF version—make sure that the plug-in's dependencies are using the latest
version of Apache CXF.
• SEI class name—specify the fully-qualified class name of the SEI in the
configuration/className element.
For example, the following POM fragment shows how to configure the
cxf-java2ws-plugin plug-in to generate WSDL from the CustomerService
SEI:
<project ...>
...
<properties>
<cxf.version>2.4.2-fuse-00-05</cxf.version>
</properties>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-java2ws-plugin</artifactId>
<version>${cxf.version}</version>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 31
Chapter 2. Java-First Service Implementation
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-simple</artifactId>
<version>${cxf.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>process-classes</id>
<phase>process-classes</phase>
<configuration>
<className>org.fusesource.demo.camelcxf.ws.server.CustomerService</className>
<outputFile>${basedir}/../src/main/resources/wsdl/CustomerService.wsdl</out
putFile>
<genWsdl>true</genWsdl>
<verbose>true</verbose>
</configuration>
<goals>
<goal>java2ws</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Generated WSDL When using the Java-first approach to defining a Web service, there are
typically other parts of your application (for example, WS clients) that depend
on the generated WSDL file. For this reason, it is generally a good idea to
output the generated WSDL file to a common location, which is accessible
to other projects in your application, using the outputFile configuration
element.
32 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Java-to-WSDL Maven Plug-In
BaseDir/target/generated/wsdl/SEIClassName.wsdl
Reference For full details of how to configure the Java-to-WSDL plug-in, see the Maven
2
Java2WS plug-in reference page .
2
http://cxf.apache.org/docs/maven-java2ws-plugin.html
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 33
34 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 3. WSDL-First Service
Implementation
WSDL-First Overview .............................................................................................................. 36
CustomerService WSDL Contract ............................................................................................... 38
WSDL-to-Java Maven Plug-In ................................................................................................... 41
Instantiate the WS Endpoint ..................................................................................................... 44
Deploy to an OSGi Container .................................................................................................... 46
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 35
Chapter 3. WSDL-First Service Implementation
WSDL-First Overview
Overview If you are familiar with the syntax of WSDL and you want to have ultimate
control over the layout and conventions applied to the WSDL contract, you
will probably prefer to develop your Web service using the WSDL-first
approach. In this approach, you start with the WSDL contract and then use
the provided Apache CXF utilities to generate the requisite Java stub files
from the WSDL contract.
Demonstration location The code presented in this chapter is taken from the following demonstration:
DemoDir/src/fuse-webinars/cxf-webinars/customer-ws-osgi-bundle
For details of how to download and install the demonstration code, see
Demonstration Code for Camel/CXF on page 11
Service Endpoint Interface (SEI) The most important piece of the generated stub code is the SEI, which is an
ordinary Java interface that represents the Web service interface in the Java
language.
• Proxy type (client side)—on the client side, you use the SEI to invoke
operations on the client proxy object.
The CustomerService Figure 3.1 on page 37 shows an overview of the files required to implement
demonstration and build the CustomerService Web service using the WSDL-first approach.
36 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-First Overview
Implementing and building the To implement and build the WSDL-first example shown in
service Figure 3.1 on page 37, starting from scratch, you would perform the following
steps:
2. Generate the Java stub code from the WSDL contract using a WSDL-to-Java
converter, ws2java. This gives you the SEI, CustomerService, and its
related classes, such as Customer.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 37
Chapter 3. WSDL-First Service Implementation
Because the WSDL contract is a fairly verbose format, it is not shown in here
in full. The main point you need to be aware of is that the CustomerSerivice
WSDL contract exposes the following operations:
lookupCustomer
Given a customer ID, the operation returns the corresponding Customer
data object.
updateCustomer
Stores the given Customer data object against the given customer ID.
getCustomerStatus
Returns the status of the customer with the given customer ID.
Parts of the WSDL contract A WSDL contract has the following main parts:
Port type The port type is defined in the WSDL contract by the wsdl:portType element.
It is analogous to an interface and it defines the operations that can be invoked
on the Web service.
38 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
CustomerService WSDL Contract
...
<wsdl:portType name="CustomerService">
<wsdl:operation name="lookupCustomer">
<wsdl:input message="tns:lookupCustomer"></wsdl:input>
<wsdl:output message="tns:lookupCustomerResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="updateCustomer">
<wsdl:input message="tns:updateCustomer"></wsdl:input>
<wsdl:output message="tns:updateCustomerResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="getCustomerStatus">
<wsdl:input message="tns:getCustomerStatus"></wsdl:input>
<wsdl:output message="tns:getCustomerStatusResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
...
</wsdl:definitions>
WSDL binding A WSDL binding describes how to encode all of the operations and data types
associated with a particular port type. A binding is specific to a particular
protocol—for example, SOAP or JMS.
WSDL port A WSDL port specifies the transport protocol and contains addressing data
that enables clients to locate and connect to a remote server endpoint.
</wsdl:definitions>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 39
Chapter 3. WSDL-First Service Implementation
The getCustomerStatus operation Because a WSDL contract is fairly verbose, it can be a bit difficult to see what
the parameters of an operation are. Typically, for each operation, you can
find data types in the XML schema section that represent the operation request
and the operation response. For example, the getCustomerStatus operation
has its request parameters (IN parameters) encoded by the
getCustomerStatus element and its response parameters (OUT parameters)
encoded by the getCustomerStatusResponse element, as follows:
<wsdl:definitions name="CustomerService"
targetNamespace="http://demo.fusesource.com/wsdl/CustomerService/"
...>
<wsdl:types>
<xsd:schema ...>
...
<xsd:element name="getCustomerStatus">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="customerId" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="getCustomerStatusResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="status" type="xsd:string"/>
<xsd:element name="statusMessage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
...
</wsdl:definitions>
References For more details about the format of WSDL contracts and how to create your
own WSDL contracts, see Writing WSDL Contracts from the Fuse Service
1
Framework documentation library and the Eclipse JAX-WS Tools Component .
1
http://wiki.eclipse.org/JAXWS
40 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-to-Java Maven Plug-In
To generate Java stub code from the WSDL contract, you can use either the
ws2java command-line utility or the cxf-codegen-plugin Maven plug-in.
The plug-in approach is ideal for Maven-based projects: after you paste the
requisite plug-in configuration into your POM file, the WSDL-to-Java code
generation step is integrated into your build.
Configure the WSDL-to-Java Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most
Maven plug-in of the default configuration settings can be left as they are. After copying and
pasting the sample plugin element into your project's POM file, there are
just a few basic settings that need to be customized, as follows:
• CXF version—make sure that the plug-in's dependencies are using the latest
version of Apache CXF.
For example, the following POM fragment shows how to configure the
cxf-codegen-plugin plug-in to generate Java stub code from the
CustomerService.wsdl WSDL file:
<project ...>
...
<properties>
<cxf.version>2.4.2-fuse-00-05</cxf.version>
</properties>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 41
Chapter 3. WSDL-First Service Implementation
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<!-- Maven auto-compiles any source files under target/generated-sources/ --
>
<sourceRoot>${basedir}/target/generated-sources/jaxws</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/../src/main/resources/wsdl/CustomerService.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Generated Java source code With the sample configuration shown here, the generated Java source code
is written under the target/generated-sources/jaxws directory. Note
that the Web service implementation is dependent on this generated stub
code—for example, the service implementation class must implement the
generated CustomerService SEI.
Adding the generated source to If you are using an IDE such as Eclipse or Intellij's IDEA, you need to make
an IDE sure that the IDE is aware of the generated Java code. For example, in Eclipse
it is necessary to add the target/generated-sources/jaxws directory to
the project as a source code directory.
Compiling the generated code You must ensure that the generated Java code is compiled and added to the
deployment package. By convention, Maven automatically compiles any
source files that it finds under the following directory:
BaseDir/target/generated-sources/
42 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-to-Java Maven Plug-In
Hence, if you configure the output directory as shown in the preceding POM
fragment, the generated code is automatically compiled by Maven.
Reference For full details of how to configure the Java-to-WSDL plug-in, see the Maven
2
cxf-codegen-plugin reference page.
2
http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 43
Chapter 3. WSDL-First Service Implementation
1. Create an instance of the implementor class, using the Spring bean element.
Define JAX-WS endpoint in XML The following sample Spring file shows how to define a JAX-WS endpoint in
XML, using the jaxws:endpoint element.
<?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:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframe
work.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:endpoint
xmlns:customer="http://demo.fusesource.com/wsdl/CustomerService/"
id="customerService"
address="http://0.0.0.0:9191/Customer"
serviceName="customer:CustomerService"
endpointName="customer:SOAPOverHTTP"
implementor="#customerServiceImpl">
</jaxws:endpoint>
44 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
<bean id="customerServiceImpl"
class="com.fusesource.customer.ws.CustomerServiceImpl"/>
</beans>
Address for the Jetty container To instantiate a custom Jetty container for the endpoint, specify a complete
HTTP URL, including the host and IP port (the value of the IP port effectively
identifies the target Jetty container). Typically, for a Jetty container, you
specify the host as 0.0.0.0, which is interpreted as a wildcard that matches
every IP network interface on the local machine (that is, if deployed on a
multi-homed host, Jetty opens a listening port on every network card).
Referencing the service The implementor attribute of the jaxws:endpoint element is used to
implementation reference the implementation of the WS service. The value of this attribute
can either be the name of the implementation class or (as in this example) a
bean reference in the format, #BeanID, where the # character indicates that
the following identifier is the name of a bean in the bean registry.
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. In the most
recent version of Apache CXF (later than 2.4.3), only the
META-INF/cxf/cxf.xml resource is needed.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 45
Chapter 3. WSDL-First Service Implementation
Using the Maven bundle plug-in The Maven bundle plug-in is used to package your project as an OSGi bundle,
in preparation for deployment into the OSGi container. There are two essential
modifications to make to your project's pom.xml file:
1. Change the packaging type to bundle (by editing the value of the
project/packaging element in the POM).
2. Add the Maven bundle plug-in to your POM file and configure it as
appropriate.
Configuring the Maven bundle plug-in is quite a technical task (although the
default settings are often adequate). For full details of how to customize the
plug-in configuration, consult the Deploying into the OSGi Container guide
and the Managing OSGi Dependencies guide from the Fuse ESB
documentation library.
Sample bundle plug-in The following POM fragment shows a sample configuration of the Maven
configuration bundle plug-in, which is appropriate for the current example.
<?xml version="1.0"?>
<project ...>
...
<groupId>org.fusesource.sparks.fuse-webinars.cxf-webinars</groupId>
<artifactId>customer-ws-osgi-bundle</artifactId>
<name>customer-ws-osgi-bundle</name>
<url>http://www.fusesource.com</url>
<packaging>bundle</packaging>
...
46 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to an OSGi Container
<build>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven-bundle-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
!com.fusesource.customer.ws,
!com.fusesource.demo.customer,
!com.fusesource.demo.wsdl.customerservice
</Export-Package>
<Import-Package>
META-INF.cxf,
META-INF.cxf.osgi,
*
</Import-Package>
<DynamicImport-Package>
org.apache.cxf.*,
org.springframework.beans.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
Dynamic imports The Java packages from Apache CXF and the Spring API are imported using
dynamic imports (specified using the DynamicImport-Package element).
This is a pragmatic way of dealing with the fact that Spring XML files are not
terribly well integrated with the Maven bundle plug-in. At build time, the
Maven bundle plug-in is not able to figure out which Java classes are required
by the Spring XML code. By listing wildcarded package names in the
DynamicImport-Package element, however, you allow the OSGi container
to figure out which Java classes are needed by the Spring XML code at run
time.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 47
Chapter 3. WSDL-First Service Implementation
Note
In general, using DynamicImport-Package headers is not
recommended in OSGi, because it short-circuits OSGi version
checking. Normally, what should happen is that the Maven bundle
plug-in lists the Java packages used at build time, along with their
versions, in the Import-Package header. At deploy time, the OSGi
container then checks that the available Java packages are
compatible with the build-time versions listed in the
Import-Package header. With dynamic imports, this version
checking cannot be performed.
Build and deploy the service After you have configured the POM file, you can build the Maven project and
bundle install it in your local repository by entering the following command:
mvn install
To deploy the service bundle, enter the following command at the Apache
ServiceMix console:
karaf@root> install -s mvn:org.fusesource.sparks.fuse-we
binars.cxf-webinars/customer-ws-osgi-bundle
Note
If your local Maven repository is stored in a non-standard location,
you might need to customize the value of the
org.ops4j.pax.url.mvn.localRepository property in the
EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before
you can use the mvn: scheme to access Maven artifacts.
Fuse ESB default servlet Fuse ESB has a default Jetty container which, by default, listens for HTTP
container requests on port 8181. Moreover, WS endpoints in this container are implicitly
deployed under the servlet context cxf/. Hence, any WS endpoint whose
address attribute is configured in the jaxws:endpoint element as
/EndpointContext will have the following effective address:
http://Hostname:8181/cxf/EndpointContext
You can optionally customize the default servlet container by editing settings
in the following file:
48 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to an OSGi Container
EsbInstallDir/etc/org.ops4j.pax.web.cfg
Full details of the properties you can set in this file are given in the Ops4j Pax
3
Web configuration reference ..
Check that the service is running A simple way of checking that the service is running is to point your browser
at the following URL:
http://localhost:8181/cxf/Customers?wsdl
3
http://team.ops4j.org/wiki/display/paxweb/Basic+Configuration
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 49
50 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 4. Implementing a WS Client
WS Client Overview ................................................................................................................ 52
WSDL-to-Java Maven Plug-In ................................................................................................... 54
Instantiate the WS Client Proxy ................................................................................................. 57
Invoke WS Operations ............................................................................................................. 60
Deploy to an OSGi Container .................................................................................................... 61
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 51
Chapter 4. Implementing a WS Client
WS Client Overview
Overview The key object in a WS client is the WS client proxy object, which enables
you to access the remote Web service by invoking methods on the SEI. The
proxy object itself can easily be instantiated using the jaxws:client element
in Spring XML.
Demonstration location The code presented in this chapter is taken from the following demonstration:
DemoDir/src/fuse-webinars/cxf-webinars/customer-ws-client
For details of how to download and install the demonstration code, see
Demonstration Code for Camel/CXF on page 11
Service Endpoint Interface (SEI) The most important piece of the generated stub code is the SEI, which is an
ordinary Java interface that represents the Web service interface in the Java
language.
WS client proxy The WS client proxy is an object that converts Java method invocations to
remote procedure calls, sending and receiving messages to a remote instance
of the Web service across the network. The methods of the proxy are exposed
through the SEI.
Note
The proxy type is generated dynamically by Apache CXF at run time.
That is, their is no class in the stub code that corresponds to the
implementation of the proxy (the only relevant entity is the SEI, which
defines the proxy's interface).
The CustomerService client To take a specific example, consider the customer-ws-client demonstration,
which is available from the following location:
52 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WS Client Overview
http://fusesource.com/unknown/fuse-webinars/cxf-webinars/cus
tomer-ws-client
Implementing and building the To implement and build the sample WS client shown in
WS client Figure 4.1 on page 53, starting from scratch, you would perform the following
steps:
2. Generate the Java stub code from the WSDL contract using a WSDL-to-Java
converter, ws2java. This gives you the SEI, CustomerService, and its
related classes, such as Customer.
3. Implement the main client class, ClientInvoker, which invokes the Web
service operations. In this class define a bean property of type,
CustomerService, so that the client class can receive a reference to the
WS client proxy by property injection.
4. In a Spring XML file, instantiate the WS client proxy and inject it into the
main client class, ClientInvoker.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 53
Chapter 4. Implementing a WS Client
Configure the WSDL-to-Java Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most
Maven plug-in of the default configuration settings can be left as they are. After copying and
pasting the sample plugin element into your project's POM file, there are
just a few basic settings that need to be customized, as follows:
• CXF version—make sure that the plug-in's dependencies are using the latest
version of Apache CXF.
For example, the following POM fragment shows how to configure the
cxf-codegen-plugin plug-in to generate Java stub code from the
CustomerService.wsdl WSDL file:
<project ...>
...
<properties>
<cxf.version>2.4.2-fuse-00-05</cxf.version>
</properties>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
54 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-to-Java Maven Plug-In
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/target/generated-sources/jaxws</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/../src/main/resources/wsdl/CustomerService.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Generated Java source code With the sample configuration shown here, the generated Java source code
is written under the target/generated-sources/jaxws directory. Note
that the client implementation is dependent on this generated stub code—for
example, the client invokes the proxy using the generated CustomerService
SEI.
Add generated source to IDE If you are using an IDE such as Eclipse or Intellij's IDEA, you need to make
sure that the IDE is aware of the generated Java code. For example, in Eclipse
it is necessary to add the target/generated-sources/jaxws directory to
the project as a source code directory.
Compiling the generated code You must ensure that the generated Java code is compiled and added to the
deployment package. By convention, Maven automatically compiles any
source files that it finds under the following directory:
BaseDir/target/generated-sources/
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 55
Chapter 4. Implementing a WS Client
Hence, if you configure the output directory as shown in the preceding POM
fragment, the generated code is automatically compiled by Maven.
Reference For full details of how to configure the Java-to-WSDL plug-in, see the Maven
1
cxf-codegen-plugin reference page.
1
http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html
56 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Client Proxy
Define the WS client in XML The following Spring XML fragment shows how to instantiate a client proxy
bean using the jaxws:client element.
<?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:soap="http://cxf.apache.org/bindings/soap"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframe
work.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<jaxws:client
id="customerServiceProxy"
address="http://localhost:9191/Customers"
serviceClass="com.fusesource.demo.wsdl.customerservice.CustomerService"
/>
<bean id="customerServiceClient"
class="com.fusesource.customer.client.ClientInvoker"
init-method="init" destroy-method="destroy">
<property name="customerService" ref="customerServiceProxy"/>
</bean>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 57
Chapter 4. Implementing a WS Client
</beans>
The jaxws:client element The jaxws:client element creates a client proxy dynamically (that is, there
is no dedicated class that represents a proxy implementation in the Java stub
code). The following attributes are used to define the proxy:
id
The ID that you specify here is entered in the bean registry and can be
used to reference the proxy instance from other beans.
address
The full address of the remote Web service that this proxy connects to.
serviceClass
The fully-qualified class name of the Web service's SEI (you invoke
methods on the proxy through the SEI).
Injecting with the proxy reference To access the proxy instance, simply inject the proxy into one or more other
beans defined in XML. Given that the proxy ID has the value,
customerServiceProxy, you can inject it into a bean property using the
Spring property element, as follows:
<bean ...>
<property name="customerService" ref="customerServiceProxy"/>
</bean>
58 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Client Proxy
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. In the most
recent version of Apache CXF (later than 2.4.3), only the
META-INF/cxf/cxf.xml resource is needed.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 59
Chapter 4. Implementing a WS Client
Invoke WS Operations
Proxy interface is SEI interface The proxy implements the SEI. Hence, to make remote procedure calls on
the Web service, simply invoke the SEI methods on the proxy instance.
Invoking the lookupCustomer For example, the CustomerService SEI exposes the lookupCustomer
operation method, which takes a customer ID as its argument and returns a Customer
data object. Using the proxy instance, customerService, you can invoke
the lookupCustomer operation as follows:
// Java
com.fusesource.demo.customer.Customer response
= customerService.lookupCustomer("1234");
When you are experimenting with the demonstration code in the latter chapters
of this guide, you might need to modify the ClientInvoker class, possibly
adding operation invocations.
60 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to an OSGi Container
Using the Maven bundle plug-in The Maven bundle plug-in is used to package your project as an OSGi bundle,
in preparation for deployment into the OSGi container. There are two essential
modifications to make to your project's pom.xml file:
1. Change the packaging type to bundle (by editing the value of the
project/packaging element in the POM).
2. Add the Maven bundle plug-in to your POM file and configure it as
appropriate.
Configuring the Maven bundle plug-in is quite a technical task (although the
default settings are often adequate). For full details of how to customize the
plug-in configuration, consult the Deploying into the OSGi Container guide
and the Managing OSGi Dependencies guide from the Fuse ESB
documentation library.
Sample bundle plug-in The following POM fragment shows a sample configuration of the Maven
configuration bundle plug-in, which is appropriate for the current example.
<?xml version="1.0"?>
<project ...>
...
<groupId>org.fusesource.sparks.fuse-webinars.cxf-webinars</groupId>
<artifactId>customer-ws-osgi-bundle</artifactId>
<name>customer-ws-osgi-bundle</name>
<url>http://www.fusesource.com</url>
<packaging>bundle</packaging>
...
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 61
Chapter 4. Implementing a WS Client
<build>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven-bundle-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>
!com.fusesource.customer.client,
!com.fusesource.demo.customer,
!com.fusesource.demo.wsdl.customerservice
</Export-Package>
<Import-Package>
META-INF.cxf,
*
</Import-Package>
<DynamicImport-Package>
org.apache.cxf.*,
org.springframework.beans.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
Dynamic imports The Java packages from Apache CXF and the Spring API are imported using
dynamic imports (specified using the DynamicImport-Package element).
This is a pragmatic way of dealing with the fact that Spring XML files are not
terribly well integrated with the Maven bundle plug-in. At build time, the
Maven bundle plug-in is not able to figure out which Java classes are required
by the Spring XML code. By listing wildcarded package names in the
DynamicImport-Package element, however, you allow the OSGi container
to figure out which Java classes are needed by the Spring XML code at run
time.
Note
In general, using DynamicImport-Package headers is not
recommended in OSGi, because it short-circuits OSGi version
62 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to an OSGi Container
Build and deploy the client After you have configured the POM file, you can build the Maven project and
bundle install it in your local repository by entering the following command:
mvn install
To deploy the client bundle, enter the following command at the Apache
ServiceMix console:
karaf@root> install -s mvn:org.fusesource.sparks.fuse-we
binars.cxf-webinars/customer-ws-client
Note
If your local Maven repository is stored in a non-standard location,
you might need to customize the value of the
org.ops4j.pax.url.mvn.localRepository property in the
EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before
you can use the mvn: scheme to access Maven artifacts.
Check that the client is running Assuming that you have already deployed the corresponding Web service into
the OSGi container (see Build and deploy the service bundle on page 48),
you can verify that the client is successfully invoking WSDL operations by
checking the log, as follows:
karaf@root> log:display -n 10
The client invokes an operation on the Web service once every second.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 63
64 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 5. Pojo-Based Route
Processing Messages in POJO Format ......................................................................................... 66
WSDL-to-Java Maven Plug-In ................................................................................................... 69
Instantiate the WS Endpoint ..................................................................................................... 72
Sort Messages by Operation Name ............................................................................................. 76
Process Operation Parameters ................................................................................................... 78
Deploy to OSGi ..................................................................................................................... 82
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 65
Chapter 5. Pojo-Based Route
• The big advantage of the POJO data format is that the operation parameters
are encoded using the JAX-B standard, which makes them easy to
manipulate in Java.
• The downside of the POJO data format, on the other hand, is that it requires
that the WSDL metadata is converted to Java in advance (as defined by
the JAX-WS and JAX-B mappings) and compiled into your application. This
means that a POJO-based route is not very dynamic.
Demonstration location The code presented in this chapter is taken from the following demonstration:
DemoDir/src/fuse-webinars/cxf-webinars/customer-ws-camel-cxf-
pojo
For details of how to download and install the demonstration code, see
Demonstration Code for Camel/CXF on page 11
Camel CXF component The Camel CXF component is an Apache CXF component that integrates Web
services with routes. You can use it either to instantiate consumer endpoints
(at the start of a route), which behave like Web service instances, or to
instantiate producer endpoints (at any other points in the route), which behave
like WS clients.
Note
Came CXF endpoints—which are instantiated using the
cxf:cxfEndpoint XML element and are implemented by the Apache
Camel project—are not to be confused with the Apache CXF JAX-WS
66 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Processing Messages in POJO Format
POJO data format POJO data format is the default data format used by the Camel CXF
component and it has the following characteristics:
• JAX-WS and JAX-B stub code (as generated from the WSDL contract) must
be provided.
• One Java object for each part or parameter of the corresponding WSDL
operation.
• The SOAP headers are converted into headers in the exchange's In message.
Implementing and building a To implement and build the demonstration POJO-based route, starting from
POJO route scratch, you would perform the following steps:
1. Obtain a copy of the WSDL contract that is to be integrated into the route.
2. Generate the Java stub code from the WSDL contract using a WSDL-to-Java
converter. This gives you the SEI, CustomerService, and its related
classes, such as Customer.
4. Implement the route in XML, where you can use the content-based router
to sort requests by operation name.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 67
Chapter 5. Pojo-Based Route
Sample POJO route Figure 5.1 on page 68 shows an outline of the route that is used to process
the operations of the CustomerService Web service using the POJO data
format. After sorting the request messages by operation name, an
operation-specific processor bean reads the incoming request parameters and
then generates a response in the POJO data format.
68 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-to-Java Maven Plug-In
Configure the WSDL-to-Java Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most
Maven plug-in of the default configuration settings can be left as they are. After copying and
pasting the sample plugin element into your project's POM file, there are
just a few basic settings that need to be customized, as follows:
• CXF version—make sure that the plug-in's dependencies are using the latest
version of Apache CXF.
For example, the following POM fragment shows how to configure the
cxf-codegen-plugin plug-in to generate Java stub code from the
CustomerService.wsdl WSDL file:
<project ...>
...
<properties>
<cxf.version>2.4.2-fuse-00-05</cxf.version>
</properties>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
...
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 69
Chapter 5. Pojo-Based Route
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/target/generated-sources/jaxws</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/../src/main/resources/wsdl/CustomerService.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Generated Java source code With the sample configuration shown here, the generated Java source code
is written under the target/generated-sources/jaxws directory. Note
that the route is dependent on this generated stub code—for example, when
processing the POJO parameters, the parameter processor uses the Customer
data type from the stub code.
Add generated code to IDE If you are using an IDE such as Eclipse or Intellij's IDEA, you need to make
sure that the IDE is aware of the generated Java code. For example, in Eclipse
it is necessary to add the target/generated-sources/jaxws directory to
the project as a source code directory.
Compiling the generated code You must ensure that the generated Java code is compiled and added to the
deployment package. By convention, Maven automatically compiles any
source files that it finds under the following directory:
BaseDir/target/generated-sources/
70 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
WSDL-to-Java Maven Plug-In
Hence, if you configure the output directory as shown in the preceding POM
fragment, the generated code is automatically compiled by Maven.
Reference For full details of how to configure the Java-to-WSDL plug-in, see the Maven
1
cxf-codegen-plugin reference page.
1
http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 71
Chapter 5. Pojo-Based Route
Maven dependency The Camel CXF component requires you to add a dependency on the
camel-cxf component in your Maven POM. For example, the pom.xml file
from the customer-ws-camel-cxf-pojo demonstration project includes
the following dependency:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-cxf</artifactId>
<version>${camel-version}</version>
</dependency>
The cxf:bean: URI syntax The cxf:bean: URI is used to bind an Apache CXF endpoint to a route and
has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
72 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
For example, to start a route with a Apache CXF endpoint that is configured
by the bean with ID, customer-ws, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
Note
There is an alternative URI syntax, cxf://WsAddress[?Options],
which enables you to specify all of the WS endpoint details in the
URI (so there is no need to reference a bean instance). This typically
results in a long and cumbersome URI, but is useful in some cases.
For details, see CXF in Apache Camel Documentation.
The cxf:cxfEndpoint element The cxf:cxfEndpoint element is used to define a WS endpoint that binds
either to the start (consumer endpoint) or the end (producer endpoint) of a
route. For example, to define the customer-ws WS endpoint referenced in
the preceding route, you would define a cxf:cxfEndpoint element as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
xmlns:cxf="http://camel.apache.org/schema/cxf" ...>
...
<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-extension-
http.xml"/>
<import resource="classpath:META-INF/cxf/osgi/cxf-exten
sion-osgi.xml"/>
<cxf:cxfEndpoint id="customer-ws"
address="http://0.0.0.0:9191/Customer"
endpointName="c:SOAPOverHTTP"
serviceName="c:CustomerService"
serviceClass="com.fusesource.demo.wsdl.customerser
vice.CustomerService"
xmlns:c="http://demo.fusesource.com/wsdl/CustomerSer
vice/"/>
...
</beans>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 73
Chapter 5. Pojo-Based Route
Important
Remember that the cxf:cxfEndpoint element and the
jaxws:endpoint element use different XML schemas (although the
syntax looks superficially similar). These elements bind a WS endpoint
in different ways: the cxf:cxfEndpoint element instantiates and
binds a WS endpoint to an Apache Camel route, whereas the
jaxws:endpoint element instantiates and binds a WS endpoint to
a Java class (using the JAX-WS mapping).
2
Address for the Jetty container Apache CXF deploys the WS endpoint into a Jetty servlet container instance
and the address attribute of cxf:cxfEndpoint is therefore used to configure
the addressing information for the endpoint in the Jetty container.
Specify a complete HTTP URL, including the host and IP port (the value of
the IP port effectively identifies the target Jetty container). Typically, for a
Jetty container, you specify the host as 0.0.0.0, which is interpreted as a
wildcard that matches every IP network interface on the local machine (that
is, if deployed on a multi-homed host, Jetty opens a listening port on every
network card). For example, to deploy the endpoint to the custom Jetty
container listening on IP port, 9191:
address="http://0.0.0.0:9191/Customers"
Note
If you want to configure a secure endpoint (secured by SSL), you
would specify the https: scheme in the address.
Referencing the SEI The serviceClass attribute of the cxf:cxfEndpoint element references
the SEI of the Web service, which in this case is the CustomerService
interface.
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. In the most
recent version of Apache CXF (later than 2.4.3), only the
META-INF/cxf/cxf.xml resource is needed.
2
http://jetty.codehaus.org/jetty/
74 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 75
Chapter 5. Pojo-Based Route
Sorting by operation name For example, the customer-ws-camel-cxf-pojo demonstration defines the
following route, which uses the content-based router pattern to sort incoming
messages, based on the operation name. The when predicates check the value
of the operationName header using simple language expressions, sorting
messages into invocations on the updateCustomer operation, the
lookupCustomer operation, or the getCustomerStatus operation.
<beans ...>
...
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:customer-ws"/>
<choice>
<when>
<simple>${in.header.operationName} == 'updateCustomer'</simple>
<to uri="updateCustomer"/>
</when>
<when>
<simple>${in.header.operationName} == 'lookupCustomer'</simple>
<to uri="lookupCustomer"/>
</when>
<when>
<simple>${in.header.operationName} == 'getCustomerStatus'</simple>
<to uri="getCustomerStatus"/>
</when>
</choice>
</route>
</camelContext>
<bean id="updateCustomer"
class="com.fusesource.customerwscamelcxfpojo.UpdateCustomerProcessor"/>
<bean id="getCustomerStatus"
class="com.fusesource.customerwscamelcxfpojo.GetCustomerStatusProcessor"/>
<bean id="lookupCustomer"
class="com.fusesource.customerwscamelcxfpojo.LookupCustomerProcessor"/>
76 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Sort Messages by Operation Name
</beans>
Beans as endpoints Note how the preceding route uses a convenient shortcut to divert each branch
of the choice DSL to a different processor bean. The DSL for sending
exchanges to producer endpoints (for example, <to uri="Destination"/>)
is integrated with the bean registry: if the Destination does not resolve to
an endpoint or a component, the Destination is used as a bean ID to look
up the bean registry. In this example, the exchange is routed to processor
beans (which implement the org.apache.camel.Processor interface).
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 77
Chapter 5. Pojo-Based Route
Contents of request message body In POJO mode, the body of the request message is an
org.apache.cxf.message.MessageContentsList object. You can also
obtain the message body as an Object[] array (where type conversion is
automatic).
When the body is obtained as an Object[] array, the array contains the list
of all the operation's IN, INOUT, and OUT parameters in exactly the same
order as defined in the WSDL contract (and in the same order as the
corresponding operation signature of the SEI). The parameter mode affects
the content as follows:
IN
Contains a parameter value from the client.
INOUT
Contains a Holder object containing a parameter value from the client.
OUT
Contains an empty Holder object, which is a placeholder for the
response.
Note
Unlike OUT parameters, there is no placeholder in the request's
Object[] array to represent a return value.
Contents of response message In POJO mode, the body of the response message can be either an
body org.apache.cxf.message.MessageContentsList object or an Object[]
array.
78 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Process Operation Parameters
When setting the response body as an Object[] array, the array should
contain only the operation's INOUT and OUT parameters in the same order
as defined in the WSDL contract, omitting the IN parameters. The parameter
mode affects the content as follows:
INOUT
Contains a Holder object, which you must set to a response value. The
Holder object used here must be exactly the Holder object for the
corresponding parameter that was extracted from the request Object[]
array. Creating and inserting a new Holder object into the Object[]
array does not work.
OUT
Contains a Holder object, which you must initialize with a response
value. The Holder object used here must be exactly the Holder object
for the corresponding parameter that was extracted from the request
Object[] array. Creating and inserting a new Holder object into the
Object[] array does not work.
Note
If you defined the Web service interface using the Java-first approach,
note that the return value (if any) must be set as the first element
in the response's Object[] array. The return type is set as a plain
object: it does not use a Holder object.
Example: getCustomerStatus For example, the getCustomerStatus operation takes three parameters: IN,
operation OUT, and OUT, respectively. The corresponding method signature in the SEI
is, as follows:
// Java
public void getCustomerStatus(
@WebParam(name = "customerId", targetNamespace = "")
java.lang.String customerId,
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 79
Chapter 5. Pojo-Based Route
javax.xml.ws.Holder<java.lang.String> statusMessage
);
Example: request and response For the getCustomerStatus operation, the bodies of the request message
bodies and the response message have the following contents:
import javax.xml.ws.Holder;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
80 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Process Operation Parameters
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 81
Chapter 5. Pojo-Based Route
Deploy to OSGi
Overview One of the options for deploying the POJO-based route is to package it as an
OSGi bundle and deploy it into an OSGi container such as Fuse ESB (the Fuse
distribution of Apache ServiceMix). Some of the advantages of an OSGi
deployment include:
Using the Maven bundle plug-in The Maven bundle plug-in is used to package your project as an OSGi bundle,
in preparation for deployment into the OSGi container. There are two essential
modifications to make to your project's pom.xml file:
1. Change the packaging type to bundle (by editing the value of the
project/packaging element in the POM).
2. Add the Maven bundle plug-in to your POM file and configure it as
appropriate.
Configuring the Maven bundle plug-in is quite a technical task (although the
default settings are often adequate). For full details of how to customize the
plug-in configuration, consult the Deploying into the OSGi Container guide
and the Managing OSGi Dependencies guide from the Fuse ESB
documentation library.
Sample bundle plug-in The following POM fragment shows a sample configuration of the Maven
configuration bundle plug-in, which is appropriate for the current example.
<?xml version="1.0"?>
<project ...>
...
<groupId>org.fusesource.sparks.fuse-webinars.cxf-webinars</groupId>
<artifactId>customer-ws-camel-cxf-pojo</artifactId>
<name>customer-ws-camel-cxf-pojo</name>
<url>http://www.fusesource.com</url>
<packaging>bundle</packaging>
82 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to OSGi
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
META-INF.cxf,
META-INF.cxf.osgi,
*
</Import-Package>
<DynamicImport-Package>
org.apache.cxf.*,
org.springframework.beans.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
Dynamic imports The Java packages from Apache CXF and the Spring API are imported using
dynamic imports (specified using the DynamicImport-Package element).
This is a pragmatic way of dealing with the fact that Spring XML files are not
terribly well integrated with the Maven bundle plug-in. At build time, the
Maven bundle plug-in is not able to figure out which Java classes are required
by the Spring XML code. By listing wildcarded package names in the
DynamicImport-Package element, however, you allow the OSGi container
to figure out which Java classes are needed by the Spring XML code at run
time.
Note
In general, using DynamicImport-Package headers is not
recommended in OSGi, because it short-circuits OSGi version
checking. Normally, what should happen is that the Maven bundle
plug-in lists the Java packages used at build time, along with their
versions, in the Import-Package header. At deploy time, the OSGi
container then checks that the available Java packages are
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 83
Chapter 5. Pojo-Based Route
Build and deploy the client After you have configured the POM file, you can build the Maven project and
bundle install it in your local repository by entering the following command:
mvn install
To deploy the route bundle, enter the following command at the Apache
ServiceMix console:
karaf@root> install -s mvn:org.fusesource.sparks.fuse-we
binars.cxf-webinars/customer-ws-camel-cxf-pojo
Note
If your local Maven repository is stored in a non-standard location,
you might need to customize the value of the
org.ops4j.pax.url.mvn.localRepository property in the
EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before
you can use the mvn: scheme to access Maven artifacts.
84 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 6. Payload-Based Route
Processing Messages in PAYLOAD Format .................................................................................... 86
Instantiate the WS Endpoint ..................................................................................................... 89
Sort Messages by Operation Name ............................................................................................. 92
SOAP/HTTP-to-JMS Bridge Use Case .......................................................................................... 93
Generating Responses Using Templates ....................................................................................... 97
Deploy to OSGi .................................................................................................................... 101
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 85
Chapter 6. Payload-Based Route
Having a message body in XML format enables you to parse the request using
XML languages such as XPath and to generate responses using templating
languages, such as Velocity.
Note
The DOM format is not the optimal type to use for large XML message
bodies. For large messages, consider using the techniques described
in Provider-Based Route on page 105.
Demonstration location The code presented in this chapter is taken from the following demonstration:
DemoDir/src/fuse-webinars/cxf-webinars/customer-ws-camel-cxf-
payload
For details of how to download and install the demonstration code, see
Demonstration Code for Camel/CXF on page 11
Camel CXF component The Camel CXF component is an Apache CXF component that integrates Web
services with routes. You can use it either to instantiate consumer endpoints
(at the start of a route), which behave like Web service instances, or to
instantiate producer endpoints (at any other points in the route), which behave
like WS clients.
Note
Came CXF endpoints—which are instantiated using the
cxf:cxfEndpoint XML element and are implemented by the Apache
Camel project—are not to be confused with the Apache CXF JAX-WS
86 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Processing Messages in PAYLOAD Format
PAYLOAD data format The PAYLOAD data format is selected by setting the dataFormat=PAYLOAD
option on a Camel CXF endpoint URI and it has the following characteristics:
• Enables you to access the message body as a DOM object (XML payload).
• The SOAP headers are converted into headers in the exchange's In message,
of org.apache.cxf.binding.soap.SoapHeader type.
Implementing and building a To implement and build the demonstration PAYLOAD-based route, starting
PAYLOAD route from scratch, you would perform the following steps:
2. Implement the route in XML, where you can use the content-based router
to sort requests by operation name.
Sample PAYLOAD route Figure 6.1 on page 88 shows an outline of the route that is used to process
the operations of the CustomerService Web service using the PAYLOAD
data format. After sorting the request messages by operation name, an
operation-specific processor bean reads the incoming request parameters.
Finally, the response messages are generated using Velocity templates.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 87
Chapter 6. Payload-Based Route
88 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
The cxf:bean: URI syntax The cxf:bean: URI is used to bind an Apache CXF endpoint to a route and
has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
For example, to start a route with an endpoint in PAYLOAD mode, where the
endpoint is configured by the customer-ws bean, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws?dataFormat=PAYLOAD"/>
...
</route>
The cxf:cxfEndpoint element The cxf:cxfEndpoint element is used to define a WS endpoint that binds
either to the start (consumer endpoint) or the end (producer endpoint) of a
route. For example, to define the customer-ws WS endpoint in PAYLOAD
mode, you define a cxf:cxfEndpoint element as follows:
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 89
Chapter 6. Payload-Based Route
Note
In the case of PAYLOAD mode, you do not need to reference the SEI
and you must specify the WSDL location instead. In fact, in PAYLOAD
mode, you do not require any Java stub code at all.
1
Address for the Jetty container Apache CXF deploys the WS endpoint into a Jetty servlet container instance
and the address attribute of cxf:cxfEndpoint is therefore used to configure
the addressing information for the endpoint in the Jetty container.
Specify a complete HTTP URL, including the host and IP port (the value of
the IP port effectively identifies the target Jetty container). Typically, for a
Jetty container, you specify the host as 0.0.0.0, which is interpreted as a
wildcard that matches every IP network interface on the local machine (that
is, if deployed on a multi-homed host, Jetty opens a listening port on every
network card). For example, to deploy the endpoint to the custom Jetty
container listening on IP port, 9191:
address="http://0.0.0.0:9191/Customers"
Note
If you want to configure a secure endpoint (secured by SSL), you
would specify the https: scheme in the address.
Specifying the WSDL location The wsdlURL attribute of the cxf:cxfEndpoint element is used to specify
the location of the WSDL contract for this endpoint. The WSDL contract is
1
http://jetty.codehaus.org/jetty/
90 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
used exclusively as the source of metadata for this endpoint: there is need to
specify an SEI in PAYLOAD mode.
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. In the most
recent version of Apache CXF (later than 2.4.3), only the
META-INF/cxf/cxf.xml resource is needed.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 91
Chapter 6. Payload-Based Route
<beans ...>
...
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:customer-ws?dataFormat=PAYLOAD"/>
<choice>
<when>
<simple>${in.header.operationName} == 'updateCustomer'</simple>
...
</when>
<when>
<simple>${in.header.operationName} == 'lookupCustomer'</simple>
...
</when>
<when>
<simple>${in.header.operationName} == 'getCustomerStatus'</simple>
...
</when>
</choice>
</route>
</camelContext>
</beans>
92 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
SOAP/HTTP-to-JMS Bridge Use Case
Figure 6.2 on page 93 shows the general outline of a bridge that can
transform synchronous SOAP/HTTP invocations into asynchronous JMS
message deliveries.
Transforming RPC operations to As shown in Figure 6.2 on page 93, the route for transforming synchronous
One Way SOAP/HTTP to asynchronous JMS works as follows:
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 93
Chapter 6. Payload-Based Route
2. The inOnly DSL command pushes a copy of the XML payload onto a JMS
queue, so that it can be processed offline at some later time.
4. The Camel CXF component supports implicit type conversion of the XML
string to payload format.
Evidently, this transformation can only work, if the original operation invocation
has no return value. Otherwise, it would be impossible to generate a response
message before the request has been processed.
Creating a broker instance You can use Apache ActiveMQ as the JMS implementation. A convenient
approach to use in this demonstration is to embed the Apache ActiveMQ
broker in the bridge bundle. Simply define an amq:broker element in the
Spring XML file, as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:amq="http://activemq.apache.org/schema/core"
...>
Note
This broker instance is created with the persistent attribute set
to false, so that the messages are stored only in memory.
Configuring the JMS component Because the broker is co-located with the bridge route (in the same JVM),
the most efficient way to connect to the broker is to use the VM (Virtual
94 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
SOAP/HTTP-to-JMS Bridge Use Case
Note
By defining the bean with an id value of activemq, you are implicitly
overriding the component associated with the endpoint URI prefix,
activemq:. In other words, your custom ActiveMQComponent
instance is used instead of the default ActiveMQComponent instance
from the camel-activemq JAR file.
Sample SOAP/HTTP-to-JMS route For example, you could define a route that implements the SOAP/HTTP-to-JMS
bridge specifically for the updateCustomer operation from the
CustomerService SEI, as follows:
<when>
<simple>${in.header.operationName} == 'updateCustomer'</simple>
<log message="Placing update customer message onto queue."/>
<inOnly uri="activemq:queue:CustomerUpdates?jmsMessageType=Text"/>
<transform>
<constant>
<![CDATA[
<ns2:updateCustomerResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/"/>
]]>
</constant>
</transform>
</when>
Sending to the JMS endpoint in Note how the message payload is sent to the JMS queue using the inOnly
inOnly mode DSL command instead of the to DSL command. When you send a message
using the to DSL command, the default behavior is to use the same invocation
mode as the current exchange. But the current exchange has an InOut MEP,
which means that the to DSL command would wait forever for a response
message from JMS.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 95
Chapter 6. Payload-Based Route
The invocation mode we want to use when sending the payload to the JMS
queue is InOnly (asynchronous), and we can force this mode by inserting the
inOnly DSL command into the route.
Note
By specifying the option, jmsMessageType=Text, Camel CXF
implicitly converts the message payload to an XML string before
pushing it onto the JMS queue.
Returning a literal response value The transform DSL command uses an expression to set the body of the
exchange's Out message and this message is then used as the response to
the client. Your first impulse when defining a response in XML format might
be to use a DOM API, but in this example, the response is specified as a
string literal. This approach has the advantage of being both efficient and
very easy to program.
The final step of processing, which consists of converting the XML string to
a DOM object, is performed by Apache Camel's implicit type conversion
mechanism.
96 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Generating Responses Using Templates
Sample template-based route For example, you could define a template-based route specifically for the
getCustoemrStatus operation, as follows:
...
<when>
<simple>${in.header.operationName} == 'getCustomerStatus'</simple>
<convertBodyTo type="org.w3c.dom.Node"/>
<setHeader headerName="customerId">
<xpath resultType="java.lang.String">/cus:getCustomerStatus/customerId</xpath>
</setHeader>
<to uri="getCustomerStatus"/>
<to uri="velocity:getCustomerStatusResponse.vm"/>
</when>
</choice>
</route>
</camelContext
...
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 97
Chapter 6. Payload-Based Route
<bean id="getCustomerStatus"
class="com.fusesource.customerwscamelcxfpayload.GetCustomerStatus"/>
Route processing steps Given the preceding route definition, any message whose operation name
matches getCustomerStatus would be processed as follows:
3. The next step sends the message to the getCustomerStatus bean, which
does whatever processing is required to get the customer status for the
specified customer ID. The results from this step are stashed in message
headers.
Tip
A common pattern when implementing Apache Camel routes is to
use message headers as a temporary stash to hold intermediate
results (you could also use exchange properties in the same way).
Converting XPath result to a string Because the default return type of XPath is a node list, you must explicitly
convert the result to a string, if you want to obtain the string contents of an
element. There are two alternative ways of obtaining the string value of an
element:
• Specify the result type explicitly using the resultType attribute, as follows:
<xpath resultType="java.lang.String">/cus:getCustomer
Status/customerId</xpath>
98 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Generating Responses Using Templates
// Java
package com.fusesource.customerwscamelcxfpayload;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
exchng.getIn().setHeader("status", "Away");
exchng.getIn().setHeader("statusMessage", "Going to
sleep.");
}
}
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 99
Chapter 6. Payload-Based Route
Note
An exceptional case occurs when the message exchange pattern is
inOnly, in which case the Out message value is always copied into
the In message, even if it is null.
getCustomerStatusResponse.vm You can generate a response message very simply using a Velocity template.
Velocity template The Velocity template consists of a message in plain text, where specific
pieces of data can be inserted using expressions—for example, the expression
${header.HeaderName} substitutes the value of a named header.
100 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to OSGi
Deploy to OSGi
Overview One of the options for deploying the payload-based route is to package it as
an OSGi bundle and deploy it into an OSGi container such as Fuse ESB (the
Fuse distribution of Apache ServiceMix). Some of the advantages of an OSGi
deployment include:
Using the Maven bundle plug-in The Maven bundle plug-in is used to package your project as an OSGi bundle,
in preparation for deployment into the OSGi container. There are two essential
modifications to make to your project's pom.xml file:
1. Change the packaging type to bundle (by editing the value of the
project/packaging element in the POM).
2. Add the Maven bundle plug-in to your POM file and configure it as
appropriate.
Configuring the Maven bundle plug-in is quite a technical task (although the
default settings are often adequate). For full details of how to customize the
plug-in configuration, consult the Deploying into the OSGi Container guide
and the Managing OSGi Dependencies guide from the Fuse ESB
documentation library.
Sample bundle plug-in The following POM fragment shows a sample configuration of the Maven
configuration bundle plug-in, which is appropriate for the current example.
<?xml version="1.0"?>
<project ...>
...
<groupId>org.fusesource.sparks.fuse-webinars.cxf-webinars</groupId>
<artifactId>customer-ws-camel-cxf-payload</artifactId>
<name>customer-ws-camel-cxf-payload</name>
<url>http://www.fusesource.com</url>
<packaging>bundle</packaging>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 101
Chapter 6. Payload-Based Route
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
org.apache.camel.component.velocity,
META-INF.cxf,
META-INF.cxf.osgi,
javax.jws,
javax.wsdl,
javax.xml.bind,
javax.xml.bind.annotation,
javax.xml.namespace,
javax.xml.ws,
org.w3c.dom,
<!-- Workaround to access DOM XPathFactory -->
org.apache.xpath.jaxp,
*
</Import-Package>
<DynamicImport-Package>
org.apache.cxf.*,
org.springframework.beans.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
Dynamic imports The Java packages from Apache CXF and the Spring API are imported using
dynamic imports (specified using the DynamicImport-Package element).
This is a pragmatic way of dealing with the fact that Spring XML files are not
terribly well integrated with the Maven bundle plug-in. At build time, the
Maven bundle plug-in is not able to figure out which Java classes are required
by the Spring XML code. By listing wildcarded package names in the
DynamicImport-Package element, however, you allow the OSGi container
to figure out which Java classes are needed by the Spring XML code at run
time.
102 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to OSGi
Note
In general, using DynamicImport-Package headers is not
recommended in OSGi, because it short-circuits OSGi version
checking. Normally, what should happen is that the Maven bundle
plug-in lists the Java packages used at build time, along with their
versions, in the Import-Package header. At deploy time, the OSGi
container then checks that the available Java packages are
compatible with the build time versions listed in the Import-Package
header. With dynamic imports, this version checking cannot be
performed.
Build and deploy the client After you have configured the POM file, you can build the Maven project and
bundle install it in your local repository by entering the following command:
mvn install
To deploy the route bundle, enter the following command at the Apache
ServiceMix console:
karaf@root> install -s mvn:org.fusesource.sparks.fuse-we
binars.cxf-webinars/customer-ws-camel-cxf-payload
Note
If your local Maven repository is stored in a non-standard location,
you might need to customize the value of the
org.ops4j.pax.url.mvn.localRepository property in the
EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before
you can use the mvn: scheme to access Maven artifacts.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 103
104 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 7. Provider-Based Route
Provider-Based JAX-WS Endpoint ............................................................................................. 106
Create a Provider<?> Implementation Class ............................................................................... 109
Instantiate the WS Endpoint ................................................................................................... 110
Sort Messages by Operation Name ........................................................................................... 112
SOAP/HTTP-to-JMS Bridge Use Case ........................................................................................ 113
Generating Responses Using Templates ..................................................................................... 117
TypeConverter for SAXSource .................................................................................................. 120
Deploy to OSGi .................................................................................................................... 121
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 105
Chapter 7. Provider-Based Route
Demonstration location The code presented in this chapter is taken from the following demonstration:
DemoDir/src/fuse-webinars/cxf-webinars/customer-ws-camel-cxf-
provider
For details of how to download and install the demonstration code, see
Demonstration Code for Camel/CXF on page 11
Camel CXF component The Camel CXF component is an Apache CXF component that integrates Web
services with routes. You can use it either to instantiate consumer endpoints
(at the start of a route), which behave like Web service instances, or to
instantiate producer endpoints (at any other points in the route), which behave
like WS clients.
Note
Came CXF endpoints—which are instantiated using the
cxf:cxfEndpoint XML element and are implemented by the Apache
Camel project—are not to be confused with the Apache CXF JAX-WS
endpoints—which are instantiated using the jaxws:endpoint XML
element and are implemented by the Apache CXF project.
Provider-based approach and the The provider-based approach is a variant of the PAYLOAD data format, which
PAYLOAD data format is enabled as follows:
106 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Provider-Based JAX-WS Endpoint
• The SOAP headers are converted into headers in the exchange's In message,
of org.apache.cxf.binding.soap.SoapHeader type.
Implementing and building a To implement and build the demonstration provider-based route, starting from
provider-based route scratch, you would perform the following steps:
3. Implement the route in XML, where you can use the content-based router
to sort requests by operation name.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 107
Chapter 7. Provider-Based Route
Sample provider-based route Figure 7.1 on page 108 shows an outline of the route that is used to process
the operations of the CustomerService Web service using the provider-based
approach. After sorting the request messages by operation name, an
operation-specific processor bean reads the incoming request parameters.
Finally, the response messages are generated using Velocity templates.
108 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Create a Provider<?> Implementation Class
By implementing the provider class in the way shown here, you are merely
indicating to the Apache CXF runtime that the WS endpoint should operate
in in PAYLOAD mode and the type of the message PAYLOAD should be
SAXSource.
The SAXSourceService provider The definition of the provider class is relatively short and the complete
class definition of the customer provider class, SAXSourceService, is as follows:
// Java
package com.fusesource.customerwscamelcxfprovider;
import javax.xml.transform.sax.SAXSource;
import javax.xml.ws.Provider;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;
@WebServiceProvider()
@ServiceMode(Mode.PAYLOAD)
public class SAXSourceService implements Provider<SAXSource>
{
public SAXSource invoke(SAXSource t) {
throw new UnsupportedOperationException("Not supported
yet.");
}
}
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 109
Chapter 7. Provider-Based Route
The cxf:bean: URI syntax The cxf:bean: URI is used to bind an Apache CXF endpoint to a route and
has the following general syntax:
cxf:bean:CxfEndpointID[?Options]
For example, to start a route with an endpoint in provider mode, where the
endpoint is configured by the customer-ws bean, define the route as follows:
<route>
<from uri="cxf:bean:customer-ws"/>
...
</route>
The cxf:cxfEndpoint element The cxf:cxfEndpoint element is used to define a WS endpoint that binds
either to the start (consumer endpoint) or the end (producer endpoint) of a
110 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Instantiate the WS Endpoint
Specifying the WSDL location The wsdlURL attribute of the cxf:cxfEndpoint element is used to specify
the location of the WSDL contract for this endpoint. The WSDL contract is
used as the source of metadata for this endpoint.
Specifying the service class A key difference between provider mode and ordinary PAYLOAD mode is that
the serviceClass attribute must be set to the provider class,
SAXSourceService.
Importing XML resources Because of the modular structure of Apache CXF, additional configuration is
added as needed using the relevant <import ...> tags in XML. In the most
recent version of Apache CXF (later than 2.4.3), only the
META-INF/cxf/cxf.xml resource is needed.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 111
Chapter 7. Provider-Based Route
<beans ...>
...
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxf:bean:customer-ws"/>
<choice>
<when>
<simple>${in.header.operationName} == 'updateCustomer'</simple>
...
</when>
<when>
<simple>${in.header.operationName} == 'lookupCustomer'</simple>
...
</when>
<when>
<simple>${in.header.operationName} == 'getCustomerStatus'</simple>
...
</when>
</choice>
</route>
</camelContext>
...
</beans>
112 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
SOAP/HTTP-to-JMS Bridge Use Case
Figure 7.2 on page 113 shows the general outline of a bridge that can
transform synchronous SOAP/HTTP invocations into asynchronous JMS
message deliveries.
Transforming RPC operations to As shown in Figure 7.2 on page 113, the route for transforming synchronous
One Way SOAP/HTTP to asynchronous JMS works as follows:
2. The inOnly DSL command pushes a copy of the XML payload onto a JMS
queue, so that it can be processed offline at some later time.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 113
Chapter 7. Provider-Based Route
Evidently, this transformation can only work, if the original operation invocation
has no return value. Otherwise, it would be impossible to generate a response
message before the request has been processed.
Creating a broker instance You can use Apache ActiveMQ as the JMS implementation. A convenient
approach to use in this demonstration is to embed the Apache ActiveMQ
broker in the bridge bundle. Simply define an amq:broker element in the
Spring XML file, as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:amq="http://activemq.apache.org/schema/core"
...>
Note
This broker instance is created with the persistent attribute set
to false, so that the messages are stored only in memory.
Configuring the JMS component Because the broker is co-located with the bridge route (in the same JVM),
the most efficient way to connect to the broker is to use the VM (Virtual
Machine) transport. Configure the Apache ActiveMQ component as follows,
to connect to the co-located broker using the VM protocol:
<beans ...>
...
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="vm:local"/>
</bean>
114 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
SOAP/HTTP-to-JMS Bridge Use Case
...
</beans>
Note
By defining the bean with an id value of activemq, you are implicitly
overriding the component associated with the endpoint URI prefix,
activemq:. In other words, your custom ActiveMQComponent
instance is used instead of the default ActiveMQComponent instance
from the camel-activemq JAR file.
Sample SOAP/HTTP-to-JMS route For example, you could define a route that implements the SOAP/HTTP-to-JMS
bridge specifically for the updateCustomer operation from the
CustomerService SEI, as follows:
<when>
<simple>${in.header.operationName} == 'updateCustomer'</simple>
<log message="Placing update customer message onto queue."/>
<inOnly uri="activemq:queue:CustomerUpdates?jmsMessageType=Text"/>
<transform>
<constant>
<![CDATA[
<ns2:updateCustomerResponse xmlns:ns2="http://demo.fusesource.com/wsdl/CustomerService/"/>
]]>
</constant>
</transform>
<convertBodyTo type="javax.xml.transform.sax.SAXSource"/>
</when>
Sending to the JMS endpoint in Note how the message payload is sent to the JMS queue using the inOnly
inOnly mode DSL command instead of the to DSL command. When you send a message
using the to DSL command, the default behavior is to use the same invocation
mode as the current exchange. But the current exchange has an InOut MEP,
which means that the to DSL command would wait forever for a response
message from JMS.
The invocation mode we want to use when sending the payload to the JMS
queue is InOnly (asynchronous), and we can force this mode by inserting the
inOnly DSL command into the route.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 115
Chapter 7. Provider-Based Route
Note
By specifying the option, jmsMessageType=Text, Camel CXF
implicitly converts the message payload to an XML string before
pushing it onto the JMS queue.
Returning a literal response value The transform DSL command uses an expression to set the body of the
exchange's Out message and this message is then used as the response to
the client. Your first impulse when defining a response in XML format might
be to use a DOM API, but in this example, the response is specified as a
string literal. This approach has the advantage of being both efficient and
very easy to program.
The final step of processing, which consists of converting the XML string to
a DOM object, is performed by Apache Camel's implicit type conversion
mechanism.
Type conversion of the response In this example, the reply message (like the request message) is required to
message be of type, javax.xml.transform.sax.SAXSource. In the last step of the
route, therefore, you must convert the message body from String type to
javax.xml.transform.sax.SAXSource type, by invoking the
convertBodyTo DSL command.
116 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Generating Responses Using Templates
Sample template-based route For example, you could define a template-based route specifically for the
getCustoemrStatus operation, as follows:
...
<when>
<simple>${in.header.operationName} == 'getCustomerStatus'</simple>
<setHeader headerName="customerId">
<xpath resultType="java.lang.String">/cus:getCustomerStatus/customerId</xpath>
</setHeader>
<to uri="getCustomerStatus"/>
<to uri="velocity:getCustomerStatusResponse.vm"/>
<convertBodyTo type="javax.xml.transform.sax.SAXSource"/>
</when>
</choice>
</route>
</camelContext
...
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 117
Chapter 7. Provider-Based Route
<bean id="getCustomerStatus"
class="com.fusesource.customerwscamelcxfpayload.GetCustomerStatus"/>
Route processing steps Given the preceding route definition, any message whose operation name
matches getCustomerStatus would be processed as follows:
2. The next step sends the message to the getCustomerStatus bean, which
does whatever processing is required to get the customer status for the
specified customer ID. The results from this step are stashed in message
headers.
4. Finally, the XML string generated by the Velocity template must be explicitly
converted to the javax.xml.transform.sax.SAXSource type using
convertBodyTo (which implicitly relies on a type converter).
Tip
A common pattern when implementing Apache Camel routes is to
use message headers as a temporary stash to hold intermediate
results (you could also use exchange properties in the same way).
XPath expressions and SAXSource XPath expressions can be applied directly to SAXSource objects. The XPath
implementation has a pluggable architecture that supports a variety of XML
parsers and when XPath encounters a SAXSource object, it automatically
loads the plug-in required to support SAXSource parsing.
// Java
package com.fusesource.customerwscamelcxfpayload;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
118 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Generating Responses Using Templates
exchng.getIn().setHeader("status", "Away");
exchng.getIn().setHeader("statusMessage", "Going to
sleep.");
}
}
getCustomerStatusResponse.vm You can generate a response message very simply using a Velocity template.
Velocity template The Velocity template consists of a message in plain text, where specific
pieces of data can be inserted using expressions—for example, the expression
${header.HeaderName} substitutes the value of a named header.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 119
Chapter 7. Provider-Based Route
String to SAXSource type The String to SAXSource type converter is implemented in the
converter AdditionalConverters class, as follows:
// Java
package com.fusesource.customerwscamelcxfprovider;
import java.io.ByteArrayInputStream;
import javax.xml.transform.sax.SAXSource;
import org.apache.camel.Converter;
import org.xml.sax.InputSource;
@Converter
public class AdditionalConverters {
@Converter
public static SAXSource toSAXSource(String xml) {
return new SAXSource(new InputSource(new ByteArrayInput
Stream(xml.getBytes())));
}
}
Reference For full details of the type converter mechanism in Apache Camel, see "Built-In
Type Converters" in Programing EIP Components and "Type Converters" in
Programing EIP Components.
120 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to OSGi
Deploy to OSGi
Overview One of the options for deploying the provider-based route is to package it as
an OSGi bundle and deploy it into an OSGi container such as Fuse ESB (the
Fuse distribution of Apache ServiceMix). Some of the advantages of an OSGi
deployment include:
Using the Maven bundle plug-in The Maven bundle plug-in is used to package your project as an OSGi bundle,
in preparation for deployment into the OSGi container. There are two essential
modifications to make to your project's pom.xml file:
1. Change the packaging type to bundle (by editing the value of the
project/packaging element in the POM).
2. Add the Maven bundle plug-in to your POM file and configure it as
appropriate.
Configuring the Maven bundle plug-in is quite a technical task (although the
default settings are often adequate). For full details of how to customize the
plug-in configuration, consult the Deploying into the OSGi Container guide
and the Managing OSGi Dependencies guide from the Fuse ESB
documentation library.
Sample bundle plug-in The following POM fragment shows a sample configuration of the Maven
configuration bundle plug-in, which is appropriate for the current example.
<?xml version="1.0"?>
<project ...>
...
<groupId>org.fusesource.sparks.fuse-webinars.cxf-webinars</groupId>
<artifactId>customer-ws-camel-cxf-provider</artifactId>
<name>customer-ws-camel-cxf-provider</name>
<url>http://www.fusesource.com</url>
<packaging>bundle</packaging>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 121
Chapter 7. Provider-Based Route
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
org.apache.camel.component.velocity,
META-INF.cxf,
META-INF.cxf.osgi,
javax.jws,
javax.wsdl,
javax.xml.bind,
javax.xml.bind.annotation,
javax.xml.namespace,
javax.xml.ws,
org.w3c.dom,
<!-- Workaround to access DOM XPathFactory -->
org.apache.xpath.jaxp,
*
</Import-Package>
<DynamicImport-Package>
org.apache.cxf.*,
org.springframework.beans.*
</DynamicImport-Package>
</instructions>
</configuration>
</plugin>
...
</plugins>
</build>
</project>
Dynamic imports The Java packages from Apache CXF and the Spring API are imported using
dynamic imports (specified using the DynamicImport-Package element).
This is a pragmatic way of dealing with the fact that Spring XML files are not
terribly well integrated with the Maven bundle plug-in. At build time, the
Maven bundle plug-in is not able to figure out which Java classes are required
by the Spring XML code. By listing wildcarded package names in the
DynamicImport-Package element, however, you allow the OSGi container
to figure out which Java classes are needed by the Spring XML code at run
time.
122 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Deploy to OSGi
Note
In general, using DynamicImport-Package headers is not
recommended in OSGi, because it short-circuits OSGi version
checking. Normally, what should happen is that the Maven bundle
plug-in lists the Java packages used at build time, along with their
versions, in the Import-Package header. At deploy time, the OSGi
container then checks that the available Java packages are
compatible with the build time versions listed in the Import-Package
header. With dynamic imports, this version checking cannot be
performed.
Build and deploy the client After you have configured the POM file, you can build the Maven project and
bundle install it in your local repository by entering the following command:
mvn install
To deploy the route bundle, enter the following command at the Apache
ServiceMix console:
karaf@root> install -s mvn:org.fusesource.sparks.fuse-we
binars.cxf-webinars/customer-ws-camel-cxf-provider
Note
If your local Maven repository is stored in a non-standard location,
you might need to customize the value of the
org.ops4j.pax.url.mvn.localRepository property in the
EsbInstallDir/etc/org.ops4j.pax.url.mvn.cfg file, before
you can use the mvn: scheme to access Maven artifacts.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 123
124 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 8. Proxying a Web Service
A common use case for the Camel CXF component is to use a route as a proxy for a Web service. That is, in order
to perform additional processing of WS request and response messages, you interpose a route between the WS
client and the original Web service.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 125
Chapter 8. Proxying a Web Service
Figure 8.1 on page 126 shows an overview of how to proxy a Web service
using an Apache Camel route, where the route treats the messages as HTTP
packets. The key feature of this route is that both the consumer endpoint (at
the start of the route) and the producer endpoint (at the end of the route)
must be compatible with the HTTP packet format.
Alternatives for the consumer The following Apache Camel endpoints can be used as consumer endoints
endpoint for HTTP format messages:
• Jetty endpoint—is a lightweight Web server. You can use Jetty to handle
messages for any HTTP-based protocol, including the commonly-used Web
service SOAP/HTTP protocol.
Consumer endpoint for HTTP A Jetty endpoint has the general form, jetty:HttpAddress. To configure the
Jetty endpoint to be a proxy for a Web service, use a HttpAddress value that
is almost identical to the HTTP address the client connects to, except that
Jetty's version of HttpAddress uses the special hostname, 0.0.0.0 (which
matches all of the network interfaces on the current machine).
126 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Proxying with HTTP
<route>
<from uri="jetty:http://0.0.0.0:9093/Customers?matchOnUri
Prefix=true"/>
...
</route>
matchOnUriPrefix option Normally, a Jetty consumer endpoint accepts only an exact match on the
context path. For example, a request that is sent to the address
http://localhost:9093/Customers would be accepted, but a request
sent to http://localhost:9093/Customers/Foo would be rejected. By
setting matchOnUriPrefix to true, however, you enable a kind of
wildcarding on the context path, so that any context path prefixed by
/Customers is accepted.
Alternatives for the producer The following Apache Camel endpoints can be used as producer endoints for
endpoint HTTP format messages:
Producer endpoint for HTTP To configure a Jetty HTTP endpoint to send HTTP requests to a remote
SOAP/HTTP Web service, set the uri attribute of the to element at the end
of the route to be the address of the remote Web service, as follows:
<route>
...
<to uri="jetty:http://localhost:8083/Customers?bridgeEnd
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 127
Chapter 8. Proxying a Web Service
point=true&throwExceptionOnFailure=false"/>
</route>
bridgeEndpoint option The HTTP component supports a bridgeEndpoint option, which you can
enable on a HTTP producer endpoint to configure the endpoint appropriately
for operating in a HTTP-to-HTTP bridge (as is the case in this demonstration).
In particular, when bridgeEndpoint=true, the HTTP endpoint ignores the
value of the Exchange.HTTP_URI header, using the HTTP address from the
endpoint URI instead.
Handling message headers When defining a HTTP bridge application, the CamelHttp* headers set by
the consumer endpoint at the start of the route can affect the behavior of the
producer endpoint. For this reason, in a bridge application it is advisable to
remove the CamelHttp* headers before the message reaches the producer
endpoint, as follows:
<route>
<from uri="jetty:http:..."/>
...
<removeHeaders pattern="CamelHttp*"/>
<to uri="jetty:http:..."/>
</route>
Outgoing HTTP headers By default, any headers in the exchange that are not prefixed by Camel will
be converted into HTTP headers and sent out over the wire by the HTTP
producer endpoint. This could have adverse consequences on the behavior
of your application, so it is important to be aware of any headers that are
set in the exchange object and to remove them, if necessary.
For more details about dealing with headers, see "Handling HTTP Headers"
on page 134.
128 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Proxying with POJO Format
Figure 8.2 on page 129 shows an overview of how to proxy a Web service
using an Apache Camel route, where the route processes the messages in
POJO format. The key feature of this route is that both the consumer endpoint
(at the start of the route) and the producer endpoint (at the end of the route)
must be compatible with the POJO data format.
Consumer endpoint for CXF/POJO To parse incoming messages into POJO data format, the consumer endpoint
at the start of the route must be a Camel CXF endpoint that is configured to
use POJO mode. Use the cxf:bean:BeanID URI format to reference the
Camel CXF endpoint as follows (where the dataFormat option defaults to
POJO):
<route>
<from uri="cxf:bean:customerServiceProxy"/>
...
</route>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 129
Chapter 8. Proxying a Web Service
address="/Customers"
endpointName="c:SOAPOverHTTP"
serviceName="c:CustomerService"
wsdlURL="wsdl/CustomerService.wsdl"
serviceClass="org.fusesource.demo.wsdl.camelcxf.Custom
erService"
/>
...
</beans>
Producer endpoint for CXF/POJO To convert the exchange body from POJO data format to a SOAP/HTTP
message, the producer endpoint at the end of the route must be a Camel CXF
endpoint configured to use POJO mode. Use the cxf:bean:BeanID URI format
to reference the Camel CXF endpoint as follows (where the dataFormat
option defaults to POJO):
<route>
...
<to uri="cxf:bean:customerServiceReal"/>
</route>
130 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Proxying with PAYLOAD Format
Figure 8.3 on page 131 shows an overview of how to proxy a Web service
using an Apache Camel route, where the route processes the messages in
PAYLOAD format. The key feature of this route is that both the consumer
endpoint (at the start of the route) and the producer endpoint (at the end of
the route) must be compatible with the PAYLOAD data format.
Consumer endpoint for To parse incoming messages into PAYLOAD data format, the consumer
CXF/PAYLOAD endpoint at the start of the route must be a Camel CXF endpoint that is
configured to use PAYLOAD mode. Use the cxf:bean:BeanID URI format to
reference the Camel CXF endpoint as follows, where you must set the
dataFormat option to PAYLOAD:
<route>
<from uri="cxf:bean:customerServiceProxy?dataFormat=PAY
LOAD"/>
...
</route>
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 131
Chapter 8. Proxying a Web Service
xmlns:c="http://demo.fusesource.org/wsdl/camelcxf"
address="/Customers"
endpointName="c:SOAPOverHTTP"
serviceName="c:CustomerService"
wsdlURL="wsdl/CustomerService.wsdl"
/>
...
</beans>
Producer endpoint for To convert the exchange body from PAYLOAD data format to a SOAP/HTTP
CXF/PAYLOAD message, the producer endpoint at the end of the route must be a Camel CXF
endpoint configured to use PAYLOAD mode. Use the cxf:bean:BeanID URI
format to reference the Camel CXF endpoint as follows, where you must set
the dataFormat option to PAYLOAD:
<route>
...
<to uri="cxf:bean:customerServiceReal?dataFormat=PAYLOAD"/>
</route>
Outgoing HTTP headers By default, any headers in the exchange that are not prefixed by Camel will
be converted into HTTP headers and sent out over the wire by the Camel CXF
producer endpoint. This could have adverse consequences on the behavior
of your application, so it is important to be aware of any headers that are
set in the exchange object and to remove them, if necessary.
132 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Proxying with PAYLOAD Format
For more details about dealing with headers, see "Handling HTTP Headers"
on page 134.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 133
Chapter 8. Proxying a Web Service
HTTP-based components The behavior described in this section affects not just the Camel HTTP
component (camel-http), but also a number of other HTTP-based
components, including:
camel-http
camel-http4
camel-jetty
camel-restlet
camel-cxf
HTTP consumer endpoint When a HTTP consumer endpoint receives an incoming message, it creates
an In message with the following headers:
CamelHttp* headers
Several headers with the CamelHttp prefix are created, which record
the status of the incoming message. For details of these internal headers,
see HTTP in Apache Camel Documentation.
HTTP headers
All of the HTTP headers from the original incoming message are mapped
to headers on the exchange's In message.
134 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Handling HTTP Headers
HTTP producer endpoint When a HTTP producer endoint receives an exchange and converts it to the
target message format, it handles the In message headers as follows:
CamelHttp*
Headers prefixed by CamelHttp are used to control the behavior of the
HTTP producer entpoint. Any headers of this kind are consumed by the
HTTP producer endpoint and the endpoint behaves as directed.
Camel*
All other headers prefixed by Camel are presumed to be meant for internal
use and are not mapped to HTTP headers in the target message (in other
words, these headers are ignored).
*
All other headers are converted to HTTP headers in the target message,
with the exception of the following headers, which are blocked (based
on a case-insensitive match):
content-length
content-type
cache-control
connection
date
pragma
trailer
transfer-encoding
upgrade
via
warning
Implications for HTTP bridge When defining a HTTP bridge application (that is, a route starting with a
applications HTTP consumer endpoint and ending with a HTTP producer endpoint), the
CamelHttp* headers set by the consumer endpoint at the start of the route
can affect the behavior of the producer endpoint. For this reason, in a bridge
application it is advisable to remove the CamelHttp* headers, as follows:
from("http://0.0.0.0/context/path")
.removeHeaders("CamelHttp*)
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 135
Chapter 8. Proxying a Web Service
...
.to("http://remoteHost/context/path");
Setting a custom header filter If you want to customize the way that a HTTP producer endpoint processes
headers, you can define your own customer header filter by defining the
headerFilterStrategy option on the endpoint URI. For example, to
configure a producer endpoint with the myHeaderFilterStrategy filter,
you could use a URI like the following:
http://remoteHost/context/path?headerFilterStrategy=#myHeader
FilterStrategy
136 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Chapter 9. Filtering SOAP Message
Headers
The Camel CXF component supports a flexible header filtering mechanism, which enables you to process SOAP
headers, applying different filters according to the header's XML namespace.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 137
Chapter 9. Filtering SOAP Message Headers
Basic Configuration
Overview When more than one CXF endpoint appears in a route, you need to decide
whether or not to allow headers to propagate between the endpoints. By
default, the headers are relayed back and forth between the endpoints, but
in many cases it might be necessary to filter the headers or to block them
altogether. You can control header propagation by applying filters to producer
endpoints.
relayHeaders option The semantics of the relayHeaders option can be summarized as follows:
In-band headers An in-band header is a header that is explicitly defined as part of the WSDL
binding contract for an endpoint.
Out-of-band headers An out-of-band header is a header that is serialized over the wire, but is not
explicitly part of the WSDL binding contract. In particular, the SOAP binding
138 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Basic Configuration
permits out-of-band headers, because the SOAP specification does not require
headers to be defined in the WSDL contract.
Payload format The CXF endpoint's payload format affects the filter behavior as follows:
POJO
(Default) Only out-of-band headers are available for filtering, because
the in-band headers have already been processed and removed from the
list by CXF. The in-band headers are incorporated into the
MessageContentList in POJO mode. If you require access to headers
in POJO mode, you have the option of implementing a custom CXF
interceptor or JAX-WS handler.
PAYLOAD
In this mode, both in-band and out-of-band headers are available for
filtering.
MESSAGE
Not applicable. (In this mode, the message remains in a raw format and
the headers are not processed at all.)
Overriding the default filter You can override the default CxfHeaderFilterStrategy instance by defining
a new CxfHeaderFilterStrategy bean and associating it with a CXF
endpoint.
Sample relayHeaders The following example shows how you can use the relayHeaders option to
configuration create a CxfHeaderFilterStrategy bean that blocks all message headers.
The CXF endpoints in the route use the headerFilterStrategy option to
install the filter strategy in the endpoint, where the headerFilterStrategy
setting has the syntax, headerFilterStrategy=#BeanID.
<beans ...>
...
<bean id="dropAllMessageHeadersStrategy" class="org.apache.camel.component.cxf.common.head
er.CxfHeaderFilterStrategy">
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 139
Chapter 9. Filtering SOAP Message Headers
relayAllMessageHeaders option The relayAllMessageHeaders option is used to propagate all SOAP headers,
without applying any filtering (any installed filters would be bypassed). In
order to enable this feature, you must set both relayHeaders and
relayAllMessageHeaders to true.
Sample relayAllMessageHeaders The following example shows how to configure CXF endpoints to propagate
configuration all SOAP message headers. The propagateAllMessages filter strategy sets
both relayHeaders and relayAllMessageHeaders to true.
<beans ...>
...
<bean id="propagateAllMessages" class="org.apache.camel.component.cxf.common.header.Cxf
HeaderFilterStrategy">
<!-- Set both properties to true to propagate *all* SOAP headers -->
<property name="relayHeaders" value="true"/>
<property name="relayAllMessageHeaders" value="true"/>
</bean>
140 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Header Filtering
Header Filtering
Overview You can optionally install multiple headers in a CxfHeaderFilterStrategy
instance. The filtering mechanism then uses the header's XML namespace to
lookup a particular filter, which it then applies to the header.
Filter map Figure 9.1 on page 141 shows an overview of the filter map that is contained
within a CxfHeaderFilterStrategy instance. For each filter that you install
in CxfHeaderFilterStrategy, corresponding entries are made in the filter
map, where one or more XML schema namespaces are associated with each
filter.
Filter behavior When a header is filtered, the filter mechanism peeks at the header to discover
the header's XML namespace. The filter then looks up the XML namespace
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 141
Chapter 9. Filtering SOAP Message Headers
in the filter map to find the corresponding filter implementation. This filter is
then applied to the header.
PAYLOAD mode In PAYLOAD mode, both in-band and out-of-band messages pass through
the installed filters.
POJO mode In POJO mode, only out-of-band messages pass through the installed filters.
In-band messages bypass the filters and are propagated by default.
142 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Implementing a Custom Filter
import java.util.List;
import org.apache.camel.spi.HeaderFilterStrategy.Direction;
import org.apache.cxf.headers.Header;
Implementing the filter() method The MessageHeaderFilter.filter() method is reponsible for applying
header filtering. Filtering is applied both before and after an operation is
invoked on an endpoint. Hence, there are two directions to which filtering is
applied, as follows:
Direction.OUT
When the direction parameter equals Direction.OUT, the filter is
being applied to a request either leaving a consumer endpoint or entering
a producer endpoint (that is, it applies to a WS request message
propagating through a route).
Direction.IN
When the direction parameter equals Direction.IN, the filter is
being applied to a response either leaving a producer endpoint or entering
a consumer endpoint (that is, it applies to a WS response message being
sent back).
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 143
Chapter 9. Filtering SOAP Message Headers
Binding filters to XML It is possible to register multiple header filters against a given CXF endpoint.
namespaces The CXF endpoint selects the appropriate filter to use based on the XML
namespace of the WSDL binding protocol (for example, the namespace for
the SOAP 1.1 binding or for the SOAP 1.2 binding). If a header's namespace
is unknown, the header is propagated by default.
Identifying the namespace to bind Example 9.1 on page 144 illustrates how to identify the namespaces to which
to you can bind a filter. This example shows the WSDL file for a Bank server
that exposes SOAP endpoints.
From the soap:binding tag, you can infer that namespace associated with
the SOAP binding is http://schemas.xmlsoap.org/wsdl/soap/.
Implementing a custom filter If you want to implement your own custom filter, define a class that inherits
from the MessageHeaderFilter interface and implement its methods as
described in this section. For example, Example 9.2 on page 145 shows an
example of a custom filter, CustomHeaderFilter, that binds to the
144 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Implementing a Custom Filter
import java.util.Arrays;
import java.util.List;
import org.apache.camel.component.cxf.common.header.Message
HeaderFilter;
import org.apache.camel.spi.HeaderFilterStrategy.Direction;
import org.apache.cxf.headers.Header;
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 145
Chapter 9. Filtering SOAP Message Headers
Installing Filters
Overview To install message header filters, set the messageHeaderFilters property
of the CxfHeaderFilterStrategy object. When you initialize this property
with a list of message header filters, the header filter strategy combines the
specified filters to make a filter map.
Installing filters in XML The following example shows how to create a CxfHeaderFilterStrategy
instance, specifying a customized list of header filters in the
messageHeaderFilters property. There are two header filters in this
example: SoapMessageHeaderFilter and CustomHeaderFilter.
<bean id="customMessageFilterStrategy" class="org.apache.camel.component.cxf.common.head
er.CxfHeaderFilterStrategy">
<property name="messageHeaderFilters">
<list>
<!-- SoapMessageHeaderFilter is the built in filter. It can be removed by
omitting it. -->
<bean class="org.apache.camel.component.cxf.common.header.SoapMessageHeaderFil
ter"/>
</list>
</property>
<!-- The 'relayHeaders' property is 'true' by default -->
</bean>
This filter peeks at the header element, in order to decide whether or not to
block a particular header. If the soap:actor attribute (SOAP 1.1) or the
146 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0
Installing Filters
soap:role attribute (SOAP 1.2) is present and has the value next, the header
is removed from the message. Otherwise, the header is propagated.
Namespace clashes Normally, each namespace should be bound to just a single header filter. If
a namespace is bound to more than one header filter, this normally causes
an error. It is possible, however, to override this policy by setting the
allowFilterNamespaceClash property to true in the
CxfHeaderFilterStrategy instance. When this policy is set to true, the
nearest to last filter is selected, in the event of a namespace clash.
Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0 147
148 Fuse ESB Enterprise Web Services and Routing with Camel/CXF Version 7.0