viernes, 6 de abril de 2007

Construyendo proyectos con Maven 2

Maven es una excelente herramienta que nos permite simplificar el proceso de construcción de un proyecto (jar, ear, ejb, war, etc). La herramienta es tan poderosa que se ha convertido en una de mis favoritas, y la uso prácticamente todos los días. Alguna de las características que la han convertido en indispensable son:

  1. Se puede construir, ejecutar tests y empaquetar un proyecto con un solo comando.
  2. Permite administrar las dependencias de un proyecto de forma eficiente
  3. Permite unificar la estructura de los proyectos
  4. Permite generar una pagina web del proyecto con información general y con reportes variados relacionados al proyecto.
  5. Define una guia de buenas practicas de desarrollo

Quizás lo mas interesante es el primer punto ya que es lo que uno hace en el día a día. Por ejemplo, para generar un war el comando seria

$ mvn clean war:war

La definición del proyecto se hace en el archivo pom.xml y debe estar ubicado en el directorio raíz del proyecto. Allí se define información general del proyecto así como todas las dependencias del mismo.

La instalación es bien sencilla:

  1. Bajar maven 2.0.x del site de Apache
  2. Unzip maven en algun directorio. Ejm: /home/usuario/maven
  3. Agregar al PATH el dir bin de maven.

  4. export PATH=$PATH:/home/usuario/maven/bin:

  5. Agregar la variable MAVEN_OPTS al ambiente. Esta variable define parametros del JVM para maven.

  6. $ export MAVEN_OPTS=-Xmx256M

  7. Crear el archivo settings.xml en el directorio {home}/.m2 del usuario. Este archivo contiene variables de configuración globales de MAVEN. A continuación se tiene un ejemplo del archivo

  8. <settings>
    <localRepository>/home/usuario/m2_local_repo</localRepository>
    <proxies />
    <servers />
    <mirrors />
    <profiles />
    </settings>

  9. La entrada localRepository debe apuntar a donde estar el repositorio local de maven. Es aquí donde maven almacena todas las dependencias de nuestros proyectos.
  10. Probar la instalación

  11. $ mvn --version
    Maven version: 2.0.6

  12. Ahora solo falta crear el pom.xml de un proyecto y listo. Supongamos que tenemos un proyecto A que debe generar un war. El pom.xml puede ser como:


  13. <?xml version="1.0" encoding="UTF-8"?>
    <project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.test.maven</groupId>
    <artifactId>proyectoA</artifactId>
    <packaging>war</packaging>
    <name>Proyecto A</name>
    <version>0.0.1</version>
    <description>Test maven</description>
    <dependencies>
    <dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-j2ee_1.4_spec</artifactId>
    <version>1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring</artifactId>
    <version>2.0.3</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.0.5</version>
    </dependency>
    <dependency>
    <groupId>xerces</groupId>
    <artifactId>xercesImpl</artifactId>
    <version>2.8.1</version>
    </dependency>
    <dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.2.1</version>
    </dependency>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>3.8.1</version>
    <scope>test</scope>
    </dependency>
    </dependencies>
    </project>

  14. Fijense que se definieron varias dependencias como spring, mysql connectors, etc. Estas dependencias en principio no existen en nuestro proyecto pero al tratar de compilar con maven este se conectara a internet al repositorio global de maven y bajara las versiones de las dependencias que se especifican. El siguiente comando va a bajar las dependencias no presentes, compilar el proyecto, ejecutar cualquier test definido, generar el war y copiar el war en el repositorio local. El nombre del war será proyectoA-0.0.1.war y sera copiado dentro del repositorio local en la ruta definida por el groupId (org.test.maven)


  15. $ mvn clean install
    [INFO] Scanning for projects...
    [INFO] ----------------------------------------------------------------------------
    [INFO] Building Proyecto A
    [INFO] task-segment: [clean, install]
    [INFO] ----------------------------------------------------------------------------
    [INFO] [clean:clean]
    [INFO] Deleting directory /home/usuario/proyector/proyectoA/target
    [INFO] Deleting directory /home/usuario/proyector/proyectoA/target/classes
    [INFO] Deleting directory /home/usuario/proyector/proyectoA/target/test-classes
    [INFO] [resources:resources]
    [INFO] Using default encoding to copy filtered resources.
    Downloading: http://repo1.maven.org/maven2/commons-dbcp/commons-dbcp/1.2.1/commons-dbcp-1.2.1.pom
    6K downloaded
    Downloading: http://repo1.maven.org/maven2/commons-dbcp/commons-dbcp/1.2.1/commons-dbcp-1.2.1.jar
    105K downloaded
    [INFO] [compiler:compile]
    Compiling 8 source files to /home/usuario/proyector/proyectoA/target/target/classes
    [INFO] [resources:testResources]
    [INFO] Using default encoding to copy filtered resources.
    [INFO] [compiler:testCompile]
    Compiling 1 source file to /home/usuario/proyector/proyectoA/target/target/test-classes
    [INFO] [surefire:test]
    [INFO] Surefire report directory: /home/usuario/proyector/proyectoA/target/target/surefire-reports

    -------------------------------------------------------
    T E S T S
    -------------------------------------------------------
    Running test.TestUserDao
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.797 sec

    Results :
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

    [INFO] [war:war]
    [INFO] Exploding webapp...
    [INFO] Assembling webapp ProyectoA in /home/usuario/proyector/proyectoA/target/ProyectoA-0.0.1
    [INFO] Copy webapp webResources to /home/usuario/proyector/proyectoA/target/ProyectoA-0.0.1
    [INFO] Generating war /home/usuario/proyector/proyectoA/target/ProyectoA-0.0.1.war
    [INFO] Building war: /home/usuario/proyector/proyectoA/target/ProyectoA-0.0.1.war
    [INFO] [install:install]
    [INFO] Installing /home/usuario/proyector/proyectoA/target/ProyectoA-0.0.1.war to /home/usuario/m2_local_repo/org/test/maven/ProyectoA/0.0.1/ProeyctoA-0.0.1
    war
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESSFUL
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 25 seconds
    [INFO] Finished at: Fri Apr 06 18:37:46 EDT 2007
    [INFO] Final Memory: 5M/15M
    [INFO] ------------------------------------------------------------------------

