Mostrando entradas con la etiqueta programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta programación. Mostrar todas las entradas

viernes, 8 de noviembre de 2013

Integración y transacciones con Spring en Apache Tapestry

Apache Tapestry
Spring
En otra entrada comentaba como hacer transacciones en una base de datos relacional con Apache Tapestry y como mejorar el soporte que ofrece de por si con la anotación CommitAfter mediante con una solución propia que proporciona la anotación Transactional. La solución propia mejora la anotación CommitAfter y es usable en más casos como cuando dos servicios distintos necesitan colaborar en una transaccion y compartirla. Sin embargo, si el correcto funcionamiento de las transacciones es una parte importante de la aplicación (y en una aplicación grande lo será) podemos evaluar si optar por Spring o los EJB en vez de la solución propia o la anotación CommitAfter.

Unos buenos motivos para optar tanto por Spring como por los EJB es que son soluciones ya desarrolladas con lo que solo tendremos que integrarlo en nuestros proyectos y no tendremos que preocuparnos de mantener nuestra solución en caso de que tenga errores, además ambas son ampliamente usadas incluso en proyectos grandes y complejos y están ya probadas lo que es una garantía. Entre optar por Spring o los EJB depende de varios factores como puede ser si la aplicación va ha ser desplegada en un servidor de aplicaciones con soporte para EJB (como JBoss/Wildfly, Geronimo, ...) o no (Tomcat, Jetty) o de nuestras preferencias entre ambas opciones. En esta entrada explicaré como integrar Spring con el framework Apache Tapestry y como hacer uso de las transacciones de Spring en los servicios que contienen la lógica de la aplicación.

Primeramente, decir que en cierta medida la funcionalidad proporcionada por el contenedor de dependencias de Tapestry y el contenedor de dependencias de Spring se solapan, ambos proporcionan Inversion of Control (IoC). Pero el contenedor de dependencias de Tapestry tiene algunas ventajas como permitir configuración distribuida, esto hace referencia a que cada librería jar puede contribuir con su configuración al contenedor de dependencias y que la configuración se hace mediante código Java en vez de xml como en Spring con la ventaja de que es más rápido, tenemos la ayuda del compilador para detectar errores y el lenguaje Java es más adecuado para expresar la construcción de objetos. De modo que si podemos es mejor usar el contenedor de Tapestry que el de Spring, sin embargo, Spring ofrece un montón de funcionalidades muy útiles y esto nos puede obligar a usar el contenedor de Spring para ciertos objetos. Una de ellas son las transacciones para cumplir con las reglas ACID de las bases de datos relacionales, para ello deberemos definir en el contenedor de Spring (y no en el de Tapestry) los servicios con la lógica de negocio con necesidades transaccionales y las dependencias referidas por esos servicios en la configuración del contexto de Spring. A pesar de todo en los demás casos podemos optar por la opción que prefiramos ya que tanto a los servicios de Spring se les pueden inyectar dependencias del contenedor de Tapestry y, el caso contrario, a los servicios de Tapestry se les pueden inyectar servicios de Spring.

Veamos en código un ejemplo de como conseguir integración entre Tapestry y Spring. La primera cosa que cambia es que hay que usar un filtro de Tapestry especial para integrarse con Spring con lo que deberemos modificarlo en el archivo web.xml. Si normalmente usamos el filtro org.apache.tapestry5.TapestryFilter para que Tapestry procese las peticiones que llegan a la aplicación, integrándonos con Spring usaremos un filtro especial, org.apache.tapestry5.spring.TapestrySpringFilter. También mediante una propiedad de contexto indicaremos el (o los) xml con la definición de los beans de Spring.

En el xml del contexto para Spring definimos la configuración para que Hibernate se conecte a la base de datos, definimos el SesionFactory que creará la sesiones de Hibernate, el gestor de transacciones y los servicios con la lógica de negocio. En este ejemplo he optado por definir las transacciones mediante anotaciones en los servicios con la lógica de negocio. Spring también permite definir la transaccionalidad de forma declarativa en este xml.

Como Spring se encargará de la configuración de Hibernate si incluimos la dependencia tapestry-hibernate tendremos un problema ya que este módulo de Tapestry también intenta inicializar Hibernate. Para evitarlo y disponer de toda la funcionalidad que ofrece este módulo como encoders para las entidades de dominio, la página de estadísticas de Hibernate o el objeto Session como un servicio inyectable en páginas o componentes hay que redefinir el servicio HibernateSessionSource. El nuevo servicio es muy sencillo, básicamente obtiene el la configuración de Hibernate mediante el bean SessionFactory definido en Spring y además mediante el mismo bean se crea el objeto Session que podrá inyectarse en los componentes y páginas de Tapestry en los que lo necesitemos. También deberemos añadir un poco de configuración en el módulo de la aplicación para redefinir este servicio.

Para definir la transaccionalidad de una operación debemos usar la anotación Transactional usando los valores por defecto o indicando la propagación, el aislamiento, si es de solo lecura, timeout, etc, ... según consideremos. Debido a lo simple de la lógica de negocio de la aplicación de este ejemplo la anotación se aplica al DAO, sin embargo, en una aplicación más compleja y con mas clases sería mejor definirlo a nivel de servicio de lógica de negocio o punto de entrada a la lógica de negocio y no al nivel de los DAO que están en una capa de la aplicación más baja.

Finalmente, debemos añadir o modificar las dependencias de nuestra aplicación. La dependencia tapestry-spring usa por defecto la versión 3.1.0 de Spring, en el ejemplo la sustituyo por la versión 3.2.4 más reciente. A continuación incluyo la parte relevante.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.

Referencia:
Transacciones en Apache Tapestry
Persistencia con JPA y Apache Tapestry
Acceso a base de datos con Hibernate y JPA
Transaction Management (Spring)

viernes, 1 de noviembre de 2013

Transacciones en Apache Tapestry

Apache Tapestry
Tapestry no proporciona de por sí un soporte completo a las aplicaciones que necesitan realizar operaciones en una base de datos relacional de forma transaccional. La dependencia tapestry-hibernate provee la anotación @CommitAfter para Hibernate y la dependencia tapestry-jpa otra del mismo nombre para JPA pero esta anotación en ambos casos proporciona una funcionalidad muy básica y probablemente no no sirva en casos de uso complejos. Esto ha sido objeto de discusión varias veces en la lista de distribución de los usuarios [1] [2] y el JIRA de Tapestry [3].

Con la anotación CommitAfter si se produce una excepción no controlada («unchecked») se hará un rollback de la transacción y, esto es importante, aún produciendose una excepción controlada («checked») se hará el commit de la transacción y es responsabilidad del programador tratar la excepción adecuadamente. Se puede usar en los métodos de los servicios y en los métodos manejadores de eventos de los componentes.

