LibraryPrintFeedback

Web Services and Routing with Camel CXF

Version 7.1

December 2012
Trademark Disclaimer
Third Party Acknowledgements

Updated: 08 Jan 2014

Table of Contents

1. Demonstration Code for Camel/CXF
Downloading and Installing the Demonstrations
Running the Demonstrations
2. Java-First Service Implementation
Java-First Overview
Define SEI and Related Classes
Annotate SEI for JAX-WS
Instantiate the WS Endpoint
Java-to-WSDL Maven Plug-In
3. WSDL-First Service Implementation
WSDL-First Overview
CustomerService WSDL Contract
WSDL-to-Java Maven Plug-In
Instantiate the WS Endpoint
Deploy to an OSGi Container
4. Implementing a WS Client
WS Client Overview
WSDL-to-Java Maven Plug-In
Instantiate the WS Client Proxy
Invoke WS Operations
Deploy to an OSGi Container
5. Pojo-Based Route
Processing Messages in POJO Format
WSDL-to-Java Maven Plug-In
Instantiate the WS Endpoint
Sort Messages by Operation Name
Process Operation Parameters
Deploy to OSGi
6. Payload-Based Route
Processing Messages in PAYLOAD Format
Instantiate the WS Endpoint
Sort Messages by Operation Name
SOAP/HTTP-to-JMS Bridge Use Case
Generating Responses Using Templates
Deploy to OSGi
7. Provider-Based Route
Provider-Based JAX-WS Endpoint
Create a Provider<?> Implementation Class
Instantiate the WS Endpoint
Sort Messages by Operation Name
SOAP/HTTP-to-JMS Bridge Use Case
Generating Responses Using Templates
TypeConverter for SAXSource
Deploy to OSGi
8. Proxying a Web Service
Proxying with HTTP
Proxying with POJO Format
Proxying with PAYLOAD Format
Handling HTTP Headers
9. Filtering SOAP Message Headers
Basic Configuration
Header Filtering
Implementing a Custom Filter
Installing Filters

List of Figures

2.1. Building a Java-First Web Service
3.1. Building a WSDL-First Web Service
4.1. Building a WS Client
5.1. Sample POJO Route
6.1. Sample PAYLOAD Route
6.2. SOAP/HTTP-to-JMS Bridge
6.3. Response Generated by Velocity
7.1. Sample Provider-Based Route
7.2. SOAP/HTTP-to-JMS Bridge
7.3. Response Generated by Velocity
8.1. Proxy Route with Message in HTTP Format
8.2. Proxy Route with Message in POJO Format
8.3. Proxy Route with Message in PAYLOAD Format
9.1. Filter Map

List of Examples

9.1. Sample Binding Namespaces
9.2. Sample Header Filter Implementation

For building and running the demonstration code, you must have the following prerequisites installed:

  • Java platform—the demonstrations must run on the Java 6 platform from Oracle.

  • Apache Maven build tool—to build the demonstration, you require Apache Maven 3.0.x (or Maven 2.2.1).

  • Internet connection—Maven requires an Internet connection in order to download required dependencies from remote repositories while performing a build.

  • Fuse ESB Enterprise—the demonstrations are deployed into the Fuse ESB Enterprise container, which can be downloaded from the FuseSource site.

Start and configure the Fuse ESB Enterprise container as follows:

It is now a relatively straightforward task to run each of the demonstrations by installing the relevant features.

For example, to start up the WSDL-first Web service (discussed in WSDL-First Service Implementation), 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), 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

You should see log output like the following:

18:03:58,609 | INFO  | qtp5581640-231   | CustomerServiceImpl              | ?                                   ? |
 218 - org.fusesource.sparks.fuse-webinars.cxf-webinars.customer-ws-osgi-bundle - 1.1.1 | Getting status for custome
 r 1234
18:03:58,687 | INFO  |  invoker thread. | ClientInvoker                    | ?                                   ? |
 219 - org.fusesource.sparks.fuse-webinars.cxf-webinars.customer-ws-client - 1.1.1 | Got back: status = Active, stat
 usMessage = In the park, playing with my frisbee.
