[SWS-120]

[SWS-125]

Documentation corrections.
This commit is contained in:
Rick Evans
2007-05-23 20:37:09 +00:00
parent 99e597b315
commit 1ffa706f30
8 changed files with 143 additions and 135 deletions

View File

@@ -7,14 +7,14 @@
<title>Introduction</title>
<para>
Spring-WS provides a client-side Web service API that allows for consistent, XML-driven access to Web
services. It also allows for use of <link linkend="oxm">marshallers and unmarshallers</link>.
services. It also allows for the use of <link linkend="oxm">marshallers and unmarshallers</link>.
</para>
<para>
The package <package>org.springframework.ws.client.core</package> provides the core functionality for using
the client-side access API. It contains template classes that simplifies the use of Web services, much like
the <classname>JdbcTemplate</classname> 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
the essence of the processing task to user implemented callback interfaces. The Web service template
to user implemented callback interfaces. The Web service template
follows the same design. The classes offer various convenience methods for the sending and receiving of XML
messages, marshalling objects to XML before sending, and allows for multiple transports,
</para>
@@ -82,6 +82,7 @@ import org.springframework.ws.transport.WebServiceMessageSender;
public class WebServiceClient {
private static final String MESSAGE = "<message xmlns=\"http://tempuri.org\">Hello Web Service World</message>";
private WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
public void setDefaultUri(String defaultUri) {
@@ -95,9 +96,6 @@ public class WebServiceClient {
}
}]]></programlisting>
<para>
Here is the corresponding configuration:
</para>
<programlisting><![CDATA[
<beans xmlns="http://www.springframework.org/schema/beans">
@@ -121,7 +119,7 @@ public class WebServiceClient {
<title>Marshalling, sending, receiving, and unmarshalling</title>
<para>
In order to facilitate the sending of plain Java objects, the <classname>WebServiceTemplate</classname>
has a send methods that take an object as an argument for a message's data content.
has a number of send methods that take an object as an argument for a message's data content.
The method <methodname>marshalSendAndReceive</methodname> in <classname>WebServiceTemplate</classname>
delegates the conversion of the request object to XML to a <interface>Marshaller</interface>, and
the conversion of the response XML to an object to an <interface>Unmarshaller</interface>.
@@ -138,7 +136,7 @@ public class WebServiceClient {
<interface>WebServiceMessageCallback</interface>
</title>
<para>
To accommodate the setting of a SOAP headers, and other settings on the message, the
To accommodate the setting of SOAP headers, and other settings on the message, the
<interfacename>WebServiceMessageCallback</interfacename> interface gives you access to the message
after it has been created, but before it is sent. The example below demonstrates how to set the SOAP
Action header on a message that is created by marshalling an object.

View File

@@ -6,7 +6,7 @@
<para>
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.
it is important to understand what they do, even if you do not use them directly.
</para>
<section id="web-service-messages">
<title>Web service messages</title>
@@ -123,7 +123,7 @@
<para>
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 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>
@@ -139,8 +139,9 @@
<section id="message-context">
<title><interfacename>MessageContext</interfacename></title>
<para>
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
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.
</para>
<para>
@@ -149,8 +150,8 @@
messages.
On the client-side, the message context is created by the <link linkend="client-web-service-template">
<classname>WebServiceTemplate</classname></link>.
On the server-side, the message context is read from the transport-specific input stream. In HTTP,
it is read from the <interfacename>HttpServletRequest</interfacename> and the response is written back
On the server-side, the message context is read from the transport-specific input stream.
For example, in HTTP, it is read from the <interfacename>HttpServletRequest</interfacename> and the response is written back
to the <interfacename>HttpServletResponse</interfacename>.
</para>
</section>
@@ -158,7 +159,8 @@
<section id="xpath">
<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:
One of the best ways to handle XML is to use XPath.
Quoting <xref linkend="effective-xml"/>, item 35:
</para>
<blockquote>
<para>
@@ -173,14 +175,14 @@
</para>
<attribution>Elliotte Rusty Harold</attribution>
</blockquote>
<para>
<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>
<section id="xpath-expression">
<title><interfacename>XPathExpression</interfacename></title>
<para>
The <interfacename>XPathExpression</interfacename> is an abstraction over a compiled XPath expressions,
The <interfacename>XPathExpression</interfacename> is an abstraction over a compiled XPath expression,
such as the Java 5 <interfacename>javax.xml.xpath.XPathExpression</interfacename>, or the Jaxen
<classname>XPath</classname> class.
To construct an expression in an application context, there is the
@@ -189,7 +191,7 @@
<programlisting><![CDATA[<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="nameExpression" class="org.springframework.xml.xpath.XPathExpressionFactoryBean">
<property name="expression" value="/Contacts/Contact/Name"/>
@@ -202,14 +204,14 @@
</beans>]]></programlisting>
<para>
The expression above does not use namespaces, but we could set those using the
<property>namespaces</property> property of the factory bean. The expression can be used in the code
as follows:
<property>namespaces</property> property of the factory bean. The expression
can be used in the code as follows:
</para>
<programlisting><![CDATA[package sample;
public class MyXPathClass {
private XPathExpression nameExpression;
private final XPathExpression nameExpression;
public MyXPathClass(XPathExpression nameExpression) {
this.nameExpression = nameExpression;
@@ -230,24 +232,24 @@ public class MyXPathClass {
public class MyXPathClass {
private XPathExpression contactExpression;
private final XPathExpression contactExpression;
public MyXPathClass(XPathExpression contactExpression) {
this.contactExpression = contactExpression;
}
public MyXPathClass(XPathExpression contactExpression) {
this.contactExpression = contactExpression;
}
public void doXPath(Document document) {
List contacts = nameExpression.evaluate(requestElement,
new NodeMapper() {
public Object mapNode(Node node, int nodeNum) throws DOMException {
Element contactElement = (Element) node;
Element nameElement = (Element) contactElement.getElementsByTagName("Name").item(0);
Element phoneElement = (Element) contactElement.getElementsByTagName("Phone").item(0);
return new Contact(nameElement.getTextContent(), phoneElement.getTextContent());
}
} );
// do something with list of Contact objects
}
public void doXPath(Document document) {
List contacts = nameExpression.evaluate(requestElement,
new NodeMapper() {
public Object mapNode(Node node, int nodeNum) throws DOMException {
Element contactElement = (Element) node;
Element nameElement = (Element) contactElement.getElementsByTagName("Name").item(0);
Element phoneElement = (Element) contactElement.getElementsByTagName("Phone").item(0);
return new Contact(nameElement.getTextContent(), phoneElement.getTextContent());
}
});
]]><lineannotation>// do something with list of <classname>Contact</classname> objects</lineannotation><![CDATA[
}
}]]></programlisting>
<para>
Similar to mapping rows in Spring JDBC's <interfacename>RowMapper</interfacename>, each result node is
@@ -271,12 +273,13 @@ public class MyXPathClass {
public void doXPath(Source source) {
String name = template.evaluateAsString("/Contacts/Contact/Name", request);
// do something with name
]]><lineannotation>// do something with name</lineannotation><![CDATA[
}
}]]></programlisting>
<para>
Of course, the template could have been injected with a constructor argument or a setter.
Of course, the template could have been injected with a
constructor argument or a setter.
</para>
</section>
</section>

View File

@@ -37,8 +37,8 @@
<partintro>
<para>
This first part of the reference documentation gives an overview of Spring Web Services, and the
underlying concepts. We will introduce Spring-WS, and explain the concepts behind contract-first
Web service development.
underlying concepts. Spring-WS is introduced, and the concepts behind contract-first
Web service development are explained.
</para>
</partintro>
<xi:include href="what-is-spring-ws.xml" />
@@ -49,8 +49,8 @@
<title>Reference</title>
<partintro>
<para>
This part of the reference documentation gives an in-depth look into the various pieces that make up
Spring Web Services.
This part of the reference documentation gives an in-depth look into the various components that
comprise Spring Web Services.
It consists of a chapter which discusses the parts common to both client- and server-side, a chapter
about writing server-side Web services, about using Web services on the client-side, using WS-Security,
and the flexible Object/XML mapping.

View File

@@ -5,9 +5,9 @@
<title>Preface</title>
<para>
In the current age of Service Oriented Architectures, more and more people are using Web Services to
connect previously unconnected systems. Initially, Web services where 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 RPC and Web services. Especially when interoperability with other platforms is important, it is often
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, containing all the data necessary to process the request.
Conceptually, XML-based Web services are better off being compared to message queues rather than remoting
solutions.

View File

@@ -6,25 +6,26 @@
<section id="ws-introduction">
<title>Introduction</title>
<para>
Spring Web Services's server-side support in designed around a <classname>MessageDispatcher</classname>
that dispatches incoming messages to endpoints, with configurable endpoint mappings, response generation,
and endpoint interception.
Spring-WS's server-side support is designed around a
<classname>MessageDispatcher</classname> that dispatches incoming
messages to endpoints, with configurable endpoint mappings, response
generation, and endpoint interception.
The simplest endpoint is a <interfacename>PayloadEndpoint</interfacename>, just offering a
<literal>Source invoke(Source request)</literal> method. This interface can be implemented for creating an
endpoint, but you will prefer the included implementation hierarchy, consisting of, for example
<literal>Source invoke(Source request)</literal> method. You are of course free to
implement this interface directly, but you will probably prefer to extend one of
the included abstract implementations such as
<classname>AbstractDomPayloadEndpoint</classname>, <classname>AbstractSaxPayloadEndpoint</classname>, and
of course <classname>AbstractMarshallingPayloadEndpoint</classname>. Application endpoints will typically
be subclasses of those.
<classname>AbstractMarshallingPayloadEndpoint</classname>.
Alternatively, there is a endpoint development that uses Java 5 annotations, such as
<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
a large amount of XML handling libraries supported by Spring-WS, including the DOM family (W3C DOM, JDOM,
dom4j, and XOM), SAX or StAX for faster performance, XPath to extract information from the message, or even
<link linkend="oxm">marshalling techniques</link> (JAXB, Castor, XMLBeans, JiBX, or XStream) to convert
the XML to objects and vice-versa.
</para>
<para>
Spring-WS's XML handling is extremely flexible. An endpoint can choose from
a large amount of XML handling libraries supported by Spring-WS, including the DOM family (W3C DOM, JDOM,
dom4j, and XOM), SAX or StAX for faster performance, XPath to extract information from the message, or even
<link linkend="oxm">marshalling techniques</link> (JAXB, Castor, XMLBeans, JiBX, or XStream) to convert
the XML to objects and vice-versa.
</para>
</section>
<section>
@@ -33,7 +34,7 @@
The server-side of Spring-WS is designed around a central class that dispatches incoming XML messages to
endpoints. Spring-WS's <classname>MessageDispatcher</classname> is extremely flexible, allowing you to
use any sort of class as an endpoint, as long as it can be configured in the Spring IoC container.
In a way, the message dispatcher resembles Spring's<classname>DispatcherServlet</classname>, the
In a way, the message dispatcher resembles Spring's <classname>DispatcherServlet</classname>, the
<quote>Front Controller</quote> used in Spring Web MVC.
</para>
<para>
@@ -55,20 +56,23 @@
When a <classname>MessageDispatcher</classname> is set up for use and a request comes in for that
specific dispatcher, said <classname>MessageDispatcher</classname> starts processing the request. The
list below describes the complete process a request goes through when handled by a
<classname>MessageDispatcher</classname>:
<classname>MessageDispatcher</classname>:
</para>
<orderedlist>
<listitem>
<para>
An appropriate endpoint is searched for. If an endpoint is found, the invocation chain associated
with the endpoint (preprocessors, postprocessors, and endpoints) will be executed in order to create
An appropriate endpoint is searched for using the configured
<literal>EndpointMapping(s)</literal>. If an endpoint is found,
the invocation chain associated with the endpoint (preprocessors,
postprocessors, and endpoints) will be executed in order to create
a response.
</para>
</listitem>
<listitem>
<para>
An appropriate adapter is searched for the endpoint. The <classname>MessageDispatcher</classname>
delegates to this adapter to invoke the endpoint.
An appropriate adapter is searched for the endpoint. The
<classname>MessageDispatcher</classname> delegates to this adapter
to invoke the endpoint.
</para>
</listitem>
<listitem>
@@ -107,7 +111,7 @@
The <classname>MessageDispatcherServlet</classname> is a standard <interface>Servlet</interface> which
conveniently extends from the standard Spring Web <classname>DispatcherServlet</classname>, and wraps
a <classname>MessageDispatcher</classname>. As such, it combines the attributes of these into one:
as a <classname>MessageDispatcher</classname>, if follows the same request handling flow as described
as a <classname>MessageDispatcher</classname>, it follows the same request handling flow as described
in the previous section.
As a servlet, the
<classname>MessageDispatcherServlet</classname> is configured in the <filename>web.xml</filename> of
@@ -129,11 +133,13 @@
<url-pattern>/*</url-pattern>
</servlet-mapping>
]]><lineannotation>&lt;!-- ... --&gt;</lineannotation><![CDATA[
</web-app>]]></programlisting>
<para>
In the example above, all requests will be handled by the <literal>'spring-ws'</literal>
<classname>MessageDispatcherServlet</classname>. This is only the first step in setting up Spring Web
Services; the various endpoint and other beans used by the Spring Web Services framework also need to be
Services; the various endpoint and other beans used by the Spring-WS framework also need to be
configured.
</para>
<para>
@@ -149,21 +155,21 @@
<title>Endpoints</title>
<para>
Endpoints are the central concept in Spring-WS's server-side support. Endpoints provide access to the
application behavior which is typically defined by a business service interface. Endpoint interpret the XML
request message and uses that input to invoke a method on the business service. The result of that service
application behavior which is typically defined by a business service interface. An endpoint interprets the XML
request message and uses that input to invoke a method on the business service (typically). The result of that service
invocation is represented as a response message. Spring-WS has a wide variety of endpoints, using various
ways to handle the XML message, and to create a response.
</para>
<para>
The basis for most endpoint in Spring Web Services is the
The basis for most endpoints in Spring Web Services is the
<interfacename>org.springframework.ws.server.endpoint.PayloadEndpoint</interfacename> interface, the source
code of which is listed below.
</para>
<programlisting><![CDATA[public interface PayloadEndpoint {
/**
]]><lineannotation>/**
* Invokes an operation.
*/
*/</lineannotation><![CDATA[
Source invoke(Source request) throws Exception;
}]]></programlisting>
<para>
@@ -176,11 +182,11 @@
most basic responsibility required of every endpoint; namely handling a request and returning a response.
</para>
<para>
Alternatively, there is the <interfacename>MessageEndpoint</interfacename>, which operated on a
Alternatively, there is the <interfacename>MessageEndpoint</interfacename>, which operates on a
whole <link linkend="message-context"><interfacename>MessageContext</interfacename></link> rather than just
the payload. Typically, your code should only not be dependent on messages, because the payload should
contain the interesting information. Only when it is necessary to perform actions on the mesage a whole,
such as adding a SOAP header, get an attachment, etc., should you need to cast to implement
contain the interesting information. Only when it is necessary to perform actions on the mesage as a whole,
such as adding a SOAP header, get an attachment, and so forth, should you need to implement
<interfacename>MessageEndpoint</interfacename>, though these actions are usually performed in a
<link linkend="server-endpoint-interceptor">endpoint interceptor</link>.
</para>
@@ -192,7 +198,7 @@
<package>org.w3c.dom.Element</package> and related classes to handle the request, and create the
response. When using the <classname>AbstractDomPayloadEndpoint</classname> as the baseclass for your
endpoints you only have to override the <methodname>invokeInternal(Element, Document)</methodname>
method, implement your logic, and return an <interfacename>Element</interfacename> if we want a
method, implement your logic, and return an <interfacename>Element</interfacename> if you want a
response. Here is a short example consisting of a class and a declaration in the application context.
</para>
<programlisting><![CDATA[package samples;
@@ -220,7 +226,7 @@ public class SampleEndpoint extends AbstractDomPayloadEndpoint {
<constructor-arg value="Hello World!"/>
</bean>]]></programlisting>
<para>
The above class and the declaration in the application context is all you need besides setting up a
The above class and the declaration in the application context is all you need besides setting up an
endpoint mapping (see the section entitled <xref linkend="server-endpoint-mapping" />) to get this very
simple endpoint working. The SOAP message handled by this endpoint will look something like:
</para>
@@ -255,8 +261,8 @@ public class SampleEndpoint extends AbstractDomPayloadEndpoint {
<classname>AbstractJDomPayloadEndpoint</classname> allows you to use JDOM, and the
<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"/>.
Also, consider using Spring-WS's XPath support to extract the information you need out of the payload.
(See the section entitled <xref linkend="xpath"/> for details.)
</para>
</section>
<section>
@@ -314,7 +320,7 @@ public class MarshallingOrderEndpoint extends AbstractMarshallingPayloadEndpoint
<bean id="orderService" class="samples.DefaultOrderService"/>
<!-- Other beans, such as the endpoint mapping -->
]]><lineannotation>&lt;!-- Other beans, such as the endpoint mapping --&gt;</lineannotation><![CDATA[
</beans>]]></programlisting>
<para>
In this sample, we configure a <link linkend="oxm-jaxb2">Jaxb2Marshaller</link> for the
@@ -516,16 +522,16 @@ public class AnnotationOrderEndpoint {
interceptors that are 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 invoce the endpoint and any interceptors in the chain.
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. Think of a custom endpoint mapping that
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 a specific SOAP headers.
</para>
<para>
Most endpoint mappings inherit from the <classname>AbstractEndpointMapping</classname>, which offers a
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>EndpointInterceptor</interfacename>s are discussed in
<xref linkend="server-endpoint-interceptor"/>. Additionally, there is the
@@ -565,9 +571,7 @@ public class AnnotationOrderEndpoint {
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>'createController'</literal>. As a result of this mapping, the SOAP message
shown <link linkend="server-order-request">above</link> will be mapped to the
<literal>getOrderEndpoint</literal>.
be routed to the <literal>'createOrderEndpoint'</literal>.
</para>
</section>
<section>
@@ -607,9 +611,9 @@ public class AnnotationOrderEndpoint {
<section id="server-method-endpoint-mapping">
<title><classname>MethodEndpointMapping</classname></title>
<para>
As explain in <xref linkend="server-at-endpoint"/>, the <interfacename>@Endpoint</interfacename> model
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, 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>
@@ -643,17 +647,18 @@ public class AnnotationOrderEndpoint {
Interceptors located in the endpoint mapping must implement
<interfacename>EndpointInterceptor</interfacename> from the
<package>org.springframework.ws.server</package> package. This interface defines three methods, one that
can be used for handling the request message has been determined, <emphasis>before</emphasis> the actual
can be used for handling the request message has been determined <emphasis>before</emphasis> 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 <emphasis>after</emphasis> the
endpoint is executed. These three methods should provide enough flexibility to do all kinds of
pre- and post-processing.
</para>
<para>
The <methodname>handleRequest(..)</methodname> 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
The <methodname>handleRequest(..)</methodname> 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 <literal>true</literal>, the endpoint execution chain will continue, when it returns
<literal>false</literal>, the <classname>MessageDispatcher</classname> assumes the interceptor itself
<literal>false</literal>, the <classname>MessageDispatcher</classname> interprets this to mean that
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 <methodname>handleResponse(..)</methodname> and
<methodname>handleFault(..)</methodname> methods also have a boolean return value. When these methods
@@ -697,7 +702,7 @@ public class AnnotationOrderEndpoint {
<para>
Both of these interceptors have two properties: <property>logRequest</property> and
<property>logResponse</property>, which can be set to <literal>false</literal> to disable logging
for either request of response messages.
for either request or response messages.
</para>
</section>
<section>
@@ -737,8 +742,8 @@ 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 with multiple version of a Web service:
you simply can transform the older message format to the new format.
stylesheets, and is especially useful when supporting multiple versions of a Web service:
you simply can transform the older message format to the newer format.
Here is an example to use the <classname>PayloadTransformingInterceptor</classname>:
</para>
<programlisting><![CDATA[<bean id="transformingInterceptor"
@@ -768,17 +773,17 @@ public class AnnotationOrderEndpoint {
Furthermore, a programmatic way of handling exceptions gives you many more options for how to respond
appropriately.
Finally, rather than expose the innards of your application by giving an exception and stack trace, you
can handle the exception any way you want, e.g. return a SOAP fault with a specific fault code and string.
can handle the exception any way you want, for example return a SOAP fault with a specific fault code and string.
</para>
<para>
Endpoint exception resolvers are automatically picked up by the <classname>MessageDispatcher</classname>, so
you don't have to configure them explicitely.
you don't have to configure them explicitly.
</para>
<para>
Besides implementing the <classname>EndpointExceptionResolver</classname> interface, which is only a
matter of implementing the <methodname>resolveException(MessageContext, endpoint, Exception)</methodname>
method, you may also use one of the default implementations.
The simples implementation is the <classname>SimpleSoapExceptionResolver</classname>, which simply
The simplest implementation is the <classname>SimpleSoapExceptionResolver</classname>, which simply
always creates a SOAP 1.1 Server or SOAP 1.2 Receiver Fault, and uses the exception message as the fault
string.
</para>

View File

@@ -82,18 +82,18 @@
</Employee>
</HolidayRequest>]]></programlisting>
<para>
The order of the two element does not matter: <literal>Employee</literal> could have been the first
The order of the two elements does not matter: <literal>Employee</literal> could have been the first
element just as well. As long as all the data is there; that's what is important. In fact, the data
is the only thing that is important: we are taking a <emphasis>data-driven</emphasis> approach.
</para>
</section>
</section>
<section id="tutorial.xsd">
<title>Data Constract</title>
<title>Data Contract</title>
<para>
Now that we have seen some examples of the XML data that we will use, it makes sense to formalize this into
a schema. This data contract defines the message format we accept.
Basically, there are four different ways of defining such a contract for XML:
There are four different ways of defining such a contract for XML:
</para>
<itemizedlist>
<listitem><para>DTDs</para></listitem>
@@ -152,7 +152,7 @@
&lt;xs:element name=&quot;LastName&quot; type=&quot;xs:NCName&quot;/&gt;</emphasis>
&lt;/xs:schema&gt;</programlisting>
<para>
The generated schema can obviously be improved. The first thing to notice is that every type has a root-level
This generated schema obviously can be improved. The first thing to notice is that every type has a root-level
element declaration. This means that the Web service should be able to accept all of these elements as data. This is not
desirable: we only want to accept a <literal>HolidayRequest</literal>. By removing the wrapping element tags
(thus keeping the types), and inlining the results, we can accomplish this.
@@ -263,7 +263,7 @@
</calloutlist>
</programlistingco>
<para>
We store this file with as <filename>hr.xsd</filename>.
We store this file as <filename>hr.xsd</filename>.
</para>
</section>
<section id="tutorial-service-contract">
@@ -450,7 +450,7 @@
</para>
<para>
The following command creates a Maven2 web application project for us, using the Spring-WS archetype
(i.e. project template)
(that is, project template)
</para>
<screen>mvn archetype:create -DarchetypeGroupId=org.springframework.ws \
-DarchetypeArtifactId=spring-ws-archetype \
@@ -462,12 +462,14 @@
This command will create a new directory called <filename>holidayService</filename>. In this directory,
there is a <filename>src/main/webapp</filename> directory, which will contain the root of the WAR file.
You will find the standard web application deployment descriptor <filename>WEB-INF/web.xml</filename> here,
which defines a Spring-WS <classname>MessageDispatcherServlet</classname>, and maps all incoming requests
which defines a Spring-WS <classname>MessageDispatcherServlet</classname> and maps all incoming requests
to this servlet:
</para>
<programlisting><![CDATA[
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>MyCompany HR Holiday Service</display-name>
@@ -565,10 +567,9 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint {
<para>
The <classname>HolidayEndpoint</classname> requires the
<interfacename>HumanResourceService</interfacename> business service to operate, so we
use the constructor to inject it.
Next, we set up XPath expressions
use the constructor to inject it. Next, we set up XPath expressions
using the JDOM API. There are three expressions: <literal>//hr:StartDate</literal> for
extracting the <literal>&gt;StartDate&lt;</literal> text value,
extracting the <literal>&lt;StartDate&gt;</literal> text value,
<literal>//hr:EndDate</literal> for
extracting the end date and <literal>concat(//hr:FirstName,' ',//hr:LastName)</literal>
for extracting and concatenating the names of the employee.
@@ -634,7 +635,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint {
<dependencies>
]]></programlisting>
<para>
Here's how we would wire up these classes in our <filename>spring-ws-servlet.xml</filename>
Here is how we would wire up these classes in our <filename>spring-ws-servlet.xml</filename>
application context:
</para>
<programlisting><![CDATA[
@@ -673,8 +674,8 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint {
<literal>http://mycompany.com/hr/schemas</literal> and the
<literal>HolidayRequest</literal> local name, it will be routed to the
<varname>holidayEndpoint</varname>.
It also adds a <classname>PayloadInterceptor</classname>,
which dumps incoming and outgoing messages to the log.
It also adds a <classname>PayloadLoggingInterceptor</classname>,
that dumps incoming and outgoing messages to the log.
</para>
</section>
</section>
@@ -683,7 +684,7 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint {
<para>
Finally, we need to publish the WSDL. As stated in <xref linkend="tutorial-service-contract"/>, we don't
need to write a WSDL ourselves; Spring-WS can generate one for us based on some conventions.
Here's how we define the generation:
Here is how we define the generation:
</para>
<programlistingco>
<areaspec>
@@ -746,9 +747,8 @@ public class HolidayEndpoint extends AbstractJDomPayloadEndpoint {
You can create a WAR file using <command>mvn install</command>.
If you deploy the application, and point your browser at
<ulink url="http://localhost:8080/holidayService/holiday.wsdl">this location</ulink>, you will
see the generated WSDL.
This WSDL is ready to be used by clients, such as <ulink url="http://www.soapui.org/">soapUI</ulink>, or
other SOAP frameworks.
see the generated WSDL. This WSDL is ready to be used by clients, such as
<ulink url="http://www.soapui.org/">soapUI</ulink>, or other SOAP frameworks.
</para>
</section>
<para>

View File

@@ -23,14 +23,14 @@
<formalpara>
<title>Powerful mappings</title>
<para>
You can distribute incoming XML request to any object, depending on message payload, SOAP Action header,
You can distribute incoming XML requests to any object, depending on message payload, SOAP Action header,
or an XPath expression.
</para>
</formalpara>
<formalpara>
<title>XML API support</title>
<para>
Incoming XML messages can be handled in standard JAXP APIs such as DOM, SAX, and StAX, but also JDOM,
Incoming XML messages can be handled not only with standard JAXP APIs such as DOM, SAX, and StAX, but also JDOM,
dom4j, XOM, or even marshalling technologies.
</para>
</formalpara>
@@ -45,7 +45,7 @@
<formalpara>
<title>Reuses your Spring expertise</title>
<para>
Spring-WS uses Spring application contexts for all configuration, which should help Spring developers
Spring-WS uses Spring application contexts for all configuration, which should help Spring developers
get up-to-speed nice and quickly. Also, the architecture of Spring-WS resembles that of Spring-MVC.
</para>
</formalpara>
@@ -82,21 +82,23 @@
Spring Web Services runs within a standard Java 1.3 Runtime Environment. It also supports Java 5.0,
although the Java types which are specific to this release are packaged in a separate modules with the
suffix "tiger" in their JAR filename.
</para>
<para>
Spring-WS consists of a number of modules, which are described in the remainder of this section.
</para>
<itemizedlist>
<listitem>
<para>
The XML module (<filename>spring-xml.jar</filename>) contains various XML support classes for Spring Web
Services. This module is mainly targeted at the Spring-WS framework itself, and not a Web service
Services. This module is mainly intended for the Spring-WS framework itself, and not a Web service
developers.
</para>
</listitem>
<listitem>
<para>
The Core package (<filename>spring-ws-core.jar</filename> and <filename>spring-ws-core-tiger.jar</filename>)
is the central part of the Web services
functionality. It provides the central <link linkend="web-service-messages">
is the central part of the Spring's Web services functionality.
It provides the central <link linkend="web-service-messages">
<classname>WebServiceMessage</classname></link> and <link linkend="soap-message">
<classname>SoapMessage</classname></link> interfaces, the <link linkend="server">server-side</link>
framework, with powerful message dispatching, and the various support classes for implementing Web service
@@ -122,7 +124,7 @@
</listitem>
</itemizedlist>
<para>
The following figure illustrates the modules, and the dependencies between them. Arrows indicate
The following figure illustrates the Spring-WS modules and the dependencies between them. Arrows indicate
dependencies, i.e. Spring-WS Core depends on Spring-XML and Spring-OXM.
<mediaobject>
<imageobject role="fo">

View File

@@ -22,7 +22,7 @@
</para>
</sidebar>
<para>
Spring-WS only supports the contract-first development style. This section explains why.
Spring-WS only supports the contract-first development style, and this section explains why.
</para>
</section>
<section>
@@ -32,7 +32,7 @@
<ulink url="http://en.wikipedia.org/wiki/Object-Relational_impedance_mismatch">Object/Relational impedance mismatch</ulink>,
there is a similar problem when converting Java objects to XML.
At first glance, the O/X mapping problem appears simple: create an XML element for each Java object,
converting all Java properties and fields to sub-elements or attributes. However, things are not so
converting all Java properties and fields to sub-elements or attributes. However, things are not as
simple as they appear: there is a fundamental difference between hierarchical languages such as XML
(and especially XSD) and the graph model of Java<footnote>
<para>Most of the contents in this section was inspired by <xref linkend="alpine"/> and
@@ -42,7 +42,7 @@
<title>XSD extensions</title>
<para>
In Java, the only way to change the behavior of a class is to subclass it, adding the new behavior to
that subclass. In XSD, you can extend a data type by restricting it: i.e. constraning the valid values
that subclass. In XSD, you can extend a data type by restricting it: that is, constraining the valid values
for the elements and attributes.
For instance, consider the following example:<programlisting><![CDATA[
<simpleType name="AirportCode">
@@ -96,8 +96,8 @@ public Map getFlights() {
</element>]]></programlisting>
This contract defines a request that takes an <type>date</type>, which is a XSD datatype representing
a year, month, and day. If we call this service from Java, we will probably use
either a <classname>java.util.Data</classname> or <classname>java.util.Calendar</classname>. However,
both of these classes actually describe times, rather than dates. So, we will actually send data that
either a <classname>java.util.Date</classname> or <classname>java.util.Calendar</classname>. However,
both of these classes actually describe times, rather than dates. So, we will actually end up sending data that
represents the fourth of April 2007 at midnight (<literal>2007-04-04T00:00:00</literal>), which is not
the same as <literal>2007-04-04</literal>.
</para>
@@ -151,7 +151,7 @@ public class Passenger {
</passengers>
</flight>]]></programlisting>
This solves the recursiveness problem, but introduces new ones. For one, you cannot use an XML validator
to validate this structure. Another issue is that the standard way to use these references in the SOAP
to validate this structure. Another issue is that the standard way to use these references in SOAP
(RPC/encoded) has been deprecated in favor of document/literal (see WS-I
<ulink url="http://www.ws-i.org/Profiles/BasicProfile-1.1.html#SOAP_encodingStyle_Attribute">Basic
Profile</ulink>).
@@ -199,7 +199,7 @@ public class Passenger {
When Java is automatically transformed into XML, there is no way to be sure as to what is sent across
the wire. An object might reference another object, which refers to another, etc. In the end, half of
the objects on the heap in your virtual machine might be converted into XML,
which will result in a slow service.
which will result in slow response times.
</para>
<para>
When using contract-first, you explicitly describe what XML is sent where, thus making sure that it is
@@ -209,7 +209,7 @@ public class Passenger {
<section>
<title>Reusability</title>
<para>
Defining your schema in a separate file allows you to reuse that file in different scenario's. If you
Defining your schema in a separate file allows you to reuse that file in different scenarios. If you
define an <type>AirportCode</type> in a file called <filename>airline.xsd</filename>, like so:
</para>
<programlisting><![CDATA[
@@ -219,7 +219,7 @@ public class Passenger {
</restriction>
</simpleType>]]></programlisting>
<para>
You can reuse this definition in other schema's, or even WSDL files, using an
You can reuse this definition in other schemas, or even WSDL files, using an
<literal>import</literal> statement.
</para>
</section>
@@ -227,7 +227,7 @@ public class Passenger {
<title>Versioning</title>
<para>
Even though a contract must remain constant for as long as possible, they <emphasis>do</emphasis> need
to be changed sometimes. In Java, this typically result in a new Java interface, such as
to be changed sometimes. In Java, this typically results in a new Java interface, such as
<interfacename>AirlineService2</interfacename>, and a (new) implementation of that interface. Of
course, the old service must be kept around, because there might be clients who have not migrated
yet.
@@ -235,7 +235,7 @@ public class Passenger {
<para>
If using contract-first, we can have a looser coupling between contract and implementation. Such a
looser coupling allows us to implement both versions of the contract in one class. We could, for
instance, use an XSLT to convert any "old-style" messages to the "new-style" messages.
instance, use an XSLT stylesheet to convert any "old-style" messages to the "new-style" messages.
</para>
</section>
</section>