I went through all the Asciidoc files to correct spelling, grammar, punctuation, and usage. Wherever possible, I also made it more clear and more concise. I also added links wherever they were reasonable. Accommodating changes that came while I was editing Various folks made changes (one of which I recommended) to the documents while I spent a month editing. I had to edit that new and changed content as well, so I need this second commit. Accommodating Artem's requested changes for `aggregator.adoc` Artem reviewed `aggregator.adoc` as a starting point, so that he could get some questions answered. I have made the changes he requested (and answered his questions on Github).
338 lines
16 KiB
Plaintext
338 lines
16 KiB
Plaintext
[[ws]]
|
|
== Web Services Support
|
|
|
|
This chapter describes Spring Integration's support for web services, including:
|
|
|
|
* <<webservices-outbound>>
|
|
* <<webservices-inbound>>
|
|
* <<webservices-namespace>>
|
|
* <<outbound-uri>>
|
|
* <<ws-message-headers>>
|
|
* <<mtom-support>>
|
|
|
|
[[webservices-outbound]]
|
|
=== Outbound Web Service Gateways
|
|
|
|
To invoke a web service when you send a message to a channel, you have two options, both of which build upon the http://projects.spring.io/spring-ws/[Spring Web Services] project: `SimpleWebServiceOutboundGateway` and `MarshallingWebServiceOutboundGateway`.
|
|
The former accepts either a `String` or `javax.xml.transform.Source` as the message payload.
|
|
The latter supports any implementation of the `Marshaller` and `Unmarshaller` interfaces.
|
|
Both require a Spring Web Services `DestinationProvider`, to determine the URI of the web service to be called.
|
|
The following example shows both options for invoking a web service:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
simpleGateway = new SimpleWebServiceOutboundGateway(destinationProvider);
|
|
|
|
marshallingGateway = new MarshallingWebServiceOutboundGateway(destinationProvider, marshaller);
|
|
----
|
|
====
|
|
|
|
NOTE: When using the namespace support (<<webservices-namespace,described later>>), you need only set a URI.
|
|
Internally, the parser configures a fixed URI `DestinationProvider` implementation.
|
|
If you need dynamic resolution of the URI at runtime, however, then the `DestinationProvider` can provide such behavior as looking up the URI from a registry.
|
|
See the Spring Web Services http://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/client/support/destination/DestinationProvider.html[`DestinationProvider`] Javadoc for more information about this strategy.
|
|
|
|
Starting with version 5.0, you can supply the `SimpleWebServiceOutboundGateway` and `MarshallingWebServiceOutboundGateway` with an external `WebServiceTemplate` instance, which you can configure for any custom properties, including `checkConnectionForFault` (which allows 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 http://docs.spring.io/spring-ws/docs/current/reference/html/client.html[client access] and the chapter covering http://docs.spring.io/spring/docs/current/spring-framework-reference/html/oxm.html[Object/XML mapping].
|
|
|
|
[[webservices-inbound]]
|
|
=== Inbound Web Service Gateways
|
|
|
|
To send a message to a channel upon receiving a web service invocation, you again have two options: `SimpleWebServiceInboundGateway` and `MarshallingWebServiceInboundGateway`.
|
|
The former extracts a `javax.xml.transform.Source` from the `WebServiceMessage` and sets it as the message payload.
|
|
The latter supports implementation of the `Marshaller` and `Unmarshaller` interfaces.
|
|
If the incoming web service message is a SOAP message, the SOAP action header is added to the headers of the `Message` that is forwarded onto the request channel.
|
|
The following example shows both options:
|
|
|
|
====
|
|
[source,java]
|
|
----
|
|
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 http://docs.spring.io/spring-ws/docs/current/reference/html/server.html[creating a web service].
|
|
The chapter covering http://docs.spring.io/spring/docs/current/spring-framework-reference/html/oxm.html[Object/XML mapping] is also applicable again.
|
|
|
|
To add the `SimpleWebServiceInboundGateway` and `MarshallingWebServiceInboundGateway` configurations to the Spring WS
|
|
infrastructure, you should add the `EndpointMapping` definition between `MessageDispatcherServlet` and the target
|
|
`MessageEndpoint` implementations, as you would for a normal Spring WS application.
|
|
For this purpose (from the Spring Integration perspective), Spring WS provides the following 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`
|
|
|
|
You must specify the beans for these classes in the application context and reference the
|
|
`SimpleWebServiceInboundGateway` and/or `MarshallingWebServiceInboundGateway` bean definitions according to the WS
|
|
mapping algorithm.
|
|
|
|
See the http://docs.spring.io/spring-ws/docs/current/reference/html/server.html#server-endpoint-mapping[endpoint mappings] for more information.
|
|
|
|
[[webservices-namespace]]
|
|
=== Web Service Namespace Support
|
|
|
|
To configure an outbound web service gateway, use the `outbound-gateway` element from the `ws` namespace, as the following example shows:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<int-ws:outbound-gateway id="simpleGateway"
|
|
request-channel="inputChannel"
|
|
uri="http://example.org"/>
|
|
----
|
|
====
|
|
|
|
NOTE: This example does not provide a 'reply-channel'.
|
|
If the web service returns a non-empty response, the `Message` containing that response is sent to the reply channel defined in the request message's `REPLY_CHANNEL` header.
|
|
If that is not available, a channel resolution exception is thrown.
|
|
If you want to send the reply to another channel instead, provide a 'reply-channel' attribute on the 'outbound-gateway' element.
|
|
|
|
TIP: By default, when you invoke a web service that returns an empty response after using a String payload for the request `Message`, no reply `Message` is sent.
|
|
Therefore, you need not set a 'reply-channel' or have a `REPLY_CHANNEL` header in the request `Message`.
|
|
If you actually do want to receive the empty response as a `Message`, you can set the 'ignore-empty-responses' attribute to `false`.
|
|
Doing so works only for `String` objects, because using a `Source` or a `Document` object leads to a null response and consequently never generates a reply `Message`.
|
|
|
|
To set up an inbound Web Service Gateway, use the `inbound-gateway` element, as the following example shows:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<int-ws:inbound-gateway id="simpleGateway"
|
|
request-channel="inputChannel"/>
|
|
----
|
|
====
|
|
|
|
To use Spring OXM marshallers or unmarshallers, you must provide bean references.
|
|
The following example shows how to provide a bean reference for an outbound marshalling gateway:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<int-ws:outbound-gateway id="marshallingGateway"
|
|
request-channel="requestChannel"
|
|
uri="http://example.org"
|
|
marshaller="someMarshaller"
|
|
unmarshaller="someUnmarshaller"/>
|
|
----
|
|
====
|
|
|
|
The following example shows how to provide a bean reference for an inbound marshalling gateway:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<int-ws:inbound-gateway id="marshallingGateway"
|
|
request-channel="requestChannel"
|
|
marshaller="someMarshaller"
|
|
unmarshaller="someUnmarshaller"/>
|
|
----
|
|
====
|
|
|
|
NOTE: Most `Marshaller` implementations also implement the `Unmarshaller` interface.
|
|
When using such a `Marshaller`, only the `marshaller` attribute is necessary.
|
|
Even when using a `Marshaller`, you may also provide a reference for the `request-callback` on the outbound gateways.
|
|
|
|
For either outbound gateway type, you can specify a `destination-provider` attribute instead of the `uri` (exactly one of them is required).
|
|
You can then reference any Spring Web Services `DestinationProvider` implementation (for example, to lookup the URI from a registry at runtime).
|
|
|
|
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, you can set the `extract-payload` attribute to `false` to forward the entire `WebServiceMessage` instead of just its payload as a `Message` to the request channel.
|
|
Doing so 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 lets you inject a `WebServiceTemplate` with any possible custom properties.
|
|
|
|
[[outbound-uri]]
|
|
=== Outbound URI Configuration
|
|
|
|
For all URI schemes supported by Spring Web Services (see http://docs.spring.io/spring-ws/docs/current/reference/html/client.html#client-transports[URIs and Transports]) `<uri-variable/>` substitution is provided.
|
|
The following example shows how to define it:
|
|
|
|
[source,xml]
|
|
----
|
|
<ws:outbound-gateway id="gateway" request-channel="input"
|
|
uri="http://springsource.org/{thing1}-{thing2}">
|
|
<ws:uri-variable name="thing1" expression="payload.substring(1,7)"/>
|
|
<ws:uri-variable name="thing2" 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 you supply a `DestinationProvider`, variable substitution is not supported and a configuration error occurs if you provide variables.
|
|
|
|
==== Controlling URI Encoding
|
|
|
|
By default, the URL string is encoded (see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html[`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/>` element provides an `encode-uri` attribute.
|
|
To disable encoding the URL, set this attribute `false` (it defaults to `true`).
|
|
If you wish to partially encode some of the URL, you can do so by using an `expression` within a `<uri-variable/>`, as the following example shows:
|
|
|
|
====
|
|
[source,xml]
|
|
----
|
|
<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: If you set `DestinationProvider`, `encode-uri` is ignored.
|
|
|
|
[[ws-message-headers]]
|
|
=== WS Message Headers
|
|
|
|
The Spring Integration web service gateways automatically map the SOAP action header.
|
|
By default, it is copied to and from Spring Integration `MessageHeaders` by using the
|
|
http://docs.spring.io/spring-integration/api/org/springframework/integration/ws/DefaultSoapHeaderMapper.html[`DefaultSoapHeaderMapper`].
|
|
|
|
You can pass in your own implementation of SOAP-specific header mappers, as the gateways have properties to support doing so.
|
|
|
|
Unless explicitly specified by the `requestHeaderNames` or `replyHeaderNames` properties of the `DefaultSoapHeaderMapper`, any user-defined SOAP headers are not copied to or from a SOAP Message.
|
|
|
|
When you use the XML namespace for configuration, you can set these properties by using the `mapped-request-headers` and
|
|
`mapped-reply-headers` attributes, you can provide a custom mapper by setting the `header-mapper` attribute.
|
|
|
|
TIP: When mapping user-defined headers, the values can also contain simple wildcard patterns (such `myheader*` or `*myheader`).
|
|
For example, if you need to copy all user-defined headers, you can use the wildcard character: `*`.
|
|
|
|
Starting with version 4.1, the `AbstractHeaderMapper` (a `DefaultSoapHeaderMapper` superclass) lets the `NON_STANDARD_HEADERS` token be configured for the `requestHeaderNames` and `replyHeaderNames` properties (in addition to existing `STANDARD_REQUEST_HEADERS` and `STANDARD_REPLY_HEADERS`) to map all user-defined headers.
|
|
|
|
NOTE: Rather than using the wildcard (`*`), we recommend using the following combination : `STANDARD_REPLY_HEADERS, NON_STANDARD_HEADERS`.
|
|
Doing so avoids mapping `request` headers to the reply.
|
|
|
|
Starting with version 4.3, you can negate patterns in the header mappings by preceding the pattern with `!`.
|
|
Negated patterns get priority, so a list such as
|
|
`STANDARD_REQUEST_HEADERS,thing1,thing*,!thing2,!thing3,qux,!thing1` does not map `thing1`, `thing2`, or `thing3`. It does map the standard headers, `thing4`, and `qux`.
|
|
(Note that `thing1` is included in both non-negated and negated forms. Because negated values take precedence, `thing1` is not mapped.)
|
|
|
|
IMPORTANT: If you have a user-defined header that begins with `!` that you do wish to map, you can escape it with
|
|
`\`, as follows: `STANDARD_REQUEST_HEADERS,\!myBangHeader`. `!myBangHeader` is then mapped.
|
|
|
|
Inbound SOAP headers (request headers for the inbound gateway and reply headers for the outbound gateway) are mapped as
|
|
`SoapHeaderElement` objects.
|
|
You can explore the contents by accessing the `Source`:
|
|
|
|
====
|
|
[source, xml]
|
|
----
|
|
<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, ca*`, the `auth`, `cat`, and `can` headers are mapped, but `qux` is not mapped.
|
|
|
|
The following example shows how to get a value named `user` from a header named `auth`:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
...
|
|
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>`.
|
|
The following example shows how to do so:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
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");
|
|
----
|
|
====
|
|
|
|
The result of the preceding examples is the following SOAP envelope:
|
|
|
|
====
|
|
[source, xml]
|
|
----
|
|
<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>
|
|
----
|
|
====
|
|
|
|
[[mtom-support]]
|
|
=== MTOM Support
|
|
|
|
The marshalling inbound and outbound web service gateways support attachments directly through built-in functionality of the marshaller (for example, `Jaxb2Marshaller` provides the `mtomEnabled` option).
|
|
Starting with version 5.0, the simple web service gateways can directly operate with inbound and outbound `MimeMessage` instances, which have an API to manipulate attachments.
|
|
When you need to send web service 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.
|
|
The following example shows how to do so:
|
|
|
|
====
|
|
[source, java]
|
|
----
|
|
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));
|
|
----
|
|
====
|