viernes, 25 de diciembre de 2009

Spring in Action Second Edition

Spring es un framework Java que trata de simplificar el desarrollo de aplicaciones Java basándose en la inyección de dependencias y la programación orientada a aspectos. En este libro, Craig Walls hace una explicación exhaustiva de Spring cubriendo todas las capas del desarrollo de una aplicación.

El libro consta de los siguientes capítulos:
  1. Pasar a la acción: Se presenta Spring y los módulos que lo componen. Se introducen los conceptos principales de Spring, la inyección de dependencias y la programación orientada a aspectos.

  2. Conexión básica de beans: Se presentan los distintos tipos de contenedores de beans, las fábricas de bean y los contextos de aplicación. A continuación se ve cómo crear beans en un contenedor y cómo inyectar valores y propiedades en ellos mediante inyección de dependencias. Después se muestra qué es la autoconexión de beans y, por último, se explica cómo controlar la creación de beans a través de métodos de inicio y destrucción del bean.

  3. Conexión avanzada de beans: Se muestran conceptos avanzados del contenedor de beans de Spring. Primero se ve cómo declarar beans padre de los que otros beans hijos pueden heredar propiedades. Después se enseña la inyección de métodos. Luego se pasa a la inyección de beans que no han sido creados dentro del contenedor de Spring. También se ve cómo registrar editores de propiedades y cómo trabajar con beans especiales de Spring que se integran en el ciclo de vida de otros bean. Por último, se ve cómo crear beans con lenguajes dinámicos como Ruby, Groovy o Beanshell.

  4. Notificaciones a beans: En primer lugar, se hace una introducción a la programación orientada a aspectos (AOP). Posteriormente se explica cómo crear aspectos clásicos de Spring y qué es el autoproxying. Después se ve la declaración de aspectos POJO y cómo se pueden inyectar aspectos creados con AspectJ.

  5. Peticiones a la base de datos: Se examinan las capacidades de acceso a base de datos que ofrece Spring, y su fillosofía de acceso a datos a través de plantillas. Posteriormente se ve cómo se puede integrar Spring con JDBC puro o con ORMs como Hibernate, JPA o iBatis. Por último, se muestran las capacidades de cacheo en Spring.

  6. Gestión de transacciones: Se revisa la gestión de transacciones en Spring, comenzando por una explicación de sus conceptos fundamentales. Después se enumeran los distintos gestores de transacciones disponibles y se explica cómo manejar las transacciones en Spring, tanto de forma programática como de forma declarativa

  7. Seguridad en Spring: Se hace una introducción a la seguridad en Spring, que se implementa mediante la antigua librería Acegi Security. Posteriormente vamos viendo cómo se autentican los usuarios y se controla el acceso. Finalmente se ve cómo asegurar una aplicación web y cómo asegurar las invocaciones a métodos.

  8. Servicios remotos basados en Spring y POJO: Se ve cómo implementar y consumir servicios remotos en Spring mediante RMI, Hessian, Burlap, Spring HttpInvoker y Web Services.

  9. Construcción de servicios web contract-first en Spring: Comienza con una introducción a Spring-WS, un framework que permite construir servicios web a partir de un contrato definido en primer lugar. Después se ve cómo se manejan los mensajes de estos servicios mediante puntos finales de servicio y como juntar todo esto para la creación de un servicio. Para terminar, se ve cómo consumir servicios web usando Spring-WS.

  10. Mensajería Spring: Se explica qué es JMS y cómo se puede usar desde Spring. Después se explica cómo construir POJOS dirigidos por mensajes y, por último, cómo utilizar RPC basado en mensajes, en contraposición a los servicios remotos vistos en el capítulo 8.

  11. Spring y Enterprise Java Beans: Se muestra cómo conectarse a EJBs desde Spring. Después se ve cómo desarrollar EJBs que puedan aprovecharse de las capacidades de Spring. Por último, se ve cómo utilizar anotaciones EJB 3, a través del proyecto Pitchfork, para realizar inyección de dependencia y AOP en Spring.

  12. Acceso a servicios empresariales: En este capítulo se estudia el uso en Spring de capacidades empresariales como JNDI, correo electrónico JMS, planificación de tareas y gestión de beans mediante JMX.

  13. Manejo de peticiones Web: Se introduce el marco MVC de Spring para la capa web, en el que las peticiones son manejadas por controladores. Se ve cómo mapear las peticiones a los controladores de la aplicación y los distintos tipos de controladores que se pueden utilizar. También se ve cómo se manejan las excepciones que se pueden producir durante el procesamiento de estos controladores.

  14. Mostrar vistas Web: Se ve cómo Spring MVC resuelve la vista que debe mostrar como respuesta a una petición. Se examinan las diferentes posibilidades, como JSP, con o sin Tiles, y otras alternativas a JSP, como Velocity y Freemarker. También se ve cómo es posible generar salida no-HTML, como documentos de Excel o PDFs.

  15. Spring Web Flow: Se explica qué es Spring Web Flow, un marco de trabajo que permite definer el flujo de navegación de una aplicación. Se ve cómo se puede definir el flujo de la aplicación desde los conceptos básicos hasta técnicas más avanzadas. También se ve cómo se puede integrar Spring Web Flow con otros frameworks web como Struts o JSF.

  16. Integración con otros marcos de trabajo Web: Se explica cómo se pueden utilizar las capacidades empresariales de Spring junto con otros conocidos frameworks web como Struts, WebWork/Struts2, Tapestry, JSF y aplicaciones Ajax con DWR.

Este libro es sencillo de leer y te va introduciendo paulatinamente dentro de Spring, explicando los conceptos principales y utilizando gran parte de sus funcionalidades. A mí me ha servido para aprender Spring desde cero, así como para entender la inyección de dependencias y la programación orientada a aspectos.

(ACTUALIZACION 26/10/2011: Ya está disponible la tercera versión de este libro, actualizada a Spring 3.)

domingo, 13 de diciembre de 2009

Hibernate in Action Second Edition

Este libro, escrito por Christian Bauer y Gavin King, es una revisión de otro libro anterior, Hibernate in Action. Está actualizado a la versión 3 de Hibernate y, además, presenta el estándar de persistencia de de EJB 3.0 (JPA).

Se trata de un libro de referencia no sólo para Hibernate, sino también para JPA. En él se puede encontrar información de introducción a estas dos tecnologías ORM, enseña a realizar con éxito los mapeos de objetos a entidades relacionales, explica el funcionamiento interno de Hibernate y cómo optimizar su comportamiento y da pautas sobre cómo construir aplicaciones que hagan uso Hibernate y/o JPA.

