Maven

RECU-0322 (Recurso Manual)

Descripción

La construcción de aplicaciones Java EE es un proceso complejo en el cual deben realizarse tareas de construcción, empaquetado y despliegue en múltiples entornos. Estas aplicaciones suelen depender frecuentemente de un gran número librerías y frameworks de terceros. Por otro lado, se suelen gestionar recursos estáticos (CSS, Javascript, documentos...), ficheros de configuración, descriptores de despliegue; se requiere la realización de pruebas unitarias y, normalmente, se integran en sistemas de control de versiones como CVS o Subversion.

El problema es que cada aplicación puede tomar un enfoque diferente para desarrollar cada una de estas necesidades. Esto provoca numerosos problemas:

  • Existe gran heterogeneidad en los aplicativos.
  • No se suele reutilizar todo lo que se pudiera.
  • El tiempo de adaptación de una persona a un proyecto suele ser alto, ya que cada proyecto tiene un propio enfoque tecnológico y funcional.
  • Este aspecto es aún más grave en el mantenimiento de un sistema de información, donde la curva de aprendizaje es demasiado elevada.
  • Es difícil llevar un control de la calidad del código fuente y la documentación entregada.
  • El proceso de subida de versiones suele ser engorroso: los ficheros que empaquetan la aplicación (usualmente un WAR o un EAR) suelen contener en su interior ficheros de configuración, por lo que no se puede utilizar el mismo fichero en diversos entornos (como desarrollo, preproducción o producción).

Apache Maven intenta solucionar estos déficits. Maven es un “Project Management Framework”, esto es, un framework de gestión de proyectos de software, que proporciona un modelo estándar de gestión y descripción de proyectos. Maven da soluciones a tareas que abarcan desde la compilación hasta la distribución, despliegue y documentación de los proyectos. Se podría describir como “un sistema de estándares, un repositorio, y un software usado para manejar y describir proyectos. Define un ciclo de vida estándar para la construcción, prueba, y despliegue de componentes del proyecto. Proporciona un marco que permita la reutilización fácil de la lógica común de la estructura para todo los proyectos que siguen los estándares Maven.”

Podemos ver la estructura que marca MADEJA para un proyecto en Maven en la sección de Requisitos de la Entrega. El principal objetivo de Maven es que un desarrollador pueda adaptarse al método de trabajo de un proyecto en el menor tiempo posible, disminuyendo su curva de aprendizaje.

Para lograr este objetivo primordial de Maven se encarga de diversas materias:

  • Facilita el proceso de construcción.
  • Proporciona un sistema de construcción uniforme. Maven se basa en la definición de metadatos del proyecto, en el Project Object Model (POM), almacenados en un fichero denominado pom.xml, unida a la utilización de una serie de plugins comunes a los proyectos que utilizan Maven. Todos los proyectos Maven funcionan de la misma forma, por lo que el esfuerzo de aprendizaje sólo se hace una vez.
  • Proporciona información útil sobre el proyecto. Partiendo de la información almacenada en el POM (Project Object Model) Maven puede gestionar automáticamente información del proyecto de gran utilidad, como por ejemplo:
    • Lista de cambios (CHANGELOG) desde el control de versiones.
    • Dependencias transitivas. Por ejemplo: struts.jar, que a su vez depende de commons-beanutils.jar
    • Informes de la ejecución de pruebas unitarias.
  • Ayuda a utilizar las “mejores practicas” de desarrollo (Best Practices). Maven obliga a aceptar una serie de convenciones y costumbres que aportan claros beneficios. Por ejemplo, marca una estructura estándar para el código fuente, la documentación, existe un único sitio donde describir el proyecto, obliga a tener el código fuente de las pruebas unitarias de forma separada pero relacionada, etc.
  • Permite introducir nuevos servicios de forma sencilla: plugins para la creación automática de un portal Web del proyecto fácilmente configurable, para el cálculo de métricas de calidad del código fuente, para su despliegue en los entornos de desarrollo, preproducción y producción, etc.

Características

Maven dispone por defecto de una serie de funcionalidades avanzadas, las cuales describiremos a continuación. De todas formas hemos de tener en cuenta que Maven dispone de un gran número de plugins que le otorgan un enorme valor añadido, además, aquel que quiera puede crear sus propios plugins.

