03 noviembre, 2013

Spring Web Service Cliente usando JAX-WS y JAXB

En un post anterior vimos como crear servicios web con Spring-WS, en esta ocación vamos a crear un cliente que consume ese servicio, usando Spring, JAX-WS y JAXB.
Spring-WS provee una API para Web service del lado del cliente que nos da acceso conducido por XML y tambien nos permite en la capa de servicios tratar directamente con objetos Java mediante el uso de marshallers y unmarshallers.
El paquete org.springframework.ws.client.core provee las funcionalidades del nucleo para usar la API mencionada. Esta contiene las clases template que simplifican el uso de Web services, para ver mas información de webServiceTemplate puedes leer la documentacion de Spring

1. Creando la estructura de la aplicación

Al final nuestra aplicación tendrá la siguiente estructura, donde las clases contenidas en el paquete com.codelious.clientejaxb.generados serán generadas automaticamente por la herramienta wsimport.

2. Incluyendo las dependencias

El archivo pom.xml de este proyecto incluye las siguientes dependencias.
<dependencies>
 <!-- Spring -->
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>3.1.1.RELEASE</version>
  <exclusions>
   <!-- Exclude Commons Logging in favor of SLF4j -->
   <exclusion>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    </exclusion>
  </exclusions>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
   
 <!-- AspectJ -->
 <dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.6.10</version>
 </dependency> 
 
 <!-- Logging -->
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.6</version>
 </dependency>
 <dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.15</version>
  <exclusions>
   <exclusion>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
   </exclusion>
   <exclusion>
    <groupId>javax.jms</groupId>
    <artifactId>jms</artifactId>
   </exclusion>
   <exclusion>
    <groupId>com.sun.jdmk</groupId>
    <artifactId>jmxtools</artifactId>
   </exclusion>
   <exclusion>
    <groupId>com.sun.jmx</groupId>
    <artifactId>jmxri</artifactId>
   </exclusion>
  </exclusions>
  <scope>runtime</scope>
 </dependency>

 <!-- @Inject -->
 <dependency>
  <groupId>javax.inject</groupId>
  <artifactId>javax.inject</artifactId>
  <version>1</version>
 </dependency>
   
 <!-- Servlet -->
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
 </dependency>
 <dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.1</version>
  <scope>provided</scope>
 </dependency>
 <dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
 </dependency>

 <!-- Test -->
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.7</version>
  <scope>test</scope>
 </dependency>
 <dependency>
  <groupId>org.springframework.ws</groupId>
  <artifactId>spring-ws-core</artifactId>
  <version>2.1.4.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>jdom</groupId>
  <artifactId>jdom</artifactId>
  <version>1.1</version>
 </dependency>
 <dependency>
  <groupId>jaxen</groupId>
  <artifactId>jaxen</artifactId>
  <version>1.1.4</version>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
 <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>3.1.1.RELEASE</version>
 </dependency>
  <dependency>
  <groupId>commons-httpclient</groupId>
  <artifactId>commons-httpclient</artifactId>
  <version>3.1</version>
  <type>jar</type>
  <scope>compile</scope>
    </dependency>
</dependencies>

3. Generando los artefactos JAX-WS

Para generar los artefactos JAX-WS automaticamente debemos conocer la url del WSDL que en nuestro caso es http://localhost:18080/MiWS/services/saludar.wsdl y utilizaremos la herramienta wsimport que debería estar incluida en la instalacion de java, por tanto en una consola de comandos escribimos...

wsimport -d midirectorio -keep http://localhost:18080/MiWS/services/saludar.wsdl

Con lo anterior se generarán automaticamente varios archivos en el directorio indicado, de los cuales debemos copiar solo los .java a nuestro paquete com.codelious.clientejaxb.generados
  • ObjectFactory.java
  • package-info.java
  • Saludar.java
  • SaludarService.java
  • SaludoRequest.java
  • SaludoResponse.java
Una vez copiados los archivos anteriores, debemos asegurarnos de que hagan referencia al paquete correcto de nuestro proyecto, por ejemplo package com.codelious.clientejaxb.generados; dado que por lo general la herramienta wsimport creará como paquete el directorio que le indicamos y este no siempre es el mismo de nuestra aplicación.
Para mas información acerca de wsimpot puedes ver la documentacion oficial de oracle

4. Escribiendo el Controlador

Ahora escribamos la clase SaludoController.java con el metodo saludo() que se encargará de consumir el web service

package com.codelious.clientejaxb.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ws.client.core.WebServiceTemplate;

import com.codelious.clientejaxb.generados.SaludoRequest;
import com.codelious.clientejaxb.generados.SaludoResponse;

@Controller
public class SaludoController {