Consta de los siguientes capítulos:
  1. Comprender la persistencia objeto/relacional: Se hace una introducción a los problemas de la persistencia en aplicaciones orientadas a objetos que usan bases de datos relacionales, explicando los desajustes que se producen entre estas dos tecnologías. Se presentan las distintas alternativas existentes para la capa de persistencia y se presentan los ORM como la solución que nos permite abstraernos de los desajustes anteriormente mencionados.

  2. Comenzar un proyecto: Se presentan las posibles alternativas de desarrollo con Hibernate, dependiendo de si empezamos desde un modelo de clases o desde un modelo relacional. A continuación se muestra la configuración de Hibernate en un proyecto y se implementa el mismo proyecto de distintas formas: usando Hibernate y mapeo XML, anotaciones, JPA mediante el Hibernate EntityManager y componentes EJB. Posteriormente se hace una introducción a la ingeniería inversa con Hibernate dada una base de datos. Por último, se presenta cómo se integra Hibernate con otros servicios de la plataforma JEE como JTA, JNDI y JMX.

  3. Modelos de dominio y metadatos: Se presenta el modelo de dominio de ejemplo que se utilizará en el libro, un sistema de subastas. Se presentan las pautas para la implementación de este modelo, como el desarrollo de POJOs. A continuación se muestran las distintas alternativas para los metadatos de mapeo, XML, anotaciones, XDoclet y de forma programática en la ejecución. Por último se presentan representaciones alternativas de las entidades mediante mapas y XML.

  4. Mapear clases persistentes: Se explica la diferencia entre las entidades y los tipos de valor. También se ve el concepto de identidad en Hibernate. Después se ven algunas opciones para el mapeo de clases. Por último, se ve como mapear tipos de valor, tanto para tipos de datos Java como para clases.

  5. Herencia y tipos personalizados: Se muestran las distintas formas de manejar la herencia en Hibernate. También se ve el conjunto de tipos de datos que ofrece Hibernate y explica como crear tipos de datos personalizados.

  6. Mapear colecciones y asociaciones de entidades: Se presentan los distintos tipos de colecciones que maneja Hibernate y se muestra cómo mapear colecciones de tipos de valor tanto en el caso de tipos simples como de clases. Posteriormente se ve cómo mapear una relación padre/hijo entre entidades.

  7. Mapeo avanzado de asociaciones de entidades: Se continúa viendo cómo mapear relaciones entre entidades, tanto relaciones simples como múltiples. También se ven las asociaciones polimórficas entre entidades.

  8. Bases de datos heredadas y SQL personalizado: Se comentan los principales problemas en la integración con bases de datos heredadas. Después se estudia la personalización del SQL que genera Hibernate en las consultas, y se ve la integración de procedimientos almacenados y funciones. Por último, se muestra cómo mejorar el DDL generado por Hibernate para personalizar los nombres y los tipos de datos, añadir restricciones o crear índices.

  9. Trabajar con objetos: En este capítulo se comienza exponiendo el ciclo de vida de los objetos persistentes y después se habla de los conceptos de identidad e igualdad de objetos, introduciendo las conversaciones y el ámbito de identidad de un objeto. A continuación se ven los interfaces de persistencia de Hibernate y de JPA, terminando con una explicación de cómo usar JPA en componentes EJB.

  10. Transacciones y concurrencia: Se revisan los conceptos básicos de las transacciones en las bases de datos y cómo pueden ser manejadas en Hibernate y JPA. También se trata el control del acceso concurrente en las bases de datos, revisando el control optimista de la concurrencia y cómo se pueden obtener garantías adicionales en el aislamiento. Por último, se estudia el acceso no transaccional, viendo en qué casos se puede trabajar en modo autocommit tanto con Hibernate como con JPA.

  11. Implementando conversaciones: Se comienza viendo cómo se propaga la sesión en Hibernate, que puede ser a través de una variable thread-local, a través de JTA o mediante EJBs. Después se ve cómo se pueden implementar convesaciones en Hibernate, JPA y EJB a través de objetos “separados” (detached) y extendiendo la sesión.

  12. Modificar objetos eficientemente: En primer lugar se estudia la persistenca transitiva de objetos a través de las asociaciones en cascada, tanto con Hibernate como con JPA. Posteriormente se pasa a ver cómo manejar operaciones que implican grandes volúmenes de datos a través de HQL y JPA QL y cómo procesar lotes. Por último, se ve cómo filtrar los datos de las consultas y cómo interceptar eventos en Hibernate.

  13. Optimizar la recuperación y el cacheo: Comenzamos viendo cómo definir el plan de obtención de datos en Hibernate y se dan pautas de qué estrategia elegir y cóm optimizarla. Posteriormente se exponen los principios de cacheo en Hibernate y se explica cómo establecer una cache de segundo nivel a través de proveedores de cache.

  14. Hacer consultas con HQL y JPA QL: Veremos cómo crear y ejecutar consultas a base de datos. Se aprenderá a crear consultas básicas con HQL y JPA QL y cómo se usan las joins, las consultas de informes y las subselects.

  15. Opciones de consulta avanzadas: En este capítulo se ve cómo usar las APIs Criteria y Example para construir consultas de forma programática. También se ve cómo hacer consultas nativas en SQL. Después se ve cómo filtrar colecciones, y, por último, se habla del cacheo de resultados de consultas y en qué casos es conveniente hacerlo.

  16. Crear y probar aplicaciones en capas: En este capítulo se dan pautas para el diseño de aplicaciones web con Hibernate, a través de patrones como OSIV (Open Session In View), Command y DAO (Data Access Object). También se trata el diseño de aplicaciones con EJB 3.0. Por último, se trata el tema de cómo probar estas aplicaciones y se presentan herramientas como TestNG y DBUnit.

  17. Introducción a JBoss Seam: En este capítulo se hace un introducción al marco de trabajo JBoss Seam, un marco de trabajo orientado a Java EE 5.0 que se base en JSF y EJB 3.0. Se ve cómo mejorar una aplicación usando este marco, cómo utilizar componentes contextuales, cómo validar los datos de entrada y cómo simplificar la persistencia.

Se trata de un libro difícil de leer de corrido por la complejidad de los temas que trata. Sin embargo, creo que es un libro de referencia excelente sobre Hibernate y JPA.

viernes, 11 de diciembre de 2009

Control de versiones con ClearCase

Rational ClearCase es el sistema de control de versiones de IBM. Aunque Subversion es más de mi agrado por su sencillez, esta herramienta es la que utilizo en el trabajo. Estamos teniendo un montón de problemas trabajando con ella, aunque estoy convencido que es más por desconocimiento que por la herramienta en sí. Así que voy a exponer a continuación que es ClearCase, cómo lo usamos y qué problemas estamos encontrando de cara a compartir experiencias con otros usuarios de ClearCase.

Cómo otros sistemas de control de versiones, ClearCase almacena distintas versiones de los elementos que forman parte de un proyecto, que pueden ser directorios o archivos. Estos elementos se almacenan en un repositorio que en ClearCase se llama base de objetos de versionado (VOB).

ClearCase proporciona un proceso de gestión de la configuración llamado gestión del cambio unificado (UCM). UCM se situa sobre la base de ClearCase simplificando el trabajo.

En UCM un proyecto es un producto de un desarrollo de software que contiene información de configuración sobre el mismo. Un proyecto está formado por componentes, que constituyen las partes de un proyecto, como módules web o módulos JAR en un proyecto Java.

Las modificaciones que se llevan a cabo durante las tareas de desarrollo dentro de la ejecución de un proyecto se registran en actividades, que consisten en varias versiones de distintos elementos de un componente.

Un proyecto consta de un área de trabajo compartido y muchas áreas de trabajo privadas. Cada área de trabajo está formada por una corriente y una o varias vistas. Una corriente es un objeto de ClearCase que mantiene una lista de actividades y líneas base que determinan que versiones de elementos aparecen en la vista. Una vista es un árbol de directorio que muestra una única versión de cada archivo del proyecto.

Todo proyecto tiene un área de trabajo compartido que se maneja mediante una corriente y una vista de integración. Su función es registrar las líneas base del proyecto y recibir las nuevas versiones de los elementos compartidos del proyecto para su integración conjunta.

Cada línea base representa una versión de los elementos de un componente en un determinado momento del desarrollo. A lo largo del proyecto, el administrador crea y recomienda líneas base para reflejar hitos del proyecto.

Según UCM, los desarrolladores tienen un área de trabajo privada donde realizan sus cambios. Esta área de trabajo consta una de corriente de desarrollo que mantiene la lista de actividades del desarrollador y determina qué versiones de los elementos del proyecto aparecen en su vista de desarrollo.

Cuando los desarrolladores se unen a un proyecto incluyen en sus áreas de trabajo las versiones de los elementos del proyecto marcados en la línea base recomendada del proyecto. Éstos harán sus cambios dentro de actividades en su área de trabajo privada y, una vez finalizados y probados, harán entrega (deliver) de estas actividades a la corriente de integración, lo que podría llevar a tener que combinar elementos si otro desarrollador ha hecho modificaciones en los mismos elementos.

