25 ago. 2011

Spring ROO - HOWTO (Parte I)

 Hoy toca probar la última release de Spring-ROO (1.1.5.RELEASE), como ya comenté en un post anterior, sigo sin entender (del todo) el motivo por el que Springsource se ha embarcado en el crear un proyecto de desarrollo rápido tras la compra de la empresa que desarrollaba Grails.


Como no puede ser de otra forma vamos a dar los primeros pasos con Spring-ROO a través de un Mini HOWTO con el ejemplo tipo de la agenda. Para ello debemos seguir unos sencillos pasos que intento explicar a continuación.

Preparar el entorno de trabajo


Lo primero que debemos hacer es descargarnos la última versión de Spring-ROO de la página de Spring y seguir los siguientes pasos para su instalación:
  1. Se descomprime el archivo descargado en una ruta que podamos recordar.
    (en mi caso USER_HOME/java/spring-roo-1.1.5.RELEASE)
  2. Establecemos la variable de entorno ROO_HOME apuntando a la ruta anterior.
  3. Añadimos ROO_HOME/bin al path de nuestro sistema para que reconozca los comandos de spring-roo.
  4. En caso de que tengáis un sistema Linux o un MAC os recomiendo que creéis un enlace simbólico a roo.sh

    ln -s ${ROO_HOME}/bin/roo.sh /usr/bin/roo
Ahora comprobamos que tenemos el sistema preparado para poder empezar a trabajar. Las necesidades mínimas son:
  1. Una instalación de JDK5 o JDK6 de Sun, JRocket o IBM y la variable de entrono $JAVA_HOME establecida.
  2. Apache Maven 2.0.9 o superior instalado y con el PATH configurado correctamente.
Con esto ya podemos probar que tenemos instalado y listo para usar spring-roo, para ello en un terminal ejecutamos lo siguiente:

roo quit

Si obtenemos una salida parecida a la que muestro a continuación es que todo ha ido bien y podemos empezar con el howto.



Creación del proyecto

Como podéis ver en el propio shell de roo ya hay una ayuda, esto veremos que es muy útil durante la creación de la aplicación, pero ahora vamos a empezar con el ejemplo.

En un terminal, navegamos hasta donde tengamos nuestros proyectos, en mi caso ${USER_HOME}/proyectos/blog/roo-howto-series y ejecutamos lo siguiente:

~/proyectos/blog/roo-howto-series/$ mkdir agenda
~/proyectos/blog/roo-howto-series/$ cd agenda
~/proyectos/blog/roo-howto-series/$ roo

Ahora tendríamos que estar viendo el shell de roo en la carpeta de la agenda, por lo que ya podemos empezar a usar la ayuda del shell.

Para crear un proyecto nuevo roo tiene un comando que nos facilita la vida se trata del comando project, para crear el proyecto tecleamos en el shell lo siguiente:

project -topLevelPackage org.agenda

Esto producirá la siguiente salida en el shell:

roo> project -topLevelPackage org.agenda
Created ${USER_HOME}/proyectos/roo-howto-series/agenda/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml

Esto nos ha creado la estructura necesaria para poder empezar a trabajar con un proyecto maven y con la configuración spring necesaria para usar roo.

Adición de un contenedor JPA para persistencia

Para añadir la capa de persistencia roo ofrece un nuevo comando que facilita la creación de los archivos necesarios para la persistencia y que incluye las dependencias necesarias en el pom de maven.

Este comando es “persistence setup” y para nuestro proyecto deberemos ejecutar lo siguiente dentro del shell de roo:

roo>persistence setup --provider OPENJPA --database HYPERSONIC_PERSISTENT

Esto producirá la siguiente salida en el shell:

roo>persistence setup --provider OPENJPA --database HYPERSONIC_PERSISTENT
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Managed ROOT/pom.xml

Para ver la configuración creada teclearemos lo “database properties list” dentro de la shell obteniendo la salida siguiente:

roo>database properties list
database.driverClassName = org.hsqldb.jdbcDriver
database.password =
database.url = jdbc:hsqldb:file:contacts;shutdown=true
database.username = sa

Para cambiar la configuración de alguna de las propiedades roo facilita un comando, nosotros vamos a cambiar la ubicación de la url de la base de datos, ejecutamos el siguiente comando:

roo>database properties set --key database.url --value jdbc:hsqldb:${user.home}/agenda
Updated SRC_MAIN_RESOURCES/META-INF/spring/database.properties