Sobre las características disponibles, destacamos las siguientes:

  • Creación sencilla y ágil de un nuevo proyecto o módulo.
  • Estandarización de la estructura de un proyecto, y de las técnicas relacionadas con éste. De esta forma, se mejora la adaptación de los desarrolladores y la homogeneización del software. Maven propone una estructura estándar de un proyecto: El proyecto se describe en su totalidad en el fichero pom.xml, y existe una localización estándar para el código fuente, los recursos, el código de la aplicación Web, etc.
  • Maven incluye un potente mecanismo de gestión de las dependencias de un proyecto sobre librerías propias o de terceros. Gracias a la descripción de estas dependencias en el pom.xml, Maven puede realizar una serie de tareas útiles como actualizaciones automáticas (incluyendo la descarga de las librerías necesarias), y la resolución de dependencias transitivas (una librería depende de otra). Maven posibilita la reutilización de librerías propias.
  • Maven permite una sencilla gestión simultánea de varios proyectos.
  • Maven dispone de un enorme repositorio de librerías Open Source en constante actualización, de forma que los desarrolladores pueden acceder a las versiones más actualizadas de las mismas.
  • Maven es extensible: dispone de multitud de plugins y de la posibilidad de creación de otros que necesitemos.
  • Nos proporciona un acceso inmediato a nuevas funcionalidades requiriendo un esfuerzo muy pequeño de configuración.
  • Integración con tareas ANT: aquellos grupos de desarrollo que ya dispongan de scripts ant podrán seguir utilizándolos.
  • Construcción basada en modelos: en función de la definición, Maven puede generar diversos formatos de empaquetado de proyectos: WAR, EAR, JAR...
  • Generación de un portal Web del proyecto coherente con la descripción dada en el POM. En este portal Web se puede incluir la documentación del proyecto, informes sobre el estado del proyecto, sobre la calidad del código… por ejemplo, los portales de cada producto de Apache están generados con Maven.
  • Gestión de releases y publicación: Maven se integra con sistemas de gestión de versiones (como CVS o SVN) y gestiona la publicación de releases.

Maven se basa en la invocación de una serie de objetivos o goals. Estos goals se invocan por línea de comandos (o desde un IDE como Eclipse) para realizar una tarea.

Por ejemplo, “mvn site” es una ejecución al goal site, que crea un portal Web para el proyecto en función de su definición en el pom.xml. Para crear este portal, tendremos que crear nuestro descriptor site.xml, en la carpeta src/site y ejecutar el comando anterior mvn site o mvn site-deploy si además de crear la Web queremos que se despliegue en algún sitio tras generarla. En la siguiente tabla especificamos las carpetas existentes:

site/aptEsta carpeta contiene ficheros con formato apt, que es un formato tipo wiki para escribir documentos de texto estructurados de forma simple. La referencia a este formato la podemos encontrar en esta url: http://maven.apache.org/doxia/references/apt-format.html
site/fmlEsta carpeta contien ficheros de formato FAQ.Se trata de un formato XML simple para gestión de FAQ's.
site/xdocEsta carpeta contine ficheros xml. Estos ficheros son traducidos automáticamente por Maven a páginas html. Usaremos este sistema para crear una página propia dentro del sitio web que acceda a documentos guardados en Alfresco junto con las que se generen en maven.
site/resourcesAquí se guardan todos los recursos que queremos que se copien al sitio web cuando se generen, y que no necesitan ningun otro tratamiento. Por ejemplo las css, scripts, imagenes, etc.

En el fichero pom.xml se almacena toda la información necesaria para el ciclo de vida del proyecto: dependencias, plugins, repositorios de donde obtener estos, configuración de los informes. Además de estos datos, se pueden guardar otros como SCM del proyecto, equipo de desarrollo, listas de distribución, etc. Toda esta información puede ser publicada en el portal Web del proyecto generado con Maven.

 

Prerequisitos e Incompatibilidades

Los requisitos e incompatibilidades detectados por el desarrollador son los siguientes:

  • Se requiere como mínimo un JDK 1.4 para ejecutar Maven2 y un JDK 1.5 para Maven3, aunque para compilar los proyectos se pueden especificar versiones anteriores (1.3 o anteriores).
  • No existe un requisito mínimo de memoria.
  • No existe un requisito mínimo de espacio en disco. Aproximadamente se usan 100MB para el repositorio local, de todas formas, esto variara dependiendo del uso y puede ser eliminado y se puede volver a descargar en cualquier momento.
  • No existe un sistema operativo mínimo requerido.

 

Modo de empleo

Instalación

En este apartado vamos a describir brevemente el proceso de instalación de la versión recomendada de Maven para los distintos entornos existentes (entornos Windows y entornos basados en sistemas operativos Unix).

