La llegada de la crisis se está dejando ver en todos los ámbitos y la informática no es una excepción. Hasta hace no mucho las empresas no daban excesiva importancia al coste de sus servidores y se pagaban las licencias de software religiosamente. Pero, la crisis ha dado un vuelco a esta situación. El gasto se controla más y allí donde antes se utilizaba un servidor de pago para dar servicio, ahora se busca sustituirlo por versiones de código abierto y gratuitas.
Concretamente, en el cliente para el que trabajo actualmente se ha decido empezar a utilizar Apache Tomcat para aquellas aplicaciones que no necesitan de la pila Enterprise de Java.
Esta entrada recoge cómo publicar servicios web JAX-WS en un Apache Tomcat 6.x.
Requisitos
Antes de comenzar con el código puro y duro voy a hacer un pequeño repaso del entorno necesario para seguir la solución propuesta en la entrada.
La máquina virtual Java es la Jrockit-jdk1.6.0_45-R28.2.7-4.1.0. Utilizo esta versión porque en los entornos productivos es esta máquina virtual la que se instala. El ejemplo puede funcionar igualmente con la HotSpot 1.6. La versión en concreto que estoy utilizando contiene la versión JAX-WS RI 2.1.6. Si quieres averiguar que versión de JAX-WS incorpora tu máquina virtual basta con ejecutar el siguiente comando:
${java-home}/bin/wsimport -version
El servidor Tomcat elegido para las pruebas es la versión 6.0.37. No utilizo la versión 7 de Tomcat porque los entornos productivos están configurados con la versión Tomcat 6. Esta versión admite las especificaciones Servlet/2.5, JSP/2.1 y requiere la versión 1.5 o versiones superiores de la máquina virtual Java.
Instalación básica de Tomcat.
El primer paso es realizar una instalación básica de Tomcat.
El servidor se puede descargar de la página oficial de Apache Tomcat. La instalación básica es muy sencilla, basta con descomprimir el fichero descargado en un directorio que a partir de ahora voy a llamar ${TOMCAT_HOME}.
Antes de arrancar el servidor hay que configurar el usuario administrador para poder acceder a la aplicación de despliegue de Tomcat. Los usuarios de Tomcat se configuran en el fichero ${TOMCAT_HOME}/conf/tomcat-users.xml. En este fichero se añaden las siguientes líneas:
<role rolename="manager"/> <role rolename="admin"/> <user username="admin" password="admin" roles="admin,manager"/>
No tendría que decirlo, pero por si acaso, ni que decir tiene que el nombre del usuario administrador así como su password no tiene porque coincidir con el ejemplo, queda a elección de la persona que instala el servidor crear los roles y usuarios que más le convengan.
Para el ejemplo básico creo el rol manager, el rol admin y el usuario admin que estará compuesto por estos dos roles.
Una vez modificado este fichero se puede poner en marcha el servidor. Para arrancar y parar, el propio servidor proporciona dos scripts que facilitan enormemente la tarea. El script de arranque es ${TOMCAT_HOME}/bin/startup.bat (en entornos Windows) o ${TOMCAT_HOME}/bin/startup.sh (en entornos unix). Para parar el servidor el script es ${TOMCAT_HOME}/bin/shutdown.bat (Windows) y ${TOMCAT_HOME}/bin/shutdown.sh (Unix).
Creación de la aplicación de ejemplo con servicios web JAXWS.
La aplicación de ejemplo se crea utilizando Maven 3.x para facilitar el manejo del ciclo de vida en general y de las dependencias en particular.
Desde Eclipse se crea un nuevo Maven Project a partir del arquetipo org.apache.maven.archetypes – maven-archetype-webapp en su versión RELEASE. Esto proporciona la base de una aplicación web dinámica. La estructura se parece a lo que se ve en la siguiente captura:

Para facilitar el desarrollo, publicación y pruebas de la aplicación se incluye en el fichero pom.xml que ha generado el arquetipo la configuración de dos plugins; maven-war-plugin y maven-clean-plugin.
El plugin maven-war-plugin configura el empaquetado WAR de la aplicación con ciertas características:
- Se va a publicar la aplicación directamente en el directorio de despliegues por defecto de Tomcat. Esto se hace añadiendo el tag <webappDirectory> en las configuración del plugin y permite hacer pruebas inmediatas de la aplicación sin necesidad de estar publicándola constantemente desde el Deployer.
- Se va a dejar una versión empaquetada en un fichero WAR en el directorio dist de la aplicación. Esto se consigue con el tag <outputDirectory>. La idea es poder tener un WAR independiente para poder enviar la aplicación a otros entornos de forma fácil.
<build>
[…]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webappDirectory>E:\srv\dominio\aplic\dominio_tomcat\apache-tomcat-6.0.37\webapps\ExampleWS</webappDirectory>
<outputDirectory>./dist</outputDirectory>
<warName>ExampleWS-${version}</warName>
</configuration>
</plugin>
</plugins>
[…]
</build>
El plugin maven-clean-plugin limpia los compilados de la aplicación. Como se ha añadido la generación del fichero war en un directorio específico, se configura este plugin para que lo elimine cuando se ejecute un mvn clean.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<configuration>
<filesets>
<fileset>
<directory>./dist</directory>
<followSymlinks>false</followSymlinks>
<useDefaultExcludes>true</useDefaultExcludes>
<includes>
<include>*.war</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin>
Adicionalmente, se añaden las dependencias necesarias para que la aplicación entienda y publique los servicios web JAXWS:
- jaxws-rt v2.1.6
<dependencies>
[…]
<dependency>
<groupId>>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.1.7</version>
</dependency>
[…]
</dependencies>
Creación el servicio web de ejemplo.
Desde que la JDK 1.5 incorporó las anotaciones y JAX-WS hizo uso de ellas, crear un servicio web de ejemplo se ha convertido en una tarea sencilla.
package com.egv.webservices.jaxws;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService (name="WebServiceUno", targetNamespace="http://egv.com/webservices/jaxws")
@SOAPBinding(style=SOAPBinding.Style.DOCUMENT,
use=SOAPBinding.Use.LITERAL,
parameterStyle=SOAPBinding.ParameterStyle.WRAPPED)
public class WebServiceUno {
@WebMethod(operationName="HolaMundo")
public void HolaMundo(@WebParam(name="nombre")String nombre) {
System.out.println("Hola mundo! Te saluda " + nombre);
}
}
Este servicio web se llama WebServiceUno y tiene un único método que se llama HolaMundo que recibe un nombre como parámetro y que una vez ejecutado escribe en consola Hola mundo! te saluda ${nombre}. Un servicio web muy simple pero perfecto para probar la publicación de WS JAXWS en Tomcat 6.
Configuración de la aplicación para publicar el servicio web en Tomcat.
Para publicar los servicios web en tomcat es necesario que la aplicación publique un servlet específico de JAXWS en el arranque. Este servlet se encuentra en el paquete com.sun.xml.ws.transport.http.servlet.WSServlet y viaja con la implementación de JAXWS que se ha descargado con la dependencia oportuna. En el fichero web.xml de la aplicación se incluye el siguiente código:
<web-app>
[…]
<servlet>
<servlet-name>WebServiceUno</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>WebServiceUno</servlet-name>
<url-pattern>/wsUno</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>120</session-timeout>
</session-config>
[…]
</web-app>
El servlet WSServlet ejecuta los servicios web que se incluyan en la aplicación. Pero, para que Tomcat sepa que servicios web tiene que publicar hay que incluir el fichero sun-jaxws.xml. Este fichero contiene la configuración de los endpoints de los servicios web.
<?xml version="1.0" encoding="UTF-8"?>
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="WebServiceUno"
implementation="com.egv.webservices.jaxws.WebServiceUno"
url-pattern="/wsUno"/>
</endpoints>
Tomcat entiende este fichero gracias al listener com.sun.xml.ws.transport.http.servlet.WSServletContextListener específico de JAXWS. Este listener es el encargado de parsear el fichero y crear un HttpAdapter por cada endpoint definido. El listener hay que incluirlo en la aplicación añadiendo las siguientes líneas en el fichero web.xml:
<web-app>
[…]
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>
[…]
</web-app>
El war generado presenta la siguiente estructura:

Desplegar y probar.
Una vez que todo está creado, se ejecuta mvm install.
Si la compilación es correcta, ésta ejecución debería dejar en el directorio de despliegue de tomcat la aplicación correctamente publicada. En el deployer de tomcat se verá la aplicación correctamente publicada.
![]()
Accediendo a la URI del servicio web se ve el servicio web publicado.
Probando la aplicación a través de SOAPUi se comprueba el funcionamiento correcto.

En la consola del servidor encontramos la traza escrita.

Conclusión
Como se ha visto a lo largo de la entrada, no es especialmente difícil publicar servicios web JAXWS en Apache Tomcat. La ventaja es que Tomcat cuenta con una licencia de código abierto ahorrando a las empresas bastantes euros en costosas licencias de servidores de aplicación.
Por tanto, si la aplicación que se desea desarrollar no tiene exigencias Enterprise y va a tener una carga normal de trabajo, ésta configuración se puede utilizar sin problemas.