Minientrada

Internacionalizando una aplicación web basada en JSF 2.x

En esta entrada voy a realizar una aplicación muy básica con JSF 2.x y voy a internacionalizarla, de forma que se pueda ejecutar en dos lenguajes diferentes: español e inglés.

Es conveniente si tenemos claro que la aplicación debe aceptar varios idiomas que la internacionalización la apliquemos en la fase más temprana posible. Incorporar la internacionlización cuando la aplicación ya está muy avanzada suele ser bastante más costoso que hacerlo en etapas tempranas por varios motivos, pero principalmente las diferencias que hay entre los diferentes idiomas en cuanto a decir lo mismo con más o menos palabras pueden afectar al diseño de las páginas.

Requisitos para desarrollar el ejemplo.

Para que se pueda reproducir el ejemplo y esté operativo al 100% comento qué entorno he utilizado 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
Tecnología: JSF 2.2 (Java EE 7)

Recomiendo la lectura de la entrada JSF 2.x Hola Mundo pues en ella comento todos los aspectos de configuración que en esta entrada voy a dar por supuestos, como la elección de librerías, configuración de servlets, etcétera.

Módulo web de aplicación.

Este ejemplo es tan sencillo que va a contar con un único módulo; el módulo web. El módulo web genera un WAR que se despliega directamente en Apache Tomcat.

Estructura

2016-09-09_14-18-13

Fichero: pom.xml

<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>es.egv.jee6.jsf2</groupId>
 <artifactId>i18nBasico</artifactId>
 <version>1.0.0</version>
 <packaging>war</packaging>

 <dependencies>
   <dependency>
     <groupId>com.sun.faces</groupId>
     <artifactId>jsf-api</artifactId>
     <version>2.2.11</version>
   </dependency>

   <dependency>
     <groupId>com.sun.faces</groupId>
     <artifactId>jsf-impl</artifactId>
     <version>2.2.11</version>
   </dependency>

   <dependency>
     <groupId>javax.el</groupId>
     <artifactId>javax.el-api</artifactId>
     <version>3.0.1-b04</version>
   </dependency>

   <dependency>
     <groupId>javax.servlet.jsp.jstl</groupId>
     <artifactId>jstl-api</artifactId>
     <version>1.2</version>
   </dependency>
 </dependencies>

</project>

Fichero: WEB-INF/web.xml

<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>BasicoI18N</display-name>
  <welcome-file-list>
    <welcome-file>i18nwelcome.xhtml</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
 
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  
  <context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>WEB-INF/faces-config.xml</param-value>
  </context-param>

  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  
</web-app>

Destacar la inclusión de un parámetro de configuración que indica donde se encuentra el fichero de configuración de JSF. En este ejemplo vamos a incluir este fichero de configuración ya que va a ser necesario indicar los ficheros donde se encuentran las traducciones del idioma y el idioma por defecto de la aplicación.

Fichero: WEB-INF/faces-config.xml

<faces-config 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">
    <application>
        <locale-config>
            <default-locale>es</default-locale>
        </locale-config>
        <resource-bundle>
            <base-name>i18n.i18nBasico</base-name>
            <var>i18n</var>
        </resource-bundle>
    </application>
</faces-config>

El campo <locale-config> sirve para definir las configuraciones relativas a la situación geográfica, entre ellas las localizaciones permitidas <supported-locale> o la localización por defecto <default-locale>. La localización es imprescindible para internacionalizar la aplicación.

El campo <resource-bundle> es la piedra angular de la internacionalización, ya que en él se indica donde va a encontrar la aplicación los ficheros que contienen las etiquetas en sus respectivos idiomas <base-name> y el nombre de la variable que se va a utilizar para hacer referencias a ellas <var>. Así podremos encontrar en las páginas dinámicas código como el siguiente donde se hace referencia a la etiqueta i18nwelcome.saludo del grupo de recursos identificado por el nombre de variable i18n:

<h:outputText value="#{i18n['i18nwelcome.saludo']}" />

El fichero faces-config.xml añade un montón de posibilidades de configuración más, pero se escapan al ámbito de esta entrada. Pueden consultarse en el siguiente link.

Los ficheros de recursos para los idiomas.

Estos ficheros contienen las traducciones a diferentes idiomas de las etiquetas de la aplicación. El nombre es el indicado en el campo <base-name> al que se le concatena el lenguaje de la variable Locale. Por ejemplo, para contener las etiquetas en inglés de la aplicación, el fichero se llama i18nBasico_en.properties.