Windows

Para realizar la instalación en Sistemas Operativos Windows procedemos como sigue:

  • Descomprimimos el archivo zip de la versión recomendada (apache-maven-3.0.4-bin.zip) al directorio en el que queremos instalarlo. Por ejemplo:

    C:\Desarrollo\apache-maven-3.0.4
  • Agregamos el directorio bin del directorio creado a la variable PATH del SO:

    "C:\Desarrollo\apache-maven-3.0.4\bin";%PATH%
  • Agregamos también la variable JAVA_HOME a la ruta donde tengamos instalado el JDK. Por ejemplo:

    C:\Desarrollo\Java\jdk1.5.0_02
  • Acto seguido procedemos a ejecutar desde línea de comandos la siguiente instrucción:

    mvn --version

    con esto nos debería de dar la versión actual del sistema Maven que hayamos instalado.

Sistemas operativos basados en Unix (Linux, Solaris y Mac).

Para realizar la instalación en cualquier otro entorno, procedemos como sigue:

  • Extraemos los archivos de la distribución que vamos a instalar a la ruta donde queramos que quede instalada, por ejemplo:

    usr/local/apache-maven-3.0.4
  • Agregamos la carpeta bin a la variable PATH del sistema como sigue:

    export PATH=/usr/local/apache-maven-3.0.4/bin:$PATH
  • Nos aseguramos que la variable JAVA_HOME esta apuntando a la carpeta de instalación del JDK que queramos usar:

    export JAVA_HOME=/usr/java/jdk1.5.0_02
  • A continuación, nos aseguramos que se ha instalado correctamente ejecutando el comando siguiente:

    mvn --version

Fichero pom.xml

Pasamos a describir un ejemplo de un pom.xml básico:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>ejemplos</groupId>
  <artifactId>EjemploMaven1</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>EjemploMaven1</name>
  <url>http://maven.apache.org</url>
<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Creación con archetypes

Si no queremos partir de un fichero previo, podemos crear nuestro proyecto usando los archetypes de Maven. Usando una archetype Maven nos crea la estructura predefinida para un tipo de proyecto (struts,jsf, etc) que le indiquemos o simplemente un proyecto vacío. Por ejemplo, el siguiente archetype usa appFuse para generar una apliación con jsf, spring e hibernate:

mvn archetype:create 
-DarchetypeGroupId=org.appfuse.archetypes
-DarchetypeArtifactId=appfuse-modular-jsf
-DremoteRepositories=http://static.appfuse.org/releases
-DarchetypeVersion=2.0.1
-DgroupId=com.mycompany.app
-DartifactId=myproject

El resultado lo podemos ver en la siguiente imagen.

Goals básicos

Veamos alguas de las tareas que podemos lanzar en Maven. Para compilar el código de la aplicación se empleará el goal siguiente:

mvn compile

Para generar el paquete (jar, war, ear, sar, etc) que hayamos indicado en el pom.xml basta con ejecutar el goal package. Además como este goal esta asociado a una fase del ciclo de maven posterior a la de compilar y ejecutar los test unitarios, al ejecutar el goal package maven compilaria los fuentes de la aplicación, los test unitarios y los ejecutaría.

mvn package

El goal install además de hacer todo lo que hace el package instala el paquete resultante en el repositorio local de maven de nuestra máquina.

mvn install

Si se quiere desplegar el paquete resultante en un repositorio central para ponerlo a disposición de todo el equipo de desarrollo, se ejecutará la siguiente orden:

mvn deploy

Después de compilar y ejecutar las pruebas, en la carpeta target se encontrará el fichero EjemploMaven1-4.0-SNAPSHOT.jar. En el fichero pom.xml se puede cambiar la versión del artefacto, maven por defecto agregará -SNAPSHOT para indicar que es una versión que está en desarrollo.

Plugins para informes

Podemos agregar una entrada de plugin en la sección de informes del fichero pom.xml, como la siguiente:

<project>
...
<reporting>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
      </plugin>
   </plugins>
</reporting>
...
</project>

Y ejecutamos a continuación el comando:

mvn site

Maven nos generará en /target/site una documentación web por defecto, incluyendo el javadoc del proyecto. También se pueden incluir informes de análisis de código como CheckStyle o PMD para que se ejecuten en el ciclo de vida site.

Un sitio creado con maven generalmente dispone de un menú lateral con los siguientes apartados:

  • Información del proyecto.
  • Informes del proyecto.

