Minientrada

Publicar aplicaciones en Tomcat mediante MAVEN.

La mayoría de las veces que desarrollo aplicaciones web para Tomcat necesito hacer pruebas rápidamente para comprobar que lo que estoy haciendo funciona correctamente y se ve como debe.

Para conseguir una velocidad óptima en estas pruebas, existe la opción de crear un Servidor en Eclipse y publicar la aplicación, así cada vez que haga un cambio en el código fuente, este se compila y despliega automáticamente en el servidor, pudiendo pasar rápidamente a la fase de pruebas.

Este método está muy bien y puede que sea la manera más rápida de probar, de hecho, suelo utilizarla mucho en las fases iniciales de los proyectos cuando todo es desarrollo nuevo y nada es mantenimiento. Desafortunadamente esta opción tiene también sus contras. La mayoría de las veces, los entornos de integración, de calidad o pre-productivos no tienen instaladas herramientas de desarrollo como Eclipse, incluso ni si quiera tienen instalados gestores de ventanas para así aligerar el consumo de RAM y de CPU.

Por esto, una de mis alternativas favoritas y dado que la mayor parte de las veces utilizo MAVEN para la gestión del ciclo de vida de las aplicaciones Java, es utilizar el plugin Maven de Tomcat.

Esta entrada no es más que un resúmen práctico para incluir este plugin en los desarrollos Java.

Requisitos para seguir el ejemplo.

Para reproducir el ejemplo y tenerlo operativo al 100% he utilizado las siguientes herramientas para hacerlo funcionar.

IDE desarrollo: Eclipse 3.6 (Neon).
Máquina virtual Java: JDK 1.8.0_65.
Servidor de aplicaciones: Apache Tomcat 8.5
Ciclo de vida: Maven 3.x (en mi caso la 3.3.9).

Es necesario haberse descargado el servidor de aplicaciones (contenedor JSP/Servlets en este caso) y poder acceder a la URL http://<dirección ip>:<puerto>/manager. También es necesaria una aplicación web a la que añadiremos todo lo necesario para probar el despliegue automático en dicho servidor.

Configurar tomcat para poder hacer despliegues vía script.

Para subir al servidor de Tomcat una aplicación, el plugin de maven utiliza por defecto la interfaz de administración http://servidor:puerto/manager/text. Para poder utilizar esta interfaz, el usuario de tomcat debe contar con el rol manager-script, si no la publicación no funcionará correctamente.

Para ello, en el fichero $CATALINA_BASE/conf/tomcat_users.xml hay que asignar este rol a un usuario existente, o crear un usuario para este tipo de despliegues con este rol.

Fichero: $CATALINA_BASE/conf/tomcat_users.xml

[...]
<user username="eduardo" password="xxxxxxx" roles="manager-gui,manager-script"/>
[...]

En este caso, el usuario eduardo tiene permisos para subir aplicaciones desde la interfaz web (manager-gui) y desde el plugin de Maven (manager-script).

Añadir el plugin de tomcat a la aplicación.

Añadir el plugin de tomcat en la aplicación se hace en el fichero pom.xml.

Fichero: pom.xml

    [...]
    <build>
        <plugins>
            [...]
            <!-- Tomcat plugin -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <url>http://localhost:8080/manager/text</url>
                    <username>username</username>
                    <password>password</password>
                </configuration>
            </plugin>
            [...]
        </plugins>
    </build>

El plugin tomcat7-maven-plugin pese al nombre funciona correctamente con Tomcat7, Tomcat8 y Tomcat85. No lo he probado con Tomcat9 debido a que todavía está en su versión Milestone en el momento de crear esta entrada.

La url para desplegar en Tomcat mediante script es http://servidor:puerto/manager/text.

El username y el password son el usuario y la contraseña de un usuario con el rol manager-script.

Por defecto, el plugin publica la aplicación con el nombre como contexto de aplicación. Se puede cambiar este contexto en la configuración del plugin añadiendo la entrada <path>/nombre-contexto</path>. Por ejemplo, imaginemos que se quiere diferenciar las publicaciones hechas en el entorno de integración de las hechas en el entorno de desarrollo, se añade <path>/xxxxx-integracion</path>; donde xxxxxx puede ser el nombre de la aplicación. De esta forma  ya podríamos acceder a la aplicación desde este nuevo contexto: http://localhost:8080/xxxxxx-integracion/.