 @Autowired
 @Qualifier("webServiceTemplate")
 private WebServiceTemplate webServiceTemplate;
 
 @RequestMapping("/saludo")
 public ModelAndView saludo() {
  
  // crear solicitud al ws
  SaludoRequest solicitud = new SaludoRequest();
  solicitud.setNombre("Mario Espinoza Aguayo");
  
  // obtener la respuesta
  SaludoResponse respuesta = (SaludoResponse) webServiceTemplate.marshalSendAndReceive(solicitud);
     
  // obtiene el saludo
  String mensaje = respuesta.getSaludo();
  
  return new ModelAndView("saludo", "mensaje", mensaje);
 }
}
Como se ve arriba, estamos instanciando un webServiceTemplate, SaludoRequest y SaludoResponse que en conjunto nos ayudan a simplificar las tareas de transformación de xml a objetos java. webServiceTemplate está inyectado por el bean de su mismo nombre desde el archivo spring-ws.xml que veremos luego...

5. Escribiendo la vista Saludo

La vista saludo.jsp simplemente desplegará en el navegador el mensaje devuelto por el controlador...
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cliente WS</title>
</head>
<body>
 <h1>${mensaje}</h1>
</body>
</html>

6. Escribiendo la página de entrada

La pagina de entrada a la aplicación index.jsp contiene el link que llama al controlador saludo...

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Cliente WS</title>
</head>
<body>
 <h1>Bienvenido al ClienteWS</h1>
 <p>
  Presiona el link para ver el <a href="saludo.html">saludo</a>
 </p>
</body>
</html>

7. Configurando la aplicación

Para configurar la aplicación escribiremos varios archivos xml...

por convención Spring buscará el archivo applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      http://www.springframework.org/schema/context
      http://www.springframework.org/schema/context/spring-context-3.0.xsd
   http://www.springframework.org/schema/mvc 
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <!-- Escanea el classpath para componentes anotados que seran auto-registrados como beans de Spring.
  For ejemplo @Controller y @Service. Asegurate de establecer el base-package correcto --> 
    <context:component-scan
        base-package="com.codelious.clientejaxb.controller" /> 

 <!-- Activa varias anotaciones para ser detectadas en las clases bean -->
 <context:annotation-config />
  
 <!-- Configura el modelo de programacion annotation-driven de Spring MVC Controller.
   Nota que, con Spring 3.0, este tag trabaja en Servlet MVC solamente! -->
 <mvc:annotation-driven />
  
 <!-- Contiene configuraciones relacionadas a Spring WS -->
 <import resource="spring-ws.xml" />
 
</beans>

Nuestro archivo spring-ws.xml contendrá el bean webServiceTemplate que inyectamos anteriormente en nuestro controlador...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:sws="http://www.springframework.org/schema/web-services"
 xmlns:oxm="http://www.springframework.org/schema/oxm"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/web-services
           http://www.springframework.org/schema/web-services/web-services-2.0.xsd
           http://www.springframework.org/schema/oxm
           http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">

 <!-- * El WebServiceTemplate requiere un messageSender y messageFactory
   * Para facilitar el envio de plain Java objects, el WebServiceTemplate
   requiere un marshaller y unmarshaller.
   * La clase WebServiceTemplate usa una URI como el destinatario del mensaje.
   Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
  p:marshaller-ref="jaxbMarshaller" p:unmarshaller-ref="jaxbMarshaller"
  p:defaultUri="http://localhost:18080/MiWS/services"
  p:messageSender-ref="messageSender">
  <constructor-arg ref="messageFactory" />
 </bean>

 <!-- Hay dos implementaciones del WebServiceMessageSender: HttpUrlConnectionMessageSender
  y CommonsHttpMessageSender. el CommonsHttpMessageSender provee funcionalidades avanzadas
  y faciles de usar (tales como authentication, HTTP connection pooling, y asi sucesivamente).
  Esta usa el Jakarta Commons HttpClient. 
  Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="messageSender"
  class="org.springframework.ws.transport.http.CommonsHttpMessageSender" />

 <!-- Hay dos message factories para SOAP: SaajSoapMessageFactory y AxiomSoapMessageFactory.
  Si no se especifica ningun message factory (via la propiedad messageFactory), Spring-WS usara
  el SaajSoapMessageFactory por defecto. 
  Mira http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template -->
 <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />

 <!-- Aqui usamos el Jaxb2 marshaller para marshall y unmarshal nuestros objetos Java -->
 <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
  p:contextPath="com.codelious.clientejaxb.generados" />

</beans>

El archivo spring-servlet.xml como siempre es nuestro dispatcher servlet, es decir que es el encargado de despachar solicitudes a controladores y luce asi...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd">
         
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