Estas secciones se generan automáticamente y extraen su información de lo que aparece en el pom.xml Además de estas podemos añadir nuevas secciones y modificar la estructura del sitio modificando el fichero site.xml. Un posible ejemplo del fichero site.xml puede ser el que sigue:

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="Libreria Grafica en Java">

   <bannerLeft>
      <name>CICE</name>
      <src>logo_cice.gif</src>
      <href>www.juntadeandalucia.es/innovacioncienciayempresa/</href>
   </bannerLeft>

   <body>
      <links>
         <item name="Libreria Grafica en Java"
            href="http://proyectos.cice.com/graficos/index.html" />
         <item name="Foro" href="http://foro.cice.com/" />
         <item name="Blog" href="http://blog.cice.com/" />
      </links>

      <menu name="Librería Gráfica">
         <item name="Introducción" href="/servicios/madeja/documentos.html" />
      </menu>

   </body>
</project>

Configuración de un plugin

También podemos modificar la configuración por defecto de un plugin, para esto utilizamos la etiqueta dentro del fichero pom.xml. Un posible ejemplo:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>       
    <artifactId>maven-site-plugin</artifactId>
<version>3.2</version>
    <configuration>
        <locales>es_ES</locales>
        <encoding>UTF-8</encoding>
        <inputEncoding>UTF-8</inputEncoding>
        <outputEncoding>UTF-8</outputEncoding>
    </configuration>
</plugin>

Además, podemos indicar que un plugin se utilizará sólo en una fase determinada del ciclo de vida:

<executions>
          <execution>
            <id>it-test</id>
            <phase>integration-test</phase>
            <goals>
              <goal>test</goal>
            </goals>
            <configuration>
              <includes>
                <include>**/*TestIt.class</include>
              </includes>
            </configuration>
          </execution>
</executions>

Ciclo de vida

Pasamos a describir cuales son las fases Maven de un proyecto:

  • validate: Esta es la fase en la que valida que el proyecto este correcto y tenga toda la información necesaria para su construcción.
  • generate-sources: Genera codigo fuente para incluirlo en la compilación.
  • process-sources: Procesa el código fuente. Por ejemplo, para el filtrado de valores.
  • generate-resources: Genera los recursos para inclusión en el paquete.
  • process-resources: Copia y procesa los recursos dentro de la carpeta de destino, preparados para empaquetarse.
  • compile: Es la fase en la que se compila el código fuente del proyecto.
  • process-classes: Post procesa los ficheros generados de la compilación para, por ejemplo, hacer optimización de los bytecode en clases Java.
  • generate-test-sources: Genera código fuente para la inclusión en la compilación.
  • process-test-sources: Procesa el código fuente de los test, por ejemplo, para el filtrado de valores.
  • generate-test-resources: Genera los recursos para pruebas.
  • process-test-resources: Copia y procesa los recursos dentro de la carpeta de destino.
  • test-compile: Compila el código fuente de los test.
  • test: fFase en la que se ejecutan los test de la aplicación. Estos test no necesitan que la aplicación este empaquetada ni desplegada.
  • package: Es la fase en la que se toman las clases compiladas y recursos y se crea un paquete con el proyecto (jar, war, ear).
  • integration-test: Fase en la que se ejecutan los test de integración. Aquí se procesa y despliega el paquete si es necesario para que corran las pruebas de integración.
  • verfy: Fase en la que se realiza algún tipo de chequeo para comprobar si el paquete cumple con las normas de calidad.
  • install: Fase en la que se instala el paquete en el repositorio local para ser usado como dependencia por otros proyectos locales.
  • deploy: En esta fase se copia el paquete a un repositorio remoto para ser compartido con otros usuario y proyectos.

SCM. Control de versiones

Con el plugin SCM podemos acceder a un sistema de control de versiones. Se configuraría como sigue:

 <connection>
    scm:svn:http://localhost/repositorio/cice
</connection>

Cargo. Despliegue de aplicaciones

A continuación describimos el plugin Cargo. Este plugin nos da la posibilidad de trabajar directamente desde Maven con distintos contenedores y servidores de aplicaciones (Tomcat, Jboss, Jetty, jo!, OC4J, Orion, Resin, Weblogic).

Para usarlo añadimos la configuración al pom.xml de nuestro proyecto, ejecutamos: mvn cargo:deploy, o mvn cargo:undeploy para quitar el paquete antes desplegado. También podemos configurarlo para usar una instalación de tomcat local al proyecto y levantarlo y tirarlo con el plugin: mvn cargo:start o mvn cargo:stop.

Una posible configuración del pom.xml para utilizar cargo puede ser la siguiente:

<plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven2-plugin</artifactId>
            <version>0.2</version>
            <configuration>
                <configuration>
                    <type>runtime</type>
                    <properties>
                        <cargo.remote.username>${usuario.deployer}</cargo.remote.username>
                        <cargo.remote.password>${password.deployer}</cargo.remote.password>
                        <cargo.tomcat.manager.url>${url.manager.deployer}</cargo.tomcat.manager.url>
                        <cargo.servlet.port>${puerto.manager.deployer}</cargo.servlet.port>
                    </properties>
                </configuration>
                <container>
                    <containerId>tomcat5x</containerId>
                    <type>remote</type>
                </container>
               </configuration>
</plugin>

Profiles

Podemos definir distintos perfiles, cada uno con una configuración específica para el ciclo de vida. De esta manera podemos tener un perfil para pruebas y otro para producción con propiedades diferentes y desplegando en entornos diferentes.

Para definir perfiles podemos usar las etiquetas en el pom.xml o también, si estamos usando Maven2, crearlos en un fichero profiles.xml aparte. Si se está empleando Maven3, los perfiles deben estar incluidos en pom.xml. Un ejemplo del uso de perfiles:

<profiles>
     <profile>
         <id>tomcat5x</id>
        <activation>
      <activeByDefault>
        true
     </activeByDefault>
    <build>
     <plugins> </plugis>
    </build>
    </profile>
</profiles>

Filtering

El Filtering nos da la posibilidad de cambiar los properties que se incluiran en el paquete de la aplicación de forma dinámica. El primer paso es indicar en el pom.xml que quieremos que los properties de nuestra aplicación sean filtrados, para esto añadiremos esta lineas a nuestro pom.xml:

<build>        
    <!-- para filtrar los recursos y poder usar properties -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

Veamos un ejemplo en combinación con los perfiles. Tenemos un properties con la url y clave para conexión con @firma. Y queremos crear a partir de los fuentes el war con un properties que ya tenga los valores de uno u otro entorno.

Añadimos la siguiente definición de perfiles:

  <profiles>
     <profile>
         <id>desarrollo</id>
         <properties>
                  <afirma.url>url1</afirma.url>
                  <afirma.clave>clave1</afirma.clave>
         </properties>
     </profile>
     <profile>
          <id>pruebas</id>           
          <properties>
                   <afirma.url>url2</afirma.url>
                   <afirma.clave>clave2</afirma.clave>
          </properties>
      </profile>
      <profile>
           <id>produccion</id>           
           <properties>
                    <afirma.url>url3</afirma.url>
                    <afirma.clave>clave3</afirma.clave>
           </properties>
      </profile>
  </profiles>

Además de tener definidos los perfiles con unas propiedades creamos el properties que finalmente ira en el war, por ejemplo afirma.properties. El properties esta en la carpeta src/main/resources.

#Variables de ruta de autenticacion en afirma
AFIRMA_URL=${afirma.url}
AFIRMA_CLAVE=${afirma.clave}

Si tras esto ejecutamos el comando mvn package, Maven antes de crear el paquete pasara por la fase en que procesa los recursos para el filtrado y copiará el properties afirma.properties, sustituirá las referencias ${} por el valor de la propiedad que tengamos. Los valores de las propiedades se pueden definir en maven en el pom.xml, en el profiles.xml si se está usando Maven2, en otros properties o por linea de comandos poniendo -D delante del nombre de la propiedad. En este caso Maven cogeria los valores que hemos puesto en la definición de perfiles para cada perfil.

Para indicar el perfil cuando creemos el paquete usamos la opción -P.

mvn package -P desarrollo

El property que finalmente se guarda en el paquete (war, jar etc..) resultante quedaría así:

AFIRMA_URL=url1
AFIRMA_CLAVE=clave1

Proyecto Multimódulo

Si nuestro proyecto es realmente un conjunto de varios módulos o proyectos independientes, como puede ser una aplicación enterprise con un modulo de persistencia, uno de negocio y otro web y queremos construirlos todos a la vez, se empleará la siguiente estructura:

+- pom.xml
    +- capaWeb
        | +- pom.xml
    +- capaNegocio
        | +- pom.xml
    +- capaPersistencia
        | +- pom.xml

Como se puede ver en el árbol anterior, la idea es tener un pom.xml en lo que sería la carpeta del proyecto global.

<project xmlns="http://maven.apache.org/POM/4.0.0"
.......
  <packaging>pom</packaging>
  <modules>
    <module>capaPersistencia</module>
    <module>capaNegocio</module>
    <module>capaWeb</module>
  </modules>
</project>

A continuación, añadiremos a cada pom.xml de los submódulos, la dependencia con los otros y la referencia al pom.xml global. Por ejemplo en el pom.xml de la capaWeb.

<parent>
    <groupId>es.juntadeandalucia.ejemplos</groupId>
    <artifactId>capaWeb</artifactId>
    <version>1.0</version>
  </parent>

   <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>capaNegocio</artifactId>
      <version>1.0</version>
    </dependency>

   <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>capaPersistencia</artifactId>
      <version>1.0</version>
    </dependency>

Plugin Assembly

Este plugin se usa para crear una distribución binaria de nuestro proyecto en Maven que incluya soporte de scripts, ficheros de configuración y dependencias en tiempos de ejecución. Vamos a usar Assembly para crear un zip con todo lo necesario para entregar. Hay ya varios predefinidos, algunos ejemplos pueden ser:

mvn assembly:assembly -DdescriptorId=bin
mvn assembly:assembly -DdescriptorId=jar-with-dependencies
mvn assembly:assembly -DdescriptorId=src

También podemos crear un fichero dep.xml donde indicar que cosas empaquetar dentro de un zip. Y añadimos la configuración al pom.xml para que coja por defecto este fichero.

<plugin>
     <artifactId>maven-assembly-plugin</artifactId>
     <configuration>
          <descriptors>
               <!-- Sitio en el que esta el fichero anterior -->
               <descriptor>src/main/assembly/dep.xml</descriptor>
          </descriptors>
     </configuration>
</plugin>

A continuación mostramos el que podría ser un ejemplo del fichero dep.xml que nos crease un zip con los fuentes por un lado y con el war y los jar necesarios por otro.

<assembly>
    <id>entrega</id>
    <formats>
        <format>zip</format>
    </formats>
    <fileSets>
         <fileSet><!--src con los fuentes -->
        <directory>src</directory>
        <outputDirectory>/fuentes</outputDirectory>
         </fileSet>

         <fileSet><!--pom.xml-->
        <outputDirectory>/fuentes</outputDirectory>
        <includes>
          <include>*.xml</include>
         </includes>
         </fileSet>

         <fileSet> <!-- war de la aplicación y jar de dependencias -->
        <directory>target</directory>
        <outputDirectory>/binarios</outputDirectory>
        <includes>
           <include>*.jar</include>
            <include>*.war</include>
        </includes>
         </fileSet>

     </fileSets>

    <dependencySets>
         <dependencySet>
        <outputDirectory>/binarios</outputDirectory>
        <scope>runtime</scope>
           </dependencySet>
    </dependencySets>
</assembly>

Interacción con otros subsistemas y componentes

Pasamos a describir algunos plugins de Maven y que pueden ser útiles en el trabajo del día a día y para integrarse con otros sistemas.

Plugins Utilidades (tools)

Apache Maven dispone de una serie de plugins para utilidades diversas, como por ejemplo:

Archetype

Este plugin crea plantillas de proyectos. Existen a priori plantillas de proyectos Java simples, proyectos simples Java EE, aplicaciones Web, aplicaciones basadas en portlets, etc. y, lo que es más útil, permite definir nuevos arquetipos acorde a nuestra arquitectura. Esto permite estandarizar arquitecturas base y facilitar la creación de un nuevo proyecto.

SCM

Este plugin permite interactuar con un sistema de control de versiones como Subversion (SVN) o CVS, definiendo la conexión al repositorio.

Surefire

Utilizado para ejecutar una serie de pruebas unitarias JUnit y generar un informe con los resultados obtenidos tras la aplicación de dichas pruebas.

Plugins de Informes (Reporting)

Apache Maven dispone de una serie de plugins para realizar informes o documentos de forma automática, como por ejemplo los siguientes plugins:

Surefire-Report

Relacionado con el plugin Surefire anteriormente mencionado, genera informe con los resultados de las pruebas unitarias JUnit.

Javadoc

Este plugin crea el Javadoc del proyecto.

Changelog

Este plugin crea un documento con los cambios más recientes del proyecto almacenados en el Sistema de Control de Versiones (como SVN o CVS).

Checkstyle

Checkstyle es una aplicación que sirve para verificar buenas prácticas de desarrollo, realizando métricas útiles como código repetido, exceso de líneas de código, etc. Este plugin utiliza Checkstyle para generar informes de calidad de código.

PMD

De forma similar a CheckStyle, se genera un informe invocando a PMD, herramienta que analiza puntos delicados en el desarrollo Java EE, como:

  • Posibles fallos: sentencias try, catch, finally o switch vacías.
  • Código inalcanzable, variables locales, parámetros o métodos privados no utilizados.
  • Código ineficiente (uso excesivo de String o StringBuffer).
  • Expresiones complicadas en exceso de forma innecesaria, por ejemplo, bucles FOR que podrían ser WHILE.
  • Código duplicado en varias clases, en lugar de especializarlo en una clase e invocarlo en el resto.

Plugins de Integración con IDEs

Apache Maven dispone de una serie de plugins para integrarse con plataformas de desarrollo (IDEs) como IDEA o Eclipse.

Plugins de Empaquetamiento (Packaging)

Apache Maven dispone de una serie de plugins para realizar el empaquetamiento de proyectos / módulos en varios formatos, como:

  • EAR
  • WAR
  • EJB
  • JAR
  • RAR

Otros Plugins

Uno de los plugins más interesantes es Cargo, el cual permite desplegar nuestro proyecto en diversos contenedores o servidores de aplicaciones, como JBoss, Tomcat, Geronimo, Jetty, OC4J, Weblogic, Resin, etc.

Como se comentó anteriormente, podemos desarrollar nuestros propios plugins para ampliar la funcionalidad Maven que consideremos oportuna

Herramientas sobre Maven

  • Continuum: Es un servidor de integración continua para proyectos basados en Java. Soporta proyectos en Maven 2, Maven 1, Ant, Shell scripts. La integración continua es una metodología informática propuesta inicialmente por Martin Fowler que consiste en hacer integraciones automáticas de un proyecto lo más a menudo posible para así poder detectar fallos cuanto antes. Entendemos por integración la compilación y ejecución de tests de todo un proyecto.
  • Maven Proxy: Es un motor ligero de servlets que se instala en tu servidor e imita otros repositorios como, por ejemplo, ibiblio. Cuando recibe una petición de un jar y no lo tiene, lo consigue de los servidores y lo almacena en cache antes de devolver la petición. No tiene administración, ni navegador visual.
  • Archiva: Esta herramienta permite la publicación y gestión de un repositorio de dependencias para Maven remoto. Algunas de sus funcionalidades son: busqueda de información en los pom.xml y ficheros, creación y gestión un repositorio, proxy, mantenimiento y reporting.
  • Artifactory: Ofrece funcionalidades de proxy, cache y seguridad muy avanzas y tiene funciones de backup y de búsqueda de librerías. Artifactory utiliza un JSR - 170 compatible con Java Content Repository (JCR) para el almacenamiento, lo que hace fácil de manejar los metadatos totalmente indexados y buscables para proporcionar características extendidas como la seguridad, las operaciones transaccionales,la realización de auditorías, bloqueo, etc.

Documentos de formación

Versiones

La versión recomendada es la última estable homologada, concretamente es la 3.0.4, la cual puede descargarse desde la página del desarrollador (incluida en la sección de enlaces). En caso de que se necesite emplear la versión 2 de Maven, la versión recomendada es la 2.2.1

Buenas prácticas y recomendaciones de uso

Debido al uso de distintos repositorios de librerías, puede darse el caso que algunas dependencias que necesite nuestro proyecto nos descarguen además otras dependencias que, pese a no ser necesarias para nuestro proyecto, si sean necesarias para el correcto funcionamiento de la librería a usar. En estos casos, al no tener control total sobre los repositorios con los que estamos trabajando, se hace necesario la utilización de exclusiones de dependencias.

Estas exclusiones nos permiten que, según el caso, nos bajemos todas las dependencias que vienen definidas en el pom de esa librería concreta o sólo la librería que estamos solicitando, de forma que no interfiera con ninguna otra versión de una dependencia que tengamos definida en nuestro proyecto.

Un ejemplo de este tipo de problemas y su resolución puede ser el siguiente caso:

Fichero pom.xml

<?xml version="1.0" encoding="UTF-8"?><project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>es.juntadeandalucia.cice.test</groupId>
  <artifactId>Dependencias</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <description></description>

  <build>
    <finalName>Dependencias</finalName>
    <plugins>   
        <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <configuration>
            <source>1.5</source>
            <target>1.5</target>
       </configuration>
     </plugin>
     </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-el</artifactId>
      <version>1.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-api</artifactId>
      <version>1.1.5</version>
    </dependency>

  </dependencies>

</project>

En este fichero, vemos que tenemos dos dependencias: commons-el y myfaces-api. El problema puede surgir si se incluyen las mismas dependencias pero de versiones distintas en ambas.

Fichero pom.xml de commons-el

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-el</artifactId>
  <name>EL</name>
  <version>1.0</version>
  <description>JSP 2.0 Expression Language Interpreter Implementation</description>
  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.0.3</version>
    </dependency>
  </dependencies>
</project>

Hace referencia a la versión 1.0.3 de la librería commons-logging, si en la librería myfaces-api se hace referencia a esta librería también:

Fichero pom.xml de myfaces-api

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-api</artifactId>
  <name>myfaces-api</name>
  <version>1.1.5</version>
  <dependencies>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.0.4</version>
    </dependency>
  </dependencies>
</project>

Como resultado de esto, en el war generado para nuestro proyecto estarían dos librerías commons-logging de versiones distintas: 1.0.3 y 1.0.4 debido a las dependencias transitivas de nuestro proyecto. Para evitar los problemas derivados de este tipo de dependencias, se utilizan las exclusiones dentro de cada dependencia concreta. Una forma de solucionar el problema puede ser la siguiente:

<?xml version="1.0" encoding="UTF-8"?><project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>es.juntadeandalucia.cice.test</groupId>
  <artifactId>Dependencias</artifactId>
  <packaging>war</packaging>
  <version>1.0.0</version>
  <description></description>

  <build>
    <finalName>Dependencias</finalName>
    <plugins>   
        <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <configuration>
            <source>1.5</source>
            <target>1.5</target>
       </configuration>
     </plugin>
     </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-el</artifactId>
      <version>1.0</version>
      <exclusions>
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.apache.myfaces.core</groupId>
      <artifactId>myfaces-api</artifactId>
      <version>1.1.5</version>
    </dependency>

  </dependencies>

</project>

Al hacer esto evitamos que, al descargar el proyecto, la dependencia commons-el se descargue también el commons-logging, dejando el proyecto con el commons-logging de myfaces-api (versión 1.0.4).

Recomendaciones de uso

Podemos describir un proyecto en Maven como una carpeta en la que tenemos un fichero descriptor de proyecto (pom.xml). En lugar de crear el proyecto a mano podemos hacer uso de un gran número de plantillas o archetype. Un posible ejemplo de creación de proyecto de struts mediante maven sería el siguiente:

mvn archetype:create -DgroupId=proyectoStruts -DartifactId=proyectoStruts 
-DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts2-archetype-starter
-DarchetypeVersion=2.0.2-SNAPSHOT

De esta sentencia podemos destacar las siguientes características:

  • archetype:create: Es un modelo estándar a partir del cual se se generan otros proyectos del mismo tipo, genera una estructura de proyecto estándar
  • groupId: Es el nombre bajo el que uno o más proyectos pudieran estar, siendo el paquete inicial para las clases Java.
  • artifactId: Es el nombre del proyecto, es decir el nombre del jar o war que se generará.

Todos los componentes software que necesitemos en algún momento del ciclo de vida son dependencias. Estas dependencias no acompañan el código fuente de nuestro desarrollo sino que se incluirán según el momento en el que se vaya a necesitar cada dependencia. Esta dependencia puede tener un ámbito que puede ser: compile, test, provided, run-time o system. Si no se identifica el goal se entiende que por defecto es compile. Las dependencias del proyecto se obtienen automáticamente del repositorio local o de uno remoto que haya sido definido.

Los elementos que describirán nuestra dependencia son los siguientes:

  • groupId: Hace referencia a la organización, suele coincidir con el paquete.
  • artifactId: Identificador del componente que se este desarrollando.
  • version: Identificador de la versión en desarrollo.
  • scope: Ámbito en el que se usa , puede ser compile, test, provided, run-time o system.
  • type: Tipo de empaquetamiento de la dependencia.
  • classifier: Texto adicional que describe la dependencia como por ejemplo: “Esta en producción”.

Contenidos relacionados

Pautas
Recursos
Área: Entorno » Área Gestión de la Entrega
Código Título Tipo Carácter
RECU-0323 Guía de la Estructura del Software Manual Recomendado
RECU-0681 Características de Maven3 respecto a Maven2 Referencia Recomendado
Área: Entorno » Área Gestión de la Entrega » Repositorio de Artefactos
Código Título Tipo Carácter
RECU-0327 Artifactory Manual Recomendado