Adicionalmente, el contenido de <path> podría incluirse en un fichero de propiedades para diferentes perfiles de maven y así conseguir que el pom.xml sea el mismo en todos los entornos y solo cambie la manera de invocarlo. Pero estas configuraciones más avanzadas de MAVEN no son el objeto de esta entrada y las dejaremos para otro momento.

Ejecutar el despliegue en Tomcat utilizando Maven.

Una vez que todo está configurado correctamente, es el momento de ejecutar el despliegue utilizando Maven.

Para ejecutarlo se lanza el siguiente comando:

   mvn org.apache.tomcat.maven:tomcat7-maven-plugin:2.2:redeploy   

La respuesta sería algo así:

[INFO]
[INFO] <<< tomcat7-maven-plugin:2.2:redeploy (default-cli) < package @ xxxxxx<<<
[INFO]
[INFO] --- tomcat7-maven-plugin:2.2:redeploy (default-cli) @ xxxxxx---
[INFO] Deploying war to http://localhost:8080/xxxxxx
Uploading: http://localhost:8080/manager/text/deploy?path=%2Fxxxxxx&update=true
Uploaded: http://localhost:8080/manager/text/deploy?path=%2Fxxxxxx&update=true (3118 KB at 1734.6 KB/sec)

[INFO] tomcatManager status code:200, ReasonPhrase:
[INFO] OK - Desplegada aplicación en trayectoria de contexto /xxxxxxx
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.679 s
[INFO] Finished at: 2016-09-02T12:36:59+02:00
[INFO] Final Memory: 15M/201M
[INFO] ------------------------------------------------------------------------

 Links

Página oficial del plugin de maven para Tomcat 7

 

Minientrada

Tomcat 8.5 en Eclipse Neon 4.6.0 (Build id: 20160613-1800)

No existe Runtime Enviroment para Tomcat 8.5 en Eclipse Neon.

Me descargué el otro día la nueva versión de Eclipse para comenzar mis nuevos proyectos basados en JEE 6 con un entorno de desarrollo puesto al día. Adicionalmente descargué también la última versión de Apache Tomcat 8.5 para probar los trabajos.

Mi sopresa surgió cuando al enlazar la versión de Eclipse con la Server Runtime de Apache Tomcat 8.5, encuentro que puedo seleccionar la versión 8.0 y la 9.0, pero no la susodicha.

2016-08-25_10-57-12

Al seleccionar cualquiera de las otras dos 8.0 o 9.0 obtengo el error «The Apache Tomcat installation at this directory is version 8.5.4. A Tomcat 8.0 (9.0 si selecciono la 9) installation is expected«.

Buscando en la base de datos Bugzilla de Eclipse encuentro el bug 494936. En el se comenta  de forma resumida que Eclipse Neon todavía no está preparado para Apache Tomcat 8.5 y que está previsto para futuras versiones.

Una solución temporal.

Para salir del paso, en el propio caso abierto de bugzilla, Levan Kekelidze proporciona una nueva versión del plugin de tomcat que permite añadir Tomcat 8.5 como si fuera la versión 9.0 del server runtime.

La versión de este plugin está publicado por Levan como attachment y se puede descargar directamente desde este enlace.

Se reemplaza el fichero org.eclipse.jst.server.tomcat.core_1.1.800.v201602282129.jar que se encuentra en <ECLIPSE_NEON_INSTALLATION_DIR>\plugins por el fichero descargado en el enlace previo.

Et voila!!! Ya podemos agregar una instancia de Apache Tomcat 8.5 como si fuera de tipo Apache Tomcat 9.0.

2016-08-25_11-13-11

Mientras sale el parche que permita agregar de manera nativa la Server Runtime Enviroment para Apache Tomcat 8.5 se puede continuar trabajando de manera temporal con esta solución. Con esta «solución», todo funciona correctamente, se puede arrancar, parar, depurar y desplegar aplicaciones desde Eclipse al servidor.

Espero que esta entrada os sea de utilidad.

 

Publicar servicios web JAX-WS 2.1 en Tomcat 6

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:

Arquitectura creada por Maven para una aplicación web.

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:

Estructura del fichero War.

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.

Aplicación correctamente desplegada.

Accediendo a la URI del servicio web se ve el servicio web publicado.

Web Service correctamente desplegado.

Probando la aplicación a través de SOAPUi se comprueba el funcionamiento correcto.

Ejecución desde SOAPUi

En la consola del servidor encontramos la traza escrita.

Consola de salida del servidor.

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.