Periódicamente, los desarrolladores deben hacer rebase para actualizarse a las últimas líneas base recomendadas. Si las líneas base incluyen nuevas versiones de los elementos que se están modificando en la vista de desarrollo, la operación de rebase fusiona las dos versiones en una nueva versión dentro de la corriente de desarrollo.

Lo explicado hasta ahora es el proceso de gestión de la configuración que define UCM, que implica que cada desarrollador tiene su propio área de trabajo privada. Esto permite que los desarrolladores trabajen de forma paralela e independiente sin colisionar entre ellos a la hora de modificar los mismo elementos. Estos serán fusionados posteriormente en las operaciones de deliver y rebase.

Sin embargo, esto añade carga de gestión al desarrollo, porque para ver las últimas modificaciones de otro desarrollador es necesario que haya entregado sus actividades, se haya hecho una nueva línea base y los otros desarrolladores hagan un rebase.

Para aligerar esta carga, nosotros usamos una única área de desarrollo para todos los desarrolladores, que tienen vistas a ella. Todos los cambios que un desarrollador registra pueden ser vistos por los demás desarrolladores sin más que hacer un update de su vista, permitiendo que los nuevos cambios se publiquen de manera más inmediata.

Sin embargo, si todos los desarrolladores están desarrollando en vistas de la misma corriente, se pueden producir situaciones no deseadas:

Modificaciones concurrentes de los mismos archivos
  • Un desarrollador desaA está modificando un archivo fich1, para lo cual lo ha reservado (check out).
  • Otro desarrollador desaB también quiere modificar este archivo, y, si no quiere quedarse bloqueado en su trabajo, lo reserva (check out) después de que aparece un aviso de que el desarrollador desaA lo ha reservado previamente.
  • El desarrollador desaA sube (check in) el archivo con sus modificaciones.
  • El desarrollador desaB sube (check in) el archivo con sus modificaciones, pero en ese momento ClearCase le avisa de que en el repositorio hay una versión de este archivo posterior a aquella que reservó, por lo que debe fusionar las dos versiones (merge). Este merge puede ser automático o manual, a través de la herramienta de ClearCase para esto.
  • Este problema, que con un solo archivo puede ser fácil de solucionar, se complica cuando se están modificando varios archivos que coinciden por parte de varios desarrolladores. Se puede llegar a situaciones de bloqueo, por ejemplo, si un desarrollador no puede actualizarse un archivo que ha modificado otro desarrollador y es necesario para que los cambios en otros archivos compilen sin error porque el archivo necesario está reservado y siendo modificado por el desarrollador. Se puede llegar a situaciones difíciles de salir.

Dependencia entre actividades no relacionadas
  • Un desarrollador desaA está realizando modificaciones dentro de una actividad activA que implican a los ficheros fich1, fich2 y fich3.
  • Comienza reservando (check out) fich1, haciendo los cambios pertinentes y subiéndolo (check in) al repositorio, y después pasa a reservar fich2 y modificarlo.
  • En ese momento, otro desarrollador desaB realiza otras modificaciones distintas dentro de otra actividad activB que implican modificar el fichero fich2, previamente modificado en la actividad activA de desaA.
  • Por necesidades del proyecto, hace falta crear una nueva versión (línea base) del proyecto sólo con la modificación realizada en la actividad activB y no las modificaciones de activA. Por ejemplo, porque activB es una corrección de un bug que queremos solucionar rapidamente en producción, pero activA es un nuevo desarrollo que no queremos subir hasta no haberlo probado concienzudamente.
  • Al tratar de subir la actividad activB, ClearCase nos dirá que esta actividad depende de la actividad activA y que también hay que subirla. Esto es debido a que la modificación del fichero fich2 se hizo sobre la versión modificada en la actividad activA.
  • Resultado, no se puede subir activB de forma independiente de activA. Y este problema se puede complicar exponencialmente a mayor número de desarrolladores.

Conclusión, hay que evitar que varios desarrolladores modifiquen los mismo archivos por el bien de la productividad del equipo y de la facilidad en la gestión del proyecto. Lo cual me hace pensar que lo mejor sería un área de desarrollo privada por cada desarrollador como dicta UCM, pero esta forma de trabajar, que también usamos en otro proyecto aumentaría el número de merges de forma considerable con el riego que conllevan.

Aquí os pido colaboración. ¿Alguien tiene experiencia con ClearCase? Me gustaría saber qué estrategias se están usando en otros proyectos y cómo solucionan todos estos problemas.

Referencias:
Introducción a Rational ClearCase LT (Rosa María Carretero López)
ClearCase en Wikipedia
Comparación de software de control de versiones

viernes, 4 de diciembre de 2009

Manifiesto en defensa de los derecho fundamentales en Internet

Ante la inclusión en el Anteproyecto de Ley de Economía sostenible de modificaciones legislativas que afectan al libre ejercicio de las libertades de expresión, información y el derecho de acceso a la cultura a través de Internet, los periodistas, bloggers, usuarios, profesionales y creadores de internet manifestamos nuestra firme oposición al proyecto, y declaramos que…

1.- Los derechos de autor no pueden situarse por encima de los derechos fundamentales de los ciudadanos, como el derecho a la privacidad, a la seguridad, a la presunción de inocencia, a la tutela judicial efectiva y a la libertad de expresión.

2.- La suspensión de derechos fundamentales es y debe seguir siendo competencia exclusiva del poder judicial. Ni un cierre sin sentencia. Este anteproyecto, en contra de lo establecido en el artículo 20.5 de la Constitución, pone en manos de un órgano no judicial -un organismo dependiente del ministerio de Cultura-, la potestad de impedir a los ciudadanos españoles el acceso a cualquier página web.

3.- La nueva legislación creará inseguridad jurídica en todo el sector tecnológico español, perjudicando uno de los pocos campos de desarrollo y futuro de nuestra economía, entorpeciendo la creación de empresas, introduciendo trabas a la libre competencia y ralentizando su proyección internacional.

4.- La nueva legislación propuesta amenaza a los nuevos creadores y entorpece la creación cultural. Con Internet y los sucesivos avances tecnológicos se ha democratizado extraordinariamente la creación y emisión de contenidos de todo tipo, que ya no provienen prevalentemente de las industrias culturales tradicionales, sino de multitud de fuentes diferentes.

5.- Los autores, como todos los trabajadores, tienen derecho a vivir de su trabajo con nuevas ideas creativas, modelos de negocio y actividades asociadas a sus creaciones. Intentar sostener con cambios legislativos a una industria obsoleta que no sabe adaptarse a este nuevo entorno no es ni justo ni realista. Si su modelo de negocio se basaba en el control de las copias de las obras y en Internet no es posible sin vulnerar derechos fundamentales, deberían buscar otro modelo.

6.- Consideramos que las industrias culturales necesitan para sobrevivir alternativas modernas, eficaces, creíbles y asequibles y que se adecuen a los nuevos usos sociales, en lugar de limitaciones tan desproporcionadas como ineficaces para el fin que dicen perseguir.

7.- Internet debe funcionar de forma libre y sin interferencias políticas auspiciadas por sectores que pretenden perpetuar obsoletos modelos de negocio e imposibilitar que el saber humano siga siendo libre.

8.- Exigimos que el Gobierno garantice por ley la neutralidad de la Red en España, ante cualquier presión que pueda producirse, como marco para el desarrollo de una economía sostenible y realista de cara al futuro.

9.- Proponemos una verdadera reforma del derecho de propiedad intelectual orientada a su fin: devolver a la sociedad el conocimiento, promover el dominio público y limitar los abusos de las entidades gestoras.

