Cómo integrar alarife con grails

7 Feb
2010

De un tiempo a esta parte he hecho algunas modificaciones sobre alarife para poder formalizar todo lo posible el desarrollo de meorganizo.es y, de este modo, ganar en velocidad y productividad. Alarife es una pequeña librería de utilidades que creé para poder regenerar bases de datos automáticamente.

El “problema” que estaba teniendo con meorganizo.es es el que prácticamente todos tenemos a la hora de querer realizar pruebas en nuestro código:

  • Cuando realizaba pruebas sobre el navegador mientras desarrollaba tenia que estar manualmente dejando la aplicación en un estado ‘estable’.
  • Para lanzar tests de integración tenía que crear clases de utilidades que generasen juegos de datos.

Aparte se da otra circunstancia, y es que cuando libere una nueva versión de meorganizo.es y la ponga en producción prefiero haber probado 1000 veces los scripts de actualización del esquema de base de datos que sólo un par de ellas.

Para solucionar el problema de los tests de integración podría haber utilizado dbunit sobre hsqlbd, pero esto sólo me soluciona los problemas en un único escenario.

Lo que he hecho para solucionar los problemas de los 3 escenarios de golpe ha sido modificar alarife e integrarlo en mi desarrollo con grails. Las modificaciones de alarife en sí no son gran cosa:

  • He mejorado los properties donde poder configurar las conexiones con base de datos.
  • Permito tener properties distintos para distintos escenarios.
  • He mejorado la interfaz, de tal modo que invocar a alarife ahora es bastante menos ceremonioso.
  • También he hecho varios cambios en el código que mejoran el rendimiento.

He de decir que todo esto ha sido muy sencillo ya que desarrollé alarife usando TDD (desarrollo orientado a tests) y analizando estáticamente el código. De este modo he podido modificar un código que llevaba meses quieto de una manera muy rápida y, sobre todo, muy segura.

Pero esta entrada no va de alarife ni de meorganizo.es. En esta entrada quiero indicaros qué hay que hacer para integrar esta nueva versión de alarife en vuestros desarrollos con grails. Los pasos a seguir son los siguientes:

1) copiar el jar de la librería en el directorio lib/ de vuestro proyecto grails.

Podeis bajar la última versión de la librería pulsando aquí.

2) invocar a alarife cada vez que arranquemos grails.

Para ello hay que editar el fichero BootStrap.groovy, que está en el directorio conf/, con un código similar al siguiente:

import com.raulexposito.alarife.DatabaseRegenerator
import com.raulexposito.alarife.enumeration.ApplicationMode

class BootStrap {

	 static final String DEVEL_FILE = "devel.properties"
	 static final String PRODUCTION_FILE = "production.properties"

     def init = { servletContext ->
		// IMPORTANTE: antes de generar el war de pre/producción hay que cambiar:
		//
		// 1) 'DEVEL_FILE' por 'PRODUCTION_FILE'
		// 2) 'ApplicationMode.DEVELOPMENT' por 'ApplicationMode.PRODUCTION'
		new DatabaseRegenerator(DEVEL_FILE, ApplicationMode.DEVELOPMENT)
     }
     def destroy = {
     }
}

}


3) Cambiar la traza de log de la aplicación en el fichero conf/Config.groovy

Esto es opcional aunque recomendable

    warn   'org.mortbay.log'
           'com.raulexposito.alarife'


4) Revisar y configurar las conexiones de base de datos del fichero conf/DataSource.groovy.

Estos datos de conexión son los que usaremos en los properties de alarife más adelante.


5) Crear la siguiente estructura de ficheros y directorios:

5.1 Creación de ficheros .properties

Crearemos los ficheros properties en src/java con los datos de conexión con las bases de datos. En este ejemplo he creado 3 puesto que usaré alarife para los 3 escenarios posibles:

  • devel.properties
  • testing.properties
  • production.properties

A continuación muestro el contenido del properties de desarrollo (devel.properties), el cual tiene los datos del datasource que explicamos en el punto 4). Observad que el esquema es ‘azlo_devel’, que en mi caso es el esquema que uso para desarrollar:

# ---------------------------------------------------------------------------- #
# Configuration of the database connection                                     #
#                                                                              #
# IMPORTANT! the instance MUST be finished by '/' and be careful with the      #
# lower and uppercase in 'schema', 'username' and 'password'                   #
# ---------------------------------------------------------------------------- #