Si se fijan bien, commons-dbcp no estaba disponible y fue bajado de internet antes de realizar la compilación, también se encontró un test que se ejecutó y funcionó correctamente y al final se generó el war y se publico en el repo local.

Como ven, es muy sencillo instalar, configurar y ejecutar maven. Después que uno se acostumbra a usarlo es difícil volver a ant o a otras herramientas similares. Para los que usan netbeans o eclipse existen plugins que permiten usar maven desde el IDE.

6 comentarios:

alejandroF. dijo...

estimado:

primero felicitaciones pro el blog
muy buenos artículos

te cuento:

trabajo en un proyecto grande
muchos .jsp, struts, clases, pakages etc...

este proyecto esta destinado a varios clientes
cada uno con ciertas configuraciones
comas mas cosas menos
el problema es que esto se hace de manera manual

puedo con maven
crear algo así como proyectos
distintos en base a el proyecto padre y de el heredar para mis distintos clientes?

uso eclipse, oracle, svn

si me puedes guiar un poco
por favor
que maven aun no comprendo mucho

gracias.

Unknown dijo...

Por lo que entiendo lo unico que cambia es la configuracion la cual esta personalizada para cada cliente. Si ese es el caso puedes combinar perfiles de maven (http://maven.apache.org/guides/introduction/introduction-to-profiles.html) con filtros (http://maven.apache.org/guides/getting-started/index.html#How_do_I_filter_resource_files) y con eso te debe funcionar. Asi puedes generar artefactos para cada cliente usando la misma base. Hay 2 libros muy buenos pero en ingles que te pueden dar mas informacion. Estos libros son de la empresa Sonatype que es la misma que esta detras del mantenimiento de maven. Los libros estan en este enlace http://www.sonatype.com/books.html

Unknown dijo...

BUENAS TARDES, QUISIERA SABER SI PUEDES DARME INFORMACIÓN DE COMO INTEGRAR MAVEN 2 Y CRUISE CONTROL YA QUE ESTOY DESARROLLANDO UN CURSO PARA LA UNIVERSIDAD DONDE TRABAJO Y NO ENCUENTRO LA INFORMACIÓN PARA HACER DICHA INTEGRACIÓN.

Unknown dijo...

En este enlace hay informacion de como configurar cruise control y maven, espero que te sirva
http://lijinjoseji.wordpress.com/2008/04/29/configuring-cruise-control-with-maven2-and-svn-146-for-continuous-build-environment/

Anónimo dijo...

HOLA BUENAS!!! tengo un problema trabajando con maven...haber si pueden ayudarme...
trabajo con el codigo fuente de un proyecto que venia todo preparado con su pom.xml (parece que todo esta correcto, dependencias..repositorios etc..)
lo unico que quiero hacer es compilarlo y empaquetarlo en un ".war". todo correcto, se conecta a los repositorios y empieza a descargar hasta que aparece el siguiente error al final:

[ERROR] Failed to execute goal on project frontend: Could not resolve dependenci
es for project org.proyectoedita:frontend:war:1.0.1: Failed to collect dependenc
ies for [javax.servlet:servlet-api:jar:2.5 (provided), javax.servlet.jsp:jsp-api
:jar:2.1 (provided), junit:junit:jar:4.8.2 (test), com.google.gwt:gwt-user:jar:1
.5.2 (provided), com.google.gwt:gwt-servlet:jar:1.5.2 (runtime), com.gwtext:gwte
xt:jar:2.0.5 (provided), com.google.code.gwt-log:gwt-log:jar:2.5.2 (compile), or
g.proyectoedita:org-proyectoedita-components:jar:[1.4.9,) (compile), javax.servl
et:jstl:jar:1.2 (compile), commons-fileupload:commons-fileupload:jar:1.2.1 (comp
ile), commons-io:commons-io:jar:1.4 (compile)]: Failed to read artifact descript
or for com.gwtext:gwtext:jar:2.0.5: Could not transfer artifact com.gwtext:gwtex
t:pom:2.0.5 from/to gwt-ext (http://repository.jboss.org/maven2/): Access denied
to: http://repository.jboss.org/maven2/com/gwtext/gwtext/2.0.5/gwtext-2.0.5.pom
-> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e swit
ch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please rea
d the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyReso
lutionException

COMO LO VEIS, QUE DEBO HACER??? porque he probado mil cosas...

GRACIAS DE ANTEMANO!!!!

Unknown dijo...

El problema es que el pom.xml de la dependencia no esta publico en el repositorio remoto. Si colocas este url en el browser veras que retorna acceso negado
http://repository.jboss.org/maven2/com/gwtext/gwtext/2.0.5/gwtext-2.0.5.pom.
Si tienes forma de conseguir el jar entonces lo puedes importar usando el comando install:install. Ejm:
mvn install:install-file -DgroupId=com.compania... -DartifactId=nombreartefacto... -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/jarfile

Este comando copia el jar en tu repositorio local. Si formas parte de un equipo de desarrollo lo mas facil es instalar un administrador de repositorios, copias alli la dependencia y todos deberian tener acceso a ella. Yo uso Nexus de Sonatype (http://nexus.sonatype.org/download-nexus.html), es muy bueno y es gratis.