Sabiendo como funciona la anotación se nos plantean preguntas:
  1. ¿Cuál es el comportamiento cuando un método del servicio anotado llame a otro también anotado del mismo servicio?
  2. ¿Que pasa si cada método está en un servicio diferente?
Para el primer caso (métodos del mismo servicio) se hará una sola transacción ya que las anotaciones y los advices se aplican en el proxy del servicio no en la implementación. En el segundo caso (métodos en diferentes servicios) se iniciará una transacción pero haciendo un commit en la salida de cada método.

Si tenemos una aplicación compleja probablemente se nos planteará el caso de tener varios servicios que se llaman entre si y que ambos necesiten compartir la transacción, en esta situación la anotación CommitAfter probablemente no nos sirva por hacer un commit en la salida de cada método.

Tapestry no pretende proporcionar una solución propia que cubra todas las necesidades transaccionales que puedan tener todas las aplicaciones sino que con la anotación CommitAfter pretende soportar los casos simples, para casos más complejos ya existen otras opciones que están ampliamente probadas. Si necesitamos un mejor soporte para las transacciones que el que ofrece Tapestry debemos optar por Spring o por los EJB. Sin embargo, la solución de Spring nos obliga a definir los servicios transaccionales como servicios de Spring y los EJBs nos obligan a desplegar la aplicación en un servidor de aplicaciones que soporte un contenedor de EJB como JBoss/Wildfy, Gernimo, TomEE, ... Si nuestro caso no es tan complejo como para necesitar mucho de lo que ofrece Spring o no queremos o podemos usar un servidor que soporte EJB podemos aplicar el ejemplo ya comentado en Tapestry Magic #5: Advising Services.

En esta entrada pondré un ejemplo completo usando la solución de Tapestry Magic #5 pero con la adición de una anotación que permite definir más propiedades de las transacciones y la diferencia respecto a la anotación CommitAfter de que independientemente de si se produce una excepción checked o unchecked se hace un rollback de la transacción. La anotación Transactional permite definir si la transacción es de solo lectura, definir un timeout para completar la transacción o el nivel de aislamiento de la transacción además de la estrategia de propagación. Aunque no sea una solución tan buena como la de usar Spring o EJBs, puede ser suficiente para muchos más casos que la anotación CommitAfter.

La solución consiste en implementar una nueva anotación para los métodos transaccionales que he llamado Transactional, unos advices con las diferentes estrategias de transaccionalidad (REQUIRED, SUPPORTS, NEVER, NESTED, MANDATORY), un advisor que aplicará una estrategia transaccional en función de la anotación Transactional de los métodos y un poco de configuración para el contenedor IoC que define los servicios y aplica la decoración a los métodos anotados.

Hay que tener en cuenta que esta solución es una prueba de concepto que he probado en este ejemplo y puede presentar problemas que aún desconozco en una aplicación real. Una vez dicho esto veámos el código.

Primero la anotación, el enumerado de las estrategias de propagación de transacciones, el DTO (Data Transfer Object) con las propiedades de la anotación y la interfaz del servicio transaccional.

Ahora el advisor que usará el servicio transaccional y en función de la estrategia de propagación aplicará el advice adecuado.

El funcionamiento de las estrategias transaccionales son:
  • REQUIRED: si no hay una transaccion activa inicia una y hace el commit al finalizar. Si existe una al entrar en el método simplemente ejecuta la lógica usando la transacción actual
  • MANDATORY: requiere que haya una transacción iniciada, en caso contrario produce una excepción.
  • NESTED: inicia una nueva transacción siempre aún existiendo ya una, con lo que puede haber varias transacciones a la vez de forma anidada.
  • NEVER: es el caso contrario de MANDATORY, si existe una transacción produce una excepción.
  • SUPPORTS: puede ejecutarse tanto dentro como fuera de una transacción.
Probablemente con la anotación REQUIRED tengamos suficiente para la mayoría de los casos, para la estrategia NESTED necesitaremos soporte del motor de la base de datos que no todos tienen, el resto son otras posibilidades comunes en el ámbito de las transacciones: MANDATORY, NEVER, SUPPORTS.

Y ahora las implementaciones de las estrategias de propagación que iniciarán, harán el rollbak y commit de forma adecuada a la estrategia usando el servicio transaccional.

A continuación la implementación del servicio transaccional para el caso de Hibernate.

Finalmente el gestor de sesiones de Hibernate y la configuración necesaria en el módulo de la aplicación.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.

Referencia:
Integración y transacciones con Spring en Apache Tapestry

viernes, 25 de octubre de 2013

Relaciones jerárquicas en bases de datos relacionales

Otro de los problemas que se suele presentar al trabajar con bases de datos relacionales además de como internacionalizar las entidades del dominio o como hacer búsquedas de texto completo es como modelar las relaciones jerárquicas. Para resolver el problema de las búsquedas en las bases de datos relacionales con datos jerárquicos hay varias soluciones posibles cada una con sus ventajas y desventajas y una más ideal si la base de datos lo soporta, son:

Listas adjacentes

En este modelo se crea una campo adicional que indicará el nodo padre de la relación jerárquica, los nodos raíz tendrán este campo a null al no tener padre.

Buscar los descendientes de un nodo, sin el soporte de quieries recursivas y suponiendo una profundidad máxima en la jerarquía de diez se puede conseguir con la siguiente sql:

En este caso obtendremos una fila con su jerarquía por cada hoja del árbol. Todo el conjunto de identificativos obtenidos forman los descendientes. Hay que tener en cuenta que en los resultados un identificativo puede aparecer varias veces y con esta consulta el nodo del que se buscan descedientes está incluido.

Buscar los ascendientes se puede hacer de forma similar:

Con esta sql obtendremos una fila con los identificativos, c1 será el identificativo del nodo superior y c10 el nodo inferior de la jerarquía.

Con esta solución para mover un nodo de un padre a otro en el árbol basta con actualizar el identificativo del nodo padre, es simple y rápido. Sin embargo buscar descendientes y ascendientes es más complejo e ineficiente si la base de datos no soporta queries recursivas (que las bases de datos más importantes, Oracle, SQL Server, PosgreSQL salvo MySQLsoportan y a partir de laversión 5.6 ya lo hace), también puede requerir una segunda query para buscar los datos de los descendientes y ascendientes, con estas solo recuperamos los identificativos.

Conjuntos anidados

Esta solución se basa en que cada nodo de la jerarquía esté numerado, el padre tendrá dos campos el número de menor hijo y el número del mayor hijo, todos los nodos cuyos números estén entre esos dos números son descendientes del nodo padre. La consulta de buscar los nodos descendientes es simple y eficiente.