Fichero: i18n/i18nBasico_en.properties

i18nwelcome.titulo = JSF 2.x internacionalization example.
i18nwelcome.saludo = Internacionalization with JSF 2.x. 
i18nwelcome.etiquetaIdioma = Language
i18nwelcome.descripcion-metodo1 = Combo Box Method
i18nwelcome.descripcion-metodo2 = Image Method

Fichero: i18n/i18nBasico_es.properties

i18nwelcome.titulo = Ejemplo de internacionalización con JSF 2.x.
i18nwelcome.saludo = Internacionalización con JSF 2.x. 
i18nwelcome.etiquetaIdioma = Idioma
i18nwelcome.descripcion-metodo1 = Método basado en una lista seleccionable. 
i18nwelcome.descripcion-metodo2 = Método basado en imágenes.

Se puede ver que el nombre de las etiquetas es el mismo en ambos ficheros, pero el valor de las mismas está traducido al idioma que se indica en el nombre del fichero.

El Managed Bean que maneja la lógica de presentación del idioma.

Fichero: es.egv.jee6.jsf2.i18n.IdiomaBean.java

package es.egv.jee6.jsf2.i18n;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;

@ManagedBean(name="idiomaBean")
@SessionScoped
public class IdiomaBean implements Serializable {


    private static final long serialVersionUID = 1L;

    private String codigoIdioma;
    
    private Map<String,Object> listaIdiomas;
    
    public IdiomaBean() {
        super();
        this.codigoIdioma = FacesContext.getCurrentInstance().getViewRoot().getLocale().getLanguage();
        this.listaIdiomas = new LinkedHashMap<String,Object>();
        this.listaIdiomas.put("Español", new Locale("es"));
        this.listaIdiomas.put("Inglés", new Locale("en"));
    }

    public String getCodigoIdioma() {
        return codigoIdioma;
    }
    
    public void setCodigoIdioma(String codigoIdioma) {
        this.codigoIdioma = codigoIdioma;
    }
    
    public Map<String, Object> getListaIdiomas() {
        return listaIdiomas;
    }
    
    public void doCambioIdiomaConLista(ValueChangeEvent e)
    {

        String newCodigoIdioma = e.getNewValue().toString();
        System.out.println("newCodigoIdioma=" + newCodigoIdioma);
        System.out.println("idiomaBean=" + this.toString());

        //loop country map to compare the locale code
        for (Map.Entry<String, Object> entry : listaIdiomas.entrySet()) 
        {

               if(entry.getValue().toString().equals(newCodigoIdioma))
               {
                   System.out.println("Asignando nueva locale al contexto de Faces.");
                   FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale)entry.getValue());
               }
        }
    }
    
    public void doCambioIdiomaConImagen(String nuevoIdioma)
    {

        //loop country map to compare the locale code
        for (Map.Entry<String, Object> entry : listaIdiomas.entrySet()) 
        {

               if(entry.getValue().toString().equals(nuevoIdioma))
               {
                   System.out.println("Pinchado en imagen " + nuevoIdioma + ". Asignando nueva locale al contexto de Faces");
                   this.codigoIdioma = nuevoIdioma;
                   FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale)entry.getValue());
               }
        }
    }    
   
    @Override
    public String toString() {
        return "IdiomaBean [codigoIdioma=" + codigoIdioma + ", listaIdiomas=" + listaIdiomas + "]";
    }     
}

Defino un managed bean específico para manejar el idioma. Será el encargado de conservar el idioma seleccionado por el usuario, una lista de idiomas seleccionables, y las diferentes acciones que se llevan a cabo cuando se realizan acciones relacionadas con el idioma.

@ManagedBean(name="idiomaBean")
@SessionScoped
public class IdiomaBean implements Serializable {

Este ManagedBean lo defino en el ámbito de la sesión @SessionScoped. De esta manera, el idioma queda almacenado en todas las navegaciones que realice el usuario hasta que cierre el navegador, o la sesión.

    private String codigoIdioma;
    private Map<String,Object> listaIdiomas;

Se definen la variable codigoIdioma para contener el idioma seleccionado por el usuario y la variable listaIdiomas para contener los idiomas que van a mostrarse al usuario para proceder a la traducción de la aplicación.Se incluyen también sus getters y sus setters.

