[SWS-147] Mentioned 'transformWsdlLocations' init-param.

This commit is contained in:
Rick Evans
2007-07-11 16:34:46 +00:00
parent 1ee6cd1eb1
commit 2d0ea5b2b2
3 changed files with 91 additions and 56 deletions

View File

@@ -47,13 +47,13 @@ import org.springframework.ws.wsdl.WsdlDefinition;
* instances.
* <p/>
* This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, {@link EndpointMapping
* EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} by type.
* EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} <i>by type</i>.
* <p/>
* This servlet also automatically detects any {@link WsdlDefinition} in its application context. This WSDL is
* exposed under the bean name: for example, a {@link WsdlDefinition} bean named '<code>echo</code>' will be exposed as
* <code>echo.wsdl</code> in this servlet's context: <code>http://localhost:8080/spring-ws/echo.wsdl</code>. When the
* <code>transformWsdlLocations</code> init-param is set to <code>true</code> in this servlet's configuration in
* <code>web.xml</code>, all <code>location</code> attributes in the WSDL definitions will reflect the URL of the
* This servlet also automatically detects any {@link WsdlDefinition} defined in its application context. This WSDL is
* exposed under the bean name: for example, a <code>WsdlDefinition</code> bean named '<code>echo</code>' will be
* exposed as <code>echo.wsdl</code> in this servlet's context: <code>http://localhost:8080/spring-ws/echo.wsdl</code>.
* When the <code>transformWsdlLocations</code> init-param is set to <code>true</code> in this servlet's configuration
* in <code>web.xml</code>, all <code>location</code> attributes in the WSDL definitions will reflect the URL of the
* incoming request.
*
* @author Arjen Poutsma

View File