10.- En democracia las leyes y sus modificaciones deben aprobarse tras el oportuno debate público y habiendo consultado previamente a todas las partes implicadas. No es de recibo que se realicen cambios legislativos que afectan a derechos fundamentales en una ley no orgánica y que versa sobre otra materia.

viernes, 27 de noviembre de 2009

Configuración de Log4j en una aplicación web

Log4j es una librería que permite guardar registros informativos sobre el funcionamiento de una aplicación. En este artículo vamos a ver cómo configurar Log4j para su uso en una aplicación web.

En primer lugar vamos a crear en Eclipse un proyecto war Maven que se llame PruebaLog4jWeb. Crearemos también una página de inicio index.jsp y desplegaremos la aplicación en un servidor. La URL de la aplicación será http://localhost:8080/PruebaLog4jWeb/.

Añadimos la dependencia a la API de servlets para poder trabajar en nuestro proyecto con sus clases. Esta librería no hace falta desplegarla en el servidor, puesto que éste tendrá su propia implementación de esta API:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

Añadimos la dependencia a Log4j en el pom.xml del proyecto:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
</dependency>

Ahora vamos a crear el siguiente servlet:
package com.roldan.log4j;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

public class ServletPrueba extends HttpServlet {

private static final long serialVersionUID = 1L;

static Logger logger = Logger.getLogger(ServletPrueba.class);

public ServletPrueba() { }

protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

logger.debug("Se ha llamado al servlet mediante un GET.");

execute(request, response);
}

protected void doPost(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

logger.debug("Se ha llamado al servlet mediante un POST.");

execute(request, response);
}

protected void execute(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {

logger.info("Se redirige a la página de inicio.");

RequestDispatcher rd =
request.getRequestDispatcher("index.jsp");
rd.forward(request, response);
}
}

En él hemos creado un logger estático de Log4j que usamos en los distintos métodos del servlet para mostrar logs con distinto grado de importancia.

Para configurar la salida de los logs tenemos que crear un archivo log4j.properties, donde definiremos cómo queremos que se muestren los logs. Vamos a mostrar los logs de nuestra aplicación tanto por consola como en un archivo:
log4j.logger.com.roldan.log4j=debug, stdout, file

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=example.log

log4j.appender.file.MaxFileSize=100KB
# Keep one backup file
log4j.appender.file.MaxBackupIndex=1

log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%p %t %c - %m%n

Por último, debemos inicializar Log4j dentro de cada aplicación web, para que cada aplicación pueda trabajar satisfactoriamente de modo independiente. Para ello, vamos a incluir en la aplicación el siguiente servlet de inicialización:
package com.roldan.log4j;

import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Log4jInit extends HttpServlet {

public void init() {
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");

if(file != null) {
PropertyConfigurator.configure(prefix+file);
}
}

public void doGet(HttpServletRequest req, HttpServletResponse res) {}
}

E incluiremos la siguiente configuración en el archivo web.xml:
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>com.roldan.log4j.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-init-file</param-name>
<param-value>WEB-INF/log4j.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Cuando redesplegamos y ejecutamos la aplicación llamando al servlet mediante la URL http://localhost:8080/PruebaLog4jWeb/ServletPrueba se muestran los siguientes logs en la consola:
DEBUG [http-8080-2] (ServletPrueba.java:23) 
- Se ha llamado al servlet mediante un GET.
INFO [http-8080-2] (ServletPrueba.java:39)
- Se redirige a la página de inicio.

Referencias:
http://logging.apache.org/log4j/1.2/index.html
http://logging.apache.org/log4j/1.2/manual.html

miércoles, 18 de noviembre de 2009

Configuración de EhCache en Spring

En este artículo vamos a ver cómo se puede acceder a los datos almacenados en una base de datos a través de una plantilla JDBC de Spring. Para mejorar el rendimiento en este acceso a base de datos introduciremos también una caché usando EhCache que permita almacenar las consultas ya obtenidas evitando el acceso a la base de datos.

En primer lugar, creamos en Eclipse un proyecto Maven e incluimos las dependencias necesarias en el archivo pom.xml del proyecto:
<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>com.roldan.spring</groupId>
<artifactId>PruebaCache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>
<dependency>
<groupId>org.springmodules</groupId>
<artifactId>spring-modules-cache</artifactId>
<version>0.7</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>
</project>

Las dependencias necesarias para nuestro proyecto son:
  • El framework Spring.
  • Log4j para sacar logs informativos sobre la ejecución de la aplicación.
  • El conector a base de datos MySql.
  • El módulo de cache del proyecto spring-modules, que permite integrar la herramienta EhCache con Spring de forma sencilla.
  • La herramienta de cacheo EhCache.

Posteriormente hemos creado una base de datos (pruebacache) con una única tabla (elementos) cuyos elementos serán recogidos por las consultas que realiza la aplicación:

El objeto al que se mapean los registros de esta tabla está definido en la siguiente clase:
package com.roldan.spring.model;

public class Elemento {

private int id;
private String descripcion;
private int grupo;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDescripcion() {
return descripcion;
}
public void setDescripcion(String descripcion) {
this.descripcion = descripcion;
}
public int getGrupo() {
return grupo;
}
public void setGrupo(int grupo) {
this.grupo = grupo;
}
}

A continuación se muestra el archivo de configuración de Spring, spring-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ehcache="http://www.springmodules.org/schema/ehcache"
xmlns:jdbc="http://www.springmodules.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springmodules.org/schema/ehcache
http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd">
<bean id="datasource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/pruebacache"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="datasource"/>
</bean>
<bean id="elementoDao" class="com.roldan.spring.dao.ElementoDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<ehcache:config configLocation="classpath:ehcache.xml"/>
<ehcache:proxy id="proxyElementos" refId="elementoDao">
<ehcache:caching methodName="get*" cacheName="cacheElementos"/>
</ehcache:proxy>
</beans>

En este archivo se configuran los siguientes beans:
  • Un datasource sencillo a nuestra base de datos.
  • Una plantilla de acceso a JDBC de Spring.
  • Un objeto de acceso a datos para recuperar elementos de la base de datos.
  • Un bean proxy que permite incorporar cacheo en las llamadas al bean DAO.

En cuanto al los beans datasource y jdbcTemplate, no hay que hacer más que seguir las instrucciones de configuración de Spring. El bean elementDao pertenece a la clase ElementDaoImpl que implementa la interfaz ElementDao. A continuación vemos la implementación de la clase ElementDaoImpl:
package com.roldan.spring.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.roldan.spring.Prueba;
import com.roldan.spring.model.Elemento;

public class ElementoDaoImpl implements ElementoDao {

private static Logger logger =
Logger.getLogger(ElementoDaoImpl.class);

public static final String RECUPERAR_ELEMENTOS =
"SELECT * FROM ELEMENTO WHERE GRUPO = ?";
public static final String RECUPERAR_TODOS =
"SELECT * FROM ELEMENTO";

public List getElements(int grupo) {
List matches = jdbcTemplate.query(
RECUPERAR_ELEMENTOS,
new Object[] {Integer.valueOf(grupo)},
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
Elemento elemento = new Elemento();
elemento.setId(rs.getInt(1));
elemento.setDescripcion(rs.getString(2));
elemento.setGrupo(rs.getInt(3));

logger.info("Se mapea el elemento " + elemento.getId());

return elemento;
}
});
return matches;
}

public List getAllElements() {
List matches = jdbcTemplate.query(RECUPERAR_TODOS,
new Object[] {},
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
Elemento elemento = new Elemento();
elemento.setId(rs.getInt(1));
elemento.setDescripcion(rs.getString(2));
elemento.setGrupo(rs.getInt(3));

logger.info("Se mapea el elemento " + elemento.getId());

return elemento;
}
});

