To invoke a Web Service upon sending a message to a channel, there are two options - both of which build upon the Spring Web Services project: SimpleWebServiceOutboundGateway
and MarshallingWebServiceOutboundGateway
.
The former will accept either a String
or javax.xml.transform.Source
as the message payload.
The latter provides support for any implementation of the Marshaller
and Unmarshaller
interfaces.
Both require a Spring Web Services DestinationProvider
for determining the URI of the Web Service to be called.
simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider); marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
Note | |
---|---|
When using the namespace support described below, you will only need to set a URI.
Internally, the parser will configure a fixed URI |
Starting with version 5.0 the SimpleWebServiceOutboundGateway
and MarshallingWebServiceOutboundGateway
can be supplied with an external WebServiceTemplate
instance, which may be configured for any custom properties, including checkConnectionForFault
allowing your application to deal with non-conforming services.
For more detail on the inner workings, see the Spring Web Services reference guide’s chapter covering client access as well as the chapter covering Object/XML mapping.
To send a message to a channel upon receiving a Web Service invocation, there are two options again: SimpleWebServiceInboundGateway
and MarshallingWebServiceInboundGateway
.
The former will extract a javax.xml.transform.Source
from the WebServiceMessage
and set it as the message payload.
The latter provides support for implementation of the Marshaller
and Unmarshaller
interfaces.
If the incoming web service message is a SOAP message the SOAP Action header will be added to the headers of the`Message` that is forwarded onto the request channel.
simpleGateway = new SimpleWebServiceInboundGateway(); simpleGateway.setRequestChannel(forwardOntoThisChannel); simpleGateway.setReplyChannel(listenForResponseHere); //Optional marshallingGateway = new MarshallingWebServiceInboundGateway(marshaller); //set request and optionally reply channel
Both gateways implement the Spring Web Services MessageEndpoint
interface, so they can be configured with a MessageDispatcherServlet
as per standard Spring Web Services configuration.
For more detail on how to use these components, see the Spring Web Services reference guide’s chapter covering creating a Web Service. The chapter covering Object/XML mapping is also applicable again.
To include the SimpleWebServiceInboundGateway
and MarshallingWebServiceInboundGateway
configurations to the Spring WS
infrastructure you should add the EndpointMapping
definition between MessageDispatcherServlet
and the target
MessageEndpoint
implementations like you do that with normal Spring WS application.
For this purpose (from Spring Integration perspective), the Spring WS provides these convenient EndpointMapping
implementations:
o.s.ws.server.endpoint.mapping.UriEndpointMapping
o.s.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping
o.s.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping
o.s.ws.server.endpoint.mapping.XPathPayloadEndpointMapping
The beans for these classes must be specified in the application context referencing to the
SimpleWebServiceInboundGateway
and/or MarshallingWebServiceInboundGateway
bean definitions according to the WS
mapping algorithm.
Please, refer to the Endpoint mappings for the more information.
To configure an outbound Web Service Gateway, use the "outbound-gateway" element from the "ws" namespace:
<int-ws:outbound-gateway id="simpleGateway" request-channel="inputChannel" uri="http://example.org"/>
Note | |
---|---|
Notice that this example does not provide a reply-channel.
If the Web Service were to return a non-empty response, the Message containing that response would be sent to the reply
channel provided in the request Message’s |
Tip | |
---|---|
When invoking a Web Service that returns an empty response after using a String payload for the request Message, no reply Message will be sent by default. Therefore you don’t need to set a reply-channel or have a REPLY_CHANNEL header in the request Message. If for any reason you actually do want to receive the empty response as a Message, then provide the ignore-empty-responses attribute with a value of false (this only applies for Strings, because using a Source or Document object simply leads to a NULL response and will therefore never generate a reply Message). |
To set up an inbound Web Service Gateway, use the "inbound-gateway":
<int-ws:inbound-gateway id="simpleGateway" request-channel="inputChannel"/>
To use Spring OXM Marshallers and/or Unmarshallers, provide bean references. For outbound:
<int-ws:outbound-gateway id="marshallingGateway" request-channel="requestChannel" uri="http://example.org" marshaller="someMarshaller" unmarshaller="someUnmarshaller"/>
And for inbound:
<int-ws:inbound-gateway id="marshallingGateway" request-channel="requestChannel" marshaller="someMarshaller" unmarshaller="someUnmarshaller"/>
Note | |
---|---|
Most |
For either outbound gateway type, a "destination-provider" attribute can be specified instead of the "uri" (exactly one of them is required). You can then reference any Spring Web Services DestinationProvider implementation (e.g. to lookup the URI at runtime from a registry).
For either outbound gateway type, the "message-factory" attribute can also be configured with a reference to any Spring Web Services WebServiceMessageFactory
implementation.
For the simple inbound gateway type, the "extract-payload" attribute can be set to false to forward the entire WebServiceMessage
instead of just its payload as a Message
to the request channel.
This might be useful, for example, when a custom Transformer works against the WebServiceMessage
directly.
Starting with version 5.0 the web-service-template
reference attribute is presented for the injection of a WebServiceTemplate
with any possible custom properties.
For all URI-schemes supported by Spring Web Services (URIs and Transports) <uri-variable/>
substitution is provided:
<ws:outbound-gateway id="gateway" request-channel="input" uri="http://springsource.org/{foo}-{bar}"> <ws:uri-variable name="foo" expression="payload.substring(1,7)"/> <ws:uri-variable name="bar" expression="headers.x"/> </ws:outbound-gateway> <ws:outbound-gateway request-channel="inputJms" uri="jms:{destination}?deliveryMode={deliveryMode}&priority={priority}" message-sender="jmsMessageSender"> <ws:uri-variable name="destination" expression="headers.jmsQueue"/> <ws:uri-variable name="deliveryMode" expression="headers.deliveryMode"/> <ws:uri-variable name="priority" expression="headers.jms_priority"/> </ws:outbound-gateway>
If a DestinationProvider
is supplied, variable substitution is not supported and a configuration error will result if variables are provided.
Controlling URI Encoding
By default, the URL string is encoded (see UriComponentsBuilder) to the URI object before sending the request.
In some scenarios with a non-standard URI it is undesirable to perform the encoding.
Since version 4.1 the <ws:outbound-gateway/>
provides an encode-uri
attribute.
To disable encoding the URL, this attribute should be set to false
(by default it is true
).
If you wish to partially encode some of the URL, this can be achieved using an expression
within a <uri-variable/>
:
<ws:outbound-gateway url="http://somehost/%2f/fooApps?bar={param}" encode-uri="false"> <http:uri-variable name="param" expression="T(org.apache.commons.httpclient.util.URIUtil) .encodeWithinQuery('Hello World!')"/> </ws:outbound-gateway>
Note, encode-uri
is ignored, if DestinationProvider
is supplied.
The Spring Integration WebService Gateways will map the SOAP Action header automatically.
It will be copied by default to and from Spring Integration MessageHeaders
using the
DefaultSoapHeaderMapper.
Of course, you can pass in your own implementation of SOAP specific header mappers, as the gateways have respective properties to support that.
Any user-defined SOAP headers will NOT
be copied to or from a SOAP Message, unless explicitly specified by the requestHeaderNames and/or
replyHeaderNames properties of the DefaultSoapHeaderMapper
.
When using the XML namespace for configuration, these properties can be set using the mapped-request-headers
and
mapped-reply-headers
, or a custom mapper can be provided using the header-mapper
attribute.
Tip | |
---|---|
When mapping user-defined headers, the values can also contain simple wildcard patterns (e.g. "foo*" or "*foo") to be matched.
For example, if you need to copy all user-defined headers simply use the wildcard character |
Starting with version 4.1, the AbstractHeaderMapper
(a DefaultSoapHeaderMapper
superclass) allows the
NON_STANDARD_HEADERS
token to be configured for the requestHeaderNames and/or replyHeaderNames
properties (in addition to existing STANDARD_REQUEST_HEADERS
and STANDARD_REPLY_HEADERS
) to map all
user-defined headers.
Note, it is recommended to use the combination like this STANDARD_REPLY_HEADERS, NON_STANDARD_HEADERS
instead of a
*
, to avoid mapping of request headers to the reply.
Starting with version 4.3, patterns in the header mappings can be negated by preceding the pattern with !
.
Negated patterns get priority, so a list such as
STANDARD_REQUEST_HEADERS,foo,ba*,!bar,!baz,qux,!foo
will NOT map foo
(nor bar
nor baz
); the standard headers plus bad
, qux
will be mapped.
Important | |
---|---|
If you have a user defined header that begins with |
Inbound SOAP headers (request headers for the inbound gateway, reply-headers for the outbound gateway) are mapped as
SoapHeaderElement
objects.
The contents can be explored by accessing the Source
:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <auth> <username>user</username> <password>pass</password> </auth> <bar>BAR</bar> <baz>BAZ</baz> <qux>qux</qux> </soapenv:Header> <soapenv:Body> ... </soapenv:Body> </soapenv:Envelope>
If mapped-request-headers
is "auth, ba*"
, the auth
, bar
and baz
headers are mapped but qux
is not.
... SoapHeaderElement header = (SoapHeaderElement) headers.get("auth"); DOMSource source = (DOMSource) header.getSource(); NodeList nodeList = source.getNode().getChildNodes(); assertEquals("username", nodeList.item(0).getNodeName()); assertEquals("user", nodeList.item(0).getFirstChild().getNodeValue()); ...
Starting with version 5.0, the DefaultSoapHeaderMapper
supports user-defined headers of type javax.xml.transform.Source
and populates them as child nodes of the <soapenv:Header>
:
Map<String, Object> headers = new HashMap<>(); String authXml = "<auth xmlns='http://test.auth.org'>" + "<username>user</username>" + "<password>pass</password>" + "</auth>"; headers.put("auth", new StringSource(authXml)); ... DefaultSoapHeaderMapper mapper = new DefaultSoapHeaderMapper(); mapper.setRequestHeaderNames("auth");
And in the end we have SOAP envelope as:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <auth xmlns="http://test.auth.org"> <username>user</username> <password>pass</password> </auth> </soapenv:Header> <soapenv:Body> ... </soapenv:Body> </soapenv:Envelope>
The Marshalling Inbound and Outbound WebService Gateways support attachments directly via built-in functionality of the marshaller, e.g. Jaxb2Marshaller
provides the mtomEnabled
option.
Starting with version 5.0, the Simple WebService Gateways can operate with inbound and outbound MimeMessage
s directly, which have an API to manipulate attachments.
When you need to send WebService message with attachments (either a reply from a server, or a client request) you should use the WebServiceMessageFactory
directly and send a WebServiceMessage
with attachments as a payload
to the request or reply channel of the gateway:
WebServiceMessageFactory messageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance()); MimeMessage webServiceMessage = (MimeMessage) messageFactory.createWebServiceMessage(); String request = "<test>foo</test>"; TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.transform(new StringSource(request), webServiceMessage.getPayloadResult()); webServiceMessage.addAttachment("myAttachment", new ByteArrayResource("my_data".getBytes()), "plain/text"); this.webServiceChannel.send(new GenericMessage<>(webServiceMessage));