Providing multiple web service operations within a single route

The Camel CXF Component has the ability to allow a Camel route to act as a SOAP (or REST) web service listener as we saw in the Implementing a web service with a Camel route recipe. Most web services expose more than one operation as part of their interface. This recipe will show you a strategy for handling multiple web service operations within a single Camel route acting as a web service frontend.

Getting ready

This recipe assumes that you have a project with JAX-WS artifacts created as described in the Generating the service stubs from a WSDL recipe. To use the generated API, you need to include a dependency to that project in your build:

<dependency>
  <groupId>org.camelcookbook.examples</groupId>
  <artifactId>ws-payments-api</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

This recipe's example is based on paymentService2.wsdl, whose interface has two operations, transferFunds and checkStatus.

<wsdl:portType name="Payment">
  <wsdl:operation name="transferFunds">
    <wsdl:input message="tns:TransferRequest"/>
    <wsdl:output message="tns:TransferResponse"/>
    <wsdl:fault name="fault" message="tns:FaultMessage"/>
  </wsdl:operation>
  <wsdl:operation name="checkStatus">
    <wsdl:input message="tns:CheckStatusRequest"/>
    <wsdl:output message="tns:CheckStatusResponse"/>
    <wsdl:fault name="fault" message="tns:FaultMessage"/>
  </wsdl:operation>
</wsdl:portType>

All source files for this recipe are located in the ws-camel-routes project in the camel-cookbook-web-services module. The Java code for this recipe is located in the org.camelcookbook.ws.multipleoperations package. The Spring XML files are located under src/main/resources/META-INF/spring and prefixed with multipleOperations.

How to do it...

In order to provide multiple web service operations within a single Camel route, perform the following steps:

  1. Configure a Camel CXF endpoint as described in step 1 of the Implementing a web service with a Camel route recipe.
  2. Route the exchange based on the operationName header using a Content Based Router.

    In the XML DSL, this is written as:

    <route id="wsRoute">
      <from uri="cxf:bean:paymentServiceEndpoint"/>
      <transform>
        <simple>${in.body[0]}</simple>
      </transform>
      <log message="request = ${body}"/>
      <choice>
        <when>
          <simple>
            ${in.header.operationName} == 'transferFunds'
          </simple>
          <bean ref="paymentServiceImpl"/>
        </when>
        <when>
          <simple>
            ${in.header.operationName} == 'checkStatus'
          </simple>
          <bean ref="checkStatusServiceImpl"/>
        </when>
        <otherwise>
          <setFaultBody>
            <method ref="faultHandler"
                    method="createInvalidOperation"/>
          </setFaultBody>
        </otherwise>
      </choice>
      <log message="response = ${body}"/>
    </route>

    In the Java DSL, the same route is expressed as:

    from(cxfUri).id("wsRoute")
      .transform(simple("${in.body[0]}"))
      .log("request = ${body}")
      .choice()
        .when(simple(
            "${in.header.operationName} == 'transferFunds'"
        ))
          .bean(PaymentServiceV2Impl.class)
        .when(simple(
            "${in.header.operationName} == 'checkStatus'"
        ))
          .bean(CheckStatusServiceV2Impl.class)
        .otherwise()
          .setFaultBody(method(FaultHandler.class,
                               "createInvalidOperation"))
      .end()
      .log("response = ${body}");

When an invalid operation name is detected in the otherwise part of the choice block, a SOAP Fault is raised through the setFaultBody DSL statement. This mechanism is described in more detail in the Handling web service faults recipe.

How it works...

The Camel CXF endpoint consumer will place the web service operation name into the operationName header on the exchange. You use Camel's Content Based Router to route the request as appropriate, based on this value.

The consumer also sets an operationNamespace header that contains the namespace of the SOAP operation. This can be useful if your WSDL supports multiple versions of a web service through a version number in the namespace. In such a case, you can also use this header to route the exchange to different service methods.

The otherwise part of the Content Base Router will catch requests with unknown operation names. In this example, a SOAP Fault is returned. See the Handling web service faults recipe for more details on Fault handling in Camel.

There's more...

The Camel CXF Component supports the convention of returning the WSDL for a service endpoint when an HTTP request is made to the service URL that includes the ?wsdl query parameter.

For example, if your web service is accessible through http://localhost:8080/paymentServicev2, the WSDL for the service endpoint is accessible via http://localhost:8080/paymentServicev2?wsdl.

The component uses the configured JAX-WS artifacts to allow it to generate that WSDL at runtime based on the annotations of the serviceClass defined on the endpoint. There are a number of Camel CXF options that allow you to fine-tune the exposed web service and its generated WSDL contract; see the component documentation for further details.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.133.160