return matches;
}

JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
}

Tras esto, sólo nos queda revisar la configuración de EhCache en Spring, realizada a través del módulo spring-modules-cache. En el archivo spring-config.xml vemos que se ha definido que el archivo de configuración de EhCache es ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<defaultCache
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LFU"/>
<cache name="cacheElementos"
maxElementsInMemory="100"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="1"
memoryStoreEvictionPolicy="LFU"/>
</ehcache>

En este archivo se configura una cache por defecto, que es obligatoria, y una cache para las aplicación. En esta caché se pueden guardar hasta 300 elementos, y cada elemento se corresponde con una llamada a un método con unos determinados parámetros. Si se repiten llamadas al mismo método con los mismos valores de parámetros, el resultado de la llamada estará cacheado y no será necesario ir a la base de datos a recuperarlo.

Por ejemplo, si ejecutamos la siguiente clase de prueba:
package com.roldan.spring;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.roldan.spring.dao.ElementoDao;
import com.roldan.spring.model.Elemento;

public class Principal {

public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext("spring-config.xml");

ElementoDao elementoDao = (ElementoDao) ctx.getBean("proxyElementos");

List elementos = elementoDao.getElements(1);
for (Elemento elemento : elementos) {
System.out.println(elemento.getDescripcion());
}

elementos = elementoDao.getAllElements();
for (Elemento elemento : elementos) {
System.out.println(elemento.getDescripcion());
}

elementos = elementoDao.getElements(1);
for (Elemento elemento : elementos) {
System.out.println(elemento.getDescripcion());
}
}
}

Se obtienen los siguientes logs:

DEBUG - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.roldan.spring.dao.ElementoDaoImpl@2a6f16]
DEBUG - Finished creating instance of bean 'proxyElementos'
DEBUG - Returning cached instance of singleton bean 'proxyElementos'
DEBUG - Attempt to retrieve a cache entry using key <1130820531|30562044> and cache model
DEBUG - Retrieved cache element
DEBUG - Executing prepared SQL query
DEBUG - Executing prepared SQL statement [SELECT * FROM ELEMENTO WHERE GRUPO = ?]
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/pruebacache]
INFO - Se mapea el elemento 1
INFO - Se mapea el elemento 3
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Attempt to store the object <[com.roldan.spring.model.Elemento@7109c4, com.roldan.spring.model.Elemento@1385660]> in the cache using key <1130820531|30562044> and model
DEBUG - Object was successfully stored in the cache
Primer elemento
Tercer elemento
DEBUG - Attempt to retrieve a cache entry using key <23191881|23191477> and cache model
DEBUG - Retrieved cache element
DEBUG - Executing prepared SQL query
DEBUG - Executing prepared SQL statement [SELECT * FROM ELEMENTO]
DEBUG - Fetching JDBC Connection from DataSource
DEBUG - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost/pruebacache]
INFO - Se mapea el elemento 1
INFO - Se mapea el elemento 2
INFO - Se mapea el elemento 3
INFO - Se mapea el elemento 4
DEBUG - Returning JDBC Connection to DataSource
DEBUG - Attempt to store the object <[com.roldan.spring.model.Elemento@4ecfdd, com.roldan.spring.model.Elemento@30d82d, com.roldan.spring.model.Elemento@c09554, com.roldan.spring.model.Elemento@18bf072]> in the cache using key <23191881|23191477> and model
DEBUG - Object was successfully stored in the cache
Primer elemento
Segundo elemento
Tercer elemento
Cuarto elemento
DEBUG - Attempt to retrieve a cache entry using key <1130820531|30562044> and cache model
DEBUG - Retrieved cache element <[com.roldan.spring.model.Elemento@7109c4, com.roldan.spring.model.Elemento@1385660]>
Primer elemento
Tercer elemento

Se pueden apreciar los siguientes pasos:
  • En la primera llamada se buscan todos los elementos que pertenecen al grupo 1. La llamada pasa por el proxy, que trata de buscar el resultado de esta llamada en la cache y, como no lo encuentra, acude a base de datos.
  • En la segunda llamada se buscan todos los elementos. Esta llamada también pasa por el proxy, que trata de buscar el resultado de esta llamada en la cache y, como no lo encuentra, acude a base de datos.
  • En la tercera llamada se buscan de nuevo todos los elementos que pertenecen al grupo 1. Al pasar por el proxy, éste reconoce que el resultado de la llamada está en la caché y que no hace falta acudir a la base de datos, ahorrándose la consulta.

Con esto, tenemos ya un ejemplo de cómo utilizar una cache en las consultas a base de datos en Spring.

Referencias:
http://www.dosideas.com/wiki/EhCache_Con_Spring

jueves, 12 de noviembre de 2009

La Deuda Técnica

¿Quién no se ha encontrado en el siguiente dilema? Tenemos que añadir una nueva funcionalidad al sistema y tenemos prisa. Podemos hacerlo rápido y de forma no óptima, más enrevesado o menos eficiente, satisfaciendo las exigencias de entrega. O podemos (si es que podemos…) saltarnos estas exigencias y sentarnos a pensar y hacerlo mejor, con diseño más claro y mantenible.

La Deuda Técnica es una metáfora ideada por Ward Cunningham que ayuda a pensar sobre este problema. Viene a decir que en caso de hacer las cosas rápido y de manera chapucera se incurre en una “deuda” que vamos a tener que pagar en el futuro, en forma de esfuerzo de desarrollo, como consecuencia de postergar el buen diseño en la implementación. Y a medida que se siga postergando este esfuerzo y el desarrollo deficiente se siga recubriendo con nuevos desarrollos que lo enmascaren o lo usen, esta deuda será cada vez más elevada y difícil de pagar.

No se quiere decir que no sea sensato incurrir en esta deuda. En ciertas ocasiones es una decisión acertada asumir esta deuda para resolver una situación determinada en un proyecto. Sin embargo, hay que tener en cuenta las repercusiones que puede tomar en el futuro y hay que tratar de satisfacer esta deuda cuanto antes para evitar que crezca desmesuradamente, es decir, que un mal planteamiento en una funcionalidad de la aplicación comprometa la buena marcha del proyecto en el futuro.

Sobre esta idea, Martin Fowler ha desarrollado el “Cuadrante de la Deuda Técnica”. Según él, una deuda técnica asumida en un proyecto puede clasificarse de dos formas:
  • Prudente o imprudente.

  • Advertida o inadvertida.

La combinación de estas clasificaciones produce cuatro situaciones distintas:
  • Deuda prudente y advertida: Se produce cuando somos conscientes de que estamos asumiendo un mal diseño para salir de una situación puntual, como una entrega. Posteriormente se debe evaluar la conveniencia de “pagar la deuda técnica” solucionando esta carencia en función del interés que acarree.

  • Deuda prudente e inadvertida: Se produce cuando, con el paso del tiempo, se descubren cómo se deberían haber hecho las cosas. Inevitable, ya que según avanza el proyecto, se aprende de él. Llegado el momento, también se debe evaluar si resulta interesante mejorar el diseño con lo que hemos aprendido o si esto implicaría un esfuerzo demasiado alto.

  • Deuda imprudente y advertida: Se deshecha el diseño porque se pretende acelerar el desarrollo. Según la “Hipótesis de Resistencia al Diseño”, esto se puede lograr hasta un punto determinado del proyecto en el que deja de ser posible conseguir un beneficio de obviar el diseño porque la calidad del código se degrada.

  • Deuda imprudente e inadvertida: No se conocen las técnicas de diseño ni se es consciente de que se están tomando decisiones incorrectas.

Conviene saber en qué situación nos encontramos. Si bien las tres primeras situaciones se pueden asumir en un momento determinado dentro de un proyecto, la última resulta mucho más peligrosa, porque implica no saber hacia dónde se dirige el proyecto.

