Invoking a SOAP service with Apache Camel

Updated:

Invoking a SOAP service with Apache Camel

When was the last time you worked with a SOAP service? For me, it was actually yesterday.

SOAP has been around for a long time. You might think that it’s had its day, but it doesn’t seem to be disappearing yet.

I see SOAP services still in use at many companies. Some well-known enterprise apps still implement their API using SOAP (here’s looking at you, Workday! 👋).

But the problem with SOAP is that it is unbelievably complicated, and this complexity is unfortunately also reflected in the tools we use to work with them.

With that in mind, here’s a brief guide to invoking SOAP services in Camel, and the basics you need to know to get up and running.

Which component to use?

In Camel there are two main components you can use to work with SOAP services:

  • CXF component (camel-cxf) - This is a Camel wrapper for Apache CXF, a Java library for working with web services. The CXF component in Camel makes it easier to use CXF in your Camel routes. For example, you can use the CXF component to send and receive messages to/from a SOAP service.

  • SOAP dataformat (camel-soap) - This is a Camel DataFormat, so it’s designed for reading and writing SOAP messages only; it doesn’t actually send requests. You might use this dataformat if you want to create a SOAP message (in XML), but send it over a different protocol (like JMS), or write it to disk.

Since I want to invoke a SOAP service (at a SOAP endpoint), I’m going to use the CXF component in this article. So let’s go.

Introducing CXF

Apache CXF is a Java framework for working with web services. It primarily supports SOAP, but can also be used to access other types of services, such as REST and even CORBA.

Apache CXF website home page

You can download Apache CXF from the official web site. But, when you use CXF in Camel, you only need to pull in the Maven dependency below, and CXF will be downloaded as a transitive dependency to your project:

<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-cxf</artifactId>
</dependency>

CXF can be a very complicated beast; but that’s because it has to support a lot of the more advanced features of SOAP. Also the terminology can be really confusing for beginners.

The best thing I’ve learned about working with CXF, is to just start very simple. Get a simple example up and running, and then add all the bells and whistles.

Invoking a SOAP service in Camel

There are two main activities to do when invoking a SOAP service in Camel:

  1. Create client classes from the WSDL. This is essential if you want to be able to work with the SOAP messages you exchange with the SOAP service, as plain Java objects (POJOs).

  2. Create your request payload. You can do this by creating an object from the classes you created in step 1, and manipulate the data using getters and setters.

  3. Set up the CXF (SOAP) endpoint in Camel, and invoke it from your route. This is where you implement your logic in Camel to send your SOAP message.

So here’s how to invoke a SOAP service from Camel using the CXF component:

  1. Use the cxf-codegen-plugin for Maven to create Java classes from your WSDL file for you.

    Get a hold of the WSDL file from the web service, and copy it into your src/main/resources directory.

    Then, set up the cxf-codegen-plugin in your Maven pom.xml, like this:

    <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.2.4</version>
      <executions>
        <execution>
          <id>generate-sources</id>
          <phase>generate-sources</phase>
          <configuration>
            <wsdlOptions>
              <wsdlOption>
                <wsdl>src/main/resources/service.wsdl</wsdl>
              </wsdlOption>
            </wsdlOptions>
          </configuration>
          <goals>
            <goal>wsdl2java</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    

    This plugin integrates itself into your Maven build process, so whenever you run a Maven build of your application, it will create and compile Java classes from the WSDL file.

  2. Write a Java method to build your request message.

    Since Camel works well with Java beans, it makes sense for us to write a simple Java method that creates a new Object using the classes created by the cxf-codegen-plugin.

    You should start by creating a Java object of the class that represents your service’s request type, e.g. GetCustomersRequestType, or AddCustomerRequestType.

    Then it’s a simple case of writing a Java class, with a single method to create and return an object of that type:

    public class GetCustomerRequestBuilder {
    
      public GetCustomerRequestType build(String id) {
        GetCustomerRequestType request = new GetCustomerRequestType();
        request.setCustomerId(id);
        return request;
      }
    }
    

    Now that this class is written, it can be called from a Camel route.

  3. Invoke your Java method from a Camel route, to create your request message.

    from("direct:start")
        .setBody(constant("12345"))
        .bean(GetCustomerRequestBuilder.class)
        // rest of the route goes here...
    

    This code sets the message body to 12345. Then, when the GetCustomerRequestBuilder bean is invoked, Camel uses bean parameter binding to use the value 12345 as the argument to the build(String id) method.

    So, the Exchange body now contains a body of type GetCustomerRequest, for a customer ID of 12345.

  4. Finally, invoke the SOAP service using the CXF component.

    You first need to configure which SOAP operation you’re invoking, by setting the value in a Header:

    .setHeader("operationName", constant("GetCustomer"))
    

    Then, you can use the CXF component using the cxf:// endpoint, like this:

    .to("cxf://http://endpoint.mycompany.org"
        + "?serviceClass=com.mycompany.CustomerService"
        + "&wsdlURL=/wsdl/service.wsdl")
    

    Where serviceClass is the class that the cxf-codegen-plugin created that represents your SOAP service, and wsdlURL is the path to your WSDL.

Example

If you’ve followed the steps above, your final Camel route should look something like this:

from("direct:start")
    .setBody(constant("12345"))
    .bean(GetCustomerRequestBuilder.class)
    
    .setHeader("operationName", constant("GetCustomer"))
    
    .to("cxf://http://endpoint.mycompany.org"
        + "?serviceClass=com.mycompany.CustomerService"
        + "&wsdlURL=/wsdl/service.wsdl")

    .log("The response was ${body[0]}");

Got feedback about this article, or questions about working with SOAP services in Camel? Post them in the comments below! Cheers!

Photo by Letizia Bordoni on Unsplash.

Leave a Comment

You can use Markdown in your comment. To write code, indent lines by 4 spaces.