Buscar los nodos ascendientes también se puede conseguir una sql eficientemente:

La desventaja de esta solución está en el momento que queremos insertar un nuevo nodo en el árbol de la jerarquía o mover un nodo dentro del árbol ya que implica reorganizar los valores de las columnas left y right, puede que de muchas filas y por tanto resultar lento.

Consultas recursivas

Con el soporte de consultas recursivas se puede conseguir la simplicidad de las adjacency list y la eficiencia de los nested sets. El modelo de datos es similar al caso de las Adjacency List con una columna del identificativo padre del nodo.

Para buscar los descendientes de un nodo sería:

Para buscar los nodos ascendientes:

Como comentaba de las bases de datos más importantes de entre Oracle, SQL Server, PostgreSQL y MySQL solo MySQL no lo soporta aunque a partir de laversión 5.6 también lo hace. Dependiendo de si hacemos más consultas que modificaciones y de si queremos complicarnos más con los nested sets deberemos optar por una solución u otra, en cualquier caso optaremos por las queries recursivas si la base de datos lo soporta.

Referencia:
http://en.wikipedia.org/wiki/Hierarchical_query
http://en.wikipedia.org/wiki/Nested_set_model
http://en.wikipedia.org/wiki/Adjacency_list_model

http://vadimtropashko.wordpress.com/2008/08/09/one-more-nested-intervals-vs-adjacency-list-comparison/
http://stackoverflow.com/questions/4048151/what-are-the-options-for-storing-hierarchical-data-in-a-relational-database
http://explainextended.com/2009/09/24/adjacency-list-vs-nested-sets-postgresql/
http://www.postgresql.org/docs/8.4/static/queries-with.html

viernes, 18 de octubre de 2013

Solución al problema de seguridad CSRF en Apache Tapestry

Apache Tapestry
Al desarrollar una aplicación el problema de seguridad XSS (Cross-site scripting) puede afectar a los usuarios de nuestra aplicación. XSS consiste en que la aplicación permite la inyección de código malicioso que posteriormente otros usuarios obtienen al acceder a nuestra aplicación. Se produce porque nuestra aplicación no realiza el escapado correctamente de lo que envía al usuario y porque el usuario confía en lo que obtiene del servidor. Para evitar este problema Apache Tapestry por defecto realiza un escapado de lo que emite al cliente con lo que si no hacemos lo contrario la aplicación estará a salvo de este problema.

Otro problema de seguridad es CSRF (Cross-site request forgery) en el que básicamente un sitio al que se accede devuelve un enlace malicioso que provoca una acción en otro, el atacado. El enlace devuelto puede producir cualquier acción que el sitio atacado permita, el ejemplo que se suele poner es el de un sitio bancario y el intento de hacer una transferencia de la cuenta del usuario que tiene iniciada una sesión en la página de su banco a la cuenta del atacante pero podría ser la realización de un cambio de contraseña a una que conozca el atacante y de esta forma posteriormente este pueda autenticarse con la cuenta de ese usuario en el sitio atacado. En la wikipedia este problema de seguridad está más ampliamente explicado con ejemplos, limitaciones y como prevenirlo. A diferencia de XSS donde el usuario confia en lo que obtiene del servidor en el caso de CSRF es al contrario, el servidor confia en las peticiones del cliente, aunque puedan provenir de un sitio malicioso.

Una solución que suele aplicarse para resolver el problema de CSRF es incluir en los enlaces y formularios un token de seguridad, si el token no se envía o no se corresponde con el token del servidor la petición se considera inválida y no se procesa. Al acceder a una página se genera el token de seguridad y se incluye en todos los enlaces y formularios, este token no será conocido por un a tercera parte y los enlaces maliciosos no serán procesados.

En esta entrada mostraré como solucionar este problema en Tapestry con una combinación de mixin, anotación, advice y objeto de estado de aplicación (SSO), similar a lo explicado en este blog pero con la adición que no solo sirve para formularios sino también para enlaces y el componente BeanEditForm.

Primero veamos el objeto estado de aplicación que contendrá el token (sid) de seguridad, lo generará y lo validará, este objeto de estado de aplicación se guardará a nivel de sesión de modo que el token que se envía en la petición pueda ser validado con el token guardado en este SSO.

El mixin CSRF hará que en los formularios se incluya un campo oculto con el token se seguridad del SSO y en los enlaces se incluya como un parámetro. El nombre del parámetro en ambos casos será t:sid. Este mixin puede ser aplicado a los componentes Form, ActionLink, EventLink y BeanEditForm.

Creamos una anotación para marcar los manejadores de evento y métodos donde queremos que aplique la seguridad CSRF.

Para aplicar la seguridad en los manejadores de evento y métodos marcados con la anotación lo haremos con cierta metaprogramación, con ella comprobaremos que el token del SSO se corresponda con el token enviado por la petición. Esta forma de metaprogramación es lo que en Tapestry se conoce como Advice, la funcionalidad consistirá en si el token de seguridad es correcto se permite la invocación al método protegido, si el token no es correcto se lanza una excepción impidiendo la llamada al método protegido.

Finalmente, debemos modificar el módulo de nuestra aplicación para dar a conocer a Tapestry el Advice para aplicar y comprobar la seguridad con el parámetro t:sid enviado y en el objeto SSO.

Para que en los componentes sea incluido del token de seguridad haremos uso del mixin, es tan simple añadir el atributo t:mixins y el mixin csrf en los elementos a incluir el parámetro t:sid:

Y para proteger los manejadores de evento con la anotación Csrf de la siguiente manera:

Con todo esto podemos resolver el problema de seguridad CSRF de forma muy simple y de forma declarativa con una combinación de mixin y anotaciones, solo son necesarios ¡20! caracteres entre ambos.

Esta es la sección de la aplicación del ejemplo funcionando donde puede probarse el mixin y ver la diferencia del comportamiento sin el mixin aplicado.

Cuando pulsamos en el enlace que envía un t:sid inválido mediante un petición ajax provocará el siguiente informe de error con un mensaje descriptivo de lo que ha ocurrido.


En las siguientes imágenes puede verse el parámetro t:sid que se añade tanto a un formulario como a un enlace cuando le aplicamos el mixin csrf.
Parámetro t:sid en un formulario

Parámetro t:sid en un enlace

¿Ya tienes en cuenta el problema de seguridad CSRF en tus aplicaciones web? ¿Con el framework que uses aplicar una solución es tan simple como esta?