Referencias:

La Deuda Técnica
El Cuadrante de la Deuda Técnica
La Hipótesis de Resistencia al Diseño

viernes, 6 de noviembre de 2009

EclEmma: Visualizar la cobertura de los tests unitarios en Eclipse

Hace algún tiempo publiqué un post sobre herramientas de calidad del código. A las que yo publiqué, Dirty Affairs añadió otra, EclEmma, a la cual he estado echando un vistazo.

EclEmma es una herramienta para Eclipse que permite visualizar la cobertura del código de los tests unitarios que hemos hecho. Existen otras herramientas como Cobertura, que generan informes, pero que no permiten visualizar esta informacuón de forma gráfica directamente en Eclipse.

EclEmma se instala en Eclipse de forma sencilla, desde Help -> Software Updates -> Available Software -> Add Site, se añade el sitio http://update.eclemma.org/ y pasamos a realizar la instalación del plugin.

Una vez instalado el plugin y reiniciado Eclipse, aparece una nueva opción en la barra de herramientas:

A través de este botón, podemos lanzar los tests de forma que EclEmma analizará qué parte del código se está cubriendo en ellos. Veamos un ejemplo práctico.

He creado una clase OperadorAritmético, que realiza las operaciones de suma y division:
package com.roldan.tests;

public class OperadorAritmetico {

public static int suma(int a, int b) {
return a + b;
}

public static int division(int a, int b) throws Exception {
if(b==0) {
throw new Exception();
}
return a / b;
}
}

Para probar esta clase he creado una clase de test que, en principio, solo prueba la suma:
package com.roldan.tests;

import org.junit.Assert;
import org.junit.Test;

public class OperadorAritmeticoTest {

@Test
public void suma() {

int a = 5;
int b = 3;

int suma = OperadorAritmetico.suma(a, b);

Assert.assertEquals(8, suma);
}
}

Ahora lanzamos las pruebas para el proyecto, sitándonos en la raíz del proyecto y yendo al botón de EclEmma antes mostrado, seleccionamos la opción Coverage as -> JUnit Test:

Vemos como las instrucciones de la clase OperadorAritmetico has sido coloreadas, con verde aquellas que han sido cubiertas en las pruebas y con rojo aquellas que no. La pestaña Coverage muestra el informe de cobertura del proyecto.

Ahora queremos arreglar un poco esta situación y hacer un prueba para la división:
@Test
public void division() {

int a = 8;
int b = 4;

int division;
try {
division = OperadorAritmetico.division(a, b);
Assert.assertEquals(2, division);
} catch (Exception e) {
Assert.fail();
}
}

Si ahora volvemos a realizar las pruebas, vemos que la situación se ha mejorado, aunque todavía queda código sin cubrir:

De esta forma, podemos ir mejorando progresivamente la cobertura de las pruebas para asegurar el buen funcionamiento de nuestro código.

Referencias:
http://tratandodeentenderlo.blogspot.com/2009/10/herramientas-de-analisis-de-calidad-del.html
http://www.eclemma.org/
http://cobertura.sourceforge.net/

jueves, 5 de noviembre de 2009

Lecturas anteriores

DESACTUALIZADO: Puedes seguir mis lecturas en Goodreads

En esta entrada simplemente se listan los libros que he leído y que vaya leyendo, por tanto, estará en constante actualización.

También espero que sirva para recibir recomendaciones sobre estos libros o sobre otros que puedan resultar interesantes.

martes, 3 de noviembre de 2009

Próximas lecturas

DESACTUALIZADO: Puedes seguir mis lecturas en Goodreads

Esta entrada no es más que una declaración de intenciones, una recopilación de los libros que tengo previsto leer proximamente. Por tanto, estará en constante actualización.

También espero que sirva para recibir recomendaciones sobre estos libros o sobre otros que puedan resultar interesantes.

  • Growing Object-Oriented Software Guided by Tests (Steve Freeman, Nat Pryce)

  • Patterns of Enterprise Application Architecture (David Fowler)

  • Head First Design Patterns (Eric T Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra)

viernes, 30 de octubre de 2009

Pruebas de base de datos con DbUnit

Cuando se desarrollan aplicaciones que acceden a una base de datos, es conveniente verificar que los datos se están manipulando de forma correcta. Para ello, es necesario hacer pruebas sobre el código que realiza esta manipulaciones de datos.

JUnit es un framework que nos ayuda a la hora de hacer pruebas en nuestra aplicación. Además, también podemos usar DbUnit, que es una extensión de JUnit que permite llevar la base de datos a un estado definido antes de cada prueba y que proporciona clases que nos ayudan a realizar pruebas sobre el contenido de una base de datos.

DbUnit permite importar y exportar el contenido de la base de datos a ficheros xml. Por ejemplo, la tabla PROFESORES se define de la siguiente forma:

Un registro en la tabla PROFESORES, se expresaría en xml como:
<profesores PROFESOR_ID="3" NOMBRE="nombre_profesor"/>

Se puede apreciar que el nombre del elemento es el nombre de la tabla y los distintos atributos son los campos de la tabla y su valor para este registro.

Mediante registros de este tipo se pueden generar distintos conjuntos de datos (datasets) en ficheros xml, que pueden servir como semillas para probar el código que accede a la base de datos en situaciones adecuadas para cada prueba.

Vamos a ver como exportar un esquema completo de la base de datos utilizando DbUnit. En primer lugar, se debe obtener una conexión a la base de datos. Se puede hacer de la siguiente forma:
Class.forName("com.mysql.jdbc.Driver");
Connection jdbcConnection =
DriverManager.getConnection(
"jdbc:mysql://localhost/bdprueba",
"user",
"pwd");
IDatabaseConnection connection =
new DatabaseConnection(jdbcConnection);

Posteriormente pasamos a exportar los datos que hay actualmente en la base de datos. Al exportar hay que tener en cuenta el orden de las tablas ya que se podría romper la integridad referencial que existe entre ellas. Para ello se crea un dataset al que se añaden las tablas de forma ordenada, que se pueden obtener a partir de un DatabaseSequenceFilter:
DatabaseSequenceFilter filter = 
new DatabaseSequenceFilter(connection);
IDataSet datasetAll =
new FilteredDataSet(
filter,
connection.createDataSet());
QueryDataSet partialDataSet =
new QueryDataSet(connection);

String[] listTableNames =
filter.getTableNames(datasetAll);
for (int i = 0; i < listTableNames.length; i++) {
final String tableName = listTableNames[i];
partialDataSet.addTable(tableName);
}

Ahora se exportaría este dataset a un archivo xml:
FlatXmlDataSet.write(partialDataSet,
new FileOutputStream("dataset.xml"));

<?xml version='1.0' encoding='UTF-8'?<
<dataset>
<academias/>
<estilos ESTILO_ID="1" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="3" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="4" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="6" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="8" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="9" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="10" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<estilos ESTILO_ID="12" NOMBRE="nombre_estilo"
DESCRIPCION="descripcion_estilo"/>
<clases/>
<academia_clase/>
<profesores PROFESOR_ID="3" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="6" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="9" NOMBRE="nombre_profesor"/>
<profesores PROFESOR_ID="12" NOMBRE="nombre_profesor"/>
<clase_profesor/>
<profesor_estilo PROFESOR_ID="3" ESTILO_ID="3"/>
<profesor_estilo PROFESOR_ID="6" ESTILO_ID="6"/>
<profesor_estilo PROFESOR_ID="9" ESTILO_ID="9"/>
<profesor_estilo PROFESOR_ID="12" ESTILO_ID="12"/>
</dataset>

Tras esto se ha obtenido un dataset que puede ser usado como semilla para una prueba.