Esto ha actualizado el archivo de propiedades de la base de datos ejecutamos de nuevo “database properties list” y vemos que los cambios se han efectuado correctamente:

roo> database properties list
database.driverClassName = org.hsqldb.jdbcDriver
database.password =
database.url = jdbc:hsqldb:${user.home}/agenda
database.username = sa

Creación de entidades

Para crear entidades en roo existe otro comando, este comando es “entity --class”.

Procedemos con la creación de la entidad Contacto.java que será la que almacenará los datos en nuestra aplicación.

Para ello ejecutamos el comando, obteniendo la siguiente salida en el shell:

roo> entity --name org.agenda.Contacto --identifierField id
Created SRC_MAIN_JAVA/org/agenda/Contacto.java
Created SRC_MAIN_JAVA/org/agenda/Contacto_Roo_Entity.aj
Created SRC_MAIN_JAVA/org/agenda/Contacto_Roo_ToString.aj
Created SRC_MAIN_JAVA/org/agenda/Contacto_Roo_Configurable.aj

Esto ha creado la entidad Contacto, ahora debemos añadir atributos a esta entidad, para esto ejecutamos los siguientes comandos:

field string nombre --notNull --sizeMin 1 --sizeMax 30
field string apellidos --sizeMax 100
field string nick --sizeMax 100
field string direccion --sizeMax 255
field number numero --type java.lang.Integer
field number piso --type java.lang.Integer
field string puerta --sizeMax 1
field string codigoPostal --sizeMax 5
field string poblacion --sizeMax 30
field string provincia --sizeMax 30
field string email --notNull --sizeMin 8 --sizeMax 100
field string telefono --sizeMax 9
field string movil --sizeMax 9

La traza completa de la ejecución de los comandos anteriores es la siguiente:

field string nombre --notNull --sizeMin 1 --sizeMax 30
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Created SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string apellidos --sizeMax 100
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string nick --sizeMax 100
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string direccion --sizeMax 255
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field number numero --type java.lang.Integer
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field number piso --type java.lang.Integer
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string puerta --sizeMax 1
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string codigoPostal --sizeMax 5
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string poblacion --sizeMax 30
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string provincia --sizeMax 30
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string email --notNull --sizeMin 8 --sizeMax 100
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string telefono --sizeMax 9
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj
field string movil --sizeMax 9
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto.java
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_ToString.aj
Updated SRC_MAIN_JAVA/org/agenda/dominio/Contacto_Roo_JavaBean.aj

Estos comandos añaden los distintos atributos a la entidad Contacto son sus distintos tipos, este comando lo veremos en más detalle en siguientes entregas, ya que ofrece muchas posibilidades.

Creación de la capa web (MVC)

Para añadir la capa web existe, como no, otro comando de shell, este comando es “web mvc setup”.

En el shell de roo ejecutamos:

roo>web mvc setup
Created SRC_MAIN_WEBAPP/WEB-INF/spring
Created SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_WEBAPP/WEB-INF/web.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_WEBAPP/images
Created SRC_MAIN_WEBAPP/images/create.png
Created SRC_MAIN_WEBAPP/images/list.png
Created SRC_MAIN_WEBAPP/images/resultset_previous.png
Created SRC_MAIN_WEBAPP/images/resultset_next.png
Created SRC_MAIN_WEBAPP/images/show.png
Created SRC_MAIN_WEBAPP/images/favicon.ico
Created SRC_MAIN_WEBAPP/images/delete.png
Created SRC_MAIN_WEBAPP/images/resultset_first.png
Created SRC_MAIN_WEBAPP/images/springsource-logo.png
Created SRC_MAIN_WEBAPP/images/resultset_last.png
Created SRC_MAIN_WEBAPP/images/add.png
Created SRC_MAIN_WEBAPP/images/banner-graphic.png
Created SRC_MAIN_WEBAPP/images/update.png
Created SRC_MAIN_WEBAPP/styles
Created SRC_MAIN_WEBAPP/styles/alt.css
Created SRC_MAIN_WEBAPP/styles/standard.css
Created SRC_MAIN_WEBAPP/WEB-INF/classes
Created SRC_MAIN_WEBAPP/WEB-INF/classes/standard.properties
Created SRC_MAIN_WEBAPP/WEB-INF/classes/alt.properties
Created SRC_MAIN_WEBAPP/WEB-INF/layouts
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/default.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/layouts/layouts.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views
Created SRC_MAIN_WEBAPP/WEB-INF/views/header.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/footer.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/index.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/index-template.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/uncaughtException.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/resourceNotFound.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/dataAccessFailure.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/update.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/create.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/dependency.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/show.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/list.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/find.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/select.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/display.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/column.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/editor.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/checkbox.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/simple.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/input.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/textarea.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/datetime.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/table.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/form/fields/reference.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/pagination.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/theme.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/placeholder.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/panel.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/language.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/util/load-scripts.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/i18n
Created SRC_MAIN_WEBAPP/WEB-INF/i18n/messages.properties
Created SRC_MAIN_WEBAPP/images/en.png
Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Updated SRC_MAIN_WEBAPP/WEB-INF/web.xml
Updated ROOT/pom.xml [added dependencies org.springframework:spring-web:${spring.version}, org.springframework:spring-webmvc:${spring.version}, org.springframework.webflow:spring-js-resources:2.2.1.RELEASE, commons-digester:commons-digester:2.0, commons-fileupload:commons-fileupload:1.2.1, javax.servlet.jsp.jstl:jstl-api:1.2, org.glassfish.web:jstl-impl:1.2, javax.el:el-api:1.0, joda-time:joda-time:1.6, javax.servlet.jsp:jsp-api:2.1, commons-codec:commons-codec:1.4; updated project type to war; added dependencies org.apache.tiles:tiles-core:2.2.1, org.apache.tiles:tiles-jsp:2.2.1]
Updated SRC_MAIN_WEBAPP/WEB-INF/views/footer.jspx