De esta entrada aparte de resolver el problema de seguridad CSRF quiero destacar con se realiza la metaprogramación en Apache Tapestry con las clases Plastic de Tapestry en la clase CsrfWorker.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes como este en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.


Referencia:
Cross-Site Request Forgery (CSRF)
Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet
Apache Tapestry - CSRF Protection - First Prototype
http://wiki.apache.org/tapestry/Tapestry5CSRF
https://code.google.com/p/gsoc2011-csrf-protection

viernes, 11 de octubre de 2013

Solución al doble envío de peticiones en aplicaciones web

Apache Tapestry
Las aplicaciones web pueden recibir información del usuario a través de formularios o en los parámetros de los enlaces. Los formularios o enlaces pueden desencadenar en la aplicación diversas acciones. Dada la naturaleza de las aplicaciones web en ciertas ocasiones la latencia de la red o el tiempo que toma procesar la petición un usuario puede tener la oportunidad de hacer clic varias veces en un botón o enlace también cuando ve que tarda mucho en obtener la respuesta o simplemente por su desconocimiento al estar acostumbrado a hacer doble clic al trabajar con otras aplicaciones o la interfaz de su sistema operativo. En ocasiones el problema puede producirse también haciendo un refrescar con el botón del navegador si no se hace un redirect después del envío del formulario (Tapestry nos evita esto ya que hace un redirect después de cada envío de un formulario o acción, lo que se conoce como redirect after post o post/redirect/get).

El caso del doble o N-clic puede ser un problema, imagina una aplicación que borra un registro de la base de datos o una aplicación que realiza el cobro de una tarjeta de crédito. Si el usuario tienen la oportunidad de hacer doble clic en el botón o enlace enviándo dos peticiones al servidor lo más probable es que solo una de ellas funcione, la segunda petición puede producir una excepción en el servidor o peor aún dependiendo de la acción un efecto indeseado. ¿Eres consciente y tienes en cuenta que puede pasar en tu aplicación si se da esta situación?

Una de las formas de evitar este problema en cierta medida es desactivando el botón o enlace una vez que se ha pulsado y el formulario se envía o se realiza la petición. Podemos hacer uso de un código javascript que en el momento de pulsar el botón o enlace impida que desencadene su acción por segunda vez, por ejemplo desactivándolo.

En Tapestry podemos usar un mixin para reutilizar este código en todos los sitios que necesitemos de una forma muy sencilla. En el contexto de Tapestry un mixin es un componente que no se usa de forma individual sino que se usa junto a otro componente y que añade cierta funcionalidad al componente asociado. En la aplicación de demostración JumpStart se puede ver el código del componente mixin ClickOnce que en ciertos escenarios puede evitar el problema del N-clic. Sin embargo, la solución del mixin ClickOnce es válido solo para peticiones no ajax ya que una vez que el botón o enlace es pulsado se desactiva completamente, en una petición ajax el botón debería volverse a activar una vez que la petición Ajax termina.

A continuación mostraré el código de un mixin que mejora el ClickOnce resolviendo el problema N-clic tanto para peticiones ajax como no ajax. Por una parte tendremos el código Java asociado al mixin.

Y el javascript como un módulo de RequireJS que produce la desactivación del enlace o botón en el cliente una vez que es pulsado y monitoriza las peticiones Ajax para bloquear una segunda petición al servidor.

Este código javascript podría ser aprovechado después de haberlo modificado ligeramente para ser usado con otro framework de aplicaciones.

Una vez desarrollado el mixin podemos usarlo en un botón o enlace de la siguiente forma, a partir de este momento dar solución a este problema nos cuesta 20 caracteres en cada enlace o botón, los necesarios para aplicar el mixin con el atributo t:mixins, pero no solo eso, más importante aún que el número de caracteres, aplicarlos no nos ofusca el código:

Esta solución funciona en el lado del cliente, con javascript desactivado o un usuario malicioso podría producir el doble envío del formularios de forma intencionada. Otra solución en el lado del servidor que se suele utilizar es un token de un solo uso en la que solo se procesa el formulario con el token correcto, el token se envía al cliente en un campo oculto y se guarda en sesión, una vez que el formulario se envía al servidor se comprueba que el token sea el guardado en sesión, esta solución realiza la comprobación en el servidor pero requiere del uso de la sesión para guardar el token. La solución mediante el token puede evitar el problema CSRF donde una petición maliciosa puede realizar una acción sin el consentimiento del usuario. En otra entrada explicaré como solucionar el problema CSRF con el framework Tapestry.

Esta es la sección de la aplicación del ejemplo funcionando donde puede probarse el mixin y ver la diferencia del comportamiento sin el mixin aplicado.

En este ejemplo también puede verse como con tapestry se pueden actualizar varias zonas (la zona de la cuenta) de una página de forma simultánea de una página web con una única petición Ajax.

Si te ha parecido interesante esta entrada puedes descargar el libro PlugIn Tapestry en el que explico más en detalle como desarrollar aplicaciones web en Tapestry y en el que descubrirás como resolver problemas comunes como este en las aplicaciones web de una forma tan buena como esta.

Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip.

Referencia:
Libro PlugIn Tapestry
http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/creatingmixins1
http://stackoverflow.com/questions/17830171/mixins-in-tapestry5

viernes, 4 de octubre de 2013

Archivo de log de sentencias SQL en MySQL o MariaDB

MySQL
MariaDB
Muchas aplicaciones utilizan para su capa de persistencia un framework ORM que abstraen al programador de la base de datos, de las peculiaridades de cada una ellas y de las sentencias SQL que se envían a la base de datos para realizar las operaciones de recuperación, actualización, borrado y búsqueda. En Java el ORM suele ser Hibernate, en Symphony es Doctrine, en Ruby on Rails es ActiveRecord, en Django es Models pero en definitiva todas sirven para el mismo propósito que es darnos un marco de trabajo más similar a un lenguaje orientado a objetos y hacernos olvidar el lenguaje SQL que hay que utilizar para comunicarse con cualquier base de datos relacional.

Sin embargo, esa facilidad que dan los ORM puede hacer que las SQL que realmente se envían a la base de datos no sean eficientes o no sepamos el número exacto de las que se están enviando (problema N+1) lo que puede hacer que ciertas funcionalidades de una aplicación sean lentas y poco eficientes con un volumen de datos grande.

En MySQL y MariaDB se puede obtener un archivo de log con todas las sentencias que se están enviando. Además también se puede obtener un log con aquellas sentencias que tardan en ejecutarse más tiempo de que estimemos como lento para una sentencia. Para obtener estos archivos de log debemos modificar la configuración de MySQL o de MariaDB que en Linux está en el archivo /etc/mysq/my.cnf. Al final de la sección [mysqld] debemos añadir las siguiente linea para obtener un archivo con todas las sentencias:

Y lo siguiente para obtener un archivo con solo las sentencias lentas, en el caso del ejemplo las que tardan en ejecutarse más de un segundo:

Para que MySQL pueda escribir sobre estos archivos debemos crear los archivos y asignarle permisos al usuario con el que se ejecuta MySQL con:

Una vez modificada la configuración y creados los archivos de log con los permisos adecuados debemos reiniciar el servicio de MySQL.
Estos los nos ayudarán a identificar sitios con el problema de N+1 al acceder a una relación 1 a N entre dos objetos o si es necesario que creemos algún índice para hacer más rápidas ciertas consultas si vemos que algunas están saliendo en el log de sentencias lentas.

Referencia:
http://www.redips.net/mysql/query-logging/
http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html
http://stackoverflow.com/questions/6614429/logging-mysql-query-on-ubuntu

viernes, 27 de septiembre de 2013

Trazas en un gsp de Grails

Grails
Disponer de información para tratar de averiguar la causa de un problema es vital para poder resolverlo rápidamente. Para ello existen los sistemas y librerías de trazas que permiten a la aplicación sacar mensajes a un archivo para su consulta posterior ya sea en Java, Javascript o seguro que otros lenguajes.

En el caso de Grails inyecta en varias entidades como controladores, servicios y clases de dominio el objeto log con el que se pueden emitir las trazas con el nivel que deseemos.

Sin embargo, a veces nos puede resultar interesante también sacar alguna traza en los gsp para conocer que es lo que se ha emitido, especialmente si se trantan de gsp que contienen lógica de negocio con etiquetas g:if especialmente complejas. Tener mucha lógica en las vistas es una práctica no recomendada para evitar el código espagueti en los gsp que en el mantenimiento puede causarnos problemas al posiblemente tener esa lógica duplicada en varias zonas diferentes de la aplicación. Los frameworks que usan un sistema de plantillas donde por un lado están los datos y por otro la plantilla sin una posibilidad propia («built-in») de extraer esa lógica a una entidad externa suele ser habitual. Esto nos puede obligar a precalcular todas esas condiciones y pasarlas a la visa como datos lo que nos exige conocer previamente en el controlador exactamente que datos necesita la vista y mantener el código de dos archivos sincronizados o crear métodos con esa lógica en los objetos que le pasamos a la vista como podrían ser en las entidades persistentes de dominio.

Una forma de emitir trazas desde un gsp es incluir un scriptlet que obtenga un logger y posteriormente hacer log.debug. Pero si hacemos esto en muchos gsp y de forma habitual es mejor hacerlo con un tag ya que el código de los gsp nos quedará más limpio y será un poco más sencillo además de tener centralizado en un único sitio el tratamiento de los logs de todos los gsp. Ese tag necesitará recibir el nivel de la traza y el mensaje de la traza al menos. Podría ser como lo siguiente:

Su uso en un gsp sería:

Y este sería el caso para el framework grails y su parte de visualización con gsp, para otros frameworks que probablemente tengan otro sistema para la parte de la vista nos puede ser útil una solución con similar funcionalidad.

viernes, 20 de septiembre de 2013

Archivos properties con codificación UTF-8

Java
En Java los archivos Properties que se cargan con la clase ResourceBundle utilizados comúnmente para realizar la internacionalización y la localización a varios idiomas en una aplicación Java por defecto usan la codificación de caracteres ISO-8859-1 (salvo que usemos un framework o una librería lo haga de otra forma). Los caracteres que no pertenezcan al ISO-8859-1 deben ser escapados, por ejemplo \u20AC para el símbolo del euro (€). Esto hace que si tenemos una aplicación que trabaja con caracteres en varios idiomas tengamos unos ficheros properties con un montón de caracteres de escape que impide su legibilidad al momento de escribirlos o nos obliga a usar el comando native2ascii lo que nos produce también archivos poco legibles.

La clase ResourceBundle permite cargar archivos properties según un Locale pero como digo los carga con la codificación ISO-8859-1 y esto es un problema para los locales como el chino donde casi todos los caracteres deben ser escapados. Si queremos tener archivos más legibles y sin necesidad de escapar los caracteres debemos extender la clase ResourceBundle.Control y redefinirla un poco para que cargue los properties en UTF-8. La implementación sería la siguiente:

El código anterior es parte de la clase EncodingControl donde está redefinido el método newBundle. La magia está en la siguiente linea, donde al InputStreamReader se le indica la codificación de caracteres:

Su uso para cargar los ResourceBundle sería:

Y el programa completo en el que puede verse una carga de un archivo properties con codificación ISO-8859-1 y otro con codificación UTF-8:

El resultado sería el siguiente:

El código fuente del ejemplo completo lo puedes encontrar en mi repositorio de GitHub.

Referencia:
http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle

viernes, 6 de septiembre de 2013

Como optimizar módulos de RequireJS y archivos Javascript (II)

Require.js
Aunque pueda parecer que no y en muchos casos no se tenga en cuenta la diferencia que puede haber entre una aplicación web no optimizada y optimizada puede ser significativa en varios aspectos.

Marionette
¿Por que en algunos casos es importante optimizar la aplicación? Uno de los motivos es conseguir una mejor experiencia de usuario haciendo que la página le cargue más rápido. Una página que tarde en cargar demasiado puede significar pérdida de visitas y si se trata de una página de comercio electrónico de clientes y compras. Si un flujo importante de usuarios de una página procede de las búsquedas la velocidad de carga de la página es importante ya que es una de las variables que tiene muy en cuenta el algoritmo de Google para establecer el ranking de los resultados, reducir el tiempo de carga puede significar aparecer antes en los resultados de la búsqueda y esto significa más clics en nuestro resultado, más visitas y nuevamente más potenciales clientes y compras. Y en caso de que no estemos desarrollando una aplicación accesible desde internet sino una aplicación para una empresa o administración publica hacer que cargue más rápido puede suponer una mayor satisfacción de los usuarios y una aplicación más eficiente (con una menor carga para el servidor, con la posibilidad de soportar más usuarios o con menor necesidad de hardware).

La velocidad de carga de una página se ve afectada por varios elementos entre ellos el número de peticiones que hace la página para recuperar los recursos (imáges, css, fuentes, javascript) y el peso de esos archivos. Cuantas menos peticiones hagamos y menos peso de los archivos notaremos una significativa reducción de tiempo de carga de la aplicación. El tamaño de los archivos no afecta tanto a dispositivos que acceden por líneas de banda ancha de varios megas pero hay muchos dispositivos móviles como los teléfonos inteligentes que hace uso de conexiones de datos móviles, las velocidades son más modestas en estos y muchos usuarios tienen cuotas de megas descargados, es de agradecer tenerlos en cuenta también.