    public IdiomaBean() {
        super();
        this.codigoIdioma = FacesContext.getCurrentInstance().getViewRoot().getLocale().getLanguage();
        this.listaIdiomas = new LinkedHashMap<String,Object>();
        this.listaIdiomas.put("Español", new Locale("es"));
        this.listaIdiomas.put("Inglés", new Locale("en"));
    }

Se incluye un constructor para rellenar el código del idioma con el idioma configurado por JSF en el arranque, que será el idioma que se ha configurado en el <default-locale> del fichero faces-config.xml, y rellenar la lista de idiomas con los idiomas válidos para la aplicación.

   public void doCambioIdiomaConLista(ValueChangeEvent e)
    {

        String newCodigoIdioma = e.getNewValue().toString();
        System.out.println("newCodigoIdioma=" + newCodigoIdioma);
        System.out.println("idiomaBean=" + this.toString());

        //loop country map to compare the locale code
        for (Map.Entry<String, Object> entry : listaIdiomas.entrySet()) 
        {

               if(entry.getValue().toString().equals(newCodigoIdioma))
               {
                   System.out.println("Asignando nueva locale al contexto de Faces.");
                   FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale)entry.getValue());
               }
        }
    }

Se añade un método para manejar el cambio del idioma cuando se seleccione un idioma de la lista.

<h:selectOneMenu value="#{idiomaBean.codigoIdioma}" onchange="submit()"
                valueChangeListener="#{idiomaBean.doCambioIdiomaConLista}">

Y, se añade un método que se ejecutará cuando se seleccione un cambio de idioma pinchando en la imágen del mismo.

    public void doCambioIdiomaConImagen(String nuevoIdioma)
    {

        //loop country map to compare the locale code
        for (Map.Entry<String, Object> entry : listaIdiomas.entrySet()) 
        {

               if(entry.getValue().toString().equals(nuevoIdioma))
               {
                   System.out.println("Pinchado en imagen " + nuevoIdioma + ". Asignando nueva locale al contexto de Faces");
                   this.codigoIdioma = nuevoIdioma;
                   FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale)entry.getValue());
               }
        }
    }
<h:commandLink action="#{idiomaBean.doCambioIdiomaConImagen('en')}">

Destacar que se ha incluido la asignación del idioma seleccionado a la variable codigoIdioma del bean para que quede guardada la sección.

this.codigoIdioma = nuevoIdioma;

Páginas web dinámicas.

El ejemplo consta de tres páginas web dinámicas: i18nwelcome.xhtml que es la página básica de bienvenida, i18nidiomametodo1.xhtml que es la página con el manejo de idioma basado en una lista seleccionable, e i18nidiomametodo2.xhtml que es la página con el manejo del idioma basado en imágenes.

2016-09-09_15-17-48

Fichero: i18nwelcome.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:body>
    <h1>#{i18n['i18nwelcome.titulo']}</h1>
    <h:form>
        <h2>
            <h:outputText value="#{i18n['i18nwelcome.saludo']}" />
        </h2>        
        <ui:include src="i18nidiomametodo1.xhtml" />        
        <ui:include src="i18nidiomametodo2.xhtml" />
    </h:form>
</h:body>
</html>

Esta página muestra dos etiquetas a internacionalizar; i18nwelcome.titulo e i18nwelcome.saludo. Para mostrar correctamente el idioma se utiliza expresiones EL que son interpretadas por JSF en tiempo de ejecución.

#{i18n['i18nwelcome.titulo']}

Esta expresión indica que se va a recoger del bundle i18n la etiqueta i18nwelcome.titulo.

Por claridad, los dos métodos que se van a utilizar para la selección del idioma se han realizado en dos páginas dinámicas independientes que se incluyen en la página básica mediante la sentencia <ui:include src=»»/>.

<ui:include src="i18nidiomametodo1.xhtml" />

Fichero: i18nidiomametodo1.xhtml

<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:outputText value="#{i18n['i18nwelcome.descripcion-metodo1']}."/>
        <h:panelGrid columns="2">
            <h:outputText value="#{i18n['i18nwelcome.etiquetaIdioma']}:" />
            <h:selectOneMenu value="#{idiomaBean.codigoIdioma}" onchange="submit()"
                valueChangeListener="#{idiomaBean.doCambioIdiomaConLista}">
                <f:selectItems value="#{idiomaBean.listaIdiomas}" />
            </h:selectOneMenu>
        </h:panelGrid>
</ui:composition>