Finalmente nuestro archivo web.xml es donde definimos nuestro archivo de entrada a la aplicación, y nuestros dispatcher servlet...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 id="WebApp_ID" version="2.5">
 <display-name>ClienteWS JAX-WS JAXB</display-name>
 
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 
 <servlet>
  <servlet-name>spring</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 </servlet>

 <servlet-mapping>
  <servlet-name>spring</servlet-name>
  <url-pattern>*.html</url-pattern>
 </servlet-mapping>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
</web-app>

8. Probando la aplicación

Ya podemos probar nuestra aplicación en http://localhost:18080/ClienteJAXB/ y ver la página de entrada...
 Al hacer clic al link llamaremos al controlador que consume el web service y devuelve el mensaje...
Ya esta!! si quieres el codigo descargalo en github.. https://github.com/codelious/ClienteJAXB


01 noviembre, 2013

Spring Web Service Contract-First

Existen dos aproximaciones para desarrollar servicios web: Contract-Last y Contract-First, en este post vamos a desarrollar un web service con Spring y por lo tanto usaremos el acercamiento Contract-First que consiste en preparar primero los contratos de datos y de servicios, para luego implementar las clases y todo lo demás...En un post anterior puedes ver como definir un contrato así que puedes darle una mirada si aun no los has visto.
Ok... Aquí vamos a diseñar una aplicación de ejemplo muy simple, nuestro web service nos responderá con un simple saludo estilo "Hola mundo!" donde el nombre que le pasemos en la solicitud será usado para completar el saludo.

Estructura de la aplicación

Como siempre, creamos una aplicación Maven con la siguiente estructura...

Configurando las dependencias

En el archivo pom.xml incluimos las librerias que necesitaremos...
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.codelious.saludows</groupId>
  <artifactId>SaludoWS</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>SaludoWS</name>
  <description>Ejemplo de Servicios Web</description>
  <dependencies>
  <!-- Spring -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>3.1.1.RELEASE</version>
   <exclusions>
    <!-- Exclude Commons Logging in favor of SLF4j -->
    <exclusion>
     <groupId>commons-logging</groupId>
     <artifactId>commons-logging</artifactId>
     </exclusion>
   </exclusions>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>3.1.1.RELEASE</version>
  </dependency>
    
  <!-- AspectJ -->
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.6.10</version>
  </dependency> 
  
  <!-- Logging -->
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>jcl-over-slf4j</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-log4j12</artifactId>
   <version>1.6.6</version>
  </dependency>
  <dependency>
   <groupId>log4j</groupId>
   <artifactId>log4j</artifactId>
   <version>1.2.15</version>
   <exclusions>
    <exclusion>
     <groupId>javax.mail</groupId>
     <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
     <groupId>javax.jms</groupId>
     <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jdmk</groupId>
     <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
     <groupId>com.sun.jmx</groupId>
     <artifactId>jmxri</artifactId>
    </exclusion>
   </exclusions>
   <scope>runtime</scope>
  </dependency>

  <!-- @Inject -->
  <dependency>
   <groupId>javax.inject</groupId>
   <artifactId>javax.inject</artifactId>
   <version>1</version>
  </dependency>
    
  <!-- Servlet -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 
  <!-- Test -->
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.7</version>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.ws</groupId>
   <artifactId>spring-ws-core</artifactId>
   <version>2.1.4.RELEASE</version>
  </dependency>
  <dependency>
   <groupId>jdom</groupId>
   <artifactId>jdom</artifactId>
   <version>1.1</version>
  </dependency>
  <dependency>
   <groupId>jaxen</groupId>
   <artifactId>jaxen</artifactId>
   <version>1.1.4</version>
  </dependency>
 </dependencies>
</project>

Escribiendo el contrato

Como estamos usando el enfoque Contract-First, lo primero es el contrato (revisa el post definiendo un contrato), para esto simplemente escribimos el archivo saludo-service.xsd que define la estructura que tendrá nuestro wsdl...
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
 elementFormDefault="qualified" attributeFormDefault="qualified"
 targetNamespace="http://localhost:18080/com/codelious/saludows/saludar-service"
 xmlns:tns="http://localhost:18080/com/codelious/saludows/saludar-service">

 <element name="SaludoRequest">
  <complexType>
   <sequence>
    <element type="string" name="nombre" />
   </sequence>
  </complexType>
 </element>

 <element name="SaludoResponse">
  <complexType>
   <sequence>
    <element type="string" name="saludo" />
   </sequence>
  </complexType>
 </element>
 
</schema>

Las Clases del Servicio