@@ -44,8 +44,9 @@ import org.w3c.dom.Attr;
import org.w3c.dom.Document;
/**
* Adapter to use the <code>WsdlDefinition</code> interface with the generic <code>DispatcherServlet</code>. Reads the
* source from the mapped <code>WsdlDefinition</code> implementation, and writes that as result to the
* Adapter to use the <code>WsdlDefinition</code> interface with the generic <code>DispatcherServlet</code>.
* <p/>
* Reads the source from the mapped <code>WsdlDefinition</code> implementation, and writes that as the result to the
* <code>HttpServletResponse</code>.
* <p/>
* If the property <code>transformLocations</code> is set to <code>true</code>, this adapter will change
@@ -91,8 +92,8 @@ public class WsdlDefinitionHandlerAdapter extends TransformerObjectSupport imple
/**
* Sets the XPath expression used for extracting the <code>location</code> attributes from the WSDL 1.1 definition.
* <p/>
* Defaults to <code>DEFAULT_LOCATION_EXPRESSION</code>.
*
* @see #DEFAULT_LOCATION_EXPRESSION
*/
public void setLocationExpression(String locationExpression) {

View File

@@ -133,22 +133,64 @@
<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-WS framework also need to be
configured.
</para>
<para>
Because the <classname>MessageDispatcherServlet</classname> is a standard Spring
Services, because the various component beans used by the Spring-WS framework also need to be
configured; this configuration consists of standard Spring XML <literal>&lt;bean/&gt;</literal>
definitions. Because the <classname>MessageDispatcherServlet</classname> is a standard Spring
<classname>DispatcherServlet</classname>, it will <emphasis>look for a file named
<literal>[servlet-name]-servlet.xml</literal></emphasis> in the <literal>WEB-INF</literal> directory
of your web application and create the beans defined there.
In the example above, that means that it looks for <filename>spring-ws-servlet.xml</filename>.
of your web application and create the beans defined there in a Spring container. In the example above,
that means that it looks for '<filename>/WEB-INF/spring-ws-servlet.xml</filename>'. This file will
contain all of the SWS-specific beans such as endpoints, marshallers and suchlike.
</para>
<section>
<title>Automatic WSDL exposure</title>
<para>The <classname>MessageDispatcherServlet</classname> will automatically detect any
<interfacename>WsdlDefinition</interfacename> beans defined in it's Spring container. All such
<interfacename>WsdlDefinition</interfacename> beans that are detected will also be exposed via
a <classname>WsdlDefinitionHandlerAdapter</classname>; this is a very convenient way to expose your WSDL
to clients simply by just defining some beans. </para>
<para>By way of an example, consider the following bean definition, defined in the Spring-WS framework's
configuration file ('<literal>/WEB-INF/[servlet-name]-servlet.xml</literal>'). Take notice of the
value of the bean's '<literal>id</literal>' attribute, because this will be used when exposing
the WSDL.</para>
<programlisting><![CDATA[<bean id="orders" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
<constructor-arg value="/WEB-INF/wsdl/Orders.wsdl"/>
</bean>]]></programlisting>
<para>The WSDL defined in the '<filename>Orders.wsdl</filename>' file can then be accessed via
<literal>GET</literal> requests to a URL of the following form (substitute the host, port and servlet
context path as appropriate).</para>
<programlisting><![CDATA[http://localhost:8080/spring-ws/orders.wsdl]]></programlisting>
<para>Another cool feature of the <classname>MessageDispatcherServlet</classname> (or more
correctly the <classname>WsdlDefinitionHandlerAdapter</classname>) is that it is able to
transform the value of the '<literal>location</literal>' of all the WSDL that it exposes to reflect the
URL of the incoming request.</para>
<para>Please note that this '<literal>location</literal>' transformation feature is
<emphasis>off</emphasis> by default.To switch this feature on, you just need to specify an
initialization parameter to the <classname>MessageDispatcherServlet</classname>, like so:</para>
<programlisting><![CDATA[<web-app>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>]]></programlisting>
<para>Consult the class-level Javadoc on the <classname>WsdlDefinitionHandlerAdapter</classname> class
which explains the whole transformation process in more detail.</para>
</section>
</section>
</section>
<section>
@@ -404,12 +446,11 @@ public class AnnotationOrderEndpoint {
<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:
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>:
</para>
<programlisting><![CDATA[<beans>
<bean id="orderEndpoint" class="samples.AnnotationOrderEndpoint">
<constructor-arg ref="orderService"/>
</bean>
@@ -443,9 +484,9 @@ public class AnnotationOrderEndpoint {
<para>
As an alternative to using marshalling, we could have used <link linkend="xpath">XPath</link> to
extract the information out of the incoming XML request. Spring-WS offers another annotation for
this purpose: <interfacename>@XPathParam</interfacename>. You simply annotate method parameters
with this annotation, and it will be bound with the evaluation of that annotation.
Here is an example:
this purpose: <interfacename>@XPathParam</interfacename>. You simply annotate one or more method
parameter with this annotation (each), and each such annotated parameter will be bound to the
evaluation of that annotation. Here is an example:
</para>
<programlisting id="server-payload-root-annotation"><![CDATA[package samples;
@@ -467,12 +508,12 @@ public class AnnotationOrderEndpoint {
@PayloadRoot(localPart = "orderRequest", namespace = "http://samples")
public Source getOrder(]]><emphasis role="bold"><![CDATA[@XPathParam("/s:orderRequest/@id") double orderId]]></emphasis><![CDATA[) {
Order order = orderService.getOrder((int) orderId);
]]><lineannotation>// create Source from order and return it</lineannotation><![CDATA[
]]><lineannotation>// create <interfacename>Source</interfacename> from order and return it</lineannotation><![CDATA[
}
}]]></programlisting>
<para>
Since we use the prefix <literal>s</literal> in our XPath expression, we must bind it to the
Since we use the prefix '<literal>s</literal>' in our XPath expression, we must bind it to the
<uri>http://samples</uri> namespace:
</para>
@@ -514,7 +555,7 @@ public class AnnotationOrderEndpoint {
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 a
<classname>SoapActionEndpointMapping</classname>, but let's first examine the general concept of an
<interfacename>EndpointMapping</interfacename>.
</para>
<para>
@@ -528,16 +569,16 @@ public class AnnotationOrderEndpoint {
<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).
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>EndpointInterceptor</interfacename>s are discussed in
'<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
'<property>defaultEndpoint</property>', which is the default endpoint to use, when this endpoint mapping does
not result in a matching endpoint.
</para>
<section>
@@ -680,12 +721,11 @@ public class AnnotationOrderEndpoint {
<title><classname>PayloadLoggingInterceptor</classname> and
<classname>SoapEnvelopeLoggingInterceptor</classname></title>
<para>
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
<classname>PayloadLoggingInterceptor</classname> and the
<classname>SoapEnvelopeLoggingInterceptor</classname>. The former logs just 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:
When developing a Web service, it can be useful to log the incoming and outgoing XML messages.
SWS facilitates this with the <classname>PayloadLoggingInterceptor</classname> and
<classname>SoapEnvelopeLoggingInterceptor</classname> classes. The former logs just the payload of
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"
@@ -707,8 +747,8 @@ public class AnnotationOrderEndpoint {
class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</beans>]]></programlisting>
<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
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 or response messages.
</para>
</section>
@@ -725,13 +765,15 @@ public class AnnotationOrderEndpoint {
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
<emphasis>is</emphasis> a good idea, because the endpoint should adhere to adhere to its schema.
<emphasis>is</emphasis> a good idea, because the endpoint should adhere to its schema.
Remember Postel's Law:
<quote>Be conservative in what you do; be liberal in what you accept from others.</quote>
</para>
</note>
<para>
Here is an example that uses the <classname>PayloadValidatingInterceptor</classname>:
Here is an example that uses the <classname>PayloadValidatingInterceptor</classname>; in this
example, we use the schema in <filename>/WEB-INF/orders.xsd</filename> to validate the response, but
not the request.
</para>
<programlisting><![CDATA[<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
@@ -739,10 +781,6 @@ public class AnnotationOrderEndpoint {
<property name="validateRequest" value="false"/>
<property name="validateResponse" value="true"/>
</bean>]]></programlisting>
<para>
In this example, we use the schema in <filename>/WEB-INF/orders.xsd</filename> to validate the
response, but not the request.
</para>
</section>
<section>
<title><classname>PayloadTransformingInterceptor</classname></title>
@@ -750,8 +788,8 @@ public class AnnotationOrderEndpoint {
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:
you simply can transform the older message format to the newer format.
Here is an example to use the <classname>PayloadTransformingInterceptor</classname>:
you 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"
class="org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor">
@@ -793,7 +831,7 @@ public class AnnotationOrderEndpoint {
creates a SOAP 1.1 Server or SOAP 1.2 Receiver Fault, and uses the exception message as the fault string.
</para>
<para>
A more sophisticated implementation is the <classname>SoapFaultMappingExceptionResolver</classname>.
The <classname>SoapFaultMappingExceptionResolver</classname> is a more sophisticated implementation.
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:
</para>
@@ -803,11 +841,7 @@ public class AnnotationOrderEndpoint {
<property name="defaultFault" value="SERVER">
</property>
<property name="exceptionMappings">
<props>
<prop key="org.springframework.oxm.ValidationFailureException">
CLIENT,Invalid request
</prop>
</props>
org.springframework.oxm.ValidationFailureException=CLIENT,Invalid request
</property>
</bean>
</beans>]]></programlisting>