Documentation

This commit is contained in:
Arjen Poutsma
2010-12-20 15:42:28 +00:00
parent babe3de9c1
commit d2b6899f34

View File

@@ -1085,230 +1085,109 @@ public class AnnotationOrderEndpoint {
<title>Endpoint mappings</title>
<para>
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
<classname>PayloadRootQNameEndpointMapping</classname> or the
<classname>SoapActionEndpointMapping</classname>, but let's first examine the general concept of an
<interfacename>EndpointMapping</interfacename>.
There are some endpoint mappings that are enabled out of the box, for example, the
<classname>PayloadRootAnnotationMethodEndpointMapping</classname> or the
<classname>SoapActionAnnotationMethodEndpointMapping</classname>, but let's first examine the general
concept of an <interfacename>EndpointMapping</interfacename>.
</para>
<para>
An <interfacename>EndpointMapping</interfacename> delivers a <classname>EndpointInvocationChain</classname>,
which contains the endpoint that matches the incoming request, and may also contain a list of endpoint
interceptors that will be applied to the request and response. When a request comes in, the
<classname>MessageDispatcher</classname> will hand it over to the endpoint mapping to let it inspect the
request and come up with an appropriate <classname>EndpointInvocationChain</classname>. Then
the <classname>MessageDispatcher</classname> will invoke the endpoint and any interceptors in the chain.
interceptors that will be applied to the request and response.
When a request comes in, the <classname>MessageDispatcher</classname> will hand it over to the endpoint
mapping to let it inspect the request and come up with an appropriate
<classname>EndpointInvocationChain</classname>.
Then the <classname>MessageDispatcher</classname> will invoke the endpoint and any interceptors in the
chain.
</para>
<para>
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 <interfacename>EndpointMapping</interfacename>s. For example, there could be a custom endpoint
mapping that chooses an endpoint not only based on the contents of a message, but also on a specific SOAP
header (or indeed multiple SOAP headers).
the request or the response, or both) is extremely powerful.
A lot of supporting functionality can be built into custom <interfacename>EndpointMapping</interfacename>s.
For example, there could be a custom endpoint mapping that chooses an endpoint not only based on the
contents of a message, but also on a specific SOAP header (or indeed multiple SOAP headers).
</para>
<para>
Most endpoint mappings inherit from the <classname>AbstractEndpointMapping</classname>, which offers an
'<property>interceptors</property>' property, which is the list of interceptors to use.
<interfacename>EndpointInterceptors</interfacename> are discussed in
<xref linkend="server-endpoint-interceptor"/>. Additionally, there is the
'<property>defaultEndpoint</property>', which is the default endpoint to use, when this endpoint mapping does
not result in a matching endpoint.
<xref linkend="server-endpoint-interceptor"/>.
Additionally, there is the '<property>defaultEndpoint</property>', which is the default endpoint to use
when this endpoint mapping does not result in a matching endpoint.
</para>
<para>
As explained in <xref linkend="server-at-endpoint"/>, the <interfacename>@Endpoint</interfacename> style
allows you to handle multiple requests in one endpoint class.
This is the responsibility of the <classname>MethodEndpointMapping</classname>.
This mapping determines which method is to be invoked for an incoming request message.
</para>
<para>
There are two endpoint mappings that can direct requests to methods: the
<classname>PayloadRootAnnotationMethodEndpointMapping</classname> and the
<classname>SoapActionAnnotationMethodEndpointMapping</classname>, both of which are enabled by using
<literal>&lt;sws:annotation-driven/&gt;</literal> in your application context.
</para>
<para>
The <classname>PayloadRootAnnotationMethodEndpointMapping</classname> uses the
<interfacename>@PayloadRoot</interfacename> annotation, with the <literal>localPart</literal> and
<literal>namespace</literal> 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 <link linkend="server-payload-root-annotation">above</link>.
</para>
<para>
Alternatively, the <classname>SoapActionAnnotationMethodEndpointMapping</classname> uses the
<interfacename>@SoapAction</interfacename> annotation to mark methods with a particular SOAP Action.
Whenever a message comes in which has this <literal>SOAPAction</literal> header, the
method will be invoked.
</para>
<section>
<title><classname>PayloadRootQNameEndpointMapping</classname></title>
<para>
The <classname>PayloadRootQNameEndpointMapping</classname> 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 <emphasis>namespace URI</emphasis> and a <emphasis>local part</emphasis>, the combination of which
should be unique within the mapping. Here is an example:
</para>
<programlisting><![CDATA[<beans>
]]><lineannotation>&lt;!-- no <literal>'id'</literal> required, <interfacename>EndpointMapping</interfacename> beans are automatically detected by the <classname>MessageDispatcher</classname> --&gt;</lineannotation><![CDATA[
<bean id="endpointMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://samples}orderRequest">getOrderEndpoint</prop>
<prop key="{http://samples}order">createOrderEndpoint</prop>
</props>
</property>
</bean>
<bean id="getOrderEndpoint" class="samples.GetOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
<bean id="createOrderEndpoint" class="samples.CreateOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
<beans>]]></programlisting>
<para>
The qualified name is expressed as <literal>{</literal> + namespace URI + <literal>}</literal> +
local part. Thus, the endpoint mapping above routes requests for which have a payload root element with
namespace <uri>http://samples</uri> and local part <literal>orderRequest</literal> to the
<literal>'getOrderEndpoint'</literal>. Requests with a local part <literal>order</literal> will
be routed to the <literal>'createOrderEndpoint'</literal>.
</para>
</section>
<section id="server-soap-action-endpoint-mapping">
<title><classname>SoapActionEndpointMapping</classname></title>
<para>
Rather than base the routing on the contents of the message with the
<classname>PayloadRootQNameEndpointMapping</classname>, you can use the <literal>SOAPAction</literal>
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 <literal>SOAPAction</literal>
unique per operation, you can use it as a discriminator. Here is an example:
</para>
<programlisting><![CDATA[<beans>
<bean id="endpointMapping" class="org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping">
<property name="mappings">
<props>
<prop key="http://samples/RequestOrder">getOrderEndpoint</prop>
<prop key="http://samples/CreateOrder">createOrderEndpoint</prop>
</props>
</property>
</bean>
<bean id="getOrderEndpoint" class="samples.GetOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
<bean id="createOrderEndpoint" class="samples.CreateOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
</beans>]]></programlisting>
<para>
The mapping above routes requests which have a <literal>SOAPAction</literal> of
<uri>http://samples/RequestOrder</uri> to the <literal>'getOrderEndpoint'</literal>. Requests with
<uri>http://samples/CreateOrder</uri> will be routed to the <literal>'createOrderEndpoint'</literal>.
</para>
<caution>
<para>
Note that using SOAP Action headers is SOAP 1.1-specific, so it cannot be used when using Plain Old
XML, nor with SOAP 1.2.
</para>
</caution>
</section>
<section id="server-method-endpoint-mapping">
<title><classname>MethodEndpointMapping</classname></title>
<para>
As explained in <xref linkend="server-at-endpoint"/>, the <interfacename>@Endpoint</interfacename> style
allows you to handle multiple requests in one endpoint class. This is the responsibility of the
<classname>MethodEndpointMapping</classname>. Similar to the endpoint mapping described above, this
mapping determines which method is to be invoked for an incoming request message.
</para>
<para>
There are two endpoint mappings that can direct requests to methods: the
<classname>PayloadRootAnnotationMethodEndpointMapping</classname> and the
<classname>SoapActionAnnotationMethodEndpointMapping</classname>, both of which are very similar to
their non-method counterparts described above.
</para>
<para>
The <classname>PayloadRootAnnotationMethodEndpointMapping</classname> uses the
<interfacename>@PayloadRoot</interfacename> annotation, with the <literal>localPart</literal> and
<literal>namespace</literal> 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 <link linkend="server-payload-root-annotation">above</link>.
</para>
<para>
Alternatively, the <classname>SoapActionAnnotationMethodEndpointMapping</classname> uses the
<interfacename>@SoapAction</interfacename> annotation to mark methods with a particular SOAP Action.
Whenever a message comes in which has this <literal>SOAPAction</literal> header, the
method will be invoked.
</para>
</section>
<section id="server-ws-addressing">
<title>WS-Addressing</title>
<para>
WS-Addressing specifies a transport-neutral routing mechanism. It is based on a
<literal>To</literal> and <literal>Action</literal> SOAP header, which indicate the destination and
intent of the SOAP message, respectively. Additionally, WS-Addressing allows you to define a return
address (for normal messages and for faults), and a unique message identifier which can be used for
correlation
WS-Addressing specifies a transport-neutral routing mechanism.
It is based on a <literal>To</literal> and <literal>Action</literal> SOAP header, which indicate the
destination and intent of the SOAP message, respectively.
Additionally, WS-Addressing allows you to define a return address (for normal messages and for faults),
and a unique message identifier which can be used for correlation
<footnote>
<para>For more information on WS-Addressing, see <ulink url="http://en.wikipedia.org/wiki/WS-Addressing"/>.</para>
</footnote>.
Here is an example of a WS-Addressing message:
<programlisting><![CDATA[<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<SOAP-ENV::Header>
<wsa:MessageID>urn:uuid:21363e0d-2645-4eb7-8afd-2f5ee1bb25cf</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="true">http://example/com/fabrikam</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<f:maxCount>42</f:maxCount>
</f:Delete>
</SOAP-ENV:Body>
<SOAP-ENV::Header>
<wsa:MessageID>urn:uuid:21363e0d-2645-4eb7-8afd-2f5ee1bb25cf</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="true">http://example/com/fabrikam</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<f:maxCount>42</f:maxCount>
</f:Delete>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>]]></programlisting>
In this example, the destination is set to <uri>http://example/com/fabrikam</uri>, while the action is
set to <uri>http://example.com/fabrikam/mail/Delete</uri>. Additionally, there is a message identifier,
and an reply-to address. By default, this address is the "anonymous" address, indicating that a response
should be sent using the same channel as the request (i.e. the HTTP response), but it can also be
another address, as indicated in this example.
set to <uri>http://example.com/fabrikam/mail/Delete</uri>.
Additionally, there is a message identifier, and an reply-to address.
By default, this address is the "anonymous" address, indicating that a response should be sent using
the same channel as the request (i.e. the HTTP response), but it can also be another address,
as indicated in this example.
</para>
<para>
In Spring Web Services, WS-Addressing is implemented as an endpoint mapping. Using this mapping, you
associate WS-Addressing actions with endpoints, similar to the <classname>SoapActionEndpointMapping</classname>
described above.
In Spring Web Services, WS-Addressing is implemented as an endpoint mapping.
Using this mapping, you associate WS-Addressing actions with endpoints, similar to the
<classname>SoapActionAnnotationMethodEndpointMapping</classname> described above.
</para>
<section>
<title><classname>SimpleActionEndpointMapping</classname></title>
<para>
The <classname>SimpleActionEndpointMapping</classname> is meant to be used in a standard Spring
application context. It maps actions to endpoints via an exposed <property>mappings</property>
property. Here is an example:<programlisting><![CDATA[<beans>
<bean id="endpointMapping" class="org.springframework.ws.soap.addressing.server.SimpleActionEndpointMapping">
<property name="mappings">
<props>
<prop key="http://samples/RequestOrder">getOrderEndpoint</prop>
<prop key="http://samples/CreateOrder">createOrderEndpoint</prop>
</props>
</property>
</bean>
<bean id="getOrderEndpoint" class="samples.GetOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
<bean id="createOrderEndpoint" class="samples.CreateOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
</beans>]]></programlisting>
</para>
<para>
The mapping above routes requests which have a WS-Addressing <literal>Action</literal> of
<uri>http://samples/RequestOrder</uri> to the <literal>'getOrderEndpoint'</literal>. Requests with
<uri>http://samples/CreateOrder</uri> will be routed to the <literal>'createOrderEndpoint'</literal>.
</para>
<para>
By default, the <classname>SimpleActionEndpointMapping</classname> supports both the 1.0
(May 2006), and the August 2004 editions of WS-Addressing. These two versions are most popular, and
are interoperably with Axis 1 and 2, JAX-WS, XFire, Windows Communication Foundation (WCF), and
Windows Services Enhancemenets (WSE) 3.0. If necessary, specific versions of the spec can be
injected into the <property>versions</property> property.
</para>
<para>
Besides the <property>mappings</property> property, the endpoint mapping also has an
<property>address</property> property. If set, value of this property is compared to the
<literal>To</literal> header property of the incominging message.
</para>
<para>
Finally, there is the <property>messageSenders</property> property, which is required for sending
response messages to non-anonymous, out-of-bound addresses. You can set <interfacename>MessageSender</interfacename>
implementations in this property, the same as you would on the <classname>WebServiceTemplate</classname>.
See <xref linkend="client-transports"/>.
</para>
</section>
<section>
<title><classname>AnnotationActionEndpointMapping</classname></title>
<para>
The <classname>AnnotationActionEndpointMapping</classname> is quite similar to the <classname>SimpleActionEndpointMapping</classname>.
It has the same <property>versions</property> and <property>messageSenders</property> properties,
but uses Java 5 annotations.
The <classname>AnnotationActionEndpointMapping</classname> is similar to the
<classname>SoapActionAnnotationMethodEndpointMapping</classname>, but uses WS-Addressing headers
instead of the SOAP Action transport header.
</para>
<para>
To use the <classname>AnnotationActionEndpointMapping</classname>, annotate the handling methods
@@ -1341,10 +1220,30 @@ public class AnnotationOrderEndpoint {
}]]></programlisting>
</para>
<para>
The mapping above routes requests which have a WS-Addressing <literal>Action</literal> of
<uri>http://samples/RequestOrder</uri> to the <methodname>getOrder</methodname> method.
Requests with <uri>http://samples/CreateOrder</uri> will be routed to the
<methodname>order</methodname> method..
</para>
<para>
By default, the <classname>AnnotationActionEndpointMapping</classname> supports both the 1.0
(May 2006), and the August 2004 editions of WS-Addressing. These two versions are most popular, and
are interoperable with Axis 1 and 2, JAX-WS, XFire, Windows Communication Foundation (WCF), and
Windows Services Enhancements (WSE) 3.0.
If necessary, specific versions of the spec can be injected into the
<property>versions</property> property.
</para>
<para>
In addition to the <interfacename>@Action</interfacename> annotation, you can annotate the class
with the <interfacename>@Address</interfacename> annotation. If set, the value is compared to the
<literal>To</literal> header property of the incominging message.
<literal>To</literal> header property of the incoming message.
</para>
<para>
Finally, there is the <property>messageSenders</property> property, which is required for sending
response messages to non-anonymous, out-of-bound addresses. You can set <interfacename>MessageSender</interfacename>
implementations in this property, the same as you would on the <classname>WebServiceTemplate</classname>.
See <xref linkend="client-transports"/>.
</para>
</section>
</section>
@@ -1356,7 +1255,35 @@ public class AnnotationOrderEndpoint {
security-related SOAP headers, or the logging of request and response message.
</para>
<para>
Interceptors located in the endpoint mapping must implement the
Endpoint interceptors are typically defined by using a <literal>&lt;sws;interceptors &gt;</literal>
element in your application context.
In this element, you can simply define endpoint interceptor beans that apply to all endpoints defined
in that application context.
Alternatively, you can use <literal>&lt;sws:payloadRoot&gt;</literal> or
<literal>&lt;sws:soapAction&gt;</literal> elements to specify for which payload root name or SOAP
action the interceptor should apply.
For example:
<programlisting><![CDATA[<sws:interceptors>
<bean class="samples.MyGlobalInterceptor"/>
<sws:payloadRoot namespaceUri="http://www.example.com">
<bean class="samples.MyPayloadRootInterceptor"/>
</sws:payloadRoot>
<sws:soapAction value="http://www.example.com/SoapAction">
<bean class="samples.MySoapActionInterceptor1"/>
<bean class="samples.MySoapActionInterceptor2"/>
</sws:soapAction>
</sws:interceptors>]]></programlisting>
Here, we define one 'global' interceptor (<classname>MyGlobalInterceptor</classname>) that intercepts
all request and responses.
We also define an interceptor that only applies to XML messages that have the
<uri>http://www.example.com</uri> as a payload root namespace.
Here, we could have defined a <literal>localPart</literal> attribute in addition to the
<literal>namespaceUri</literal> to further limit the messages the interceptor applies to.
Finally, we define two interceptors that apply when the message has a
<uri>http://www.example.com/SoapAction</uri> SOAP action.
</para>
<para>
Interceptors must implement the
<interfacename>EndpointInterceptor</interfacename> interface from the
<package>org.springframework.ws.server</package> package. This interface defines three methods, one that
can be used for handling the request message <emphasis>before</emphasis> the actual
@@ -1391,24 +1318,11 @@ public class AnnotationOrderEndpoint {
the message to the Commons Logging Log; the latter logs the entire SOAP envelope, including SOAP
headers. The following example shows you how to define them in an endpoint mapping:
</para>
<programlisting><![CDATA[<beans>
<bean id="endpointMapping"
class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="interceptors">
<list>
<ref bean="loggingInterceptor"/>
</list>
</property>
<property name="mappings">
<props>
<prop key="{http://samples}orderRequest">getOrderEndpoint</prop>
<prop key="{http://samples}order">createOrderEndpoint</prop>
</props>
</property>
</bean>
<programlisting><![CDATA[
<sws:interceptors>
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</sws:interceptors>
<bean id="loggingInterceptor"
class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</beans>]]></programlisting>
<para>
Both of these interceptors have two properties: '<property>logRequest</property>' and
@@ -1452,7 +1366,7 @@ public class AnnotationOrderEndpoint {
<para>
To transform the payload to another XML format, Spring Web Services offers the
<classname>PayloadTransformingInterceptor</classname>. This endpoint interceptor is based on XSLT
stylesheets, and is especially useful when supporting multiple versions of a Web service:
style sheets, and is especially useful when supporting multiple versions of a Web service:
you can transform the older message format to the newer format. Here is an example to use the
<classname>PayloadTransformingInterceptor</classname>:
</para>