Nuestro servicio es simplemente un saludo, por tanto tendremos una interfaz SaludarService.java que tiene un metodo getSaludo()
package com.codelious.saludows.servicio;

public interface SaludarService {
 
    String getSaludo(String nombre);

}

Luego escribimos la clase SaludarServiceImpl.java que implementa la interfaz anterior...
package com.codelious.saludows.servicio;

public class SaludarServiceImpl implements SaludarService {

    public String getSaludo(String nombre) {
  
        String mensaje = "Hola " + nombre + " !!";
        return mensaje;

    }
}

Escribiendo la clase de EndPoint

Existen varias formas de escribir esta clase, en este caso extenderemos de AbstractDomPayloadEndpoint
package com.codelious.saludows.endpoint;

import org.springframework.ws.server.endpoint.AbstractDomPayloadEndpoint;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import com.codelious.saludows.servicio.SaludarService;

public class SaludarServiceEndPoint extends AbstractDomPayloadEndpoint {

    public static final String NAMESPACE = "http://localhost:18080/com/codelious/saludows/saludar-service";
 
    private SaludarService saludarService;
 
    public void setSaludarService(SaludarService saludarService) {
        this.saludarService = saludarService;
    }
 
    @Override
    protected Element invokeInternal(Element requestElement,
            Document responseDocument) throws Exception {
  
        // recibe un elemento de solicitud y un documento
  
        String solicitudString = buscarStringSolicitud(requestElement);
        String saludoString = invocaServicioRetornaRespuesta(solicitudString);
        Element respuestaXml = preparaRespuestaXml(responseDocument, saludoString);
  
        return respuestaXml;
    }

    private Element preparaRespuestaXml(Document responseDocument,
          String saludoString) {
  
        // prepara los nodos de la respuesta
        Element elementoRespuesta = responseDocument.createElementNS(NAMESPACE, "SaludoResponse");
        Element elementoSaludo = responseDocument.createElementNS(NAMESPACE, "saludo");
        // prepara el texto contenido en la respuesta
        Text textoRespuesta = responseDocument.createTextNode(saludoString);
        elementoRespuesta.appendChild(elementoSaludo);
        elementoSaludo.appendChild(textoRespuesta);
  
        return elementoRespuesta;
    }

    private String invocaServicioRetornaRespuesta(String solicitudString) {
  
        // invoca el servicio pasandole el nombre y retorna el saludo
        String saludoString = saludarService.getSaludo(solicitudString);
  
        return saludoString;
    }

    private String buscarStringSolicitud(Element requestElement) {
  
        // recupera el primer elemento llamado "nombre"
        Element elementoNombre = (Element) requestElement.getElementsByTagNameNS(NAMESPACE, "nombre").item(0);
        // obtiene el texto contenido
        String solicitudString = elementoNombre.getTextContent();
  
        return solicitudString;
    }
 
}

Configurando la aplicación

Nuestro archivo web.xml define el MessageDispatcherServlet, que a diferencia del DispatcherServlet de una aplicación MVC que maneja controladores, este se encargará de manipular nuestros endpoints...
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" 
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 id="WebApp_ID" version="2.5">
 
 <display-name>SaludoWS</display-name>
 
 <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>

Luego nuestro spring-ws-servlet.xml definirá la configuración de los endpoints...
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
    <bean id="saludarService" class="com.codelious.saludows.servicio.SaludarServiceImpl">
    </bean>

    <bean id="saludarServiceEndpoint"
        class="com.codelious.saludows.endpoint.SaludarServiceEndPoint">
        <property name="saludarService" ref="saludarService" />
    </bean>

    <bean id="payloadMapping"
        class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
        <property name="defaultEndpoint" ref="saludarServiceEndpoint" />
    </bean>

    <bean id="saludarSchema" class="org.springframework.xml.xsd.SimpleXsdSchema">
        <property name="xsd" value="/WEB-INF/saludo-service.xsd" />
    </bean>

    <bean id="saludar"
        class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
        <property name="schema" ref="saludarSchema" />
        <property name="portTypeName" value="saludar" />
        <property name="locationUri"
            value="http://localhost:18080/SaludoWS/services" />
    </bean>

</beans>
Este archivo spring-ws-servlet.xml define varias cosas como la interfaz del servicio, la clase EndPoint, el contrato (xsd) que usará para generar el wsdl y finalmente la ruta del wsdl que usarán los clientes para consumir el web service...
Para ver el WSDL podemos visitar la direccion http://localhost:18080/SaludoWS/services/saludar.wsdl (reemplazando el puerto 18080 por el que usemos) y también podemos probar el funcionamiento usando una herramienta como SoapUI...
That's all Folks! el código está en github... https://github.com/codelious/SaludoWS