diff --git a/gradle.properties b/gradle.properties index 10e5469e..09151836 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,5 @@ version=4.0.12-SNAPSHOT org.gradle.caching=true org.gradle.parallel=true + +springFrameworkVersion=6.0.23 \ No newline at end of file diff --git a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java index a9b54aac..1359195e 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/soap/SoapMessage.java @@ -22,10 +22,10 @@ import org.springframework.ws.FaultAwareWebServiceMessage; import org.springframework.ws.mime.MimeMessage; /** - * Represents an abstraction for SOAP messages, providing access to a SOAP Envelope. The - * contents of the SOAP body can be retrieved by {@code getPayloadSource()} and - * {@code getPayloadResult()} on {@code WebServiceMessage}, the super-interface of this - * interface. + * Represents an abstraction for SOAP messages, providing access to a + * {@linkplain #getEnvelope() SOAP Envelope}. The contents of the SOAP body can be + * retrieved by {@link #getPayloadSource()} and {@link #getPayloadResult()} on + * {@code WebServiceMessage}, the super-interface of this interface. * * @author Arjen Poutsma * @see #getPayloadSource() @@ -35,7 +35,9 @@ import org.springframework.ws.mime.MimeMessage; */ public interface SoapMessage extends MimeMessage, FaultAwareWebServiceMessage { - /** Returns the {@code SoapEnvelope} associated with this {@code SoapMessage}. */ + /** + * Returns the {@link SoapEnvelope} associated with this message. + */ SoapEnvelope getEnvelope() throws SoapEnvelopeException; /** @@ -51,15 +53,15 @@ public interface SoapMessage extends MimeMessage, FaultAwareWebServiceMessage { void setSoapAction(String soapAction); /** - * Returns the {@code SoapBody} associated with this {@code SoapMessage}. This is a - * convenience method for {@code getEnvelope().getBody()}. + * Returns the {@link SoapBody} associated with this message. This is a convenience + * method for {@code getEnvelope().getBody()}. * @see SoapEnvelope#getBody() */ SoapBody getSoapBody() throws SoapBodyException; /** - * Returns the {@code SoapHeader} associated with this {@code SoapMessage}. This is a - * convenience method for {@code getEnvelope().getHeader()}. + * Returns the {@link SoapHeader} associated with this message. This is a convenience + * method for {@code getEnvelope().getHeader()}. * @see SoapEnvelope#getHeader() */ SoapHeader getSoapHeader() throws SoapHeaderException; diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java index 0e5d0b8a..e69c9e81 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java @@ -52,7 +52,7 @@ import org.springframework.ws.transport.WebServiceConnection; * @see HttpClient * @see #setCredentials(Credentials) * @since 1.0.0 - * @deprecated In favor of {@link HttpComponentsMessageSender} + * @deprecated In favor of {@link HttpComponents5MessageSender} */ @Deprecated public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSender diff --git a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java index fd538dc3..643ffc0a 100644 --- a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java +++ b/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java @@ -30,7 +30,7 @@ import org.springframework.ws.transport.WebServiceConnection; * execute POST requests, without support for HTTP authentication or advanced * configuration options. *

- * Consider {@link HttpComponentsMessageSender} for more sophisticated needs: this class + * Consider {@link HttpComponents5MessageSender} for more sophisticated needs: this class * is rather limited in its capabilities. * * @author Arjen Poutsma diff --git a/spring-ws-docs/build.gradle b/spring-ws-docs/build.gradle index f6471e54..aeeb4531 100644 --- a/spring-ws-docs/build.gradle +++ b/spring-ws-docs/build.gradle @@ -27,6 +27,8 @@ asciidoctorj { attributes = [ "allow-uri-read": true, "numbered": true, + "spring-framework-version": springFrameworkVersion, + "spring-ws-version": project.version, "toclevels": 4 ] options = [ diff --git a/spring-ws-docs/src/docs/asciidoc/client.adoc b/spring-ws-docs/src/docs/asciidoc/client.adoc index b4babddd..c652eb8a 100644 --- a/spring-ws-docs/src/docs/asciidoc/client.adoc +++ b/spring-ws-docs/src/docs/asciidoc/client.adoc @@ -1,13 +1,13 @@ [[client]] -= Using Spring Web Services on the Client += Using Spring-WS on the Client Spring-WS provides a client-side Web service API that allows for consistent, XML-driven access to web services. It also caters to the use of marshallers and unmarshallers so that your service-tier code can deal exclusively with Java objects. The `org.springframework.ws.client.core` package provides the core functionality for using the client-side access API. It contains template classes that simplify the use of Web services, much like the core Spring `JdbcTemplate` does for JDBC. The design principle common to Spring template classes is to provide helper methods to perform common operations and, for more sophisticated usage, delegate to user implemented callback interfaces. The web service template follows the same design. The classes offer various convenience methods for -* Sending and receiving of XML messages -* Marshalling objects to XML before sending -* Allowing for multiple transport options +* Sending and receiving of XML messages. +* Marshalling objects to XML before sending. +* Allowing for multiple transport options. == Using the Client-side API @@ -16,16 +16,16 @@ This section describs how to use the client-side API. For how to use the server- [[client-web-service-template]] === `WebServiceTemplate` -The `WebServiceTemplate` is the core class for client-side web service access in Spring-WS. It contains methods for sending `Source` objects and receiving response messages as either `Source` or `Result`. Additionally, it can marshal objects to XML before sending them across a transport and unmarshal any response XML into an object again. +The {spring-ws-api}/client/core/WebServiceTemplate.html[`WebServiceTemplate`] is the core class for client-side web service access in Spring-WS. It contains methods for sending `Source` objects and receiving response messages as either `Source` or `Result`. Additionally, it can marshal objects to XML before sending them across a transport and unmarshal any response XML into an object again. [[client-transports]] ==== URIs and Transports -The `WebServiceTemplate` class uses an URI as the message destination. You can either set a `defaultUri` property on the template itself or explicitly supply a URI when calling a method on the template. The URI is resolved into a `WebServiceMessageSender`, which is responsible for sending the XML message across a transport layer. You can set one or more message senders by using the `messageSender` or `messageSenders` properties of the `WebServiceTemplate` class. +The `WebServiceTemplate` class uses a URI as the message destination. You can either set a `defaultUri` property on the template itself or explicitly supply a URI when calling a method on the template. The URI is resolved into a `WebServiceMessageSender`, which is responsible for sending the XML message across a transport layer. You can set one or more message senders by using the `messageSender` or `messageSenders` properties of the `WebServiceTemplate` class. ===== HTTP transports -There are two implementations of the `WebServiceMessageSender` interface for sending messages over HTTP. The default implementation is the `HttpUrlConnectionMessageSender`, which uses the facilities provided by Java itself. The alternative is the `HttpComponentsMessageSender`, which uses the https://hc.apache.org/httpcomponents-client-ga[Apache HttpComponents HttpClient]. Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection pooling, and so forth). +There are three implementations of the `WebServiceMessageSender` interface for sending messages over HTTP. The default implementation is the `HttpUrlConnectionMessageSender`, which uses the facilities provided by Java itself. The alternatives are either `JdkHttpClientMessageSender` that uses the JDK's `HttpClient`, or `HttpComponents5MessageSender`, which uses the https://hc.apache.org/httpcomponents-client-ga[Apache HttpClient]. Use the latter if you need more advanced and easy-to-use functionality (such as authentication, HTTP connection pooling, and so forth). To use the HTTP transport, either set the `defaultUri` to something like `http://example.com/services` or supply the `uri` parameter for one of the methods. @@ -55,10 +55,11 @@ The following example shows how to override the default configuration and how to - + - - + + + @@ -70,13 +71,13 @@ The following example shows how to override the default configuration and how to ===== JMS transport -For sending messages over JMS, Spring Web Services provides `JmsMessageSender`. This class uses the facilities of the Spring framework to transform the `WebServiceMessage` into a JMS `Message`, send it on its way on a `Queue` or `Topic`, and receive a response (if any). +For sending messages over JMS, Spring-WS provides `JmsMessageSender`. This class uses the facilities of the Spring framework to transform the `WebServiceMessage` into a JMS `Message`, send it on its way on a `Queue` or `Topic`, and receive a response (if any). -To use `JmsMessageSender`, you need to set the `defaultUri` or `uri` parameter to a JMS URI, which -- at a minimum -- consists of the `jms:` prefix and a destination name. Some examples of JMS URIs are: `jms:SomeQueue`, `jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT`, and `jms:RequestQueue?replyToName=ResponseName`. For more information on this URI syntax, see the https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/transport/jms/JmsMessageSender.html[Javadoc for `JmsMessageSender`]. +To use `JmsMessageSender`, you need to set the `defaultUri` or `uri` parameter to a JMS URI, which -- at a minimum -- consists of the `jms:` prefix and a destination name. Some examples of JMS URIs are: `jms:SomeQueue`, `jms:SomeTopic?priority=3&deliveryMode=NON_PERSISTENT`, and `jms:RequestQueue?replyToName=ResponseName`. For more information on this URI syntax, see the {spring-ws-api}/transport/jms/JmsMessageSender.html[Javadoc for `JmsMessageSender`]. By default, the `JmsMessageSender` sends JMS `BytesMessage`, but you can override this to use `TextMessages` by using the `messageType` parameter on the JMS URI -- for example, `jms:Queue?messageType=TEXT_MESSAGE`. Note that `BytesMessages` are the preferred type, because `TextMessages` do not support attachments and character encodings reliably. -The following example shows how to use the JMS transport in combination with an ActiveMQ connection factory: +The following example shows how to use the JMS transport in combination with an Artemis connection factory: ==== [source,xml] @@ -85,9 +86,9 @@ The following example shows how to use the JMS transport in combination with an - - - + + + @@ -105,7 +106,7 @@ The following example shows how to use the JMS transport in combination with an ===== Email Transport -Spring Web Services also provides an email transport, which you can use to send web service messages over SMTP and retrieve them over either POP3 or IMAP. The client-side email functionality is contained in the `MailMessageSender` class. This class creates an email message from the request `WebServiceMessage` and sends it over SMTP. It then waits for a response message to arrive at the incoming POP3 or IMAP server. +Spring-WS also provides an email transport, which you can use to send web service messages over SMTP and retrieve them over either POP3 or IMAP. The client-side email functionality is contained in {spring-ws-api}/transport/mail/MailMessageSender.html[`MailMessageSender`]. This class creates an email message from the request `WebServiceMessage` and sends it over SMTP. It then waits for a response message to arrive at the incoming POP3 or IMAP server. To use the `MailMessageSender`, set the `defaultUri` or `uri` parameter to a `mailto` URI -- for example, `mailto:john@example.com` or `mailto:server@localhost?subject=SOAP%20Test`. Make sure that the message sender is properly configured with a `transportUri`, which indicates the server to use for sending requests (typically a SMTP server), and a `storeUri`, which indicates the server to poll for responses (typically a POP3 or IMAP server). @@ -136,7 +137,7 @@ The following example shows how to use the email transport: ===== XMPP Transport -Spring Web Services 2.0 introduced an XMPP (Jabber) transport, which you can use to send and receive web service messages over XMPP. The client-side XMPP functionality is contained in the `XmppMessageSender` class. This class creates an XMPP message from the request `WebServiceMessage` and sends it over XMPP. It then listens for a response message to arrive. +Spring-WS also provides a XMPP (Jabber) transport, which you can use to send and receive web service messages over XMPP. The client-side XMPP functionality is contained in {spring-ws-api}/transport/xmpp/XmppMessageSender.html[`XmppMessageSender`]. This class creates an XMPP message from the request `WebServiceMessage` and sends it over XMPP. It then listens for a response message to arrive. To use the `XmppMessageSender`, set the `defaultUri` or `uri` parameter to a `xmpp` URI -- for example, `xmpp:johndoe@jabber.org`. The sender also requires an `XMPPConnection` to work, which can be conveniently created by using the `org.springframework.ws.transport.xmpp.support.XmppConnectionFactoryBean`. @@ -171,7 +172,7 @@ The following example shows how to use the XMPP transport: ==== Message factories -In addition to a message sender, the `WebServiceTemplate` requires a web service message factory. There are two message factories for SOAP: `SaajSoapMessageFactory` and `AxiomSoapMessageFactory`. If no message factory is specified (by setting the `messageFactory` property), Spring-WS uses the `SaajSoapMessageFactory` by default. +In addition to a message sender, the `WebServiceTemplate` requires a web service message factory. By default, `SaajSoapMessageFactory` is used. === Sending and Receiving a `WebServiceMessage` @@ -216,13 +217,15 @@ public class WebServiceClient { } ---- +==== +==== [source,xml] ---- - + @@ -232,7 +235,7 @@ public class WebServiceClient { The preceding example uses the `WebServiceTemplate` to send a "`Hello, World`" message to the web service located at `http://localhost:8080/WebService` (in the case of the `simpleSendAndReceive()` method) and writes the result to the console. The `WebServiceTemplate` is injected with the default URI, which is used because no URI was supplied explicitly in the Java code. -Note that the `WebServiceTemplate` class is thread-safe once configured (assuming that all of its dependencies are also thread-safe, which is the case for all of the dependencies that ship with Spring-WS), so multiple objects can use the same shared `WebServiceTemplate` instance. The `WebServiceTemplate` exposes a zero-argument constructor and `messageFactory` and `messageSender` bean properties that you can use to construct the instance (by using a Spring container or plain Java code). Alternatively, consider deriving from Spring-WS's `WebServiceGatewaySupport` convenience base class, which exposes convenient bean properties to enable easy configuration. (You do not have to extend this base class. It is provided as a convenience class only.) +Note that the `WebServiceTemplate` class is thread-safe once configured (assuming that all of its dependencies are also thread-safe, which is the case for all of the dependencies that ship with Spring-WS), so multiple objects can use the same shared `WebServiceTemplate` instance. The `WebServiceTemplate` exposes a zero-argument constructor and `messageFactory` and `messageSender` bean properties that you can use to construct the instance (by using a Spring container or plain Java code). Alternatively, consider deriving from Spring-WS's `WebServiceGatewaySupport` convenience base class, which exposes bean properties to enable easy configuration. (You do not have to extend this base class. It is provided as a convenience class only.) === Sending and Receiving POJOs -- Marshalling and Unmarshalling @@ -262,9 +265,9 @@ NOTE: Note that you can also use the `org.springframework.ws.soap.client.core.So ==== WS-Addressing -In addition to the <> support, Spring Web Services also has support for this specification on the client-side. +In addition to the <> support, Spring-WS also has support for this specification on the client-side. -For setting WS-Addressing headers on the client, you can use `org.springframework.ws.soap.addressing.client.ActionCallback`. This callback takes the desired action header as a parameter. It also has constructors for specifying the WS-Addressing version and a `To` header. If not specified, the `To` header defaults to the URL of the connection being made. +For setting WS-Addressing headers on the client, you can use {spring-ws-api}/soap/addressing/client/ActionCallback.html[`ActionCallback`]. This callback takes the desired action header as a parameter. It also has constructors for specifying the WS-Addressing version and a `To` header. If not specified, the `To` header defaults to the URL of the connection being made. The following example sets the `Action` header to `http://samples/RequestOrder`: @@ -277,7 +280,7 @@ webServiceTemplate.marshalSendAndReceive(o, new ActionCallback("http://samples/R === Using `WebServiceMessageExtractor` -The `WebServiceMessageExtractor` interface is a low-level callback interface that you have full control over the process to extract an `Object` from a received `WebServiceMessage`. The `WebServiceTemplate` invokes the `extractData(..)` method on a supplied `WebServiceMessageExtractor` while the underlying connection to the serving resource is still open. The following example shows the `WebServiceMessageExtractor` in action: +The `WebServiceMessageExtractor` interface is a low-level callback interface that gives you full control over the process to extract an `Object` from a received `WebServiceMessage`. The `WebServiceTemplate` invokes the `extractData(..)` method on a supplied `WebServiceMessageExtractor` while the underlying connection to the serving resource is still open. The following example shows the `WebServiceMessageExtractor` in action: ==== [source,java,subs="verbatim,quotes"] @@ -290,8 +293,8 @@ public void marshalWithSoapActionHeader(final Source s) { }, new WebServiceMessageExtractor() { public Object extractData(WebServiceMessage message) throws IOException { - _// do your own transforms with message.getPayloadResult() - // or message.getPayloadSource()_ + // do your own transforms with message.getPayloadResult() + // or message.getPayloadSource() } } }); @@ -303,17 +306,14 @@ public void marshalWithSoapActionHeader(final Source s) { When it comes to testing your Web service clients (that is, classes that use the `WebServiceTemplate` to access a Web service), you have two possible approaches: -* Write unit tests, which mock away the `WebServiceTemplate` class, `WebServiceOperations` interface, or the complete client class. -+ -The advantage of this approach is that it s easy to accomplish. The disadvantage is that you are not really testing the exact content of the XML messages that are sent over the wire, especially when mocking out the entire client class. - +* Write unit tests, which mock away the `WebServiceTemplate` class, `WebServiceOperations` interface, or the complete client class. The advantage of this approach is that it s easy to accomplish. The disadvantage is that you are not really testing the exact content of the XML messages that are sent over the wire, especially when mocking out the entire client class. * Write integrations tests, which do test the contents of the message. -The first approach can easily be accomplished with mocking frameworks, such as EasyMock, JMock, and others. The next section focuses on writing integration tests, using the test features introduced in Spring Web Services 2.0. +The first approach can easily be accomplished with mocking frameworks, such as Mockito, EasyMock, and others. The next section focuses on writing integration tests. === Writing Client-side Integration Tests -Spring Web Services 2.0 introduced support for creating Web service client integration tests. In this context, a client is a class that uses the `WebServiceTemplate` to access a web service. +Spring-WS has support for creating for creating Web service client integration tests. In this context, a client is a class that uses the `WebServiceTemplate` to access a web service. The integration test support lives in the `org.springframework.ws.test.client` package. The core class in that package is the `MockWebServiceServer`. The underlying idea is that the web service template connects to this mock server and sends it a request message, which the mock server then verifies against the registered expectations. If the expectations are met, the mock server then prepares a response message, which is sent back to the template. @@ -325,9 +325,15 @@ The typical usage of the `MockWebServiceServer` is: . . Use the `WebServiceTemplate` as normal, either directly of through client code. . Call `MockWebServiceServer.verify()` to make sure that all expectations have been met. -NOTE: Note that the `MockWebServiceServer` (and related classes) offers a 'fluent' API, so you can typically use the code-completion features in your IDE to guide you through the process of setting up the mock server. +[NOTE] +==== +`MockWebServiceServer` (and related classes) offers a 'fluent' API, so you can typically use the code-completion features in your IDE to guide you through the process of setting up the mock server. +==== -NOTE: Also note that you can rely on the standard logging features available in Spring Web Services in your unit tests. Sometimes, it might be useful to inspect the request or response message to find out why a particular tests failed. See <> for more information. +[NOTE] +==== +You can rely on the standard logging features available in Spring-WS in your unit tests. Sometimes, it might be useful to inspect the request or response message to find out why a particular tests failed. See <> for more information. +==== Consider, for example, the following Web service client class: @@ -341,10 +347,8 @@ public class CustomerClient extends WebServiceGatewaySupport { public int getCustomerCount() { CustomerCountRequest request = new CustomerCountRequest(); //<2> request.setCustomerName("John Doe"); - CustomerCountResponse response = (CustomerCountResponse) getWebServiceTemplate().marshalSendAndReceive(request); //<3> - return response.getCustomerCount(); } @@ -373,18 +377,18 @@ import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; -import org.springframework.ws.test.client.MockWebServiceServer; //<1> -import static org.springframework.ws.test.client.RequestMatchers.*; //<1> -import static org.springframework.ws.test.client.ResponseCreators.*; //<1> +import org.springframework.ws.test.client.MockWebServiceServer; +import static org.springframework.ws.test.client.RequestMatchers.*; +import static org.springframework.ws.test.client.ResponseCreators.*; -@RunWith(SpringJUnit4ClassRunner.class) //<2> -@ContextConfiguration("integration-test.xml") //<2> +@RunWith(SpringJUnit4ClassRunner.class) //<1> +@ContextConfiguration("integration-test.xml") public class CustomerClientIntegrationTest { @Autowired - private CustomerClient client; //<3> + private CustomerClient client; //<2> - private MockWebServiceServer mockServer; //<4> + private MockWebServiceServer mockServer; //<3> @Before public void createServer() throws Exception { @@ -393,37 +397,36 @@ public class CustomerClientIntegrationTest { @Test public void customerClient() throws Exception { - Source requestPayload = new StringSource( - "" + - "John Doe" + - ""); - Source responsePayload = new StringSource( - "" + - "10" + - ""); + Source requestPayload = new StringSource(""" + + John Doe + + """); + Source responsePayload = new StringSource(""" + + 10 + + """); - mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));//<5> + mockServer.expect(payload(requestPayload)).andRespond(withPayload(responsePayload));//<4> - int result = client.getCustomerCount(); //<6> - assertEquals(10, result); //<6> + int result = client.getCustomerCount(); //<5> + assertEquals(10, result); - mockServer.verify(); //<7> + mockServer.verify(); //<6> } } ---- -<1> The `CustomerClientIntegrationTest` imports the `MockWebServiceServer` and statically imports `RequestMatchers` and `ResponseCreators`. -<2> This test uses the standard testing facilities provided in the Spring Framework. This is not required but is generally the easiest way to set up the test. -<3> The `CustomerClient` is configured in `integration-test.xml` and wired into this test using `@Autowired`. -<4> In a `@Before` method, we create a `MockWebServiceServer` by using the `createServer` factory method. -<5> We define expectations by calling `expect()` with a `payload()` `RequestMatcher` provided by the statically imported `RequestMatchers` (see <>). -+ +<1> This test uses the standard testing facilities provided in the Spring Framework. This is not required but is generally the easiest way to set up the test. +<2> The `CustomerClient` is configured in `integration-test.xml` and wired into this test using `@Autowired`. +<3> In a `@Before` method, we create a `MockWebServiceServer` by using the `createServer` factory method. +<4> We define expectations by calling `expect()` with a `payload()` `RequestMatcher` provided by the statically imported `RequestMatchers` (see <>). We also set up a response by calling `andRespond()` with a `withPayload()` `ResponseCreator` provided by the statically imported `ResponseCreators` (see <>). -+ This part of the test might look a bit confusing, but the code-completion features of your IDE are of great help. After you type `expect(`, your IDE can provide you with a list of possible request matching strategies, provided you statically imported `RequestMatchers`. The same applies to `andRespond(`, provided you statically imported `ResponseCreators`. -<6> We call `getCustomerCount()` on the `CustomerClient`, thus using the `WebServiceTemplate`. The template has been set up for "`testing mode`" by now, so no real (HTTP) connection is made by this method call. We also make some JUnit assertions based on the result of the method call. -<7> We call `verify()` on the `MockWebServiceServer`, verifying that the expected message was actually received. +<5> We call `getCustomerCount()` on the `CustomerClient`, thus using the `WebServiceTemplate`. The template has been set up for "`testing mode`" by now, so no real (HTTP) connection is made by this method call. We also make some JUnit assertions based on the result of the method call. +<6> We call `verify()` on the `MockWebServiceServer`, verifying that the expected message was actually received. ==== [[client-test-request-matcher]] @@ -436,10 +439,9 @@ To verify whether the request message meets certain expectations, the `MockWebSe ---- public interface RequestMatcher { - void match(URI uri, - WebServiceMessage request) - throws IOException, - AssertionError; + void match(URI uri, WebServiceMessage request) + throws IOException, AssertionError; + } ---- ==== @@ -487,7 +489,7 @@ mockServer.expect(connectionTo("http://example.com")). ---- ==== -For more information on the request matchers provided by `RequestMatchers`, see the https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/test/client/RequestMatchers.html[Javadoc]. +For more information on the request matchers provided by `RequestMatchers`, see the {spring-ws-api}/test/client/RequestMatchers.html[Javadoc]. [[client-test-response-creator]] === Using `ResponseCreator` and `ResponseCreators` @@ -499,8 +501,7 @@ When the request message has been verified and meets the defined expectations, t ---- public interface ResponseCreator { - WebServiceMessage createResponse(URI uri, - WebServiceMessage request, + WebServiceMessage createResponse(URI uri, WebServiceMessage request, WebServiceMessageFactory messageFactory) throws IOException; @@ -530,4 +531,4 @@ The `ResponseCreators` class provides the following responses: | Creates a response message with a given SOAP fault. This method gives you the opportunity to test your Fault handling. |=== -For more information on the request matchers provided by `RequestMatchers`, see the https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/test/client/RequestMatchers.html[Javadoc]. +For more information on the request matchers provided by `RequestMatchers`, see the {spring-ws-api}/test/client/RequestMatchers.html[Javadoc]. diff --git a/spring-ws-docs/src/docs/asciidoc/common.adoc b/spring-ws-docs/src/docs/asciidoc/common.adoc index 994a1bd3..c185b597 100644 --- a/spring-ws-docs/src/docs/asciidoc/common.adoc +++ b/spring-ws-docs/src/docs/asciidoc/common.adoc @@ -13,7 +13,7 @@ This section describes the messages and message factories that Spring-WS uses. [[web-service-message]] === `WebServiceMessage` -One of the core interfaces of Spring Web Services is the `WebServiceMessage`. This interface represents a protocol-agnostic XML message. The interface contains methods that provide access to the payload of the message, in the form of a `javax.xml.transform.Source` or a `javax.xml.transform.Result`. `Source` and `Result` are tagging interfaces that represent an abstraction over XML input and output. Concrete implementations wrap various XML representations, as indicated in the following table: +One of the core interfaces of Spring-WS is the `WebServiceMessage`. This interface represents a protocol-agnostic XML message. The interface contains methods that provide access to the payload of the message, in the form of a `javax.xml.transform.Source` or a `javax.xml.transform.Result`. `Source` and `Result` are tagging interfaces that represent an abstraction over XML input and output. Concrete implementations wrap various XML representations, as indicated in the following table: [cols="2", options="header"] |=== @@ -49,7 +49,7 @@ In addition to reading from and writing to the payload, a web service message ca [[message-factories]] === Message Factories -Concrete message implementations are created by a `WebServiceMessageFactory`. This factory can create an empty message or read a message from an input stream. There are two concrete implementations of `WebServiceMessageFactory`. One is based on SAAJ, the SOAP with Attachments API for Java. The other is based on Axis 2's AXIOM (AXis Object Model). +Concrete message implementations are created by a `WebServiceMessageFactory`. This factory can create an empty message or read a message from an input stream. One concrete implementations of `WebServiceMessageFactory` is provided based on SAAJ, the SOAP with Attachments API for Java. ==== `SaajSoapMessageFactory` @@ -72,7 +72,7 @@ The `SaajSoapMessageFactory` uses the SOAP with Attachments API for Java (SAAJ) | SUN Glassfish 1 | 1.3 -2+|^1^Weblogic 9 has a known bug in the SAAJ 1.2 implementation: it implements all the 1.2 interfaces but throws an `UnsupportedOperationException` when called. Spring Web Services has a workaround: It uses SAAJ 1.1 when operating on WebLogic 9. +2+|^1^Weblogic 9 has a known bug in the SAAJ 1.2 implementation: it implements all the 1.2 interfaces but throws an `UnsupportedOperationException` when called. Spring-WS has a workaround: It uses SAAJ 1.1 when operating on WebLogic 9. |=== Additionally, Java SE 6 includes SAAJ 1.3. You can wire up a `SaajSoapMessageFactory` as follows: @@ -84,35 +84,12 @@ Additionally, Java SE 6 includes SAAJ 1.3. You can wire up a `SaajSoapMessageFac ---- ==== -NOTE: SAAJ is based on DOM, the Document Object Model. This means that all SOAP messages are stored in memory. For larger SOAP messages, this may not be performant. In that case, the `AxiomSoapMessageFactory` might be more applicable. - -==== `AxiomSoapMessageFactory` - -The `AxiomSoapMessageFactory` uses the AXis 2 Object Model (AXIOM) to create `SoapMessage` implementations. AXIOM is based on StAX, the Streaming API for XML. StAX provides a pull-based mechanism for reading XML messages, which can be more efficient for larger messages. - -To increase reading performance on the `AxiomSoapMessageFactory`, you can set the `payloadCaching` property to false (default is true). Doing so causesthe contents of the SOAP body to be read directly from the socket stream. When this setting is enabled, the payload can be read only once. This means that you have to make sure that any pre-processing (logging or other work) of the message does not consume it. - -You can use the `AxiomSoapMessageFactory` as follows: - -==== -[source,xml] ----- - - - ----- -==== - -In addition to payload caching, AXIOM supports full streaming messages, as defined in the `StreamingWebServiceMessage`. This means that you can directly set the payload on the response message, rather than writing it to a DOM tree or buffer. - -Full streaming for AXIOM is used when a handler method returns a JAXB2-supported object. It automatically sets this marshalled object into the response message and writes it out to the outgoing socket stream when the response is going out. - -For more information about full streaming, see the class-level Javadoc for `StreamingWebServiceMessage` and `StreamingPayload`. +NOTE: SAAJ is based on DOM, the Document Object Model. This means that all SOAP messages are stored in memory. For larger SOAP messages, this may not be performant. [[soap_11_or_12]] ==== SOAP 1.1 or 1.2 -Both the `SaajSoapMessageFactory` and the `AxiomSoapMessageFactory` have a `soapVersion` property, where you can inject a `SoapVersion` constant. By default, the version is 1.1, but you can set it to 1.2: +`SaajSoapMessageFactory` has a `soapVersion` property, where you can inject a `SoapVersion` constant. By default, the version is 1.1, but you can set it to 1.2: ==== [source,xml] @@ -149,14 +126,14 @@ One important thing to note with SOAP version numbers (or WS-* specification ver Typically, messages come in pairs: a request and a response. A request is created on the client-side, which is sent over some transport to the server-side, where a response is generated. This response gets sent back to the client, where it is read. -In Spring Web Services, such a conversation is contained in a `MessageContext`, which has properties to get request and response messages. On the client-side, the message context is created by the <>. On the server-side, the message context is read from the transport-specific input stream. For example, in HTTP, it is read from the `HttpServletRequest`, and the response is written back to the `HttpServletResponse`. +In Spring-WS, such a conversation is contained in a `MessageContext`, which has properties to get request and response messages. On the client-side, the message context is created by the <>. On the server-side, the message context is read from the transport-specific input stream. For example, in HTTP, it is read from the `HttpServletRequest`, and the response is written back to the `HttpServletResponse`. [[transport-context]] == `TransportContext` One of the key properties of the SOAP protocol is that it tries to be transport-agnostic. This is why, for instance, Spring-WS does not support mapping messages to endpoints by HTTP request URL but rather by message content. -However, it is sometimes necessary to get access to the underlying transport, either on the client or the server side. For this, Spring Web Services has the `TransportContext`. The transport context allows access to the underlying `WebServiceConnection`, which typically is a `HttpServletConnection` on the server side or a `HttpUrlConnection` or `CommonsHttpConnection` on the client side. For example, you can obtain the IP address of the current request in a server-side endpoint or interceptor: +However, it is sometimes necessary to get access to the underlying transport, either on the client or the server side. For this, Spring-WS has the `TransportContext`. The transport context allows access to the underlying `WebServiceConnection`, which typically is a `HttpServletConnection` on the server side or a `HttpUrlConnection` or `CommonsHttpConnection` on the client side. For example, you can obtain the IP address of the current request in a server-side endpoint or interceptor: ==== [source,java] @@ -176,7 +153,7 @@ One of the best ways to handle XML is to use XPath. Quoting <>, i [quote, Elliotte Rusty Harold] XPath is a fourth generation declarative language that allows you to specify which nodes you want to process without specifying exactly how the processor is supposed to navigate to those nodes. XPath's data model is very well designed to support exactly what almost all developers want from XML. For instance, it merges all adjacent text including that in CDATA sections, allows values to be calculated that skip over comments and processing instructions` and include text from child and descendant elements, and requires all external entity references to be resolved. In practice, XPath expressions tend to be much more robust against unexpected but perhaps insignificant changes in the input document. -Spring Web Services has two ways to use XPath within your application: the faster `XPathExpression` or the more flexible `XPathTemplate`. +Spring-WS has two ways to use XPath within your application: the faster `XPathExpression` or the more flexible `XPathOperations`. [[xpath-expression]] === `XPathExpression` @@ -261,9 +238,9 @@ public class MyXPathClass { Similar to mapping rows in Spring JDBC's `RowMapper`, each result node is mapped by using an anonymous inner class. In this case, we create a `Contact` object, which we use later on. [[xpath-template]] -=== `XPathTemplate` +=== `XPathOperations` -The `XPathExpression` lets you evaluate only a single, pre-compiled expression. A more flexible, though slower, alternative is the `XpathTemplate`. This class follows the common template pattern used throughout Spring (`JdbcTemplate`, `JmsTemplate`, and others). The following listing shows an example: +The `XPathExpression` lets you evaluate only a single, pre-compiled expression. A more flexible, though slower, alternative is the `XPathOperations`. This class follows the common template pattern used throughout Spring (`JdbcTemplate`, `JmsTemplate`, and others). The following listing shows an example: ==== [source,java,subs="verbatim,quotes"] @@ -286,28 +263,27 @@ public class MyXPathClass { [[logging]] == Message Logging and Tracing -When developing or debugging a web service, it can be quite useful to look at the content of a (SOAP) message when it arrives or before it is sent. Spring Web Services offer this functionality, through the standard Commons Logging interface. - -WARNING: Make sure to use Commons Logging version 1.1 or higher. Earlier versions have class loading issues and do not integrate with the Log4J TRACE level. +When developing or debugging a web service, it can be quite useful to look at the content of a (SOAP) message when it arrives or before it is sent. Spring-WS offer this functionality, through the standard Commons Logging interface. To log all server-side messages, set the `org.springframework.ws.server.MessageTracing` logger level to `DEBUG` or `TRACE`. On the `DEBUG` level, only the payload root element is logged. On the `TRACE` level, the entire message content is logged. If you want to log only sent messages, use the `org.springframework.ws.server.MessageTracing.sent` logger. Similarly, you can use `org.springframework.ws.server.MessageTracing.received` to log only received messages. On the client-side, similar loggers exist: `org.springframework.ws.client.MessageTracing.sent` and `org.springframework.ws.client.MessageTracing.received`. -The following example of a `log4j.properties` configuration file logs the full content of sent messages on the client side and only the payload root element for client-side received messages. On the server-side, the payload root is logged for both sent and received messages: +The following example of a `log4j2.properties` configuration file logs the full content of sent messages on the client side and only the payload root element for client-side received messages. On the server-side, the payload root is logged for both sent and received messages: ==== [source] ---- -log4j.rootCategory=INFO, stdout -log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE -log4j.logger.org.springframework.ws.client.MessageTracing.received=DEBUG +appender.console.name=STDOUT +appender.console.type=Console +appender.console.layout.type=PatternLayout +appender.console.layout.pattern=%-5p [%c{3}] %m%n -log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG +rootLogger=DEBUG,STDOUT +logger.org.springframework.ws.client.MessageTracing.sent=TRACE +logger.org.springframework.ws.client.MessageTracing.received=DEBUG +logger.org.springframework.ws.server.MessageTracing=DEBUG -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%p [%c{3}] %m%n ---- ==== diff --git a/spring-ws-docs/src/docs/asciidoc/index.adoc b/spring-ws-docs/src/docs/asciidoc/index.adoc index 7dca416b..75500fa1 100644 --- a/spring-ws-docs/src/docs/asciidoc/index.adoc +++ b/spring-ws-docs/src/docs/asciidoc/index.adoc @@ -1,5 +1,5 @@ = Spring Web Services Reference Documentation -Arjen Poutsma, Rick Evans, Tareq Abed Rabbo, Greg Turnquist, Jay Bryant, Corneil du Plessis +Arjen Poutsma, Rick Evans, Tareq Abed Rabbo, Greg Turnquist, Jay Bryant, Corneil du Plessis, Stéphane Nicoll :doctype: book :revnumber: {gradle-project-version} :revdate: {localdate} @@ -7,8 +7,12 @@ Arjen Poutsma, Rick Evans, Tareq Abed Rabbo, Greg Turnquist, Jay Bryant, Corneil :toclevels: 4 :source-highlighter: prettify :sectnumlevels: 3 - -(C) 2005-2020 The original authors. +:docs-site: https://docs.spring.io +:spring-framework-docs-root: {docs-site}/spring-framework/docs +:spring-framework-api: {spring-framework-docs-root}/{spring-framework-version}/javadoc-api/org/springframework +:spring-framework-docs: https://docs.spring.io/spring-framework/reference +:spring-ws-docs-root: {docs-site}/spring-ws/docs +:spring-ws-api: {spring-ws-docs-root}/{spring-ws-version}/api/org/springframework/ws NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically. @@ -21,7 +25,7 @@ include::preface.adoc[leveloffset=+1] = I. Introduction :sectnums: -This first part of the reference documentation <> of Spring Web Services and the underlying concepts. Spring-WS is then introduced, and <> behind contract-first web service development are explained. +This first part of the reference documentation <> of Spring Web Services and the underlying concepts. Then, <> behind contract-first web service development are explained. Finally, the third section provides <>. include::what-is-spring-ws.adoc[leveloffset=+1] diff --git a/spring-ws-docs/src/docs/asciidoc/preface.adoc b/spring-ws-docs/src/docs/asciidoc/preface.adoc index 13370a6d..781f0412 100644 --- a/spring-ws-docs/src/docs/asciidoc/preface.adoc +++ b/spring-ws-docs/src/docs/asciidoc/preface.adoc @@ -4,4 +4,4 @@ In the current age of Service Oriented Architectures, more and more people use web services to connect previously unconnected systems. Initially, web services were considered to be just another way to do a Remote Procedure Call (RPC). Over time, however, people found out that there is a big difference between RPCs and web services. Especially when interoperability with other platforms is important, it is often better to send encapsulated XML documents that contain all the data necessary to process the request. Conceptually, XML-based web services are better compared to message queues than to remoting solutions. Overall, XML should be considered the platform-neutral representation of data, the _common language_ of SOA. When developing or using web services, the focus should be on this XML and not on Java. -Spring Web Services focuses on creating these document-driven web services. Spring Web Services facilitates contract-first SOAP service development, allowing for the creation of flexible web services by using one of the many ways to manipulate XML payloads. Spring-WS provides a powerful <>, a <> solution that integrates with your existing application security solution, and a <> that follows the familiar Spring template pattern. +Spring-WS focuses on creating these document-driven web services. Spring-WS facilitates contract-first SOAP service development, allowing for the creation of flexible web services by using one of the many ways to manipulate XML payloads. Spring-WS provides a powerful <>, a <> solution that integrates with your existing application security solution, and a <> that follows the familiar Spring template pattern. diff --git a/spring-ws-docs/src/docs/asciidoc/security.adoc b/spring-ws-docs/src/docs/asciidoc/security.adoc index c43ce797..c9548bc9 100644 --- a/spring-ws-docs/src/docs/asciidoc/security.adoc +++ b/spring-ws-docs/src/docs/asciidoc/security.adoc @@ -3,26 +3,30 @@ This chapter explains how to add WS-Security aspects to your Web services. We focus on the three different areas of WS-Security: -* *Authentication*: This is the process of determining whether a principal is who they claim to be. In this context, a "`principal`" generally means a user, device or some other system that can perform an action in your application. - +* *Authentication*: This is the process of determining whether a principal is who they claim to be. In this context, a "principal" generally means a user, device or some other system that can perform an action in your application. * *Digital signatures*: The digital signature of a message is a piece of information based on both the document and the signer's private key. It is created through the use of a hash function and a private signing function (encrypting with the signer's private key). - * *Encryption and Decryption*: Encryption is the process of transforming data into a form that is impossible to read without the appropriate key. It is mainly used to keep information hidden from anyone for whom it is not intended. Decryption is the reverse of encryption. It is the process of transforming encrypted data back into an readable form. These three areas are implemented by using the `XwsSecurityInterceptor` or `Wss4jSecurityInterceptor`, which we describe in <> and <>, respectively -NOTE: Note that WS-Security (especially encryption and signing) requires substantial amounts of memory and can decrease performance. If performance is important to you, you might want to consider not using WS-Security or using HTTP-based security. +[NOTE] +==== +WS-Security (especially encryption and signing) requires substantial amounts of memory and can decrease performance. If performance is important to you, you might want to consider not using WS-Security or using HTTP-based security. +==== [[security-xws-security-interceptor]] == `XwsSecurityInterceptor` -The `XwsSecurityInterceptor` is an `EndpointInterceptor` (see <>) that is based on SUN's XML and Web Services Security package (XWSS). This WS-Security implementation is part of the Java Web Services Developer Pack (http://java.sun.com/webservices/[Java WSDP]). +The `XwsSecurityInterceptor` is an `EndpointInterceptor` (see <>) that is based on SUN's XML and Web Services Security package (XWSS). This WS-Security implementation is part of the Java Web Services Developer Pack (https://www.oracle.com/java/technologies/java-archive-jwsdp-downloads.html[Java WSDP]). Like any other endpoint interceptor, it is defined in the endpoint mapping (see <>). This means that you can be selective about adding WS-Security support. Some endpoint mappings require it, while others do not. -NOTE: Note that XWSS requires both a SUN 1.5 JDK and the SUN SAAJ reference implementation. The WSS4J interceptor does not have these requirements (see <>). +[NOTE] +==== +XWSS requires a SUN SAAJ reference implementation. The WSS4J interceptor does not have these requirements (see <>). +==== -The `XwsSecurityInterceptor` requires a security policy file to operate. This XML file tells the interceptor what security aspects to require from incoming SOAP messages and what aspects to add to outgoing messages. The basic format of the policy file is explained in the following sections, but you can find a more in-depth tutorial http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp564887[here]. You can set the policy with the `policyConfiguration` property, which requires a Spring resource. The policy file can contain multiple elements -- for example, require a username token on incoming messages and sign all outgoing messages. It contains a `SecurityConfiguration` element (not a `JAXRPCSecurity` element) as its root. +The `XwsSecurityInterceptor` requires a security policy file to operate. This XML file tells the interceptor what security aspects to require from incoming SOAP messages and what aspects to add to outgoing messages. The basic format of the policy file is explained in the following sections, but a more in-depth tutorial https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp564887[is available]. You can set the policy with the `policyConfiguration` property, which requires a Spring resource. The policy file can contain multiple elements -- for example, require a username token on incoming messages and sign all outgoing messages. It contains a `SecurityConfiguration` element (not a `JAXRPCSecurity` element) as its root. Additionally, the security interceptor requires one or more `CallbackHandler` instances to operate. These handlers are used to retrieve certificates, private keys, validate user credentials, and so on. Spring-WS offers handlers for most common security concerns -- for example, authenticating against a Spring Security authentication manager and signing outgoing messages based on a X509 certificate. The following sections indicate what callback handler to use for which security concern. You can set the callback handlers by using the `callbackHandler` or `callbackHandlers` property. @@ -57,14 +61,12 @@ For most cryptographic operations, you an use the standard `java.security.KeySto The `java.security.KeyStore` class represents a storage facility for cryptographic keys and certificates. It can contain three different sort of elements: * *Private Keys*: These keys are used for self-authentication. The private key is accompanied by a certificate chain for the corresponding public key. Within the field of WS-Security, this accounts for message signing and message decryption. - * *Symmetric Keys*: Symmetric (or secret) keys are also used for message encryption and decryption -- the difference being that both sides (sender and recipient) share the same secret key. - -* *Trusted certificates*: These X509 certificates are called a "`trusted certificate`" because the keystore owner trusts that the public key in the certificates does indeed belong to the owner of the certificate. Within WS-Security, these certificates are used for certificate validation, signature verification, and encryption. +* *Trusted certificates*: These X509 certificates are called a "trusted certificate" because the keystore owner trusts that the public key in the certificates does indeed belong to the owner of the certificate. Within WS-Security, these certificates are used for certificate validation, signature verification, and encryption. ==== Using `keytool` -The `keytool` program, a key and certificate management utility, is supplied with your Java Virtual Machine. You can use this tool to create new keystores, add new private keys and certificates to them, and so on. It is beyond the scope of this document to provide a full reference of the `keytool` command, but you can find a reference http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/keytool.html[here] or by using the `keytool -help` command on the command line. +The `keytool` program, a key and certificate management utility, is supplied with your Java Virtual Machine. You can use this tool to create new keystores, add new private keys and certificates to them, and so on. It is beyond the scope of this document to provide a full reference of the `keytool` command, check the https://docs.oracle.com/en/java/javase/17/docs/specs/man/keytool.html[standard reference] or invoke `keytool -help` on the command line. ==== Using `KeyStoreFactoryBean` @@ -116,7 +118,7 @@ To use the keystores within a `XwsSecurityInterceptor`, you need to define a `Ke Additionally, the `KeyStoreCallbackHandler` has a `privateKeyPassword` property, which should be set to unlock the private keys contained in the`keyStore`. -If the `symmetricStore` is not set, it defaults to the `keyStore`. If the key or trust store is not set, the callback handler uses the standard Java mechanism to load or create it. See the JavaDoc of the `KeyStoreCallbackHandler` to know how this mechanism works. +If the `symmetricStore` is not set, it defaults to the `keyStore`. If the key or trust store is not set, the callback handler uses the standard Java mechanism to load or create it. See {spring-ws-api}/soap/security/wss4j2/callback/KeyStoreCallbackHandler.html[`KeyStoreCallbackHandler`] for more details. For instance, if you want to use the `KeyStoreCallbackHandler` to validate incoming certificates or signatures, you can use a trust store: @@ -165,9 +167,12 @@ As stated in the <>, authentication is th The simplest form of username authentication uses plain text passwords. In this scenario, the SOAP message contains a `UsernameToken` element, which itself contains a `Username` element and a `Password` element which contains the plain text password. Plain text authentication can be compared to the basic authentication provided by HTTP servers. -WARNING: Note that plain text passwords are not very secure. Therefore, you should always add additional security measures to your transport layer if you use them (using HTTPS instead of plain HTTP, for instance). +[WARNING] +==== +Plain text passwords are not very secure. Therefore, you should always add additional security measures to your transport layer if you use them (using HTTPS instead of plain HTTP, for instance). +==== -To require that every incoming message contains a `UsernameToken` with a plain text password, the security policy file should contain a `RequireUsernameToken` element, with the `passwordDigestRequired` attribute set to `false`. You can find a reference of possible child elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459[here]. The following listing shows how to include a `RequireUsernameToken` element: +To require that every incoming message contains a `UsernameToken` with a plain text password, the security policy file should contain a `RequireUsernameToken` element, with the `passwordDigestRequired` attribute set to `false`. Fore more details, check the https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459[official reference] of possible child elements. The following listing shows how to include a `RequireUsernameToken` element: ==== [source,xml] @@ -189,7 +194,7 @@ If the username token is not present, the `XwsSecurityInterceptor` returns a SOA [[security-simple-password-validation-callback-handler]] ===== Using `SimplePasswordValidationCallbackHandler` -The simplest password validation handler is the `SimplePasswordValidationCallbackHandler`. This handler validates passwords against an in-memory `Properties` object, which you can specify byusing the `users` property: +The simplest password validation handler is the `SimplePasswordValidationCallbackHandler`. This handler validates passwords against an in-memory `Properties` object, which you can specify by using the `users` property: ==== [source,xml] @@ -210,7 +215,7 @@ In this case, we are allowing only the user, "Bert", to log in by using the pass [[using-springplaintextpasswordvalidationcallbackhandler]] ===== Using `SpringPlainTextPasswordValidationCallbackHandler` -The `SpringPlainTextPasswordValidationCallbackHandler` uses https://spring.io/projects/spring-security[Spring Security] to authenticate users. It is beyond the scope of this document to describe Spring Security, but it is a full-fledged security framework. You can read more about it in the https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/[Spring Security reference documentation]. +The `SpringPlainTextPasswordValidationCallbackHandler` uses https://spring.io/projects/spring-security[Spring Security] to authenticate users. It is beyond the scope of this document to describe Spring Security, but it is a full-fledged security framework. You can read more about it in the https://docs.spring.io/spring-security/reference[Spring Security reference documentation]. The `SpringPlainTextPasswordValidationCallbackHandler` requires an `AuthenticationManager` to operate. It uses this manager to authenticate against a `UsernamePasswordAuthenticationToken` that it creates. If authentication is successful, the token is stored in the `SecurityContextHolder`. You can set the authentication manager by using the `authenticationManager` property: @@ -223,12 +228,12 @@ The `SpringPlainTextPasswordValidationCallbackHandler` requires an `Authenticati - - + + - + @@ -240,7 +245,7 @@ The `SpringPlainTextPasswordValidationCallbackHandler` requires an `Authenticati [[using-jaasplaintextpasswordvalidationcallbackhandler]] ===== Using `JaasPlainTextPasswordValidationCallbackHandler` -The `JaasPlainTextPasswordValidationCallbackHandler` is based on the standard http://java.sun.com/products/jaas/[Java Authentication and Authorization Service]. It is beyond the scope of this document to provide a full introduction into JAAS, but a http://www.javaworld.com/javaworld/jw-09-2002/jw-0913-jaas.html[good tutorial] is available. +The `JaasPlainTextPasswordValidationCallbackHandler` is based on the standard https://www.oracle.com/java/technologies/javase/javase-tech-security.html[Java Authentication and Authorization Service]. It is beyond the scope of this document to provide a full introduction into JAAS, but https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/tutorials/index.html[tutorials] are available. The `JaasPlainTextPasswordValidationCallbackHandler` requires only a `loginContextName` to operate. It creates a new JAAS `LoginContext` by using this name and handles the standard JAAS `NameCallback` and `PasswordCallback` by using the username and password provided in the SOAP message. This means that this callback handler integrates with any JAAS `LoginModule` that fires these callbacks during the `login()` phase, which is standard behavior. @@ -262,7 +267,7 @@ In this case, the callback handler uses the `LoginContext` named `MyLoginModule` When using password digests, the SOAP message also contains a `UsernameToken` element, which itself contains a `Username` element and a `Password` element. The difference is that the password is not sent as plain text, but as a digest. The recipient compares this digest to the digest he calculated from the known password of the user, and, if they are the same, the user is authenticated. This method is comparable to the digest authentication provided by HTTP servers. -To require that every incoming message contains a `UsernameToken` element with a password digest, the security policy file should contain a `RequireUsernameToken` element, with the `passwordDigestRequired` attribute set to `true`. Additionally, the `nonceRequired` attribute should be set to `true`: You can find a reference of possible child elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459[here]. The following listing shows how to define a `RequireUsernameToken` element: +To require that every incoming message contains a `UsernameToken` element with a password digest, the security policy file should contain a `RequireUsernameToken` element, with the `passwordDigestRequired` attribute set to `true`. Additionally, the `nonceRequired` attribute should be set to `true`. For more details, check the http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp567459[official reference] of possible child elements. The following listing shows how to define a `RequireUsernameToken` element: ==== [source,xml] @@ -304,7 +309,7 @@ The `SpringDigestPasswordValidationCallbackHandler` requires a Spring Security ` A more secure way of authentication uses X509 certificates. In this scenario, the SOAP message contains a`BinarySecurityToken`, which contains a Base 64-encoded version of a X509 certificate. The certificate is used by the recipient to authenticate. The certificate stored in the message is also used to sign the message (see <>). -To make sure that all incoming SOAP messages carry a`BinarySecurityToken`, the security policy file should contain a `RequireSignature` element. This element can further carry other elements, which are covered in <>. You can find a reference of possible child elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769[here]. The following listing shows how to define a `RequireSignature` element: +To make sure that all incoming SOAP messages carry a`BinarySecurityToken`, the security policy file should contain a `RequireSignature` element. This element can further carry other elements, which are covered in <>. For more details, check the http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769[official reference] of possible child elements. The following listing shows how to define a `RequireSignature` element: ==== [source,xml] @@ -317,11 +322,10 @@ To make sure that all incoming SOAP messages carry a`BinarySecurityToken`, the s ---- ==== -When a message arrives that carries no certificate, the `XwsSecurityInterceptor` returns a SOAP fault to the sender. If it is present, it fires a `CertificateValidationCallback`. Three handlers within Spring-WS handle this callback for authentication purposes: +When a message arrives that carries no certificate, the `XwsSecurityInterceptor` returns a SOAP fault to the sender. If it is present, it fires a `CertificateValidationCallback`. Two handlers within Spring-WS handle this callback for authentication purposes: * <> * <> -* <> [NOTE] ===== @@ -412,25 +416,6 @@ The `SpringCertificateValidationCallbackHandler` requires an Spring Security `Au In this case, we use a custom user details service to obtain authentication details based on the certificate. See the http://www.springframework.org/security[Spring Security reference documentation] for more information about authentication against X509 certificates. -[[using-jaascertificatevalidationcallbackhandler]] -===== Using `JaasCertificateValidationCallbackHandler` - -The `JaasCertificateValidationCallbackHandler` requires a `loginContextName` to operate. It creates a new JAAS `LoginContext` by using this name and the `X500Principal` of the certificate. This means that this callback handler integrates with any JAAS `LoginModule` that handles X500 principals. - -You can wire up a `JaasCertificateValidationCallbackHandler` as follows: - -==== -[source,xml] ----- - - MyLoginModule - ----- -==== - -In this case, the callback handler uses the `LoginContext` named `MyLoginModule`. This module should be defined in your `jaas.config` file and should be able to authenticate against X500 principals. - === Digital Signatures The digital signature of a message is a piece of information based on both the document and the signer's private key. Two main tasks are related to signatures in WS-Security: verifying signatures and signing messages. @@ -440,7 +425,7 @@ The digital signature of a message is a piece of information based on both the d As with <>, a signed message contains a `BinarySecurityToken`, which contains the certificate used to sign the message. Additionally, it contains a `SignedInfo` block, which indicates what part of the message was signed. -To make sure that all incoming SOAP messages carry a `BinarySecurityToken`, the security policy file should contain a `RequireSignature` element. It can also contain a `SignatureTarget` element, which specifies the target message part that was expected to be signed and various other subelements. You can also define the private key alias to use, whether to use a symmetric instead of a private key, and many other properties. You can find a reference of possible child elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769[here]. The following listing configures a `RequireSignature` element: +To make sure that all incoming SOAP messages carry a `BinarySecurityToken`, the security policy file should contain a `RequireSignature` element. It can also contain a `SignatureTarget` element, which specifies the target message part that was expected to be signed and various other sub-elements. You can also define the private key alias to use, whether to use a symmetric instead of a private key, and many other properties. For more details, check the https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565769[official reference] of possible child elements. The following listing configures a `RequireSignature` element: ==== [source,xml] @@ -477,7 +462,7 @@ As described in <>, `KeyStoreCallbackHandle When signing a message, the `XwsSecurityInterceptor` adds the `BinarySecurityToken` to the message. It also adds a `SignedInfo` block, which indicates what part of the message was signed. -To sign all outgoing SOAP messages, the security policy file should contain a `Sign` element. It can also contain a `SignatureTarget` element, which specifies the target message part that was expected to be signed and various other subelements. You can also define the private key alias to use, whether to use a symmetric instead of a private key, and many other properties. You can find a reference of possible child elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565497[here]. The following example includes a `Sign` element: +To sign all outgoing SOAP messages, the security policy file should contain a `Sign` element. It can also contain a `SignatureTarget` element, which specifies the target message part that was expected to be signed and various other sub-elements. You can also define the private key alias to use, whether to use a symmetric instead of a private key, and many other properties. For more details, check the https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565497[official reference] of possible child elements. The following example includes a `Sign` element: ==== [source,xml] @@ -517,7 +502,7 @@ When encrypting, the message is transformed into a form that can be read only wi ==== Decryption -To decrypt incoming SOAP messages, the security policy file should contain a `RequireEncryption` element. This element can further carry a `EncryptionTarget` element that indicates which part of the message should be encrypted and a `SymmetricKey` to indicate that a shared secret instead of the regular private key should be used to decrypt the message. You can read a description of the other elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951[here]. The following example uses a `RequireEncryption` element: +To decrypt incoming SOAP messages, the security policy file should contain a `RequireEncryption` element. This element can further carry a `EncryptionTarget` element that indicates which part of the message should be encrypted and a `SymmetricKey` to indicate that a shared secret instead of the regular private key should be used to decrypt the message. For more details, check the https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951[official reference ] of the other elements. The following example uses a `RequireEncryption` element: ==== [source,xml] @@ -553,7 +538,7 @@ As described in <>, the `KeyStoreCallbackHa ==== Encryption -To encrypt outgoing SOAP messages, the security policy file should contain an `Encrypt` element. This element can further carry a `EncryptionTarget` element that indicates which part of the message should be encrypted and a `SymmetricKey` to indicate that a shared secret instead of the regular public key should be used to encrypt the message. You can read a description of the other elements http://java.sun.com/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951[here]. The following example uses an `Encrypt` element: +To encrypt outgoing SOAP messages, the security policy file should contain an `Encrypt` element. This element can further carry a `EncryptionTarget` element that indicates which part of the message should be encrypted and a `SymmetricKey` to indicate that a shared secret instead of the regular public key should be used to encrypt the message. For more details, check the https://docs.oracle.com/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/XWS-SecurityIntro4.html#wp565951[official reference] of the other elements. The following example uses an `Encrypt` element: ==== [source,xml] @@ -608,7 +593,7 @@ WSS4J implements the following standards: * Username Token profile V1.0 * X.509 Token Profile V1.0 -This interceptor supports messages created by the `AxiomSoapMessageFactory` and the `SaajSoapMessageFactory`. +This interceptor supports messages created by the `SaajSoapMessageFactory`. === Configuring `Wss4jSecurityInterceptor` @@ -675,13 +660,13 @@ The following table shows the available securement actions: | No action performed |=== -The order of the actions is significant and is enforced by the interceptor. If its security actions were performed in a different order than the one specified by`validationActions`, the interceptor rejects an incoming SOAP message. +The order of the actions is significant and is enforced by the interceptor. If its security actions were performed in a different order than the one specified by `validationActions`, the interceptor rejects an incoming SOAP message. === Handling Digital Certificates -For cryptographic operations that require interaction with a keystore or certificate handling (signature, encryption, and decryption operations), WSS4J requires an instance of`org.apache.ws.security.components.crypto.Crypto`. +For cryptographic operations that require interaction with a keystore or certificate handling (signature, encryption, and decryption operations), WSS4J requires an instance of `org.apache.ws.security.components.crypto.Crypto`. -`Crypto` instances can be obtained from WSS4J's `CryptoFactory` or more conveniently with the Spring-WS`CryptoFactoryBean`. +`Crypto` instances can be obtained from WSS4J's `CryptoFactory` or more conveniently with the Spring-WS `CryptoFactoryBean`. ==== CryptoFactoryBean @@ -731,7 +716,7 @@ Callback handlers are configured through the `validationCallbackHandler` of the ===== Using `SpringSecurityPasswordValidationCallbackHandler` -The `SpringSecurityPasswordValidationCallbackHandler` validates plain text and digest passwords by using a Spring Security `UserDetailService` to operate. It uses this service to retrieve the the password (or a digest of the password) of the user specified in the token. The password (or a digest of the password) contained in this details object is then compared with the digest in the message. If they are equal, the user has successfully authenticated, and a `UsernamePasswordAuthenticationToken` is stored in the`SecurityContextHolder`. You can set the service by using the `userDetailsService`. Additionally, you can set a `userCache` property, to cache loaded user details, as follows: +The `SpringSecurityPasswordValidationCallbackHandler` validates plain text and digest passwords by using a Spring Security `UserDetailService` to operate. It uses this service to retrieve the password (or a digest of the password) of the user specified in the token. The password (or a digest of the password) contained in this details object is then compared with the digest in the message. If they are equal, the user has successfully authenticated, and a `UsernamePasswordAuthenticationToken` is stored in the `SecurityContextHolder`. You can set the service by using the `userDetailsService`. Additionally, you can set a `userCache` property, to cache loaded user details, as follows: ==== [source,xml] @@ -749,7 +734,7 @@ The `SpringSecurityPasswordValidationCallbackHandler` validates plain text and d ==== Adding Username Token -Adding a username token to an outgoing message is as simple as adding `UsernameToken` to the `securementActions` property of the `Wss4jSecurityInterceptor` and specifying `securementUsername` and`securementPassword`. +Adding a username token to an outgoing message is as simple as adding `UsernameToken` to the `securementActions` property of the `Wss4jSecurityInterceptor` and specifying `securementUsername` and `securementPassword`. The password type can be set by setting the `securementPasswordType` property. Possible values are `PasswordText` for plain text passwords or `PasswordDigest` for digest passwords, which is the default. @@ -913,7 +898,7 @@ You can customize the key identifier type to use by setting the `securementSigna The `securementSignatureParts` property controls which part of the message is signed. The value of this property is a list of semicolon-separated element names that identify the elements to sign. The general form of a signature part is `{}{namespace}Element`. Note that the first empty brackets are used for encryption parts only. The default behavior is to sign the SOAP body. -The following example shows how to sign the `echoResponse` element in the Spring Web Services echo sample: +The following example shows how to sign the `echoResponse` element in the Spring-WS echo sample: ==== [source,xml] @@ -955,21 +940,21 @@ This section describes the various decryption and encryption options available i Decryption of incoming SOAP messages requires that the `Encrypt` action be added to the `validationActions` property. The rest of the configuration depends on the key information that appears in the message. (This is because WSS4J needs only a Crypto for encypted keys, whereas embedded key name validation is delegated to a callback handler.) -To decrypt messages with an embedded encrypted symmetric key (the `xenc:EncryptedKey` element), `validationDecryptionCrypto` needs to point to a keystore that contains the decryption private key. Additionally, `validationCallbackHandler` has to be injected with a `org.springframework.ws.soap.security.wss4j.callback.KeyStoreCallbackHandler` that specifies the key's password: +To decrypt messages with an embedded encrypted symmetric key (the `xenc:EncryptedKey` element), `validationDecryptionCrypto` needs to point to a keystore that contains the decryption private key. Additionally, `validationCallbackHandler` has to be injected with a {spring-ws-api}/soap/security/wss4j2/callback/KeyStoreCallbackHandler.html[`KeyStoreCallbackHandler`] that specifies the key's password: ==== [source,xml] ---- - + - + - + @@ -982,10 +967,10 @@ To support decryption of messages with an embedded key name ( `ds:KeyName` eleme ==== [source,xml] ---- - + - + @@ -1007,11 +992,11 @@ Adding `Encrypt` to the `securementActions` enables encryption of outgoing messa ==== [source,xml] ---- - + - + @@ -1027,13 +1012,13 @@ If you choose the `EmbeddedKeyName` type, you need to specify the secret key to ==== [source,xml] ---- - + - + diff --git a/spring-ws-docs/src/docs/asciidoc/server.adoc b/spring-ws-docs/src/docs/asciidoc/server.adoc index f0e854f2..f3453353 100644 --- a/spring-ws-docs/src/docs/asciidoc/server.adoc +++ b/spring-ws-docs/src/docs/asciidoc/server.adoc @@ -33,12 +33,12 @@ The message dispatcher operates on a <> and not == Transports -Spring Web Services supports multiple transport protocols. The most common is the HTTP transport, for which a custom servlet is supplied, but you can also send messages over JMS and even email. +Spring-WS supports multiple transport protocols. The most common is the HTTP transport, for which a custom servlet is supplied, but you can also send messages over JMS and even email. [[message-dispatcher-servlet]] === `MessageDispatcherServlet` -The `MessageDispatcherServlet` is a standard `Servlet` that conveniently extends from the standard Spring Web `DispatcherServlet` and wraps a `MessageDispatcher`. As a result, it combines the attributes of these into one. As a `MessageDispatcher`, it follows the same request handling flow as described in the previous section. As a servlet, the `MessageDispatcherServlet` is configured in the `web.xml` of your web application. Requests that you want the `MessageDispatcherServlet` to handle must be mapped by a URL mapping in the same `web.xml` file. This is standard Java EE servlet configuration. The following example shows such a `MessageDispatcherServlet` declaration and mapping: +The `MessageDispatcherServlet` is a standard `Servlet` that conveniently extends from the standard Spring Web `DispatcherServlet` and wraps a `MessageDispatcher`. As a result, it combines the attributes of these into one. As a `MessageDispatcher`, it follows the same request handling flow as described in the previous section. As a servlet, the `MessageDispatcherServlet` is configured in the `web.xml` of your web application. Requests that you want the `MessageDispatcherServlet` to handle must be mapped by a URL mapping in the same `web.xml` file. This is standard JavaEE servlet configuration. The following example shows such a `MessageDispatcherServlet` declaration and mapping: ==== [source,xml] @@ -60,10 +60,10 @@ The `MessageDispatcherServlet` is a standard `Servlet` that conveniently extends ---- ==== -In the preceding example, all requests are handled by the `spring-ws` `MessageDispatcherServlet`. This is only the first step in setting up Spring Web Services, because the various component beans used by the Spring-WS framework also need to be configured. This configuration consists of standard Spring XML `` definitions. Because the `MessageDispatcherServlet` is a standard Spring `DispatcherServlet`, it -looks for a file named [servlet-name]-servlet.xml in the `WEB-INF` directory of your web application and creates the beans defined there in a Spring container. In the preceding example, it looks for '`/WEB-INF/spring-ws-servlet.xml`'. This file contains all of the Spring Web Services beans, such as endpoints, marshallers, and so on. +In the preceding example, all requests are handled by the `spring-ws` `MessageDispatcherServlet`. This is only the first step in setting up Spring-WS, because the various component beans used by the Spring-WS framework also need to be configured. This configuration consists of standard Spring XML `` definitions. Because the `MessageDispatcherServlet` is a standard Spring `DispatcherServlet`, it +looks for a file named `[servlet-name]-servlet.xml` in the `WEB-INF` directory of your web application and creates the beans defined there in a Spring container. In the preceding example, it looks for `/WEB-INF/spring-ws-servlet.xml`. This file contains all the Spring-WS beans, such as endpoints, marshallers, and so on. -As an alternative for `web.xml`, if you run on a Servlet 3+ environment, you can configure Spring-WS programmatically. For this purpose, Spring-WS provides a number of abstract base classes that extend the `WebApplicationInitializer` interface found in the Spring Framework. If you also use `@Configuration` classes for your bean definitions, you should extend the `AbstractAnnotationConfigMessageDispatcherServletInitializer`: +As an alternative for `web.xml`, you can configure Spring-WS programmatically. For this purpose, Spring-WS provides a number of abstract base classes that extend the `WebApplicationInitializer` interface found in the Spring Framework. If you also use `@Configuration` classes for your bean definitions, you should extend the `AbstractAnnotationConfigMessageDispatcherServletInitializer`: ==== [source,java] @@ -85,7 +85,7 @@ public class MyServletInitializer ---- ==== -In the preceding example, we tell Spring that endpoint bean definitions can be found in the `MyEndpointConfig` class (which is a `@Configuration` class). Other bean definitions (typically services, repositories, and so on) can be found in the `MyRootConfig` class. By default, the `AbstractAnnotationConfigMessageDispatcherServletInitializer` maps the servlet to two patterns: `/services` and `*.wsdl`, though you can change this by overriding the `getServletMappings()` method. For more details on the programmatic configuration of the `MessageDispatcherServlet`, refer to the Javadoc of https://docs.spring.io/spring-ws/docs/current/org/springframework/ws/transport/http/support/AbstractMessageDispatcherServletInitializer.html[`AbstractMessageDispatcherServletInitializer`] and https://docs.spring.io/spring-ws/docs/current/org/springframework/ws/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.html[`AbstractAnnotationConfigMessageDispatcherServletInitializer`]. +In the preceding example, we tell Spring that endpoint bean definitions can be found in the `MyEndpointConfig` class (which is a `@Configuration` class). Other bean definitions (typically services, repositories, and so on) can be found in the `MyRootConfig` class. By default, the `AbstractAnnotationConfigMessageDispatcherServletInitializer` maps the servlet to two patterns: `/services` and `*.wsdl`, though you can change this by overriding the `getServletMappings()` method. For more details on the programmatic configuration of the `MessageDispatcherServlet`, refer to the Javadoc of {spring-ws-api}/transport/http/support/AbstractMessageDispatcherServletInitializer.html[`AbstractMessageDispatcherServletInitializer`] and {spring-ws-api}/transport/http/support/AbstractAnnotationConfigMessageDispatcherServletInitializer.html[`AbstractAnnotationConfigMessageDispatcherServletInitializer`]. [[server-automatic-wsdl-exposure]] ==== Automatic WSDL exposure @@ -153,9 +153,9 @@ Note that this `location` transformation feature is off by default. To switch th If you use `AbstractAnnotationConfigMessageDispatcherServletInitializer`, enabling transformation is as simple as overriding the `isTransformWsdlLocations()` method to return `true`. -Consult the class-level Javadoc on the https://docs.spring.io/spring-ws/docs/current/org/springframework/ws/transport/http/WsdlDefinitionHandlerAdapter.html[`WsdlDefinitionHandlerAdapter`] class to learn more about the whole transformation process. +Consult the class-level Javadoc on the {spring-ws-api}/transport/http/WsdlDefinitionHandlerAdapter.html[`WsdlDefinitionHandlerAdapter`] class to learn more about the whole transformation process. -As an alternative to writing the WSDL by hand and exposing it with ``, Spring Web Services can also generate a WSDL from an XSD schema. This is the approach shown in <>. The next application context snippet shows how to create such a dynamic WSDL file: +As an alternative to writing the WSDL by hand and exposing it with ``, Spring-WS can also generate a WSDL from an XSD schema. This is the approach shown in <>. The next application context snippet shows how to create such a dynamic WSDL file: ==== [source,xml] @@ -178,14 +178,13 @@ public DefaultWsdl11Definition orders() { DefaultWsdl11Definition definition = new DefaultWsdl11Definition(); definition.setPortTypeName("Orders"); definition.setLocationUri("http://localhost:8080/ordersService/"); - definition.setSchema(new SimpleXsdSchema(new ClassPathResource("echo.xsd"))); - + definition.setSchema(new SimpleXsdSchema(new ClassPathResource("Orders.xsd"))); return definition; } ---- ==== -The `` element depends on the `DefaultWsdl11Definition` class. This definition class uses WSDL providers in the https://docs.spring.io/spring-ws/sites/1.5/apidocs/org/springframework/ws/wsdl/wsdl11/provider/package-summary.html[`org.springframework.ws.wsdl.wsdl11.provider`] package and the https://docs.spring.io/spring-ws/docs/current/org/springframework/ws/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.html[`ProviderBasedWsdl4jDefinition`] class to generate a WSDL the first time it is requested. See the class-level Javadoc of these classes to see how you can extend this mechanism, if necessary. +The `` element depends on the `DefaultWsdl11Definition` class. This definition class uses WSDL providers in the https://docs.spring.io/spring-ws/sites/1.5/apidocs/org/springframework/ws/wsdl/wsdl11/provider/package-summary.html[`org.springframework.ws.wsdl.wsdl11.provider`] package and the {spring-ws-api}/wsdl/wsdl11/ProviderBasedWsdl4jDefinition.html[`ProviderBasedWsdl4jDefinition`] class to generate a WSDL the first time it is requested. See the class-level Javadoc of these classes to see how you can extend this mechanism, if necessary. The `DefaultWsdl11Definition` (and therefore, the `` tag) builds a WSDL from an XSD schema by using conventions. It iterates over all `element` elements found in the schema and creates a `message` for all elements. Next, it creates a WSDL `operation` for all messages that end with the defined request or response suffix. The default request suffix is `Request`. The default response suffix is `Response`, though these can be changed by setting the `requestSuffix` and `responseSuffix` attributes on ``, respectively. It also builds a `portType`, `binding`, and `service` based on the operations. @@ -247,7 +246,7 @@ In a similar fashion, you can wire a `WsdlDefinitionHandlerAdapter` to make sure * - + * ... @@ -258,7 +257,7 @@ In a similar fashion, you can wire a `WsdlDefinitionHandlerAdapter` to make sure === JMS transport -Spring Web Services supports server-side JMS handling through the JMS functionality provided in the Spring framework. Spring Web Services provides the `WebServiceMessageListener` to plug in to a `MessageListenerContainer`. This message listener requires a `WebServiceMessageFactory` and `MessageDispatcher` to operate. The following configuration example shows this: +Spring-WS supports server-side JMS handling through the JMS functionality provided in the Spring framework. Spring-WS provides the `WebServiceMessageListener` to plug in to a `MessageListenerContainer`. This message listener requires a `WebServiceMessageFactory` and `MessageDispatcher` to operate. The following configuration example shows this: ==== [source,xml] @@ -298,11 +297,11 @@ Spring Web Services supports server-side JMS handling through the JMS functional === Email Transport -In addition to HTTP and JMS, Spring Web Services also provides server-side email handling. This functionality is provided through the `MailMessageReceiver` class. This class monitors a POP3 or IMAP folder, converts the email to a `WebServiceMessage`, and sends any response by using SMTP. You can configure the host names through the `storeUri`, which indicates the mail folder to monitor for requests (typically a POP3 or IMAP folder), and a `transportUri`, which indicates the server to use for sending responses (typically an SMTP server). +In addition to HTTP and JMS, Spring-WS also provides server-side email handling. This functionality is provided through the `MailMessageReceiver` class. This class monitors a POP3 or IMAP folder, converts the email to a `WebServiceMessage`, and sends any response by using SMTP. You can configure the host names through the `storeUri`, which indicates the mail folder to monitor for requests (typically a POP3 or IMAP folder), and a `transportUri`, which indicates the server to use for sending responses (typically an SMTP server). You can configure how the `MailMessageReceiver` monitors incoming messages with a pluggable strategy: the `MonitoringStrategy`. By default, a polling strategy is used, where the incoming folder is polled for new messages every five minutes. You can change this interval by setting the `pollingInterval` property on the strategy. By default, all `MonitoringStrategy` implementations delete the handled messages. You can change this setting by setting the `deleteMessages` property. -As an alternative to the polling approaches, which are quite inefficient, there is a monitoring strategy that uses IMAP IDLE. The IDLE command is an optional expansion of the IMAP email protocol that lets the mail server send new message updates to the `MailMessageReceiver` asynchronously. If you use an IMAP server that supports the IDLE command, you can plug the `ImapIdleMonitoringStrategy` into the `monitoringStrategy` property. In addition to a supporting server, you need to use JavaMail version 1.4.1 or higher. +As an alternative to the polling approaches, which are quite inefficient, there is a monitoring strategy that uses IMAP IDLE. The IDLE command is an optional expansion of the IMAP email protocol that lets the mail server send new message updates to the `MailMessageReceiver` asynchronously. If you use an IMAP server that supports the IDLE command, you can plug the `ImapIdleMonitoringStrategy` into the `monitoringStrategy` property. The following piece of configuration shows how to use the server-side email support, overriding the default polling interval to check every 30 seconds (30.000 milliseconds): @@ -342,11 +341,13 @@ The following piece of configuration shows how to use the server-side email supp === Embedded HTTP Server transport -Spring Web Services provides a transport based on Sun's JRE 1.6 http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/index.html[HTTP server]. The embedded HTTP Server is a standalone server that is simple to configure. It offers a lighter alternative to conventional servlet containers. +NOTE: This should only be used for testing purposes. -When using the embedded HTTP server, you need no external deployment descriptor (`web.xml`). You need only define an instance of the server and configure it to handle incoming requests. The remoting module in the Core Spring Framework contains a convenient factory bean for the HTTP server: the `SimpleHttpServerFactoryBean`. The most important property is `contexts`, which maps context paths to corresponding `HttpHandler` instances. +Spring-WS provides a transport based on Sun's JRE 1.6 http://java.sun.com/javase/6/docs/jre/api/net/httpserver/spec/index.html[HTTP server]. The embedded HTTP Server is a standalone server that is simple to configure. It offers a lighter alternative to conventional servlet containers. -Spring Web Services provides two implementations of the `HttpHandler` interface: https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/transport/http/WsdlDefinitionHttpHandler.html[`WsdlDefinitionHttpHandler`] and https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/transport/http/WebServiceMessageReceiverHttpHandler.html[`WebServiceMessageReceiverHttpHandler`]. The former maps an incoming GET request to a `WsdlDefinition`. The latter is responsible for handling POST requests for web services messages and, thus, needs a `WebServiceMessageFactory` (typically a `SaajSoapMessageFactory`) and a `WebServiceMessageReceiver` (typically the `SoapMessageDispatcher`) to accomplish its task. +When using the embedded HTTP server, you need no external deployment descriptor (`web.xml`). You need only define an instance of the server and configure it to handle incoming requests. `SimpleHttpServerFactoryBean` wires things up, and the most important property is `contexts`, which maps context paths to corresponding `HttpHandler` instances. + +Spring-WS provides two implementations of the `HttpHandler` interface: {spring-ws-api}/transport/http/WsdlDefinitionHttpHandler.html[`WsdlDefinitionHttpHandler`] and {spring-ws-api}/transport/http/WebServiceMessageReceiverHttpHandler.html[`WebServiceMessageReceiverHttpHandler`]. The former maps an incoming GET request to a `WsdlDefinition`. The latter is responsible for handling POST requests for web services messages and, thus, needs a `WebServiceMessageFactory` (typically a `SaajSoapMessageFactory`) and a `WebServiceMessageReceiver` (typically the `SoapMessageDispatcher`) to accomplish its task. To draw parallels with the servlet world, the `contexts` property plays the role of servlet mappings in `web.xml` and the `WebServiceMessageReceiverHttpHandler` is the equivalent of a `MessageDispatcherServlet`. @@ -367,7 +368,7 @@ The following snippet shows a configuration example of the HTTP server transport - + @@ -388,13 +389,11 @@ The following snippet shows a configuration example of the HTTP server transport ---- ==== -For more information on the `SimpleHttpServerFactoryBean`, see the http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/remoting/support/SimpleHttpServerFactoryBean.html[Javadoc]. - === XMPP transport -Spring Web Services 2.0 introduced support for XMPP, otherwise known as Jabber. The support is based on the https://www.igniterealtime.org/projects/smack/index.jsp[Smack] library. +Spring-WS has support for XMPP, otherwise known as Jabber. The support is based on the https://www.igniterealtime.org/projects/smack/index.jsp[Smack] library. -Spring Web Services support for XMPP is very similar to the other transports: There is a a `XmppMessageSender` for the `WebServiceTemplate` and a `XmppMessageReceiver` to use with the `MessageDispatcher`. +Spring-WS support for XMPP is very similar to the other transports: There is a a `XmppMessageSender` for the `WebServiceTemplate` and a `XmppMessageReceiver` to use with the `MessageDispatcher`. The following example shows how to set up the server-side XMPP components: @@ -457,41 +456,37 @@ import org.springframework.ws.server.endpoint.annotation.Endpoint; import org.springframework.ws.server.endpoint.annotation.PayloadRoot; import org.springframework.ws.soap.SoapHeader; -@Endpoint // <1> +@Endpoint // <1> public class AnnotationOrderEndpoint { private final OrderService orderService; - @Autowired // <2> public AnnotationOrderEndpoint(OrderService orderService) { this.orderService = orderService; } - @PayloadRoot(localPart = "order", namespace = "http://samples") // <5> - public void order(@RequestPayload Element orderElement) { // <3> + @PayloadRoot(localPart = "order", namespace = "http://samples") // <4> + public void order(@RequestPayload Element orderElement) { // <2> Order order = createOrder(orderElement); orderService.createOrder(order); } - @PayloadRoot(localPart = "orderRequest", namespace = "http://samples") // <5> + @PayloadRoot(localPart = "orderRequest", namespace = "http://samples") // <4> @ResponsePayload - public Order getOrder(@RequestPayload OrderRequest orderRequest, SoapHeader header) { // <4> + public Order getOrder(@RequestPayload OrderRequest orderRequest, SoapHeader header) { // <3> checkSoapHeaderForSomething(header); return orderService.getOrder(orderRequest.getId()); } - ... - } ---- <1> The class is annotated with `@Endpoint`, marking it as a Spring-WS endpoint. -<2> The constructor is marked with `@Autowired` so that the `OrderService` business service is injected into this endpoint. -<3> The `order` method takes an `Element` (annotated with `@RequestPayload`) as a parameter. This means that the payload of the message is passed on this method as a DOM element. The method has a `void` return type, indicating that no response message is sent. +<2> The `order` method takes an `Element` (annotated with `@RequestPayload`) as a parameter. This means that the payload of the message is passed on this method as a DOM element. The method has a `void` return type, indicating that no response message is sent. For more information about endpoint methods, see <>. -<4> The `getOrder` method takes an `OrderRequest` (also annotated with `@RequestPayload`) as a parameter. This parameter is a JAXB2-supported object (it is annotated with `@XmlRootElement`). This means that the payload of the message is passed to this method as a unmarshalled object. The `SoapHeader` type is also given as a parameter. On invocation, this parameter contains the SOAP header of the request message. The method is also annotated with `@ResponsePayload`, indicating that the return value (the `Order`) is used as the payload of the response message. +<3> The `getOrder` method takes an `OrderRequest` (also annotated with `@RequestPayload`) as a parameter. This parameter is a JAXB2-supported object (it is annotated with `@XmlRootElement`). This means that the payload of the message is passed to this method as a unmarshalled object. The `SoapHeader` type is also given as a parameter. On invocation, this parameter contains the SOAP header of the request message. The method is also annotated with `@ResponsePayload`, indicating that the return value (the `Order`) is used as the payload of the response message. For more information about endpoint methods, see <>. -<5> The two handling methods of this endpoint are marked with `@PayloadRoot`, indicating what sort of request messages can be handled by the method: the `getOrder` method is invoked for requests with a `orderRequest` local name and a `http://samples` namespace URI. The order method is invoked for requests with a `order` local name. +<4> The two handling methods of this endpoint are marked with `@PayloadRoot`, indicating what sort of request messages can be handled by the method: the `getOrder` method is invoked for requests with a `orderRequest` local name and a `http://samples` namespace URI. The order method is invoked for requests with a `order` local name. For more information about `@PayloadRoot`, see <>. ==== @@ -536,7 +531,6 @@ To customize the `@EnableWs` configuration, you can implement `WsConfigurer` or, ---- @Configuration @EnableWs -@ComponentScan(basePackageClasses = { MyConfiguration.class }) public class MyConfiguration extends WsConfigurerAdapter { @Override @@ -556,7 +550,7 @@ public class MyConfiguration extends WsConfigurerAdapter { In the next couple of sections, a more elaborate description of the `@Endpoint` programming model is given. -NOTE: Endpoints, like any other Spring Bean, are scoped as a singleton by default. That is, one instance of the bean definition is created per container. Being a singleton implies that more than one thread can use it at the same time, so the endpoint has to be thread safe. If you want to use a different scope, such as prototype, see the https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes[Spring Reference documentation]. +NOTE: Endpoints, like any other Spring Bean, are scoped as a singleton by default. That is, one instance of the bean definition is created per container. Being a singleton implies that more than one thread can use it at the same time, so the endpoint has to be thread safe. If you want to use a different scope, such as prototype, see the {spring-framework-docs}/core/beans/factory-scopes.html#beans-factory-scopes-other-injection[Spring Reference documentation]. Note that all abstract base classes provided in Spring-WS are thread safe, unless otherwise indicated in the class-level Javadoc. @@ -628,7 +622,7 @@ The following table describes the supported parameter types. It shows the suppor | Enabled when StAX is on the classpath. | XPath -| Any boolean, double, `String`, `org.w3c.Node`, `org.w3c.dom.NodeList`, or type that can be converted from a `String` by a Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#core-convert-ConversionService-API[conversion service], and that is annotated with `@XPathParam`. +| Any boolean, double, `String`, `org.w3c.Node`, `org.w3c.dom.NodeList`, or type that can be converted from a `String` by a Spring {spring-framework-docs}/core/validation/convert.html#core-convert-ConversionService-API[conversion service], and that is annotated with `@XPathParam`. | No | Enabled by default, see <>. @@ -648,7 +642,7 @@ The following table describes the supported parameter types. It shows the suppor | Enabled when JAXB2 is on the classpath. | OXM -| Any type supported by a Spring OXM https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#oxm-marshaller-unmarshaller[`Unmarshaller`]. +| Any type supported by a Spring OXM {spring-framework-docs}/data-access/oxm.html#oxm-marshaller-unmarshaller[`Unmarshaller`]. | Yes | Enabled when the `unmarshaller` attribute of `` is specified. |=== @@ -680,7 +674,7 @@ public void handle(@RequestPayload MyJaxb2Object requestObject, @RequestPayload ---- ==== -As you can see, there are a lot of possibilities when it comes to defining how to handle method signatures. You can even extend this mechanism to support your own parameter types. See the Javadoc of https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.html[`DefaultMethodEndpointAdapter`] and https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/server/endpoint/adapter/method/MethodArgumentResolver.html[`MethodArgumentResolver`] to see how. +As you can see, there are a lot of possibilities when it comes to defining how to handle method signatures. You can even extend this mechanism to support your own parameter types. See the Javadoc of {spring-ws-api}/server/endpoint/adapter/DefaultMethodEndpointAdapter.html[`DefaultMethodEndpointAdapter`] and {spring-ws-api}/server/endpoint/adapter/method/MethodArgumentResolver.html[`MethodArgumentResolver`] to see how. [[server-xpath-param]] ===== `@XPathParam` @@ -709,8 +703,8 @@ public class AnnotationOrderEndpoint { } @PayloadRoot(localPart = "orderRequest", namespace = "http://samples") - *@Namespace(prefix = "s", uri="http://samples")* - public Order getOrder(*@XPathParam("/s:orderRequest/@id") int orderId*) { + @Namespace(prefix = "s", uri="http://samples") + public Order getOrder(@XPathParam("/s:orderRequest/@id") int orderId) { Order order = orderService.getOrder(orderId); // create Source from order and return it } @@ -729,7 +723,7 @@ By using the `@XPathParam`, you can bind to all the data types supported by XPat * `Node` * `NodeList` -In addition to this list, you can use any type that can be converted from a `String` by a Spring https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#core-convert-ConversionService-API[conversion service]. +In addition to this list, you can use any type that can be converted from a `String` by a Spring {spring-framework-docs}/core/validation/convert.html#core-convert-ConversionService-API[conversion service]. ==== Handling method return types @@ -783,12 +777,12 @@ The following table describes the supported return types. It shows the supported | Enabled when JAXB2 is on the classpath. | OXM -| Any type supported by a Spring OXM https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#oxm-marshaller-unmarshaller[`Marshaller`]. +| Any type supported by a Spring OXM {spring-framework-docs}/data-access/oxm.html#oxm-marshaller-unmarshaller[`Marshaller`]. | Yes | Enabled when the `marshaller` attribute of `` is specified. |=== -There are a lot of possibilities when it comes to defining handling method signatures. It is even possible to extend this mechanism to support your own parameter types. See the class-level Javadoc of https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/server/endpoint/adapter/DefaultMethodEndpointAdapter.html[`DefaultMethodEndpointAdapter`] and https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/server/endpoint/adapter/method/MethodReturnValueHandler.html[`MethodReturnValueHandler`] to see how. +There are a lot of possibilities when it comes to defining handling method signatures. It is even possible to extend this mechanism to support your own parameter types. See the class-level Javadoc of {spring-ws-api}/server/endpoint/adapter/DefaultMethodEndpointAdapter.html[`DefaultMethodEndpointAdapter`] and {spring-ws-api}/server/endpoint/adapter/method/MethodReturnValueHandler.html[`MethodReturnValueHandler`] to see how. [[server-endpoint-mapping]] == Endpoint mappings @@ -805,7 +799,7 @@ As explained in <>, the `@Endpoint` style lets you handle mult There are two endpoint mappings that can direct requests to methods: the `PayloadRootAnnotationMethodEndpointMapping` and the `SoapActionAnnotationMethodEndpointMapping` You can enable both methods by using `` in your application context. -The `PayloadRootAnnotationMethodEndpointMapping` uses the `@PayloadRoot` annotation, with the `localPart` and `namespace` elements, to mark methods with a particular qualified name. Whenever a message comes in with this qualified name for the payload root element, the method is invoked. For an example, see <>. +The `PayloadRootAnnotationMethodEndpointMapping` uses the `@PayloadRoot` annotation, with the `localPart` and `namespace` elements, to mark methods with a particular qualified name. Whenever a message comes in with this qualified name for the payload root element, the method is invoked. Alternatively, the `SoapActionAnnotationMethodEndpointMapping` uses the `@SoapAction` annotation to mark methods with a particular SOAP Action. Whenever a message comes in with this `SOAPAction` header, the method is invoked. @@ -819,7 +813,7 @@ WS-Addressing specifies a transport-neutral routing mechanism. It is based on th ---- - + urn:uuid:21363e0d-2645-4eb7-8afd-2f5ee1bb25cf http://example.com/business/client1 @@ -836,7 +830,7 @@ WS-Addressing specifies a transport-neutral routing mechanism. It is based on th ---- ==== -In the preceding example, the destination is set to `http://example/com/fabrikam`, while the action is set to `http://example.com/fabrikam/mail/Delete`. Additionally, there is a message identifier and a reply-to address. By default, this address is the "`anonymous`" address, indicating that a response should be sent byusing the same channel as the request (that is, the HTTP response), but it can also be another address, as indicated in this example. +In the preceding example, the destination is set to `http://example/com/fabrikam`, while the action is set to `http://example.com/fabrikam/mail/Delete`. Additionally, there is a message identifier and a reply-to address. By default, this address is the "`anonymous`" address, indicating that a response should be sent by using the same channel as the request (that is, the HTTP response), but it can also be another address, as indicated in this example. In Spring Web Services, WS-Addressing is implemented as an endpoint mapping. By using this mapping, you associate WS-Addressing actions with endpoints, similar to the `SoapActionAnnotationMethodEndpointMapping` described earlier. @@ -856,6 +850,7 @@ import org.springframework.ws.soap.addressing.server.annotation.Action @Endpoint public class AnnotationOrderEndpoint { + private final OrderService orderService; public AnnotationOrderEndpoint(OrderService orderService) { @@ -929,7 +924,7 @@ public class MyWsConfiguration extends WsConfigurerAdapter { ---- ==== -Interceptors must implement the `EndpointInterceptor` interface from the `org.springframework.ws.server` package. This interface defines three methods, one that can be used for handling the request message *before* the actual endpoint is processed, one that can be used for handling a normal response message, and one that can be used for handling fault messages. The second two are called *after* the endpoint is processed. These three methods should provide enough flexibility to do all kinds of pre- and post-processing. +Interceptors must implement {spring-ws-api}/server/EndpointInterceptor.html[`EndpointInterceptor`]. This interface defines three methods, one that can be used for handling the request message *before* the actual endpoint is processed, one that can be used for handling a normal response message, and one that can be used for handling fault messages. The second two are called *after* the endpoint is processed. These three methods should provide enough flexibility to do all kinds of pre- and post-processing. The `handleRequest(..)` method on the interceptor returns a boolean value. You can use this method to interrupt or continue the processing of the invocation chain. When this method returns `true`, the endpoint processing chain will continue. When it returns `false`, the `MessageDispatcher` interprets this to mean that the interceptor itself has taken care of things and does not continue processing the other interceptors and the actual endpoint in the invocation chain. The `handleResponse(..)` and `handleFault(..)` methods also have a boolean return value. When these methods return `false`, the response will not be sent back to the client. @@ -937,7 +932,7 @@ There are a number of standard `EndpointInterceptor` implementations that you ca ==== `PayloadLoggingInterceptor` and `SoapEnvelopeLoggingInterceptor` -When developing a web service, it can be useful to log the incoming and outgoing XML messages. Spring WS facilitates this with the `PayloadLoggingInterceptor` and `SoapEnvelopeLoggingInterceptor` classes. The former logs only the payload of the message to the Commons Logging Log. The latter logs the entire SOAP envelope, including SOAP headers. The following example shows how to define the `PayloadLoggingInterceptor` in an endpoint mapping: +When developing a web service, it can be useful to log the incoming and outgoing XML messages. Spring WS facilitates this with the `PayloadLoggingInterceptor` and `SoapEnvelopeLoggingInterceptor` classes. The former logs only the payload of the message. The latter logs the entire SOAP envelope, including SOAP headers. The following example shows how to define the `PayloadLoggingInterceptor` in an endpoint mapping: ==== [source,xml] @@ -956,8 +951,12 @@ You could use the `WsConfigurerAdapter` approach, as described earlier, for the One of the benefits of using a contract-first development style is that we can use the schema to validate incoming and outgoing XML messages. Spring-WS facilitates this with the `PayloadValidatingInterceptor`. This interceptor requires a reference to one or more W3C XML or RELAX NG schemas and can be set to validate requests, responses, or both. -NOTE: Note that request validation may sound like a good idea, but it makes the resulting Web service very strict. Usually, it is not really important whether the request validates, only if the endpoint can get sufficient information to fulfill a request. Validating the response is a good idea, because the endpoint should adhere to its schema. Remember Postel's Law: +[NOTE] +==== +While request validation may sound like a good idea, it makes the resulting Web service very strict. Usually, it is not really important whether the request validates, only if the endpoint can get sufficient information to fulfill a request. Validating the response is a good idea, because the endpoint should adhere to its schema. Remember Postel's Law: "Be conservative in what you do; be liberal in what you accept from others." +==== + The following example uses the `PayloadValidatingInterceptor`. In this example, we use the schema in `/WEB-INF/orders.xsd` to validate the response but not the request. Note that the `PayloadValidatingInterceptor` can also accept multiple schemas by setting the `schemas` property. @@ -977,7 +976,7 @@ Of course, you could use the `WsConfigurerAdapter` approach, as described earlie ==== Using `PayloadTransformingInterceptor` -To transform the payload to another XML format, Spring Web Services offers the `PayloadTransformingInterceptor`. This endpoint interceptor is based on XSLT style sheets and is especially useful when supporting multiple versions of a web service, because you can transform the older message format to the newer format. The following example uses the `PayloadTransformingInterceptor`: +To transform the payload to another XML format, Spring-WS offers the `PayloadTransformingInterceptor`. This endpoint interceptor is based on XSLT style sheets and is especially useful when supporting multiple versions of a web service, because you can transform the older message format to the newer format. The following example uses the `PayloadTransformingInterceptor`: ==== [source,xml] @@ -997,7 +996,7 @@ You could use the `WsConfigurerAdapter` approach, as described earlier, for the [[server-endpoint-exception-resolver]] == Handling Exceptions -Spring-WS provides `EndpointExceptionResolvers` to ease the pain of unexpected exceptions occurring while your message is being processed by an endpoint that matched the request. Endpoint exception resolvers somewhat resemble the exception mappings that can be defined in the web application descriptor `web.xml`. However, they provide a more flexible way to handle exceptions. They provide information about what endpoint was invoked when the exception was thrown. Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond appropriately. Rather than expose the innards of your application by giving an exception and stack trace, you can handle the exception any way you want -- for example, by returning a SOAP fault with a specific fault code and string. +Spring-WS provides {spring-ws-api}/server/EndpointExceptionResolver.html[`EndpointExceptionResolver`] implementations to ease the pain of unexpected exceptions occurring while your message is being processed by an endpoint that matched the request. Endpoint exception resolvers somewhat resemble the exception mappings that can be defined in the web application descriptor `web.xml`. However, they provide a more flexible way to handle exceptions. They provide information about what endpoint was invoked when the exception was thrown. Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond appropriately. Rather than expose the innards of your application by giving an exception and stack trace, you can handle the exception any way you want -- for example, by returning a SOAP fault with a specific fault code and string. Endpoint exception resolvers are automatically picked up by the `MessageDispatcher`, so no explicit configuration is necessary. @@ -1085,16 +1084,14 @@ Whenever the `MyBusinessException` is thrown with the constructor string `"Oops! When it comes to testing your Web service endpoints, you have two possible approaches: * Write Unit Tests, where you provide (mock) arguments for your endpoint to consume. -+ The advantage of this approach is that it is quite easy to accomplish (especially for classes annotated with `@Endpoint`). The disadvantage is that you are not really testing the exact content of the XML messages that are sent over the wire. -+ * Write Integrations Tests, which do test the contents of the message. -The first approach can easily be accomplished with mocking frameworks such as EasyMock, JMock, and others. The next section focuses on writing integration tests, using the test features introduced in Spring Web Services 2.0. +The first approach can easily be accomplished with mocking frameworks such as Mockito, EasyMock, and others. The next section focuses on writing integration tests. === Writing server-side integration tests -Spring Web Services 2.0 introduced support for creating endpoint integration tests. In this context, an endpoint is a class that handles (SOAP) messages (see <>). +Spring-WS has support for creating endpoint integration tests. In this context, an endpoint is a class that handles (SOAP) messages (see <>). The integration test support lives in the `org.springframework.ws.test.server` package. The core class in that package is the `MockWebServiceClient`. The underlying idea is that this client creates a request message and then sends it over to the endpoints that are configured in a standard `MessageDispatcherServlet` application context (see <>). These endpoints handle the message and create a response. The client then receives this response and verifies it against registered expectations. @@ -1104,9 +1101,15 @@ The typical usage of the `MockWebServiceClient` is: . . Send request messages by calling `sendRequest(RequestCreator)`, possibly by using the default `RequestCreator` implementations provided in `RequestCreators` (which can be statically imported). . Set up response expectations by calling `andExpect(ResponseMatcher)`, possibly by using the default `ResponseMatcher` implementations provided in `ResponseMatchers` (which can be statically imported). Multiple expectations can be set up by chaining `andExpect(ResponseMatcher)` calls. -NOTE: Note that the `MockWebServiceClient` (and related classes) offers a "`fluent`" API, so you can typically use the code-completion features in your IDE to guide you through the process of setting up the mock server. +[NOTE] +==== +`MockWebServiceClient` (and related classes) offers a "`fluent`" API, so you can typically use the code-completion features in your IDE to guide you through the process of setting up the mock server. +==== -NOTE: Also note that you can rely on the standard logging features available in Spring Web Services in your unit tests. Sometimes, it might be useful to inspect the request or response message to find out why a particular tests failed. See <> for more information. +[NOTE] +==== +You can rely on the standard logging features available in Spring-WS in your unit tests. Sometimes, it might be useful to inspect the request or response message to find out why a particular tests failed. See <> for more information. +==== Consider, for example, the following web service endpoint class: @@ -1121,8 +1124,8 @@ import org.springframework.ws.server.endpoint.annotation.ResponsePayload; public class CustomerEndpoint { @ResponsePayload // <2> - public CustomerCountResponse getCustomerCount( // <2> - @RequestPayload CustomerCountRequest request) { // <2> + public CustomerCountResponse getCustomerCount( + @RequestPayload CustomerCountRequest request) { CustomerCountResponse response = new CustomerCountResponse(); response.setCustomerCount(10); return response; @@ -1151,49 +1154,49 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.ws.test.server.MockWebServiceClient; // <1> -import static org.springframework.ws.test.server.RequestCreators.*; // <1> -import static org.springframework.ws.test.server.ResponseMatchers.*; // <1> +import org.springframework.ws.test.server.MockWebServiceClient; +import static org.springframework.ws.test.server.RequestCreators.*; +import static org.springframework.ws.test.server.ResponseMatchers.*; -@RunWith(SpringJUnit4ClassRunner.class) // <2> -@ContextConfiguration("spring-ws-servlet.xml") // <2> +@RunWith(SpringJUnit4ClassRunner.class) // <1> +@ContextConfiguration("spring-ws-servlet.xml") public class CustomerEndpointIntegrationTest { @Autowired - private ApplicationContext applicationContext; // <3> + private ApplicationContext applicationContext; // <2> private MockWebServiceClient mockClient; @Before public void createClient() { - mockClient = MockWebServiceClient.createClient(applicationContext); // <4> + mockClient = MockWebServiceClient.createClient(applicationContext); // <3> } @Test public void customerEndpoint() throws Exception { - Source requestPayload = new StringSource( - "" + - "John Doe" + - ""); - Source responsePayload = new StringSource( - "" + - "10" + - ""); + Source requestPayload = new StringSource(""" + + John Doe + + """); + Source responsePayload = new StringSource(""" + + 10 + + """); - mockClient.sendRequest(withPayload(requestPayload)). // <5> - andExpect(payload(responsePayload)); // <5> + mockClient.sendRequest(withPayload(requestPayload)). // <4> + andExpect(payload(responsePayload)); } } ---- -<1> The `CustomerEndpointIntegrationTest` imports the `MockWebServiceClient` and statically imports `RequestCreators` and `ResponseMatchers`. -<2> This test uses the standard testing facilities provided in the Spring Framework. This is not required but is generally the easiest way to set up the test. -<3> The application context is a standard Spring-WS application context (see <>), read from `spring-ws-servlet.xml`. In this case, the application context contains a bean definition for `CustomerEndpoint` (or perhaps a `` is used). -<4> In a `@Before` method, we create a `MockWebServiceClient` by using the `createClient` factory method. -<5> We send a request by calling `sendRequest()` with a `withPayload()` `RequestCreator` provided by the statically imported `RequestCreators` (see <>). -+ +<1> This test uses the standard testing facilities provided in the Spring Framework. This is not required but is generally the easiest way to set up the test. +<2> The application context is a standard Spring-WS application context (see <>), read from `spring-ws-servlet.xml`. In this case, the application context contains a bean definition for `CustomerEndpoint` (or perhaps a `` is used). +<3> In a `@Before` method, we create a `MockWebServiceClient` by using the `createClient` factory method. +<4> We send a request by calling `sendRequest()` with a `withPayload()` `RequestCreator` provided by the statically imported `RequestCreators` (see <>). We also set up response expectations by calling `andExpect()` with a `payload()` `ResponseMatcher` provided by the statically imported `ResponseMatchers` (see <>). -+ + This part of the test might look a bit confusing, but the code completion features of your IDE are of great help. After typing `sendRequest(`, your IDE can provide you with a list of possible request creating strategies, provided you statically imported `RequestCreators`. The same applies to `andExpect()`, provided you statically imported `ResponseMatchers`. ==== @@ -1226,8 +1229,7 @@ When the request message has been processed by the endpoint and a response has b ---- public interface ResponseMatcher { - void match(WebServiceMessage request, - WebServiceMessage response) + void match(WebServiceMessage request, WebServiceMessage response) throws IOException, AssertionError; } @@ -1276,4 +1278,4 @@ mockClient.sendRequest(...). ---- ==== -For more information on the response matchers provided by `ResponseMatchers`, see the https://docs.spring.io/spring-ws/docs/current/api/org/springframework/ws/test/server/ResponseMatchers.html[Javadoc]. +For more information on the response matchers provided by `ResponseMatchers`, see the {spring-ws-api}/test/server/ResponseMatchers.html[Javadoc]. diff --git a/spring-ws-docs/src/docs/asciidoc/tutorial.adoc b/spring-ws-docs/src/docs/asciidoc/tutorial.adoc index 9682eff5..7b8f7113 100644 --- a/spring-ws-docs/src/docs/asciidoc/tutorial.adoc +++ b/spring-ws-docs/src/docs/asciidoc/tutorial.adoc @@ -3,7 +3,7 @@ This tutorial shows you how to write <> -- that is, how to develop web services that start with the XML Schema or WSDL contract first followed by the Java code second. Spring-WS focuses on this development style, and this tutorial should help you get started. Note that the first part of this tutorial contains almost no Spring-WS specific information. It is mostly about XML, XSD, and WSDL. The <> focuses on implementing this contract with Spring-WS . -The most important thing when doing contract-first web service development is tothink in terms of XML. This means that Java language concepts are of lesser importance. It is the XML that is sent across the wire, and you should focus on that. Java being used to implement the web service is an implementation detail. +The most important thing when doing contract-first web service development is to think in terms of XML. This means that Java language concepts are of lesser importance. It is the XML that is sent across the wire, and you should focus on that. Java being used to implement the web service is an implementation detail. In this tutorial, we define a web service that is created by a Human Resources department. Clients can send holiday request forms to this service to book a holiday. diff --git a/spring-ws-docs/src/docs/asciidoc/what-is-spring-ws.adoc b/spring-ws-docs/src/docs/asciidoc/what-is-spring-ws.adoc index e8da9c01..25d47d68 100644 --- a/spring-ws-docs/src/docs/asciidoc/what-is-spring-ws.adoc +++ b/spring-ws-docs/src/docs/asciidoc/what-is-spring-ws.adoc @@ -5,7 +5,7 @@ Spring Web Services (Spring-WS) is a product of the Spring community and is focused on creating document-driven web services. Spring Web Services aims to facilitate contract-first SOAP service development, allowing for the creation of flexible web services by using one of the many ways to manipulate XML payloads. The product is based on Spring itself, which means you can use the Spring concepts (such as dependency injection) as an integral part of your web service. -People use Spring-WS for many reasons, but most are drawn to it after finding alternative SOAP stacks lacking when it comes to following web service best practices. Spring-WS makes the best practice an easy practice. This includes practices such as the WS-I basic profile, contract-first development, and having a loose coupling between contract and implementation. The other key features of Spring Web Services are: +People use Spring-WS for many reasons, but most are drawn to it after finding alternative SOAP stacks lacking when it comes to following web service best practices. Spring-WS makes the best practice an easy practice. This includes practices such as the WS-I basic profile, contract-first development, and having a loose coupling between contract and implementation. The other key features of Spring-WS are: * <> * <> @@ -28,7 +28,7 @@ Incoming XML messages can be handled not only with standard JAXP APIs such as DO [[features-flexible-xml-marshalling]] === Flexible XML Marshalling -Spring Web Services builds on the Object/XML Mapping module in the Spring Framework, which supports JAXB 1 and 2, Castor, XMLBeans, JiBX, and XStream. +Spring-WS builds on the Object/XML Mapping module in the Spring Framework, which supports JAXB 1 and 2, Castor, XMLBeans, JiBX, and XStream. [[features-reusing-your-spring-expertise]] === Reusing Your Spring expertise @@ -43,7 +43,7 @@ WS-Security lets you sign SOAP messages, encrypt and decrypt them, or authentica [[features-integration-with-spring-security]] === Integration with Spring Security -The WS-Security implementation of Spring Web Services provides integration with Spring Security. This means you can use your existing Spring Security configuration for your SOAP service as well. +The WS-Security implementation of Spring-WS provides integration with Spring Security. This means you can use your existing Spring Security configuration for your SOAP service as well. [[features-apache-license]] === Apache license @@ -52,14 +52,14 @@ You can confidently use Spring-WS in your project. == Runtime environment -Spring Web Services requires a standard Java 8 Runtime Environment. Spring-WS is built on Spring Framework 4.0.9, but higher versions are supported. +Spring-WS requires a standard Java 17 Runtime Environment. Spring-WS is built on Spring Framework 6.x. Spring-WS consists of a number of modules, which are described in the remainder of this section. -* The XML module (`spring-xml.jar`) contains various XML support classes for Spring Web Services. This module is mainly intended for the Spring-WS framework itself and not web service developers. -* The Core module (`spring-ws-core.jar`) is the central part of the Spring's web services functionality. It provides the central <> and <> interfaces, the <> framework (with powerful message dispatching), the various support classes for implementing web service endpoints, and the <> `WebServiceTemplate`. -* The Support module (`spring-ws-support.jar`) contains additional transports (JMS, Email, and others). -* The <> package (`spring-ws-security.jar`) provides a WS-Security implementation that integrates with the core web service package. It lets you sign, decrypt and encrypt, and add principal tokens to SOAP messages. Additionally, it lets you use your existing Spring Security security implementation for authentication and authorization. +* The XML module (`spring-xml`) contains various XML support classes for Spring-WS. This module is mainly intended for the Spring-WS framework itself and not web service developers. +* The Core module (`spring-ws-core`) is the central part of the Spring's web services functionality. It provides the central <> and <> interfaces, the <> framework (with powerful message dispatching), the various support classes for implementing web service endpoints, and the <> `WebServiceTemplate`. +* The Support module (`spring-ws-support`) contains additional transports (JMS, Email, and others). +* The <> module (`spring-ws-security`) provides a WS-Security implementation that integrates with the core web service package. It lets you sign, decrypt and encrypt, and add principal tokens to SOAP messages. Additionally, it lets you use your existing Spring Security security implementation for authentication and authorization. The following figure shows and the dependencies between the Spring-WS modules. Arrows indicate dependencies (that is, Spring-WS Core depends on Spring-XML and the OXM module found in Spring 3 and higher). @@ -67,7 +67,7 @@ image::images/spring-deps.png[align="center"] == Supported standards -Spring Web Services supports the following standards: +Spring-WS supports the following standards: * SOAP 1.1 and 1.2 * WSDL 1.1 and 2.0 (XSD-based generation is supported only for WSDL 1.1) diff --git a/spring-ws-docs/src/docs/asciidoc/why-contract-first.adoc b/spring-ws-docs/src/docs/asciidoc/why-contract-first.adoc index e999dc04..640bfd51 100644 --- a/spring-ws-docs/src/docs/asciidoc/why-contract-first.adoc +++ b/spring-ws-docs/src/docs/asciidoc/why-contract-first.adoc @@ -3,9 +3,8 @@ When creating web services, there are two development styles: contract-last and contract-first. When you use a contract-last approach, you start with the Java code and let the web service contract (in WSDL -- see sidebar) be generated from that. When using contract-first, you start with the WSDL contract and use Java to implement the contract. +.What is WSDL? **** -*What is WSDL?* - WSDL stands for Web Service Description Language. A WSDL file is an XML document that describes a web service. It specifies the location of the service and the operations (or methods) the service exposes. For more information about WSDL, see the https://www.w3.org/TR/wsdl[WSDL specification]. **** @@ -70,7 +69,7 @@ This problem is also present when working on the client side. Consider the follo ---- ==== -This contract defines a request that takes an `date`, which is a XSD datatype representing a year, month, and day. If we call this service from Java, we probably use either a `java.util.Date` or `java.util.Calendar`. However, both of these classes actually describe times, rather than dates. So, we actually end up sending data that represents the fourth of April 2007 at midnight (`2007-04-04T00:00:00`), which is not the same as `2007-04-04`. +This contract defines a request that takes an `date`, which is a XSD datatype representing a year, month, and day. If we call this service from Java, we probably use either a `java.time.LocalDateTime` or `java.time.Instant`. However, both of these classes actually describe times, rather than dates. So, we actually end up sending data that represents the fourth of April 2007 at midnight (`2007-04-04T00:00:00`), which is not the same as `2007-04-04`. === Cyclic Graphs diff --git a/spring-ws-platform/build.gradle b/spring-ws-platform/build.gradle index ed3fee33..d52e2b2a 100644 --- a/spring-ws-platform/build.gradle +++ b/spring-ws-platform/build.gradle @@ -12,7 +12,7 @@ dependencies { api(platform("org.eclipse.jetty.ee10:jetty-ee10-bom:12.0.16")) api(platform("org.junit:junit-bom:5.11.0")) api(platform("org.slf4j:slf4j-bom:2.0.17")) - api(platform("org.springframework:spring-framework-bom:6.0.23")) + api(platform("org.springframework:spring-framework-bom:${springFrameworkVersion}")) api(platform("org.springframework.security:spring-security-bom:6.1.9")) constraints { api("com.fasterxml.woodstox:woodstox-core:6.5.1") diff --git a/spring-ws-security/src/test/resources/org/springframework/ws/soap/security/xwss/callback/jaas/jaas.config b/spring-ws-security/src/test/resources/org/springframework/ws/soap/security/xwss/callback/jaas/jaas.config deleted file mode 100644 index 31b98de3..00000000 --- a/spring-ws-security/src/test/resources/org/springframework/ws/soap/security/xwss/callback/jaas/jaas.config +++ /dev/null @@ -1,6 +0,0 @@ -PlainText { - org.springframework.ws.soap.security.xwss.callback.jaas.PlainTextLoginModule Required; -}; -Certificate { - org.springframework.ws.soap.security.xwss.callback.jaas.CertificateLoginModule Required; -};