A la hora de hacer pruebas, DbUnit proporciona la clase DatabaseTestCase, que sirve como clase base para las pruebas. Esta clase tiene algunos métodos que debemos sobreescribir. El método getConnection() proporciona la conexión a la base de datos, de forma similar a como hemos visto antes:
protected IDatabaseConnection getConnection() 
throws Exception {

Class driverClass =
Class.forName("org.gjt.mm.mysql.Driver");

Connection jdbcConnection =
DriverManager.getConnection(
"jdbc:mysql://localhost/bdprueba",
"user",
"pwd");

return new DatabaseConnection(jdbcConnection);
}

El método getDataSet() proporciona un dataset que sería la semilla para la prueba que vamos a ejecutar:

protected IDataSet getDataSet() throws Exception {
return new FlatXmlDataSet(
new FileInputStream("dataset.xml "));
}

Los métodos getSetUpOperation() y getTearDownOperation() indican lo que debe hacer cada método antes y después de cada prueba. Antes de cada prueba vamos a limpiar la base de datos y a volver a dejarla en el estado que proporciona el dataset que hemos exportado anteriormente, y después de cada prueba no haremos nada:
protected DatabaseOperation getSetUpOperation() 
throws Exception {
return DatabaseOperation.CLEAN_INSERT;
}

protected DatabaseOperation getTearDownOperation()
throws Exception {
return DatabaseOperation.NONE;
}

Tras esto, podemos escribir nuestros casos de prueba en la clase que extiende de DatabaseTestCase, sabiendo que las pruebas partirán de un estado definido.

Referencias:
http://dbunit.sourceforge.net/index.html
http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=DBUnitEI
http://onjava.com/pub/a/onjava/2004/01/21/dbunit.html
http://www.oreillynet.com/onjava/blog/2005/10/dbunit_made_easy.html

lunes, 26 de octubre de 2009

Agile Open Spain

Los días 23 y 24 de Octubre se ha celebrado en la Escuela Universitaria de Informática del Campus Sur de la Universidad Politécnica de Madrid el Agile Open Spain, organizado por Agile Spain.

El Agile Open Spain tenía como objetivo la difusión de la metodologías ágiles en España, compartiendo experiencias entre todos los participantes. Se ha desarrollado basándose en el formato Open Space.

La tarde del viernes 23, tras la introducción al evento por parte de la organización, cualquier participante pudo presentar los temas que más interés tenían para él. Tras votación por parte de los asistentes, se seleccionaron los más votados para confeccionar el horario de charlas para el día siguiente, en el que se establecieron 5 turnos de charlas con 6 charlas distintas en cada uno para escoger.

Voy a comentar las charlas en las que yo estuve, que, desgraciadamente, no fueron todas las que me habría gustado estar.

Integración continua

La integración contínua fue el tema de la primera charla a la que asistí. Fue conducida por Juan Gutiérrez y en ella se habló de lo que es la integración continua, presentándola como un proceso continuo de integración del trabajo que se lleva a cabo dentro de un proyecto, que aglutina una serie de buenas prácticas y que está apoyado por una serie de herramientas que permiten automatizarlo.

Algunos asistentes hablaron de sus experiencias con la integración continua en sus proyectos y se llego a exponer el sistema de integración contínua con que uno de los asistentes trabajaba.

Se recalcó la idea de que el principio de la integración es el control de versiones (CVS, Subversion, Git, …) y las herramientas de construcción automática (Ant, Maven…) y que, a partir de ahí, existen un montón de herramientas que contribuyen a la automatización de las distintas pruebas (Junit, DBUnit, Selenium…). Y todo esto, orquestado por el servidor de integración continua (Hudson, Bamboo…).

Control de versiones

En la siguiente sesión se habló sobre el control de versiones en los proyectos, estableciendo la necesidad de establecer una política de ramas bien definida, para lo que se presentaron varias estrategias.

El conductor, Jose Luis Soria, presentó la serie de tareas necesarias para establecer una política de ramas:
  1. Establecer el modelo de aislamiento: sobre qué rama se realiza un nuevo cambio.
  2. Establecer listas de promoción: definir qué ramas pueden hacer merge a cuáles.
  3. Criterios de calidad.
  4. Establecer un responsable de cada rama, que se encargará de que se mantenga estable.
  5. Establecer permisos.
  6. Estrategia de testeo y construcción automatizada.

Hubo también algún firme impulsor de Git, presentándolo como una alternativa superior a CVS o Subversion, así que habrá que echarle un vistazo.

Agilismo de guerrilla

En esta charla, conducida por Xavi Gost, se habló sobre cómo intruducir el agilismo en una organización. La idea principal que se me quedó es no esperar que vengan de arriba a ofrecértelo, sino ir introduciendo técnicas ágiles en la medida de lo posible en los proyectos.

También se habló sobre la resistencia al cambio por parte de la gente. Resistencia, sobre todo, a los grandes cambios. Por el contrario, si se introducen los cambios de forma disimulada, la gente los adopta sin el miedo que supone presentar a un grupo una nueva metodología o conjunto de prácticas de golpe.

Kanban

Como dijo Xabier Quesada en la presentación, Scrum ha muerto y ahora lo que se lleva es Kanban. Como luego él mismo matizó, esto no es así, puesto que Kanban es algo que todavía se está definiendo.

Xabier, junto con Robin Diamond, nos presentaron Kanban, una nueva metodología basada en Lean. Los principios de Kanban son:
  • Limitar el trabajo en progreso, todo trabajo empzado y no terminado, puesto que está costando dinero.
  • Establecer un flujo continuo de trabajo, que entra por un lado y fluye hasta el final de la cadena de producción.

En la charla contruyeron un tablero Kanban que sirvió para hacernos una idea visual de su funcionamiento.

Historias de usuario