18:04:00,687 | INFO  | qtp5581640-232   | CustomerServiceImpl              | ?                                   ? |
 218 - org.fusesource.sparks.fuse-webinars.cxf-webinars.customer-ws-osgi-bundle - 1.1.1 | Getting status for custome
 r 1234
18:04:00,703 | INFO  |  invoker thread. | ClientInvoker                    | ?                                   ? |
 219 - org.fusesource.sparks.fuse-webinars.cxf-webinars.customer-ws-client - 1.1.1 | Got back: status = Active, stat
 usMessage = In the park, playing with my frisbee.

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

An SEI is an ordinary Java interface. In order to use the standard JAX-WS frontend, the SEI must be annotated with the @WebService annotation.[1]

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:

  • Base type of the Web service implementation (server side)—you define the Web service by implementing the SEI.

  • 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.

Figure 2.1 shows an overview of the files required to implement and build the CustomerService Web service using the Java-first approach.


To implement and build the Java-first example shown in Figure 2.1, 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).

  3. Implement any other requisite Java classes. In particular, implement the following:

    • Any data types referenced by the SEI—for example, the Customer class.

    • The implementation of the SEI, CustomerServiceImpl.

  4. Instantiate the Web service endpoint, by adding the appropriate code to a Spring XML file.

  5. Generate the WSDL contract using a Java-to-WSDL converter.

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.

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.

For example, consider the definition of the following method, getStringValues(), which takes a holder type as its second parameter:

// Java
public void getStringValues(
    String wrongWay,
    javax.xml.ws.Holder<String> rightWay
) {
    wrongWay = "Caller will never see this string!";
    rightWay.value = "But the caller *can* see this string.";
}

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);

System.out.println("Unchanged string: " + wrongWay);
System.out.println("Changed string: " + rightWay.value);

It is, perhaps, slightly unnatural to use Holder<> types in a Java-first example, because this is not a normal Java idiom. But it is interesting to include OUT parameters in the example, so that you can see how a Web service processes this kind of parameter.

For example, the Customer class appears as a related class in the definition of the CustomerService SEI (The CustomerService SEI). 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;

public class Customer {
    protected String firstName;
    protected String lastName;
    protected String phoneNumber;
    protected String id;

    // Default constructor, required by JAX-WS
    public Customer() { }
    
    public Customer(String firstName, String lastName, String phoneNumber,
            String id) {
        super();
        this.firstName = firstName;
        this.lastName = lastName;
        this.phoneNumber = phoneNumber;
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String value) {
        this.firstName = value;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String value) {
        this.lastName = value;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String value) {
        this.phoneNumber = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String value) {
        this.id = value;
    }
}

To use the JAX-WS frontend, an SEI must be annotated using standardised JAX-WS annotations. The annotations signal to the Web services tooling that the SEI uses JAX-WS and the annotations are also used to customize the mapping from Java to WSDL. Here we only cover the most basic annotations—for complete details of JAX-WS annotations, see Developing Applications Using JAX-WS from the Apache CXF library.

[Note]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).

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

Apache CXF deploys the WS endpoint into a Jetty servlet container instance and the address attribute of jaxws:endpoint is therefore used to configure the addressing information for the endpoint in the Jetty container.

Apache CXF supports the notion of a default servlet container instance. The way the default servlet container is initialized and configured depends on the particular mode of deployment that you choose. For example the Red Hat JBoss Fuse container and Web containers (such as Tomcat) provide a default servlet container.

There are two different syntaxes you can use for the endpoint address, where the syntax that you use effectively determines whether or not the endpoint is deployed into the default servlet container, as follows:

  • Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the /Customers servlet context in the default servlet container:

    address="/Customers"
  • Address syntax for custom servlet 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). For example, to deploy the endpoint to the custom Jetty container listening on IP port, 8083:

    address="http://0.0.0.0:8083/Customers"
    [Note]Note

    If you want to configure a secure endpoint (secured by SSL), you would specify the https: scheme in the address.

Configuring the Java-to-WSDL Maven plug-in is relatively easy, because most 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:

For example, the following POM fragment shows how to configure the cxf-java2ws-plugin plug-in to generate WSDL from the CustomerService SEI:



[1] If the SEI is left without annotations, Apache CXF defaults to using the simple frontend. This is a non-standard frontend, which is not recommended for most applications.

Figure 3.1 shows an overview of the files required to implement and build the CustomerService Web service using the WSDL-first approach.


To implement and build the WSDL-first example shown in Figure 3.1, starting from scratch, you would perform the following steps:

  1. Create the WSDL contract.

  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. Write the implementation of the SEI, CustomerServiceImpl.

  4. Instantiate the Web service endpoint, by adding the appropriate code to a Spring XML file.

Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most 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:

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:

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

After you have configured the POM file, you can build the Maven project and install it in your local repository by entering the following command:

mvn install

To deploy the service bundle, enter the following command at the command console:

karaf@root> install -s mvn:org.fusesource.sparks.fuse-webinars.cxf-webinars/customer-ws-osgi-bundle
[Note]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.

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]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).

To implement and build the sample WS client shown in Figure 4.1, starting from scratch, you would perform the following steps:

  1. Obtain a copy of the WSDL contract.

  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.

Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most 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:

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:

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

After you have configured the POM file, you can build the Maven project and install it in your local repository by entering the following command:

mvn install

To deploy the client bundle, enter the following command at the containers command console:

karaf@root> install -s mvn:org.fusesource.sparks.fuse-webinars.cxf-webinars/customer-ws-client
[Note]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.

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

Camel 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.

Figure 5.1 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.


Configuring the WSDL-to-Java Maven plug-in is relatively easy, because most 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:

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:

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]

Where CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in CXF in EIP Component Reference). If you do not specify any additional options, the endpoint uses the POJO data format by default.

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

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.

Apache CXF supports the notion of a default servlet container instance. The way the default servlet container is initialized and configured depends on the particular mode of deployment that you choose. For example the Red Hat JBoss Fuse container and Web containers (such as Tomcat) provide a default servlet container.

There are two different syntaxes you can use for the endpoint address, where the syntax that you use effectively determines whether or not the endpoint is deployed into the default servlet container, as follows:

  • Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the /Customers servlet context in the default servlet container:

    address="/Customers"
  • Address syntax for custom servlet container—to instantiate a custom Jetty container for this 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). For example, to deploy the endpoint to the custom Jetty container listening on IP port, 8083:

    address="http://0.0.0.0:8083/Customers"
    [Note]Note

    If you want to configure a secure endpoint (secured by SSL), you would specify the https: scheme in the address.

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

After you have configured the POM file, you can build the Maven project and 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-webinars.cxf-webinars/customer-ws-camel-cxf-pojo
[Note]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.

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

Figure 6.1 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.


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]

Where CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in CXF in EIP Component Reference). To enable payload mode, you must set the URI option, dataFormat=PAYLOAD.

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>

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.

Apache CXF supports the notion of a default servlet container instance. The way the default servlet container is initialized and configured depends on the particular mode of deployment that you choose. For example the OSGi container and Web containers (such as Tomcat) provide a default servlet container.

There are two different syntaxes you can use for the endpoint address, where the syntax that you use effectively determines whether or not the endpoint is deployed into the default servlet container, as follows:

  • Address syntax for default servlet container—to use the default servlet container, specify only the servlet context for this endpoint. Do not specify the protocol, host, and IP port in the address. For example, to deploy the endpoint to the /Customers servlet context in the default servlet container:

    address="/Customers"
  • Address syntax for custom servlet container—to instantiate a custom Jetty container for this 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). For example, to deploy the endpoint to the custom Jetty container listening on IP port, 8083:

    address="http://0.0.0.0:8083/Customers"
    [Note]Note

    If you want to configure a secure endpoint (secured by SSL), you would specify the https: scheme in the address.

As shown in Figure 6.2, the route for transforming synchronous SOAP/HTTP to asynchronous JMS works as follows:

  1. The WS client invokes a synchronous operation on the Camel CXF endpoint at the start of the route. The Camel CXF endpoint then creates an initial InOut exchange at the start of the route, where the body of the exchange message contains a payload in XML format.

  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.

  3. The transform DSL command constructs an immediate response to send back to the client, where the response has the form of an XML string.

  4. The Camel CXF component supports implicit type conversion of the XML string to payload format.

  5. The response is sent back to the WS client, thus completing the synchronous operation invocation.

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.