En esta entrada usaré el Ejemplo de la lista de tareas con Marionette, un ejemplo sencillo pero bastante completo que usa RequireJS, Backbone y Marionette, jQuery, Mustache, el plugin i18n de RequireJS para internacionalizar los textos de las plantillas, el plugin text para externalizar del html las plantillas de Mustache. Me centraré en como optimizar toda esa cantidad importante de código javascript que necesita el ejemplo cargar en el navegador del usuario. El estado inicial de la aplicación es de 28 peticiones, un peso de 737 KiB utilizando las versiones no minimizadas de las librerías javascript y un tiempo de carga de 261 ms funcionando en local, si tomásemos medidas de tiempo pero funcionando en internet la latencia haría que el tiempo de carga fuese aún mayor. En la imagen se puden apreciar estos datos en la parte inferior de las herramientas para desarrolladores de Chrome.

Para minimizar los archivos de javascript y reducir su peso y también para agregarlos en unos solo que evite muchas peticiones usaré el optimizador de RequireJS (r.js). Esta utilidad ya la que expliqué en la Optimización de módulos RequireJS y archivos javascript del ejemplo más sencillo de la Introducción a Backbone pero ahora lo aplicaré con este ejemplo de Marionette que es bastante más complejo.

Para usar r.js necesitaremos instalar previamente node.js (pacman -S nodejs en Arch Linux). Después deberemos crear el archivo de configuración para r.js, en el que básicamente indicamos la localización de los archivos a optimizar (baseUrl), el nombre del módulo de la aplicación (main), el archivo de resultado agregado y minimizado (out) y la misma configuración shim que utilizaríamos en la aplicación (shim).

Ejecutando este archivo build.js con r.js a través de node obtendremos el archivo agregado y minimizado main.min.js que será el único archivo de módulo que necesitará cargar nuestra aplicación:



Para usar este nuevo módulo deberemos cambiar el nombre del archivo de main.min.js a main.js o cambiar el nombre del módulo del archivo generado de main a main-min (al final del archivo generado, en el define) si hacemos esto último deberemos especificar este nuevo módulo en el atributo data-main de la etiqueta script que cargar el archivo require.js (en Index.tml). En el archivo parece que a pesar de optimizarse se siguen generando algunos comentarios si queremos optimizarlo completamente podemos eliminarlos. El resultado es que cargando este módulo optimizado ahora la aplicación hará tan solo 14 peticiones, la mitad de peticiones, necesitará descargar 403 KiB y se cargará en 245 ms. La diferencia de tiempo no es significativa por hacer las pruebas en local, como decía la latencia de internet o el ancho de banda de un móvil probablemente haría que el tiempo fuese bastante mayor.

Finalmente si queremos automatizar este comando con Gradle podemos hacerlo añadiendo lo siguiente en nuestro archivo de construcción:

Optimizar el javascript y los módulos de RequireJS solo es una de las cosas que podemos hacer para optimizar nuestra aplicación, hay otras muchas cosas que podemos hacer como se comentan en los siguientes enlaces, además si es el caso también deberíamos tener en cuenta el SEO:

https://developers.google.com/speed/
https://developers.google.com/speed/docs/best-practices/rules_intro?hl=nl
http://developers.google.com/speed/pagespeed/insights/
http://guestpostlabs.com/complete-guide-to-website-speed-optimization/
http://zettalab.com.my/website-speed-optimization/

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace. Referencia:
Introducción y ejemplo de Backbone.js
Ejemplo lista de tareas con Backbone, RESTEasy y Tapestry
Optimizar módulos de RequireJS y archivos Javascript

viernes, 30 de agosto de 2013

Ejemplo lista de tareas con Marionette

Marionette
Como comentaba en el ejemplo de una aplicación de una lista de tareas en una aplicación javascript Backbone es una herramienta que nos puede ayudar mucho a evitar que el código se nos convierta en difícil de manejar facilitándonos como estructurarlo con los modelos, colecciones y vistas y permitiéndonos separar el modelo de la vista actualizando estas últimas a través de los eventos que produce el modelo y escuchados en las vistas.

Backbone es una herramienta que nos da bastante libertad en cuanto a como queremos hacer las cosas y de lo que ofrece podemos usar solo lo que queramos. En algunos casos podemos considerar que Backbone ya es de por si una solución suficiente pero pero en otros podemos necesitar algo que nos facilite la tarea un poco más, de hecho hay muchas herramientas de terceros que proporciona multitud de funcionalidades adicionales sobre Backbone.

Usando Backbone por si solo a medida que vayamos haciendo varias aplicaciones nos daremos cuenta que debemos escribir código que empezaremos a considerar repetitivo, tampoco nos ayudará en desasociar los modelos de las vistas cuando eliminemos estas de la aplicación y si no lo hacemos correctamente tendremos fugas de memoria o vistas zombies que siguen escuchando eventos de los modelos cuando esperamos que se hubiesen destruido, también debemos encargarnos de gestionar donde deben visualizarse las vistas. Marionette es una de esas herramientas que nos puede ayudar a facilitarnos las tareas anteriores que en Backbone debemos hacer manualmente, además de ofrecernos algunas otras funcionalidades adicionales, pero también sin obligarnos a usar lo que no queramos siguiendo la misma filosofía de Backbone.

En esta entrada implementaré el mismo ejemplo de la lista de tareas que hice con Backbone pero esta vez implementado con Marionette aunque revisándolo incluiré un par de funcionalidades adicionales como externalizar del html las plantillas de las vistas y como internacionalizar los textos que aparecen en ellas si necesitamos soportar múltiples idiomas. Para ello utilizaré una de las versiones «bundled» que ofrece Marionette y un par de dependencias que necesita (wreq y babysiter).

El modelo y la colección de tareas es muy parecido aunque se han simplificado un poco al moverse el moverse el código que convertía el modelo a json a la vista, donde Marionette ofrece y llama al método serializeData cuando necesita y posteriormente el método render con los datos obtenidos, en el método render en definitiva se usa Mustache para producir el html de la vista. En realidad, el convertir el modelo al json que necesita a la vista está mejor colocado en la vista, ya que la vista es la que conoce los datos que necesita mostrar del modelo. Otra cosa muy útil que nos ofrece Marionette es la sección con los elementos ui de las vistas, esto evitará que tengamos los sectores de jquery repartidos por varios sitios de la vista y hará el código más simple y legible. Las secciones de las vistas modelEvents y collectionEvents sirven para los mismo que hacíamos en el método initialize con .on o .listenTo de Backbone.