Estos ficheros como se han diseñado para ser incluidos en un fichero padre y no para llamarse directamente se crean como elementos <ui:composition/>.

El valor seleccionado en la lista seleccionable es el codigoIdioma almacenado en el Managed Bean.

<h:selectOneMenu value="#{idiomaBean.codigoIdioma}"

La lista se carga con los valores almacenados en la listaIdiomas del Managed Bean.

<f:selectItems value="#{idiomaBean.listaIdiomas}" />

Cuando se cambia el elemento seleccionado se lanza el método doCambioIdiomaConLista.

onchange="submit()"
                valueChangeListener="#{idiomaBean.doCambioIdiomaConLista}"

Fichero: i18nidiomametodo2.xhtml

<ui:composition 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
        <h:outputText value="#{i18n['i18nwelcome.descripcion-metodo2']}."/>
        <h:panelGrid columns="1">
            <h:commandLink action="#{idiomaBean.doCambioIdiomaConImagen('en')}">
                <h:graphicImage library="images" name="bandera-en.png" rendered="#{idiomaBean.codigoIdioma == 'es'}"/>
            </h:commandLink>
            <h:commandLink action="#{idiomaBean.doCambioIdiomaConImagen('es')}">
                <h:graphicImage library="images" name="bandera-es.png" rendered="#{idiomaBean.codigoIdioma == 'en'}"/>
            </h:commandLink>
        </h:panelGrid>
</ui:composition>

Destacar que se muestra el botón con la bandera del idioma que no está seleccionado, para así poder cambiarlo. Para ello se utiliza el atributo rendered y expresiones EL.

rendered="#{idiomaBean.codigoIdioma == 'es'}"

Demo

El pase de diapositivas requiere JavaScript.

Link

Configurar Aplicaciones JSF
Documentación oficial JSF 2.x

 

Minientrada

Firefox, el proxy y el continuo error 407 (Proxy Authentication Required).

En el último proyecto en el que estoy recientemente involucrado he definido un entorno de trabajo virtualizado con máquinas basadas en Windows 10 que no se incluyen en el dominio y por tanto no realizan autenticación en él; la autenticación se realiza mediante usuarios locales. Sin embargo, para salir a internet se utiliza un proxy, en el que sí es necesario autenticarse a través del dominio windows de la organización.

A priori, sobre el papel esta configuración es bastante común y no da problemas. Para abrir una URL de internet desde el navegador, inicialmente se intenta hacer login con el usuario local, al no ser usuario de dominio y no poder autenticarse en el dominio, el navegador muestra una ventana para introducir el usuario y la password correctas. Si con ese usuario y password la autenticación es correcta en el dominio, automáticamente se navega a la url exterior solicitada.

En las máquinas virtuales de los desarrolladores, con Internet Explorer no hay ningún tipo de problema, se introduce el usuario, la password y la salida a internet es automática. Con Microsoft Edge el funcionamiento es correcto también, pero con Firefox (cualquier versión, aunque concretamente estamos utilizando Firefox Developer Edition 50.0a2) empiezan los problemas ya que este navegador se bucla solicitando continuamente el usuario y la password que el proxy necesita para realizar la autenticación.

2016-09-08_16-16-55

Solución

Este problema que es bastante engorroso, porque anula el funcionamiento de Firefox y lo elimina como navegador, se soluciona cambiando varias configuraciones internas de Mozilla Firefox.

Para acceder a dichas configuraciones hay que teclear la url about:config.

Es probable que si no hemos accedido antes a ésta URL, nos pida una confirmación para mostrar la página, pues modificar las configuraciones avanzadas puede ser potencialmente peligroso para el navegador.

2016-09-08_15-47-08

En este caso como estamos seguros de lo que vamos a configurar pinchamos en Aceptamos el riesgo.

Las configuraciones que hay que cambiar son:

  • signon.autologin.proxy –> TRUE
  • network.automatic-ntlm-auth.allow-proxies –> FALSE
  • network.auth.use-sspi –> FALSE

Estas configuraciones pueden ser encontradas mediante el campo de Busqueda. El cambio en los campos booleanos se realiza haciendo doble click sobre ellos.

2016-09-08_16-08-28

Completadas las configuraciones, se cierra y vuelve a abrir el navegador, se teclea la url de internet a la que se quiere navegar, se rellena el usuario y la password (una única vez), et voila, debería mostrarse el contenido web de la URL.

Links

Explicaciones de las diferentes configuraciones avanzadas de Firefox.

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