instance = jdbc:mysql://localhost:3306/
driverClassName = com.mysql.jdbc.Driver
username = usuario
password = clave
schema = azlo_devel

# ---------------------------------------------------------------------------- #
# creation and destruction of the database once connected                      #
#                                                                              #
# IMPORTANT! this commands are database dependant, so it MUST NOT BE hardcoded #
# IMPORTANT! the database name MUST BE uppercase (for instance: MYSQL)         #
# ---------------------------------------------------------------------------- #

# MySQL
MYSQL.dropDatabase = drop database if exists `{0}`;
MYSQL.createDatabase = create database if not exists `{0}`;
MYSQL.changeDatabase = use `{0}`;
MYSQL.createVersionTable = create table `{0}`.`VERSION` (`version` VARCHAR(10) NOT NULL);
MYSQL.insertVersionTable = insert into `{0}`.`VERSION` (`version`) values ('{1}');
MYSQL.recoverVersionTable = select `version` FROM `{0}`.`VERSION`;


5.2 Creación de scripts

Hay que crearlos en src/java/scripts/mysql/ para cada escenario y versión. Por ejemplo, el fichero src/java/scripts/mysql/development/0.0.1/upgradeTables-0.0.1.sql actualiza el esquema a la versión 0.0.1 en desarrollo y tiene el siguiente código:

DROP TABLE IF EXISTS `task`;
CREATE TABLE `task` (
  `id` bigint(20) NOT NULL auto_increment,
  `version` bigint(20) NOT NULL,
  `name` varchar(255) NOT NULL,
  `state` varchar(255) NOT NULL,
  `tags` varchar(255) default NULL,
  `user_id` bigint(20) default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK363585F7634DFA` (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

Y el fichero src/java/scripts/mysql/development/0.0.1/insertData-0.0.1.sql el siguiente:

INSERT INTO `task` VALUES  (1,0,'sacar la basura','NEXT','basura',1),
 (2,0,'ir de compras','NEXT','compras',1);

UPDATE `VERSION` SET version = '0.0.1';

Es importante destacar que al final de este script se almacena la versión del script que hemos lanzado en la tabla VERSION. Es decir, si hemos lanzado los scripts de la versión 1.2.3, almacenaremos en el campo version de la tabla VERSION el valor 1.2.3.

6) Tests de integración

Si quisiéramos usarlo con nuestros tests de integración deberiamos implementar el método setUp() tal como sigue:

	private static final String TESTING_FILE = "testing.properties";

	void setUp () {
		new DatabaseRegenerator(TESTING_FILE, ApplicationMode.TESTING)
	}


7) Descargas y enlaces

Todo esto como ya digo es para formalizar y con ello acelerar vuestros desarrollos. A mi personalmente me resulta muy útil pero está claro que cada uno tiene sus manías y su manera de hacer las cosas.

Si tenéis alguna duda o alguna idea que darme por favor no dudéis en usar los comentarios.

Print

2 respuestas a Cómo integrar alarife con grails

Avatar

Miguel Ángel Grau

5 de Agosto de 2010 a las 19:19

Hola Raúl,

encuentro tu librería muy interesante y útil, pero no consigo integrarla con Grails siguiendo tus indicaciones. Después de crear manualmente la tabla versión, y poner el valor de versión a 0.0.0 en la tabla, consigo que intente ejecutar los scripts para la versión 0.0.1

El problema viene cuando intenta ejecutar la actualización de la tabla versión a 0.0.1, ya que, después de ejecutar el comando UPDATE VERSION SET version=’0.0.1′, y estar dentro de una transacción (imagino que abierta por Grails), cuando obtiene el valor de la tabla para actualizar la variable currentVersion, vuelve a obtener el valor 0.0.0, así que vuelve a ejecutar los scripts de la versión 0.0.1 y así se queda en un bucle infinito.

¿Podrías ayudarme?

Un saludo
Miguel Ángel

Avatar

Raúl Expósito

5 de Agosto de 2010 a las 21:19

Muy buenas Miguel Ángel,

Mira, me emocionan tanto tu comentario como el saber que hay alguien que quiere usar algo que he creado :-)

En cuanto pueda te mando un correo y lo vemos más despacio ¿va?. Seguramente me haya explicado mal en algún punto y por eso no te funcione.

Saludos

Deja tu comentario


subir