Since Camel 2.6
Both producer and consumer are supported
The Spring WS component allows you to integrate with Spring Web Services. It offers both client-side support, for accessing web services, and server-side support for creating your own contract-first web services.
Maven users will need to add the following dependency to their pom.xml
for this component:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-ws</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency>
Be aware Spring WS version 4.x does not support Axiom anymore (because Axiom does not support Jakarta JEE 9)
The URI scheme for this component is as follows
spring-ws:[mapping-type:]address[?options]
To expose a web service mapping-type needs to be set to any of the following:
Mapping type | Description |
---|---|
|
Offers the option to map web service requests based on the qualified name of the root element contained in the message. |
|
Used to map web service requests based on the SOAP action specified in the header of the message. |
|
To map web service requests that target a specific URI. |
|
To map web service requests that target a specific path in URI. |
|
Used to map web service requests based on the evaluation of an XPath
|
|
Allows you to reference an
|
As a consumer, the address should contain a value relevant to the specified mapping-type (e.g. a SOAP action, XPath expression). As a producer, the address should be set to the URI of the web service your calling upon.
To call a web service at http://foo.com/bar
simply define a route:
from("direct:example").to("spring-ws:http://foo.com/bar")
And sent a message:
template.requestBody("direct:example", "<foobar xmlns=\"http://foo.com\"><msg>test message</msg></foobar>");
Remember if it’s a SOAP service you’re calling, you don’t have to include SOAP tags. Spring-WS will perform the XML-to-SOAP marshaling.
When a remote web service requires a SOAP action or use of the WS-Addressing standard, you define your route as:
from("direct:example")
.to("spring-ws:http://foo.com/bar?soapAction=http://foo.com&wsAddressingAction=http://bar.com")
Optionally, you can override the endpoint options with header values:
template.requestBodyAndHeader("direct:example",
"<foobar xmlns=\"http://foo.com\"><msg>test message</msg></foobar>",
SpringWebserviceConstants.SPRING_WS_SOAP_ACTION, "http://baz.com");
You can provide the SOAP header(s) as a Camel Message header when sending a message to a spring-ws endpoint, for example, given the following SOAP header in a String
String body = ...
String soapHeader = "<h:Header xmlns:h=\"http://www.webserviceX.NET/\"><h:MessageID>1234567890</h:MessageID><h:Nested><h:NestedID>1111</h:NestedID></h:Nested></h:Header>";
We can set the body and header on the Camel Message as follows:
exchange.getIn().setBody(body);
exchange.getIn().setHeader(SpringWebserviceConstants.SPRING_WS_SOAP_HEADER, soapHeader);
And then send the Exchange to a spring-ws
endpoint to call the Web
Service.
Likewise, the spring-ws consumer will also enrich the Camel Message with the SOAP header.
For example, see this unit test.
Spring WS Camel supports propagation of the headers and attachments into
Spring-WS WebServiceMessage
response. The
endpoint will use so-called "hook" the MessageFilter
(default
implementation is provided by BasicMessageFilter
) to propagate the
exchange headers and attachments into WebServiceMessage
response. Now
you can use
exchange.getOut().getHeaders().put("myCustom","myHeaderValue")
exchange.getIn().addAttachment("myAttachment", new DataHandler(...))
Note
|
If the exchange header in the pipeline contains text, it generates Qname(key)=value attribute in the soap header. Recommended is to create a QName class directly and put any key into header. |
The header transformation filter (HeaderTransformationMessageFilter
)
can be used to transform the soap header for a soap request. If you want to use
the header transformation filter, see the below example:
<bean id="headerTransformationFilter" class="org.apache.camel.component.spring.ws.filter.impl.HeaderTransformationMessageFilter">
<constructor-arg index="0" value="org/apache/camel/component/spring/ws/soap-header-transform.xslt"/>
</bean>
Use the bead defined above in the camel endpoint
<route>
<from uri="direct:stockQuoteWebserviceHeaderTransformation"/>
<to uri="spring-ws:http://localhost?webServiceTemplate=#webServiceTemplate&soapAction=http://www.stockquotes.edu/GetQuote&messageFilter=#headerTransformationFilter"/>
</route>
If you need to provide your custom processing of either headers or
attachments, extend existing BasicMessageFilter
and override the
appropriate methods or write a brand-new implementation of the
MessageFilter
interface.
To use your custom filter, add this into your spring context:
You can specify either a global a or a local message filter as follows:
-
the global custom filter that provides the global configuration for all Spring-WS endpoints
<bean id="messageFilter" class="your.domain.myMessageFiler" scope="singleton" />
-
the local messageFilter directly on the endpoint as follows:
to("spring-ws:http://yourdomain.com?messageFilter=#myEndpointSpecificMessageFilter");
For more information, see CAMEL-5724
If you want to create your own MessageFilter
, consider overriding the
following methods in the default implementation of MessageFilter
in
class BasicMessageFilter
:
protected void doProcessSoapHeader(Message inOrOut, SoapMessage soapMessage)
{your code /*no need to call super*/ }
protected void doProcessSoapAttachements(Message inOrOut, SoapMessage response)
{ your code /*no need to call super*/ }
A custom message sender or factory in the registry can be referenced like this:
from("direct:example")
.to("spring-ws:http://foo.com/bar?messageFactory=#messageFactory&messageSender=#messageSender")
Spring configuration:
<!-- authenticate using HTTP Basic Authentication -->
<bean id="messageSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<property name="credentials">
<bean class="org.apache.commons.httpclient.UsernamePasswordCredentials">
<constructor-arg index="0" value="admin"/>
<constructor-arg index="1" value="secret"/>
</bean>
</property>
</bean>
To expose a web service using this component, you first need to
set up a
MessageDispatcher
to look for endpoint mappings in a Spring XML file. If you plan on
running inside a servlet container, you probably want to use a
MessageDispatcherServlet
configured in web.xml
.
By default, the MessageDispatcherServlet
will look for a Spring XML
named /WEB-INF/spring-ws-servlet.xml
. To use Camel with Spring-WS the
only mandatory bean in that XML file is CamelEndpointMapping
. This
bean allows the MessageDispatcher
to dispatch web service requests to
your routes.
web.xml
<web-app>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
spring-ws-servlet.xml
<bean id="endpointMapping" class="org.apache.camel.component.spring.ws.bean.CamelEndpointMapping" />
<bean id="wsdl" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schema">
<bean class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="/WEB-INF/foobar.xsd"/>
</bean>
</property>
<property name="portTypeName" value="FooBar"/>
<property name="locationUri" value="/"/>
<property name="targetNamespace" value="http://example.com/"/>
</bean>
More information on setting up Spring-WS can be found in
Writing
Contract-First Web Services. Basically paragraph 3.6 "Implementing the
Endpoint" is handled by this component (specifically paragraph 3.6.2
"Routing the Message to the Endpoint" is where CamelEndpointMapping
comes in). Also remember to check out the
Spring Web Services Example included in the
Camel distribution.
With the XML configuration in place, you can now use Camel’s DSL to define what web service requests are handled by your endpoint:
The following route will receive all web service requests that have a
root element named "GetFoo" within the http://example.com/
namespace.
from("spring-ws:rootqname:{http://example.com/}GetFoo?endpointMapping=#endpointMapping")
.convertBodyTo(String.class).to(mock:example)
The following route will receive web service requests containing the
http://example.com/GetFoo
SOAP action.
from("spring-ws:soapaction:http://example.com/GetFoo?endpointMapping=#endpointMapping")
.convertBodyTo(String.class).to(mock:example)
The following route will receive all requests sent to
http://example.com/foobar
.
from("spring-ws:uri:http://example.com/foobar?endpointMapping=#endpointMapping")
.convertBodyTo(String.class).to(mock:example)
The route below will receive requests that contain the element
<foobar>abc</foobar>
anywhere inside the message (and the default
namespace).
from("spring-ws:xpathresult:abc?expression=//foobar&endpointMapping=#endpointMapping")
.convertBodyTo(String.class).to(mock:example)
For every endpoint with mapping-type beanname
one bean of type
CamelEndpointDispatcher
with a corresponding name is required in the
Registry
/ApplicationContext
. This bean acts as a bridge between the
Camel endpoint and an existing
endpoint
mapping like PayloadRootQNameEndpointMapping
.
Note
|
The use of the |
An example of a route using beanname
:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="spring-ws:beanname:QuoteEndpointDispatcher" />
<to uri="mock:example" />
</route>
</camelContext>
<bean id="legacyEndpointMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://example.com/}GetFuture">FutureEndpointDispatcher</prop>
<prop key="{http://example.com/}GetQuote">QuoteEndpointDispatcher</prop>
</props>
</property>
</bean>
<bean id="QuoteEndpointDispatcher" class="org.apache.camel.component.spring.ws.bean.CamelEndpointDispatcher" />
<bean id="FutureEndpointDispatcher" class="org.apache.camel.component.spring.ws.bean.CamelEndpointDispatcher" />
Camel’s pluggable data formats offer support for pojo/xml marshalling using libraries such as JAXB. You can use these data formats in your route to send and receive pojo’s, to and from web services.
When accessing web services, you can marshal the request and unmarshal the response message:
JaxbDataFormat jaxb = new JaxbDataFormat(false);
jaxb.setContextPath("com.example.model");
from("direct:example").marshal(jaxb).to("spring-ws:http://foo.com/bar").unmarshal(jaxb);
Similarly, when providing web services, you can unmarshal XML requests to POJO’s and marshal the response message back to XML:
from("spring-ws:rootqname:{http://example.com/}GetFoo?endpointMapping=#endpointMapping").unmarshal(jaxb)
.to("mock:example").marshal(jaxb);
spring-boot:partial$starter.adoc