Sesión conducida por Jose Luis Soria, Rodrigo Corral y otro asistente más cuyo nombre no recuerdo :-(. En esta charla se habló de la documentación en los proyectos.

La idea principal sería la de hacer simplemente la documentación que aporte valor al proyecto, bien para el desarrollador o para el usuario, y resistirse a documentar por documentar creando tochos que nadie lee ni actualiza y se quedan obsoletos de forma inmediata.

Se habló mucho de las historias de usuario, representación de un requerimiento a través de una sencilla descripción de la conversación mantenida con un usuario y sus condiciones de aceptación. Una historia de usuario debe tener las siguientes características:
  • Independente
  • Que aporte valor
  • Estimable
  • Negociable
  • Testable
  • Pequeña

De todas las charlas me marché con la sensación de haber aprendido bastante. No siempre tienes la oportunidad de tener delante gente que puede hablar sobre su experiencia en temas en los que tú estás empezando a introducirte.

La pena, no haber podido asistir a otras charlas que también me interesaban. Pero el tener que elegir hace que a las que vayas, lo hagas con el mayor interés.

Un saludo a la organización del Agile Open Spain y a todos sus participantes.

martes, 20 de octubre de 2009

Licencias de Software

Según la Wikipedia, “una licencia de software es un contrato entre el licenciante (autor/titular de los derechos de explotación/distribuidor) y el licenciatario del programa informático (usuario consumidor /usuario profesional o empresa), para utilizar el software cumpliendo una serie de términos y condiciones establecidas dentro de sus cláusulas.

Por tanto, la licencia establece las condiciones bajo las cuáles podemos usar un software determinado.

Puesto que existen una amplia variedad de licencias, voy a exponer a continuación algunas de las más comunes, junto con una breve explicación de lo que estas licencias implican desde el punto de vista del usuario.

GPL

La Licencia Pública General (General Public License) es una licencia de software libre que permite al usuario utilizar un programa licenciado bajo dicha licencia, modificarlo y distribuir las versiones modificadas de éste.

Todo software desarrollado, aunque sólo sea una parte, con material licenciado bajo GPL debe estar disponible para ser compartido de forma gratuita (copyleft), manteniendo los nombres de los autores originales.

El software con licencia GPL carece de garantía, el autor no se hace responsable por el malfuncionamiento del mismo.

Tampoco se puede establecer ningún cobro por las modificaciones realizadas sobre el software.

LGPL

La Licencia Pública General Menor (Lesser General Public License) es una modificación de la licencia GPL, que permite que los desarrolladores utilicen programas bajo la LGPL sin estar obligados a someter el programa final bajo dichas licencias.

LGPL no permite que se realicen versiones comerciales del producto licenciado bajo LGPL. Sin embargo, permite realizar versiones comerciales de un producto final que contenga como herramienta adicional un programa LGPL.

LGPL exige registrar todos los cambios realizados por terceros, a manera de no afectar la reputación del autor original del software.

BSD

La Licencia de Distribución de Software de Berkeley (Berkeley Software Distribution) permite a los programadores utilizar, modificar y distribuir a terceros el código fuente y el código binario del programa de software original con o sin modificaciones bajo licencias de código abierto o comercial.

Esta licencia permite el uso del código fuente en software no libre sin necesidad de mencionar a los autores ni proporcionar el código fuente. Esta licencia sí que establece la renuncia de garantía y la atribución de la autoría sobre trabajos derivados.

MPL

La Licencia Pública de Mozilla (Mozilla Public License) es una licencia de código abierto y sofware libre utilizada por el navegador de Internet Mozilla y sus productos derivados. La MPL deja abierto el camino a una posible reutilización comercial y no libre del software y permite la reutilización del código ni el cambio de licencia.

Apache License

La Licencia Apache es una licencia de software libre que permite al usuario usar el software para cualquier propósito, distribuirlo, modificarlo, y distribuir versiones modificadas de ese software.

La Licencia Apache no exige que las obras derivadas del software se distribuyan usando la misma licencia, ni siquiera que se tengan que distribuir como software libre. La Licencia Apache sólo exige que se mantenga una noticia que informe a los receptores que en la distribución se ha usado código con la Licencia Apache.


Actualmente, existen muchas herramientas que están siguiendo una estrategia de licenciamiento dual de software. Estas proporcionan dos tipos de licencias para el mismo software entre las que puede optar el usuario:
  • Una licencia gratuita de software libre (por ejemplo, GPL) que permite el uso del software a condición de que lo que el cliente desarrolle tambien sea puesto a disposición de otros usuarios libremente.

  • Una licencia de pago comercial que permite que no haya que publicar el código fuente de las aplicaciones desarrolladas.


Referencias:
http://es.wikipedia.org/wiki/Licencia_de_software
http://www.gnu.org/licenses/license-list.es.html
http://www.monografias.com/trabajos55/licencias-de-software/licencias-de-software.shtml
http://es.wikipedia.org/wiki/Apache_License

lunes, 19 de octubre de 2009

Scrum Manager

En los últimos tiempos se viene oyendo hablar mucho sobre metodologías ágiles y, principalmente, sobre Scrum. El creciente interés por Scrum ha hecho florecer una serie de certificaciones al respecto, promovidas por la Scrum Alliance y, por supuesto, de pago. Contra esta tendencia a lucrarse de una metodología que ha florecido dentro de ambientes “Open Source” se han alzado voces que prefieren compartir el conocimiento a través de la comunidad.

Una iniciativa en este sentido es Scrum Manager, que se define como una “comunidad profesional para la gestión flexible de proyectos y organizaciones TIC”. Su objetivo es mejorar los procedimientos y métodos de trabajo de las organizaciones y proyectos de software manteniendo de forma abierta a la comunidad profesional la plataforma de conocimiento Open Knowledge.

Esta plataforma ofrece los siguientes cursos gratuitos sobre Scrum:
  • Introducción a Scrum Manager: Su objetivo es “conocer los principios de los modelos de procesos y las prácticas ágiles, enmarcados en el mapa o marco de situación que les da sentido, y revela las fortalezas y debilidades de cada estrategia: ingeniería, procesos, gestión predictiva y gestión ágil”.

  • Scrum: Su objetivo es “conocer el modelo Scrum: origen del modelo, principios y prácticas que emplea para la gestión y seguimiento ágil del proyecto, sus componentes; junto con las razones y consideraciones de fondo para la implementación del modelo”.

  • Métricas ágiles: Su objetivo es “conocer la razón y finalidad de las métricas en la gestión ágil de proyectos, y evitar errores habituales en el diseño y aplicación de métricas, normalmente por exceso en el número de métricas o en su complejidad, que suele desbordar las necesidades de estimación y seguimiento ágil”.

Estos son cursos ofrecen recursos de aprendizaje como material didáctico y foros. Además, a la conclusión de estos cursos existe una prueba de evaluzación final cuya superación satisfactoria otorga puntos de autoridad dentro de la escala de reconocimiento profesional de Scrum Manager.

Desde aquí quiero aprovechar para felicitar a los responsables de esta iniciativa y agradecerles su esfuerzo.

Referencias:
Scrum Manager

miércoles, 14 de octubre de 2009

Gestionando un proyecto Hibernate desde Maven

Vamos a ver cómo gestionar con Maven un proyecto que utiliza Hibernate.

En primer lugar, vamos a ver cómo configurar las dependencias de Hibernate en Maven. Aquí nos encontramos con un problema, Hibernate depende de la Sun JTA API, que no está disponible en el repositorio central de Maven porque, debido a problemas de licencias, no puede ser distribuida libremente.

Para solucionar este problema existen dos posibles soluciones. La primera es descargar la Sun JTA API de la página web de Sun y despues instalarla en el repositorio local de Maven.

Usaremos el siguiente 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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roldan.hibernate</groupId>
<artifactId>HibernateMavenProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.6.ga</version>
</dependency>

</dependencies>
</project>

Para instalar la Sun JTA API en el repositorio usaremos la siguiente instrucción desde la línea de comandos:
mvn install:install-file
-DgroupId=javax.transaction
-DartifactId=jta
-Dversion=1.0.1B
-Dpackaging=jar
-Dfile=jta-1_0_1B-classes.zip

La segunda posible solución sería descartar la dependencia de la Sun JTA API que tiene Hibernate y, en su lugar, obtener una implementación alternativa de este API que pueda ser descargada libremente, como la de Geronimo:
<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>com.roldan.hibernate</groupId>
<artifactId>HibernateMavenProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.2.6.ga</version>
<exclusions>
<exclusion>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>geronimo-spec</groupId>
<artifactId>geronimo-spec-jta</artifactId>
<version>1.0-M1</version>
</dependency>

</dependencies>
</project>

Una vez resueltas las dependencias de Hibernate en Maven, podemos usar Hibernate en nuestros proyectos. Una herramienta que nos ayudará a simplificar las tareas de administración de estos proyectos es el plugin de Hibernate 3 para Maven, que se puede obtener del repositorio de Codehaus.

Por ejemplo, vamos a usar este plugin para generar el DDL de la base de datos durante el desarrollo, permitiendo reconstruir la base de datos para irnos actualizando a los cambios que se vayan produciendo:
<project>

<repositories>
<repository>
<id>codehaus</id>
<name>Maven Codehaus repository</name>
<url>http://repository.codehaus.org/</url>
</repository>
</repositories>

<build>
<extensions>
<extension>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<componentProperties>
<drop>true</drop>
<outputfilename>schema.sql</outputfilename>
</componentProperties>
</configuration>
</plugin>
</plugins>
</build>
</project>

Para lanzar la ejecución de esta tarea de actualización de la base de datos, usamos el comando:
mvn org.codehaus.mojo:hibernate3-maven-plugin:2.2:hbm2ddl