Los objetos Marionette.ItemView sirven para visuaslizar un modelo (una tarea) y Marionette.CollectionView sirve para mostrar una colección de elementos (una lista de tareas). El objeto Marionette.Layout se utiliza para componer una vista con varias secciones (tareas y estado) donde podremos colocar las vistas de la aplicación, aparte de estas secciones un Layout es como una vista Marionette.ItemView con su plantilla. Con Marionette.Controller construiremos una clase que podemos utilizar para ofrecer la interfaz de la aplicación al exterior del módulo con únicamente los métodos necesarios (sin initialize, render y los métodos onXxx del mismo ejemplo con Backbone). Y hasta aquí, son los cambios más importantes en cuanto al cambio de Backbone a Marionette.

A continuación el código del módulo tareas que contiene la mayor parte del código javascript de la aplicación y el módulo main que no cambia en nada.

Para externalizar las plantillas del html podemos usar el plugin de RequireJS text que permite cargar el contenido de archivos como dependencias de un módulo tal como sucede como los archivos javascript. Y para internacionalizar las cadenas de las plantillas el plugin i18n. Los literales de cada idioma se definen en un archivo distinto, en el caso de esta aplicación solo he proporcionado uno, para el idioma inglés en la carperta src/main/webapp/js/i18n/nls/en, cada uno de estos archivos contiene una clave/valor, algunos de los cuales son una plantilla de Mustache para sustituir las variables como en «{{completadas}} tareas de {{total}} completadas». A continuación el código de un plantilla de Mustache que se carga de forma externalizada y el archivo con los literales que se utilizarán en la localización por defecto. Estos dos plugins de RequireJS probablemente nos sean necesarios y útiles en un ejemplo real.

El idioma de la aplicación se especifica en el archivo que genera el html de la página.

La aplicación tiene el siguiente aspecto:


Para terminar y como prólogo de la siguiente entrada un detalle que comentaré es la cantidad de archivos que se cargan para este ejemplo y eso que no es excesivamente complejo, en total al cargar el ejemplo se hacen 31 peticiones, unas cuantas son de los estilos, fuentes e imágenes pero la mitad son de archivos js y plantillas mustache. En la siguiente entrada explicaré como optimizarlo para conseguir reducir esas 31 peticiones a 13, con una diferencia importante de tiempo de carga y esto en local (probablemente puesto el ejemplo en internet la latencia y la diferencia sería mayor), también conseguiremos reducir algunos kilobytes de peso a la página. La optimización será similar a lo que explique en la Optimización de módulos RequireJS y archivos javascript del ejemplo más sencillo de la Introducción a Backbone pero aplicado a este ejemplo de Marionette que es bastante más complejo. En el código fuente puede verse también como ejecutar pruebas unitarias usando Grunt, Jasmine, Sinon y como integrarlo con Gradle pero la expicación de esto será tema para otra entrada.

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Patrón de diseño MVC del lado cliente con Backbone.js
Introducción y ejemplo de Backbone.js
Ejemplo de pruebas unitarias en javascript con Jasmine y Sinon
Backbone
Marionette

sábado, 24 de agosto de 2013

Ejemplo del patrón de diseño State

Java
Un patrón de diseño aplicado adecuadamente para resolver un problema puede ayudar enormemente a simplificar el código y facilitar el mantenimiento. Si tenemos un código que es difícil de mantener y entender, hay código duplicado y no tiene ninguna organización puede que aplicar un patrón de diseño nos resuelva el problema en gran parte.

Hace ya un tiempo comente cuales son los principales patrones de diseño y hice una entrada con un ejemplo del patrón de diseño Command. En esta entrada pondré un ejemplo del patrón de diseño State.

El patrón de diseño State nos puede ser de mucha utilidad en los casos que por ejemplo una entidad tenga asociado un grafo de estados con transiciones permitidas y no permitidas entre algunos estados. En función del estado, sus datos y la transición la entidad puede comportarse de forma diferente. Por ejemplo, supongamos que tenemos una entidad Compra que a lo largo de su vida en la aplicación pasa por diferentes estados:
  • creada: la compra se acaba de crear.
  • en espera: se ha hecho una compra y se está esperando que el pago sea correcto.
  • verificada: el pago es correcto y se está esperando a enviar el producto.
  • cancelada: la compra se ha cancelado porque el usuario no quiere ya el producto, no hay existencias u otro motivo.
  • enviada: el pedido ha sido enviado.
Y tiene diferentes transiciones como:
  • comprar: la compra pasa de creada a en espera de verificarla.
  • verificar: la compra pasa de en espera a verificada y esperando a enviarse.
  • cancelar: la compra se puede cancelar excepto una vez que ya se ha enviado.
  • enviar: la compra se envía al usuario y ya no puede cancelarse.
Diagrama de estados

Si diseñamos este flujo de estados sin el patrón State probablemente acabemos con una clase con un montón de condiciones y métodos de bastantes líneas sin una organización clara a simple vista. Para evitarlo aplicaremos el patrón State a este pequeño flujo de estados. En cuanto a código este patrón se basa en dos ideas:
  • Cada estado será representado una clase.
  • Cada una de estas clases contendrá un método por cada posible transición.
Y estas dos simples ideas son suficientes para guiar la tarea de codificación. Por lo tanto tendremos los siguientes clases que representarán a los estados: CreadaCompraState, EnEsperaCompraState, VerificadaCompraState, CanceladaCompraState y EnvidaCompraState.


Según el diagrama de estados y transiciones no todas las transiciones son posibles, una compra en espera no puede enviarse. Pero en el código estamos haciendo que todos los estados tengan todos los métodos que representan todas las transiciones, la forma de hacer en el código que una transición no sea posible para un determinado estado es lanzando una excepción en su correspondiente método, el método enviar del estado en espera, lanzará una excepción ya que es este estado aún la compra no puede enviarse. La clase abstracta AbstractState implementará la interfaz CompraState y lanzará una excepción en todos los métodos, las clases que extiendan de esta podrán redefinir los métodos que necesiten utilizando la propiedad de la programación orientada a objetos del polimorfismo, esta clase abstracta nos permitirá implementar en cada clase de estado únicamente los métodos con las transiciones válidas. Las clases nos podrían quedar de la siguiente forma:

Para que los métodos puedan acceder y manipular los datos de la compra se les pasa como parámetro en el constructor. La factoría CompraStateFactory encapsula la lógica para construir cada uno de los estados. La implementación de cada uno de los estado podría ser la siguiente.

Finalmente, la clase Compra podría ser de la siguiente forma:


El patrón State puede facilitarnos bastante la vida como programadores pero si el diagrama de estados fuese más complejo, con mucha lógica de negocio y el flujo dependiense de información independiente de la compra quizá deberíamos evaluar su si un motor de procesos (BPMS) como Activiti y un sistema de reglas de negocio (BRMS) como Drools sería más adecuado.

El código fuente completo de ejemplo los puedes obtener de mi repositorio de github con los siguiente comandos:

Referencia:
Patrones de diseño en la programación orientada a objetos
Ejemplo del patrón de diseño Command y programación concurrente en Java
Ejemplo del patrón de diseño No Operation

viernes, 16 de agosto de 2013

Pruebas unitarias de código que accede a base de datos

Hibernate
Una de las dificultades que nos solemos encontrar a la hora de hacer pruebas unitarias es como probar el código que accede a la base de datos. El problema es que ese código necesita de una base de datos para ejecutarse, si se usa una base de datos como MySQL o PosgreSQL más que una prueba unitaria puede considerarse una prueba de integración y las pruebas pasan a depender de ese sistema externo con lo que las pruebas no son autónomas.

La base de datos H2 es una base de datos que puede ser embebida en una aplicación. Esta característica hace que pueda servir como base de datos contra la que lanzar los teses sin necesidad de una base de datos externa, además puede ejecutarse en memoria y sin comunicación de red lo que hace que sea muy rápida y los teses también. Tampoco es una solución perfecta ya que H2 puede tener un comportamiento diferente de la base de datos real pero en la mayoría de los casos nos servirá perfectamente.

Siguiendo los artículos anteriores en los que explicaba como acceder a una base de datos en una aplicación Java «standalone» y como hacer búsquedas en entidades de comino usando sin utilizar likes veamos como sería hacer una prueba unitaria de ese código que accede a la base de datos usando JUnit.

El método beforeClass inicializa la persistencia y crea el DAO. El método before borra los datos que haya creado un test anterior y crear los datos de prueba que una prueba puede esperar que existan, en este caso se trata de un único producto. Las pruebas consisten en probar el método findAll y search del DAO (el método removeAll puede considerarse probado en el before aunque podría crearse un caso de prueba específico):

En las pruebas unitarias al código que use el DAO puede proporcionársele un «stub» de este haciendo que devuelva los datos que necesitemos y sin necesidad de una base de datos como H2 pero para probar el DAO hay que disponer de una base de datos. Como es código que también puede contener fallos es bueno que también esté cubierto con algunas pruebas. Con Hibernate todo será más sencillo ya que con este además de abstraernos de la base de datos específica puede crear el esquema con las tablas y campos a partir del modelo de forma que antes de pasar los teses no necesitemos lanzar un script con sentencias SQL para crear las tablas.

Usar H2 como la base de datos contra que lanzar las pruebas unitarias es una solución imperfecta ya que idealmente la base de datos debería ser igual a la base de datos que vaya a usar la aplicación real (probablemente MySQL o PosgreSQL). H2 tiene la ventaja de que los teses se ejecutarán más rápido que con un sistema real externo y que las pruebas son más autónomas ya que no depende de ese sistema externo, aún así si hacemos uso de elementos nativos de la base de datos y queremos que queden cubiertos con pruebas no nos quedará más remedio que disponer de una base de datos «más real» que H2 para ellas aunque como decía estas pasarán a ser más de integración que unitarias.

Como el resto de ejemplos que escribo en el blog el código fuente lo puedes encontrar en mi repositorio de GitHub. Para probar este código en tu equipo basta con ejecutar:

Referencia:
Código fuente acceso a base de datos con Hibernate y JPA http://stackoverflow.com/questions/82949/before-and-after-suite-execution-hook-in-junit-4-x

viernes, 9 de agosto de 2013

Búsquedas de texto completo en objetos de dominio

Hibernate
Si hace un tiempo hablaba de un problema muy común que nos encontramos al desarrollar una aplicación como los es internacionalizar los textos de algunos campos de una entidad de dominio, el hacer búsquedas de texto completo sobre esos campos más allá del like que nos ofrece el lenguaje SQL de las base de datos también es un problema a resolver.

La primera solución que se nos puede ocurrir es hacer las búsquedas empleando el like del lenguaje SQL de la base de datos relacional que usemos. Sin embargo, el like de SQL tiene varias limitaciones y además es lento, supone una carga para la base de datos y las coincidencias son muy limitadas no teniendo en consideración peculiaridades del idioma como tildes y aproximaciones. Para tratar de resolver estos problemas podemos usar la librería Hibernate Search que a partir de las clases de dominio y de las propiedades sobre las que queramos hacer búsquedas creará un indice de Lucene para realizar búsquedas más rápidamente y con mejores resultados.

Hibernate Search
Con Hibernate Search que se apoya en Lucene podemos obtener resultados que son aproximaciones a la palabra búsqueda, por ejemplo, si buscamos «refactor» podemos obtener coincidencias para las palabras «refactors», «refactored» y «refactoring» en el lenguaje inglés. Cada lenguaje tiene sus propias reglas de análisis para buscar estas aproximaciones y hay analizadores para la mayoría de lenguajes. Además, podemos obtener una aproximación de las coincidencias encontradas totales al estilo de como hace Google.

Continuando el ejemplo de como usar Hibernate en una aplicación «standalone» vamos a ver que hay que hacer para crear el índice y como realizar una búsqueda empleando Hibernate Search.

SQL
Otra alternativa a Hibernate Search es si la base de datos soporta «full text search», es decir, el motor de la base de datos soporta en la sintaxis de las sentencias SQL búsquedas de texto completo. En MySQL es posible pero hasta la versión 5.5 solo si la tabla está definida con MyISAM aunque a partir de la versión 5.6 es posible hacerlo con InnoDB que es el modelo de almacenamiento recomendado. La sintaxis de la sentencia SQL para MySQL sería:

En PostgreSQL la sintaxis «full text search» es diferente:


Aunque con soluciones específicas del motor de la base de datos como esta perdemos la abstracción de la base de datos que proporciona Hibernate nos evitamos el tener que mantener el índice de Lucene con Hibernate Search.

Elasticsearch
Otra posibilidad muy interesante y tan buena o mejor que las anteriores es utilizar elasticsearch aunque al igual que con Hibernate Search debamos mantener e índice y los datos sincronizados pero eso probablemente sea tema para otra entrada :).

Referencia:
Código fuente búsqueda con Hibernate Search
Internacionalización (i18n) de campos con Hibernate
http://wiki.apache.org/solr/LanguageAnalysis
http://eraunatonteria.wordpress.com/tag/full-text-search/
http://dev.mysql.com/doc/refman/5.0/es/fulltext-search.html