diff --git a/src/docbkx/common.xml b/src/docbkx/common.xml
index af017834..32eaa7ab 100644
--- a/src/docbkx/common.xml
+++ b/src/docbkx/common.xml
@@ -76,7 +76,7 @@
The SoapMessage is an extension of
WebServiceMessage. It contains SOAP-specific methods, such as getting
- SOAP Headers, SOAP Faults, etc. Generally, your code should only not be dependent on
+ SOAP Headers, SOAP Faults, etc. Generally, your code should not be dependent on
SoapMessage, because the content of the SOAP Body can be obtained via
getPayloadSource() and getPayloadResult() in the
WebServiceMessage. Only when it is necessary to perform SOAP-specific
@@ -157,15 +157,6 @@
Handling XML With XPath
-
- What is XPath?
-
- XPath is a language for addressing parts of an XML document.
- For more information about XPath, refer to the
- XPath specification, or read the
- XPath tutorial
-
-
One of the best ways to handle XML is to use XPath. Quoting , item 35:
diff --git a/src/docbkx/security.xml b/src/docbkx/security.xml
index dc30da97..95b10dfa 100644
--- a/src/docbkx/security.xml
+++ b/src/docbkx/security.xml
@@ -53,7 +53,7 @@
- XwsSecurityInterceptor
+ XwsSecurityInterceptor
The
XwsSecurityInterceptor
diff --git a/src/docbkx/server.xml b/src/docbkx/server.xml
index 8ed13fe2..89164541 100644
--- a/src/docbkx/server.xml
+++ b/src/docbkx/server.xml
@@ -61,7 +61,7 @@
An appropriate endpoint is searched for. If an endpoint is found, the invocation chain associated
- with the handler (preprocessors, postprocessors, and endpoints) will be executed in order to create
+ with the endpoint (preprocessors, postprocessors, and endpoints) will be executed in order to create
a response.
@@ -328,7 +328,7 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
returned. The returned object is marshalled into XML, and used as the payload of the response message.
The SOAP request handled by this endpoint will look like:
-
+
@@ -357,7 +357,7 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
marshaller bean.
-
+ @Endpoint
The previous two programming models were based on inheritance, and handled individual XML mesages.
@@ -427,14 +427,16 @@ public class AnnotationOrderEndpoint {
PayloadRootAnnotationMethodEndpointMapping is the mapping that detects and
handles the @PayloadRoot annotations.
-
- As an alternative to using marshalling, we could have used XPath to
- extract the information out of the incoming XML request. Spring-WS offers another annotation for
- this purpose: @XPathParam. You simply annotate a method paramters
- with this annotation, and it will be bound with the evaluation of that annotation.
- Here is an example:
-
-
+ @XPathParam
+
+ As an alternative to using marshalling, we could have used XPath to
+ extract the information out of the incoming XML request. Spring-WS offers another annotation for
+ this purpose: @XPathParam. You simply annotate a method paramters
+ with this annotation, and it will be bound with the evaluation of that annotation.
+ Here is an example:
+
+
-
+
+ Since we use the prefix s in our XPath expression, we must bind it to the
+ http://samples namespace:
+
+
+
@@ -466,81 +473,282 @@ public class AnnotationOrderEndpoint {
-
+ ]]>
+
+
+ http://samples
+
+
+ ]]>]]>
-
- Using the @XPathParam, you can bind to all the data types supported by
- XPath:
-
- boolean or Boolean
- double or Double
- String
- Node
- NodeList
-
-
+
+ Using the @XPathParam, you can bind to all the data types supported by
+ XPath:
+
+ boolean or Boolean
+ double or Double
+ String
+ Node
+ NodeList
+
+
+ Endpoint mappings
- The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. It does this by
- delivering a EndpointInterceptorChain, which consists of the endpoint that matches
- the incoming request, and an optional list of endpoint interceptors. When a message is received by the
- MessageDispatcher, it will ask the registered endpoint mappings to come up with a
- appropriate HandlerExecutionChain. After that, the
- MessageDispatcher will invoke the endpoint and interceptors in the chain.
+ The endpoint mapping is responsible for mapping incoming messages to appropriate endpoints. There are some
+ endpoint mappings you can use out of the box, for example, the
+ PayloadRootQNameEndpointMapping or the
+ SoapActionEndpointMapping, but let's first examine the general concept of a
+ EndpointMapping.
- Most endpoint mappings inherit from the AbstractEndpointMapping, which offers the
- following properties:
-
-
-
-
-
- interceptors
-
-
- the list of interceptors use. EndpointInterceptors are
- discussed in .
-
-
-
-
- defaultHandler
-
-
- the default handler to use. This endpoint will be returned if no specific mapping was
- found.
-
-
-
-
-
-
-
-
-
-
-
+ A EndpointMapping delivers a EndpointInvocationChain,
+ which contains the endpoint that matches the incoming request, and may also contain a list of endpoint
+ interceptors that are applied to the request and response. When a request comes in, the
+ MessageDispatcher will hand it over to the endpoint mapping to let it inspect the
+ request and come up with an appropriate EndpointInvocationChain. Then
+ the MessageDispatcher will invoce the endpoint and any interceptors in the chain.
+
+
+ The concept of configurable endpoint mappings that can optionally contain interceptors (which can manipulate
+ the request or the response, or both) is extremely powerful. A lot of supporting functionality can be built
+ into custom EndpointMappings. Think of a custom endpoint mapping that
+ chooses an endpoint not only based on the contents of a message, but also a specific SOAP headers.
+
+
+ Most endpoint mappings inherit from the AbstractEndpointMapping, which offers a
+ interceptors property, which is the list of interceptors to use.
+ EndpointInterceptors are discussed in
+ . Additionally, there is the
+ defaultEndpoint, which is the default endpoint to use, when this endpoint mapping does
+ not result in a matching endpoint.
- SoapActionEndpointMapping
-
+ PayloadRootQNameEndpointMapping
+
+ The PayloadRootQNameEndpointMapping will use the qualified name of the root
+ element of the request payload to determine the endpoint that handles it. A qualified name consists of
+ a namespace URI and a local part, the combination of which
+ should be unique within the mapping. Here is an example:
+
+
+
+ ]]><!-- no 'id' required, EndpointMapping beans are automatically detected by the MessageDispatcher -->
+
+
+ getOrderEndpoint
+ createOrderEndpoint
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ The qualified name is expressed as { + namespace URI + } +
+ local part. Thus, the endpoint mapping above routes requests for which have a payload root element with
+ namespace http://samples and local part orderRequest to the
+ 'getOrderEndpoint'. Requests with a local part order will
+ be routed to the 'createController'. As a result of this mapping, the SOAP message
+ shown above will be mapped to the
+ getOrderEndpoint.
+
- PayloadRootQNameEndpointMapping
-
+ SoapActionEndpointMapping
+
+ Rather than base the routing on the contents of the message with the
+ PayloadRootQNameEndpointMapping, you can use the SOAPAction
+ HTTP header to route messages. Every client sends this header when making a SOAP request, and the
+ header value used for a request is defined in the WSDL. By making the SOAPAction
+ unique per operation, you can use it a a discriminator. Here is an example:
+
+
+
+
+
+ getOrderEndpoint
+ createOrderEndpoint
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ The mapping above routes requests which have the a SOAPAction of
+ http://samples/RequestOrder to the 'getOrderEndpoint'. Requests with
+ http://samples/CreateOrder will be routed to the 'createController'.
+ Note that using SOAP Action headers is SOAP-specific, so it cannot be used when using Plain Old XML.
+ MethodEndpointMapping
-
+
+ As explain in , the @Endpoint model
+ allows you to handle multiple requests in one endpoint class. This is the responsibility of the
+ MethodEndpointMapping. Similar to the endpoint mapping described above, the
+ mapping determines which method is to be invoked for an incoming request message.
+
+
+ There are two endpoint mappings that can direct requests to methods: the
+ PayloadRootAnnotationMethodEndpointMapping and the
+ SoapActionAnnotationMethodEndpointMapping, both of which are very similar to
+ their non-method counterparts described above.
+
+
+ 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 which has this qualified name for the payload root element, the
+ method will be invoked. For an example, see above.
+
+
+ Alternatively, the SoapActionAnnotationMethodEndpointMapping uses the
+ @SoapAction annotation to mark methods with a particular SOAP Action.
+ Whenever a message comes in which has this SOAPAction header, the
+ method will be invoked.
+
- Adding EndpointInterceptors
-
+ Intecepting requests - the EndpointInterceptor interface
+
+ The endpoint mapping mechanism has the notion of endpoint interceptors, that can be extremely useful
+ when you want to apply specific functionality to certain requests, for example, dealing with
+ security-related SOAP headers, or logging the request and response message.
+
+
+ Interceptors located in the endpoint mapping must implement
+ EndpointInterceptor from the
+ org.springframework.ws.server package. This interface defines three methods, one that
+ can be used for handling the request message has been determined, before the actual
+ endpoint will be executed, one that can be used for handling a normal response message, and one that
+ can be used for handling fault messages, both of which will be called after the
+ endpoint is executed. These three methods should provide enough flexibility to do all kinds of
+ pre- and post-processing.
+
+
+ The handleRequest(..) methods on the interceptor returns a boolean value. You
+ can use this method to break or continue the processing of the invocation chain. When this method
+ returns true, the endpoint execution chain will continue, when it returns
+ false, the MessageDispatcher assumes the interceptor itself
+ has taken care of things and does not continue executing the other interceptors and the actual endoint
+ 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.
+
+
+ There are a number of standard EndpointInterceptor implementations you
+ can use in your Web service. Additionally, there is the XwsSecurityInterceptor,
+ which is described in .
+
+
+ PayloadLoggingInterceptor and
+ SoapEnvelopeLoggingInterceptor
+
+ When developing a Web service, it can be useful to log the incoming and outgoing XML messages to
+ the log. Spring Web Services facilitates this with the
+ PayloadLoggingInterceptor and the
+ SoapEnvelopeLoggingInterceptor. The former just logs the payload of the
+ message to the Commons Logging Log; the latter logs the entire SOAP Envelope, including SOAP
+ headers. This example shows you how to define them in an endpoint mapping:
+
+
+
+
+
+
+
+
+
+
+ getOrderEndpoint
+ createOrderEndpoint
+
+
+
+
+
+]]>
+
+ Both of these interceptors have two properties: logRequest and
+ logResponse, which can be set to false to disable logging
+ for either request of response messages.
+
+
+
+ PayloadValidatingInterceptor
+
+ 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 or responses, or both.
+
+
+
+ Note that request validation may sound like a good idea, but 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 fullfill a request. Validating the response
+ is a good idea, because the endpoint should adhere to adhere to its schema.
+ Remember Postel's Law:
+ Be conservative in what you do; be liberal in what you accept from others.
+
+
+
+ Here is an example that uses the PayloadValidatingInterceptor:
+
+
+
+
+
+]]>
+
+ In this example, we use the schema in /WEB-INF/orders.xsd to validate the
+ response, but not the request.
+
+
+
+ PayloadTransformingInterceptor
+
+ To transform the payload to another XML format, Spring Web Services offers the
+ PayloadTransformingInterceptor. This endpoint interceptor is based on XSLT
+ stylesheets, and is especially useful when supporting with multiple version of a Web service:
+ you simply can transform the older message format to the new format.
+ Here is an example to use the PayloadTransformingInterceptor:
+
+
+
+
+]]>
+
+ We are simply transforming requests using /WEB-INF/oldRequests.xslt, and
+ response messages using /WEB-INF/oldResponses.xslt. Note that, since
+ endpoint interceptors are registered at the endpoint mapping level, you can simply create a
+ endpoint mapping that applies to the "old style" messages, and add the interceptor to that mapping.
+ Hence, the transformation will only apply to these "old style" message.
+
+