Después de establecer la configuración mvc procedemos con el scaffolding de la entidad, para ello ejecutamos:

roo>web mvc scaffold ~.web.ContactoController
Created SRC_MAIN_JAVA/org/agenda/web
Created SRC_MAIN_JAVA/org/agenda/web/ContactoController.java
Updated SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_JAVA/org/agenda/web/ApplicationConversionServiceFactoryBean.java
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/views.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/views.xml
Created SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/menu.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/item.tagx
Created SRC_MAIN_WEBAPP/WEB-INF/tags/menu/category.tagx
Updated SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Updated SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/views.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Created SRC_MAIN_JAVA/org/agenda/web/ApplicationConversionServiceFactoryBean_Roo_ConversionService.aj
Created SRC_MAIN_JAVA/org/agenda/web/ContactoController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/create.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/contactoes/update.jspx

Adición de test de integración con Selenium

Para añadir los test de integración roo facilita, como no podía ser de otra manera, un nuevo comando que facilita la creación de estos.

El comando es el siguiente:

selenium test --controller

Ejecutamos el comnado y obtenemos algo parecido a lo siguiente:

roo>selenium test --controller ~.web.ContactoController
Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Updated SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/selenium
Created SRC_MAIN_WEBAPP/selenium/test-contacto.xhtml
Created SRC_MAIN_WEBAPP/selenium/test-suite.xhtml
Updated ROOT/pom.xml [added plugin selenium-maven-plugin]

Configuración de log para ver los errores

Roo añade por defecto una configuración mínima de logging para la aplicación, si lo que queremos es añadir granularidad al log para ver los errores, por ejemplo, que se producen en determinado módulo tendremos que ejecutar otro comando en el shell y listo, la ejecución de este comando sería algo parecida a esto:

roo>logging setup --level ERROR --package WEB
Updated SRC_MAIN_RESOURCES/log4j.properties

Probar la aplicación

Para probar el proyecto creado, tendremos que salir del shell "quit", ejecutamos los test con Maven (lo ha integrado automáticamente añadiendo las dependencias)

mvn test

Si queremos podemos pasar Selenium para las pruebas de integración

mvn selenium:selenese

Y por último se prueba la aplicación

mvn tomcat:run

Abrimos navegador y ponemos la siguiente dirección:


Importar el proyecto en eclipse

Para importar el proyecto en eclipse existe un comando dentro del shell de roo que te permite generar los archivos necesarios para una correcta importación, aunque siempre podremos importar un proyecto maven, el comando es:

roo>perform eclipse

Espero que os sirva de ayuda para empezar a usar spring-roo que desde mi punto de vista, es muy interesante. En siguientes entregas ampliaré la funcionalidad de este proyecto incluyendo seguridad, añadiendo algún plugin y añadiendo envío de emails a nuestros contactos.

Un saludo y, como siempre, a disfrutar!

No hay comentarios: