This commit is contained in:
Arjen Poutsma
2007-05-18 12:26:58 +00:00
parent cd14b8efa2
commit 5a41659857
4 changed files with 182 additions and 102 deletions

View File

@@ -33,11 +33,8 @@
<outputDirectory>docs/api</outputDirectory>
</fileSet>
<fileSet>
<directory>doc/target/docbkx</directory>
<directory>target/site/reference</directory>
<outputDirectory>docs/reference</outputDirectory>
<excludes>
<exclude>**/*.fo</exclude>
</excludes>
</fileSet>
<!-- Samples -->
<fileSet>

View File

@@ -4,7 +4,7 @@
<chapter id="common">
<title>Shared components</title>
<para>
In this chapter, we will explore the the components which are shared between client- and server side
In this chapter, we will explore the the components which are shared between client- and server side
Spring-WS development. These interfaces and classes represent the building blocks of Spring-WS, so
it's important to understand what they do, even if you do not use them directly.
</para>
@@ -13,10 +13,10 @@
<section id="web-service-message">
<title><interfacename>WebServiceMessage</interfacename></title>
<para>
One of the core interfaces within Spring Web Services is the
One of the core interfaces within Spring Web Services is the
<interfacename>WebServiceMessage</interfacename>. 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 <interfacename>javax.xml.transform.Source</interfacename> or a
of a <interfacename>javax.xml.transform.Source</interfacename> or a
<interfacename>javax.xml.transform.Result</interfacename>. <interfacename>Source</interfacename> and
<interfacename>Result</interfacename> are tagging interfaces that represent an abstraction over XML
input and output. Concrete implementations wrap various XML representations, as indicated in the table
@@ -74,39 +74,39 @@
<section id="soap-message">
<title><interfacename>SoapMessage</interfacename></title>
<para>
The <interfacename>SoapMessage</interfacename> is an extension of
The <interfacename>SoapMessage</interfacename> is an extension of
<interfacename>WebServiceMessage</interfacename>. 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 only not be dependent on
<interfacename>SoapMessage</interfacename>, because the content of the SOAP Body can be obtained via
<methodname>getPayloadSource()</methodname> and <methodname>getPayloadResult()</methodname> in the
<interfacename>WebServiceMessage</interfacename>. Only when it is necessary to perform SOAP-specific
actions, such as adding a header, get an attachment, etc., should you need to cast
<methodname>getPayloadSource()</methodname> and <methodname>getPayloadResult()</methodname> in the
<interfacename>WebServiceMessage</interfacename>. Only when it is necessary to perform SOAP-specific
actions, such as adding a header, get an attachment, etc., should you need to cast
<interfacename>WebServiceMessage</interfacename> to <interfacename>SoapMessage</interfacename>.
</para>
</section>
<section id="message-factories">
<title>Message Factories</title>
<para>
Concrete message implementation are created by a
Concrete message implementation are created by a
<interfacename>WebServiceMessageFactory</interfacename>. This factory can create an empty message, or
read a message based on an input stream.
There are two concrete implementations of <interfacename>WebServiceMessageFactory</interfacename>.
One is based on SAAJ, the SOAP with Attachments API for Java, the other based on Axis 2's AXIOM, the
One is based on SAAJ, the SOAP with Attachments API for Java, the other based on Axis 2's AXIOM, the
AXis Object Model.
</para>
<section>
<title><classname>SaajSoapMessageFactory</classname></title>
<para>
The <classname>SaajSoapMessageFactory</classname> uses the SOAP with Attachments API for Java to
create <classname>SoapMessage</classname> implementations. SAAJ is part of J2EE 1.4, so it should be
supported under most modern application servers. You wire up a
The <classname>SaajSoapMessageFactory</classname> uses the SOAP with Attachments API for Java to
create <classname>SoapMessage</classname> implementations. SAAJ is part of J2EE 1.4, so it should be
supported under most modern application servers. You wire up a
<classname>SaajSoapMessageFactory</classname> like so:
<programlisting><![CDATA[
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />]]></programlisting>
</para>
<note>
<para>
SAAJ is based on DOM, the Document Object Model. This means that all SOAP messages are
SAAJ is based on DOM, the Document Object Model. This means that all SOAP messages are
stored in memory as a whole. For larger SOAP messages, this may not be very performant.
In that case, the <classname>AxiomSoapMessageFactory</classname> might be more applicable.
</para>
@@ -115,15 +115,15 @@
<section>
<title><classname>AxiomSoapMessageFactory</classname></title>
<para>
The <classname>AxiomSoapMessageFactory</classname> uses the AXis 2 Object Model to create
<interfacename>SoapMessage</interfacename> 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
The <classname>AxiomSoapMessageFactory</classname> uses the AXis 2 Object Model to create
<interfacename>SoapMessage</interfacename> 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.
</para>
<para>
To increase reading performance on the <classname>AxiomSoapMessageFactory</classname>,
To increase reading performance on the <classname>AxiomSoapMessageFactory</classname>,
you can set the <property>payloadCaching</property> property to false (default is true).
This this will read the contents of the SOAP body directly from the stream.
This this will read the contents of the SOAP body directly from the stream.
When this setting is enabled, the payload can only be read once.
This means that you have to make sure that any preprocessing of the message does not consume it.
</para>
@@ -133,7 +133,7 @@
<bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
<property name="payloadCaching" value="true"/>
</bean>]]></programlisting>
</para>
</para>
</section>
</section>
<section id="message-context">
@@ -144,7 +144,7 @@
sent back to the client, where it is read.
</para>
<para>
In Spring Web Services, such a conversation is contained in a
In Spring Web Services, such a conversation is contained in a
<interfacename>MessageContext</interfacename>, which has properties to get request and response
messages.
On the client-side, the message context is created by the <link linkend="client-web-service-template">
@@ -159,21 +159,30 @@
<title>Handling XML With XPath</title>
<para>
One of the best ways to handle XML is to use XPath. Quoting <xref linkend="effective-xml"/>, item 35:
<blockquote>
<para>
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.
</para>
<attribution>Elliotte Rusty Harold</attribution>
</blockquote>
</para>
<para>
<sidebar>
<title>What is XPath?</title>
<para>
XPath is a language for addressing parts of an XML document.
For more information about XPath, refer to the
<ulink url="http://www.w3.org/TR/xpath">XPath specification</ulink>, or read the
<ulink url="http://www.w3schools.com/xpath/">XPath tutorial</ulink>
</para>
</sidebar>
<blockquote>
<para>
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.
</para>
<attribution>Elliotte Rusty Harold</attribution>
</blockquote>
<para>
Spring Web Services has two ways to use XPath within your application: the faster
<interfacename>XPathExpression</interfacename> or the more flexible <classname>XPathTemplate</classname>.
</para>

View File

@@ -16,8 +16,8 @@
of course <classname>AbstractMarshallingPayloadEndpoint</classname>. Application endpoints will typically
be subclasses of those.
Alternatively, there is a endpoint development that uses Java 5 annotations, such as
<literal>@Endpoint</literal> for marking a POJO as endpoint, and marking a method with
<literal>@PayloadRoot</literal> or <literal>@SoapAction</literal>.
<interfacename>@Endpoint</interfacename> for marking a POJO as endpoint, and marking a method with
<interfacename>@PayloadRoot</interfacename> or <interfacename>@SoapAction</interfacename>.
</para>
<para>
Spring-WS's XML handling is extremely flexible. An endpoint can choose from
@@ -253,8 +253,10 @@ public class SampleEndpoint extends AbstractDomPayloadEndpoint {
base classes which use alternative DOM APIs. Spring Web Services supports most DOM APIs, so that you
can use the one you are familiar with. For instance, the
<classname>AbstractJDomPayloadEndpoint</classname> allows you to use JDOM, and the
<classname>AbstractXomPayloadEndpoint</classname> uses XOM to handle the XML. All endpoints have an
<methodname>invokeInternal</methodname> method similar to above.
<classname>AbstractXomPayloadEndpoint</classname> uses XOM to handle the XML. All of these endpoints
have an <methodname>invokeInternal</methodname> method similar to above.
Also, consider to use Spring-WS's XPath support to extract the information you need out of the payload,
see <xref linkend="xpath"/>.
</para>
</section>
<section>
@@ -295,8 +297,7 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
return order;
}
}]]></programlisting>
<programlisting><![CDATA[
<beans>
<programlisting><![CDATA[<beans>
<bean id="orderEndpoint" class="samples.MarshallingOrderEndpoint">
<constructor-arg ref="orderService"/>
<constructor-arg ref="marshaller"/>
@@ -312,6 +313,8 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
</bean>
<bean id="orderService" class="samples.DefaultOrderService"/>
<!-- Other beans, such as the endpoint mapping -->
</beans>]]></programlisting>
<para>
In this sample, we configure a <link linkend="oxm-jaxb2">Jaxb2Marshaller</link> for the
@@ -356,7 +359,74 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
</section>
<section>
<title><literal>@Endpoint</literal></title>
<para/>
<para>
The previous two programming models were based on inheritance, and handled individual XML mesages.
Spring Web Services offer another endpoint with which you aggregate multiple handling into one
controller, thus grouping functionality together. This model is based on annotations, so you can only
use it under Java 5 and higher. Here is an example that uses the same marshalled objects as above:
</para>
<programlisting><![CDATA[package samples;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
@Endpoint
public class AnnotationOrderEndpoint {
private final OrderService orderService;
public AnnotationOrderEndpoint(OrderService orderService) {
this.orderService = orderService;
}
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
public Order getOrder(OrderRequest orderRequest) {
return orderService.getOrder(orderRequest.getId());
}
@PayloadRoot(localPart = "order", namespace = "http://samples")
public void order(Order order) {
orderService.createOrder(order);
}
}]]></programlisting>
<para>
By annotating the class with <interfacename>@Endpoint</interfacename>, you mark it as a Spring-WS
endpoint. Because the endpoint class can have multiple request handling methods, we need to instruct
Spring-WS which method to invoke for which request. This is done using the
<interfacename>@PayloadRoot</interfacename> annotation: the <methodname>getOrder</methodname> method
will be invoked for requests with a <literal>orderRequest</literal> local name, and a
<uri>http://samples</uri> namespace URI; the <methodname>order</methodname> method for requests with
a <literal>order</literal> local name. For more information about these annotations, refer to
<xref linkend="server-method-endpoint-mapping"/>.
Obviously, we also need to configure Spring-WS to support the JAXB objects
<classname>OrderRequest</classname> and <classname>Order</classname> by defining a
<classname>Jaxb2Marshaller</classname>. This is what the configuration
looks like:
</para>
<programlisting><![CDATA[<beans>
<bean id="orderEndpoint" class="samples.AnnotationOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
<bean id="orderService" class="samples.DefaultOrderService"/>
<bean class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<constructor-arg ref="marshaller"/>
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="samples"/>
</bean>
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
</beans>]]></programlisting>
<para>
The <classname>MarshallingMethodEndpointAdapter</classname> converts the incoming
XML messages to marshalled objects used as parameters and return value; the
<classname>PayloadRootAnnotationMethodEndpointMapping</classname> is the mapping that detects and
handles the <interfacename>@PayloadRoot</interfacename> annotations.
</para>
</section>
</section>
<section id="server-endpoint-mapping">
@@ -411,66 +481,70 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
<title>PayloadRootQNameEndpointMapping</title>
<para/>
</section>
<section id="server-method-endpoint-mapping">
<title><classname>MethodEndpointMapping</classname></title>
<para/>
</section>
<section id="server-endpoint-interceptor">
<title>Adding <interfacename>EndpointInterceptors</interfacename></title>
<para/>
</section>
<section id="server-endpoint-exception-resolver">
<title>Handling Exceptions</title>
<para>
Spring-WS provides
<classname>EndpointExceptionResolvers</classname>
to ease the pain of unexpected
exceptions occurring while your message is being processed by an endpoint which matched the request.
<classname>EndpointExceptionResolver</classname>
s somewhat resemble the exception mappings that can be
defined in the web application descriptor
<filename>web.xml</filename>
.
Rather than expose the innards of your application by giving a client a full stack trace, you can handle
the exception any way you want, e.g. return a SOAP fault with a specific fault code and string.
Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond
appropriately.
</para>
<para>
Besides implementing the
<classname>HandlerExceptionResolver</classname>
interface, which is only a
matter of implementing the
<methodname>resolveException(MessageContext, endpoint, Exception)</methodname>
method and returning a
boolean, you may also use the
<classname>SoapFaultMappingExceptionResolver</classname>
.
This resolver enables you to take the class name of any exception that might be thrown and map it to a
SOAP Fault, like so:
<programlisting><![CDATA[
</section>
<section id="server-endpoint-exception-resolver">
<title>Handling Exceptions</title>
<para>
Spring-WS provides
<classname>EndpointExceptionResolvers</classname>
to ease the pain of unexpected
exceptions occurring while your message is being processed by an endpoint which matched the request.
<classname>EndpointExceptionResolver</classname>
s somewhat resemble the exception mappings that can be
defined in the web application descriptor
<filename>web.xml</filename>
.
Rather than expose the innards of your application by giving a client a full stack trace, you can handle
the exception any way you want, e.g. return a SOAP fault with a specific fault code and string.
Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond
appropriately.
</para>
<para>
Besides implementing the
<classname>HandlerExceptionResolver</classname>
interface, which is only a
matter of implementing the
<methodname>resolveException(MessageContext, endpoint, Exception)</methodname>
method and returning a
boolean, you may also use the
<classname>SoapFaultMappingExceptionResolver</classname>
.
This resolver enables you to take the class name of any exception that might be thrown and map it to a
SOAP Fault, like so:
<programlisting><![CDATA[
<bean id="exceptionResolver"
class="org.springframework.ws.soap.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="RECEIVER,Server error">
</property>
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.ValidationFailureException">
SENDER,Invalid request
</prop>
</props>
</property>
class="org.springframework.ws.soap.endpoint.SoapFaultMappingExceptionResolver">
<property name="defaultFault" value="RECEIVER,Server error">
</property>
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.ValidationFailureException">
SENDER,Invalid request
</prop>
</props>
</property>
</bean>
]]></programlisting>
This configuration will map exceptions of type
<classname>ValidationFailureException</classname>
to a
sender side SOAP Fault with a fault string "Invalid request".
If any other exception occurs, it will return the default fault: a server side fault with fault string
"Server error".
Refer to the Javadoc of
<classname>SoapFaultDefinitionEditor</classname>
to read more about the exact
notation of the faults.
</para>
</section>
</section>
This configuration will map exceptions of type
<classname>ValidationFailureException</classname>
to a
sender side SOAP Fault with a fault string "Invalid request".
If any other exception occurs, it will return the default fault: a server side fault with fault string
"Server error".
Refer to the Javadoc of
<classname>SoapFaultDefinitionEditor</classname>
to read more about the exact
notation of the faults.
</para>
</section>
<section>
<title>Similarities between Spring-MVC and Spring-WS</title>
@@ -535,4 +609,4 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
</informaltable>
</para>
</section>
</chapter>
</chapter>

View File

@@ -379,7 +379,7 @@
</wsdl:binding>
<wsdl:service name="HumanResourceService">
<wsdl:port binding="tns:HumanResourceBinding" name="HumanResourcePort">
<soap:address location="http://mycompany.com/humanresources"/>
<soap:address location="http://localhost:8080/holidayService/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>]]></programlisting>
@@ -431,7 +431,7 @@
</callout>
<callout arearefs="tutorial.wsdl.address">
<para>
The <uri>http://mycompany.com/humanresources</uri> address is the URL where the Web
The <uri>http://localhost:8080/holidayService/</uri> address is the URL where the Web
service can be invoked.
</para>
</callout>