One of the simplest and quickest approaches to generating a response message is to use a velocity template. Figure 6.3 shows the outline of a general template-based route. At the start of the route is a Camel CXF endpoint in PAYLOAD mode, which is the appropriate mode to use for processing the message as an XML document. After doing the work required to process the message and stashing some intermediate results in message headers, the route generates the response message using a Velocity template.


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

After you have configured the POM file, you can build the Maven project and install it in your local repository by entering the following command:

mvn install

To deploy the route bundle, enter the following command at the console:

karaf@root> install -s mvn:org.fusesource.sparks.fuse-webinars.cxf-webinars/customer-ws-camel-cxf-payload
[Note]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.

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

The provider-based approach is a variant of the PAYLOAD data format, which is enabled as follows:

The provider-based approach has the following characteristics:

  • Enables you to access the message body as a streamed XML type—for example, javax.xml.transform.sax.SAXSource.

  • No JAX-WS or JAX-B stub code required.

  • The SOAP body is marshalled into a stream-based SAXSource type.

  • The SOAP headers are converted into headers in the exchange's In message, of org.apache.cxf.binding.soap.SoapHeader type.

Figure 7.1 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.


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]

Where CxfEndpointID is the ID of a bean created using the cxf:cxfEndpoint element, which configures the details of the WS endpoint. You can append options to this URI (where the options are described in detail in CXF in EIP Component Reference). Provider mode is essentially a variant of PAYLOAD mode: you could specify this mode on the URI (by setting dataFormat=PAYLOAD), but this is not necessary, because PAYLOAD mode is already selected by the @ServiceMode annotation on the custom Provider class.

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>

As shown in Figure 7.2, the route for transforming synchronous SOAP/HTTP to asynchronous JMS works as follows:

  1. The WS client invokes a synchronous operation on the Camel CXF endpoint at the start of the route. The Camel CXF endpoint then creates an initial InOut exchange at the start of the route, where the body of the exchange message contains a payload in XML format.

  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.

  3. The transform DSL command constructs an immediate response to send back to the client, where the response has the form of an XML string.

  4. The route explicitly converts the XML string to the javax.xml.transform.sax.SAXSource type.

  5. The response is sent back to the WS client, thus completing the synchronous operation invocation.

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.

One of the simples and quickest approaches to generating a response message is to use a velocity template. Figure 7.3 shows the outline of a general template-based route. At the start of the route is a Camel CXF endpoint in provider mode, which is the appropriate mode to use for processing the message as an XML document. After doing the work required to process the message and stashing some intermediate results in message headers, the route generates the response message using a Velocity template.


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

After you have configured the POM file, you can build the Maven project and install it in your local repository by entering the following command:

mvn install

To deploy the route bundle, enter the following command at the container console:

karaf@root> install -s mvn:org.fusesource.sparks.fuse-webinars.cxf-webinars/customer-ws-camel-cxf-provider
[Note]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.

The simplest way to proxy a SOAP/HTTP Web service is to treat the request and reply messages as HTTP packets. This type of proxying can be used where there is no requirement to read or modify the messages passing through the route. For example, you could use this kind of proxying to apply various patterns of flow control on the WS messges.

Figure 8.1 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.


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 EIP Component Reference.

HTTP headers

All of the HTTP headers from the original incoming message are mapped to headers on the exchange's In message.

URL options (Jetty only)

The URL options from the original HTTP request URL are mapped to headers on the exchange's In message. For example, given the client request with the URL, http://myserver/myserver?orderid=123, a Jetty consumer endpoint creates the orderid header with value 123.

The semantics of the relayHeaders option can be summarized as follows:

 In-band headersOut-of-band headers
relayHeaders=true, dataFormat=PAYLOADFilterFilter
relayHeaders=true, dataFormat=POJORelay allFilter
relayHeaders=falseBlockBlock