Archivo de la categoría: Java

Charla en MadridJUG/Madrid GUG sobre tipos algebraicos en Java 21

El pasado 24 de octubre dí una charla sobre el soporte completo que se ha dado en Java 21 a los tipos algebraicos. Estuvo muy bien, sobre todo por el debate que se estableció durante la charla y en el networking posterior.

Diapositivas presentación: Tipos algebraicos en Java 21

El repositorio de código:

  https://github.com/logicaalternativa/algebraictypes

y también el video del directo de la charla

Charla Commit Conf 2023 sobre programación funcional y patrones funcionales

El pasado 21 de abril di una charla sobre programación reactiva y como tener conocimiento de los patrones funcionales pueden ayudar a entender mejor este tipo de programación.

En la charla también introduzco el concepto de DSL (Domain Specific Language) que permiten de una manera real abstraer nuestro código de la tecnología escogida.

En otro orden de cosas, para mí fue un honor que la organización del Commit Conf confiara en mí para ser ponente.

Aquí están las diapositivas de la presentación

Presentación Commit Conf 2023Diapositivas presentación: Programación reactiva y patrones funcionales

y el vídeo de la charla

Futuros y promesas,… y también monadas. Implementando el patrón

«Los modelos NIO no bloqueantes y la programación asíncrona y reactiva son paradigmas que poco a poco van adoptándose y utilizando más

Los modelos NIO no bloqueantes y la programación asíncrona y reactiva son paradigmas que poco a poco van adoptándose y utilizando más. No creo que diga una tontería al afirmar que muy probablemente serán la norma en un futuro cercano. La razón es clara: aunque no se obtiene un rendimiento mejor que los modelos tradicionales sincrónicos, si son modelos mucho más eficientes. Obtienen el mismo rendimiento con menos recursos al tener un mejor control de los hilos, uno de los recursos más preciados en un sistema operativo.

Futuros y promesas

Futuros y promesas

Para poder articular una programación asíncrona y reactiva es necesario utilizar patrones adaptados a este tipo de programación. Puedes utilizar el patrón observable o las señales,  pero casi podríamos decir que tu camino te llevará irremisiblemente al patrón futuro en cuando tienes que integrar varios resultados asíncronos. Si además nuestra implementación del patrón futuros-promesas cumple con las propiedades de las monadas se nos abre un mudo de posibilidades. Con la programación funcional, la composición de futuros se podrá hacer de una manera elegante obteniendo un código más legible.

Esto permite realizar DSL’s (Domain Specific Language) y separar la lógica de negocio de los efectos de lado. Por ahora “… ahí lo dejo”; prefiero no perder foco en el objetivo de este artículo, pero en mi mente esta tratar todo esto en una nueva reseña. En este artículo entraré a desarrollar todos estos nuevos conceptos intentando desmitificarlos, porque al principio todo lo de “Futuros”, “Promesas” y “Mónadas” puede que suene “muy místico”. Lo haré apoyado en mi propia implementación del patrón Futuros y promesas que está disponible en mi GitHub.

[Logo GitHub] AlternativeFuture

La implementación está basada “fuertemente” en el Api de Scala de futuros y sólo recordar que Akka en su versión de Java la exporta directamente y que además los futuros de Scala son también monadas. Cuando digo que me apoyo en el Api de Scala me refiero a seguir la definición de su contrato, de hecho, no me interesaba el código fuente y si hacer el ejercicio de, a partir de su interfaz, realizar mi propia implementación en Java. El código que podéis ver y utilizar es todo mio. Hecha esta aclaración es el momento de empezar a entrar en faena.

Intentaré hacer un acercamiento de dentro a fuera. Primero pondré el foco en las ideas principales para ir después abriendo el zoom y conseguir tener la imagen completa.

Futuros

«¿Qué es un futuro?» Pongámonos en contexto. Imaginemos dos procesos: uno será el principal que llamará a un método que devuelve un futuro de un valor. El otro será el que calcule realmente el valor de manera asíncrona ejecutado en un segundo plano con respecto al principal. Voy a poner un ejemplo para hacerlo más didáctico. Ana (el hilo A, el principal) le dice a Bartolo (el hilo B) que haga la colada (llamada al método)

Llamada asíncrona

1. Llamada asíncrona

El proceso principal obtiene un futuro como resultado de llamar a un método que se lanzará en segundo plano gracias al hilo B. En el ejemplo Bartolo manda una nota (representa el futuro) a Ana que le permitirá apuntar lo  que se quiere que se haga con la colada cuando haya terminado Bartolo. El hilo A no queda a la espera del resultado de la acción ejecutada por el hilo B y queda liberado para realizar otras operaciones. En el ejemplo Ana no espera a que Bartolo termine y  puede seguir haciendo otras tareas.

2. Se devuelve un futuro

2. Se devuelve un futuro

Este futuro es en realidad un artefacto que permite asignar, desde el proceso principal una función callback. En el siguiente paso, Ana decidirá que es lo que quiere hacer cuando termine la colada, es decir, asignará la función callback que se ejecutará cuando se obtenga el resultado del segundo proceso ejecutado por Bartolo.

Asignar callback

3. Asignar callback

Cuando, gracias al segundo proceso, se haya calculado finalmente el valor, se ejecutará la función de regreso al que se le pasará como argumento el valor final obtenido. En el ejemplo tenemos la función «planchar la ropa» y el resultado del proceso: «la ropa lavada».

Resultado del futuro

4. Resultado del futuro

Contextos de ejecución

La ejecución de las funciones callback con el valor final como argumento se hará dentro de lo que se llama un contexto de ejecución. Este no es más que un pool de hilos que permite independizar la ejecución de la función con el valor final tanto del hilo principal como del segundo proceso, es decir, se ejecutarán en un tercer hilo “reutilizable”. En el ejemplo que estamos siguiendo es Carlos (el hilo C) el que plancha la  ropa.

Ejecución de la función callback con el valor del futuro

Ejecución de la función callback con el valor del futuro

En la implementación del patrón que he propuesto a cada una de las funciones callback y de orden superior definidas en el interfaz futuro se le puede pasar un contexto de ejecución.

Más cosas de los futuros

A grandes rasgos, esta es la esencia: el futuro permite configurar desde la ejecución principal que hacer cuando finalmente exista el valor. Y se hace sin tener que bloquear hilos porque sino arruinamos la asincronía.

Teniendo esto en mente y sin perder de vista lo simple de este concepto, base de todo, voy a ir añadiendo nuevos conceptos e ideas que nos permitirá ir completando la visión general del patrón.

Dos caminos

Añadiendo una nueva capa a las funciones callback. El resultado de la ejecución de cualquier método puede ser, o bien su valor, o bien que su ejecución se haya saldado con un error, luego el resultado final que contiene un futuro puede ser:

  • un valor correcto
  • o también una excepción.

¿Por qué no contemplar esta circunstancia con dos caminos? Un camino para cuando el valor sea correcto con su correspondiente función callback (el método onSuccess) y otro que nos permita definir otra función de regreso cuando se produzca un error (el método onFailure)


Signatura de un onSuccess y onFailure de AlternativeFuture[T]:

onSuccess

void onSuccesful( final Consumer<T> function, final Executor executor );

El argumento function es una función cuyo argumento es de tipo T (es el tipo del valor final del futuro) y resultado void.

function: T => void

Esta será la función que se ejecutaría cuando de resultado final del futuro ha ido bien.

onFailure

void onFailure ( final Consumer<Throwable> function, final Executor executor );

En este caso el argumento function es una función cuyo argumento es un Throwable (la excepción que se reportaría si se produciría un error) y resultado void.

function: Throwable => void

Está será la función que se ejecutará cuando el futuro se haya solventado con un error.


¿Cuando se ejecuta la función callback?

Para dar respuesta a esta pregunta nos debemos fijar en que existan las dos cosas necesarias para la ejecución de la función: que exista la función y que exista el valor. Hay entonces dos posibilidades:

  • Puede que ya haya asignada una o varias funciones callback al futuro, entonces la ejecución de las mismas será cuando se obtenga el valor.
  • O bien puede ser que se obtenga primero el valor y el disparador de que la función se ejecute será la propia asignación de la función callback.

Es importante tener en mente que un futuro (“barra” promesa, esto lo explicaré más adelante), sólo se le puede asignar el valor una vez, además otra característica es que una función callback sólo se ejecutará una vez. Sin embargo se puede asignar al futuro, a lo largo del tiempo, todas las funciones callback que se deseen.

Promesas

Si has llegado hasta aquí probablemente ya te habrá asaltado la duda: ¿Cómo se da valor al futuro? ¿Cómo se le asigna un valor? La respuesta: a través de la promesa.

Podemos decir que la promesa y el futuro son las dos caras de la misma moneda y que una promesa está relacionada con un futuro. La idea básica que debemos tener en mente es la siguiente:

  • el futuro permite asignar la función callback para tomar decisiones una vez se haya obtenido el valor
  • la promesa permite dar valor a ese futuro.

Si volvemos al ejemplo anterior, será más sencillo de entender. Si recordamos el proceso principal llamaba a un método que permite en un segundo proceso calcular un valor de manera asíncrona en un tiempo indeterminado (puede ser antes o después). Mientras que el proceso principal tiene como herramienta al interfaz futuro que le permite indicar que es lo que se debe de hacer una vez se haya calculado el valor, el interfaz de la promesa será el instrumento que poseé  el segundo proceso encargado de calcular el valor para asignar el valor a ese futuro. En síntesis Ana usaría el futuro y Bartolo la promesa.

Diagrama de flujo Promesa-Futuro

Diagrama de flujo Promesa-Futuro

Diagrama de secuencia Promesa-Futuro

Diagrama de secuencia Promesa-Futuro


Implementación

Si echáis un vistazo al código, podéis observar que sólo existe una implementación que implementa las dos interfaces: la promesa y el futuro.

La clase AlternativePromiseImp tiene un atributo que permite almacenar el valor del futuro. Este se asignará gracias a los métodos que expone el interfaz promesa AlternativePromise.

Existen dos atributos más en AlternativePromiseImp que son del tipo de cola FIFO (el primero que entra será el primero que sale). Permiten almacenar las funciones callback gracias a los métodos expuestos por el interfaz AlternativeFuture.

Una de las colas guardará las funciones que se van a ejecutar cuando mediante la promesa relacionada se asigne un valor correcto al futuro. Las funciones se van añadiendo a esta cola utilizando el método ‘onSuccesful‘ del interfaz AlternativeFuture.

La otra cola FIFO almacenará las funciones callback que se ejecutarán cuando la promesa relacionada se resuelva con un error. De la misma manera, se van añadiendo estas las funciones gracias al método ‘onFailure‘ del interfaz AlternativeFuture.

Bien cuando se asigna un valor a la promesa o bien cuando se añade una función callback al futuro se comprueba que existan los requisitos necesarios (la función y el valor del futuro). Si es así se ejecutará las funciones callback incluidas en la cola de callbacks con el valor final. Según se vayan ejecutando las funciones se eliminarán de la cola.


El Futuro como mónada. Programación funcional con AlternativeFuture

Se puede dar una vuelta de tuerca más y seguir añadiendo capas a la cebolla. El patrón Futuro/promesa permite adoptar un nuevo patrón funcional: la monada. Este artículo ya es lo suficientemente extenso, quizás con ya demasiados conceptos así que dejo pospuesto introducir la composición mónadica con AlternativeFuture y os emplazo a un siguiente post continuación de este.

M.E.

Actores tipados, Akka por ejemplos

«Tercer y último artículo sobre Akka explicado mediante ejemplos.

En los dos anteriores se basó en como funcionan la cola de mensajes de un actor, que es un router, como se envían mensajes entre actores. Después se trató temas como la supervisión y el bus de eventos.

Ahora me centraré en los actores tipados.«

Entrada anterior: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures


Actores tipados

Los actores tipados son una funcionalidad que ofrece Akka recubriendo un actor no tipado en un interfaz java. Con un actor tipado el programador realiza llamadas a un método de una clase normal ‘sin preocuparse‘ (y pongo esto entre comillas por lo que veremos más adelante) de lo que está detrás es un actor de Akka.

[Actor tipado]

[Actor tipado]

Permite unir los dos mundos, código java estándar con el mundo de los actores. En la documentación de Akka puedes leer que tienen su nicho, pero hay que ‘usarlos con moderación‘. Recomiendan que si lo que buscas es una arquitectura de alta escalabilidad utilizar estos actores no es la solución más sencilla. Por ejemplo en este caso, aunque se puede, no es tan natural la supervisión y la monitorización padre-hijo.

Para los actores tipados, Akka utiliza el patrón de Objetos Activos y proxys de Java. Para levantar un actor tipado es necesario una interfaz y una implementación. Simplificando, en los actores tipados no existe el método ‘onReceive()‘ y se utilizan como un clase más de Java haciendo llamadas a los métodos que exporta la interfaz.

En realidad lo que hay detrás es un actor no tipado. Akka monta un proxy en el que el interfaz será la fachada y el ‘contrato público‘ que podrá utilizar el resto del código java. Los atributos de los métodos de ese interfaz serán los mensajes que se enviarán al actor y la implementación será la que dicte el comportamiento. Por lo demás se cumple con el modelo de actores que asegurá que no habrá más de un hilo ejecutando el actor.

Todo esto, que haya un actor detrás de este interfaz, hace que tenga un comportamiento diferente al esperado en una clase java, y hay que tenerlo en mente cuando se utilizan actores tipados.

Para los ejemplos se ha utilizado una clase TypedActorDummyImp que implementa el interfaz TypedActorDummy con una serie de métodos sencillos que permitirán ver con facilidad el funcionamiento de los actores tipados.

He creado dos test, uno TypedActorDummyImpTest.java que comprueba el comportamiento en una llamada normal a un método con diferentes tipos de retorno y otro TypedActorDummyImpExceptionsTest.java para ver cual será su comportamiento si se produce una excepción.

Comportamiento según el tipo de retorno.

Un método puede devolver tres tipos de respuesta: o bien es un método que no devuelve nada (void), o devuelve un objeto, o bien devuelve un futuro de objeto.

Cuando un método devuelve no devuelve nada: void

Cuando un actor tipado el tipo de respuesta es ‘void‘, lo que está ocurriendo es que se está mandando un mensaje del tipo dispara y olvida (‘fire-forget‘). En realidad se está enviado un mensaje ‘tell‘ al actor que hay por detrás, y no se espera respuesta.

Esto hace que tenga un comportamiento un poco ‘diferente‘ del esperado y es algo que se puede comprobar en los dos ejemplos.

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testReturnVoidWithSleep test

En este test se levanta un actor tipado que tiene un método que devuelve void. Se simula una operación costosa con un “Thread.sleep”.

Se comprueba que no se espera a la ejecución del método, sino que se continua inmediatamente con la siguiente orden. El mensaje se ha encolado al actor y este ejecutará la implementación en segundo plano, sin ningún tipo de espera en el hilo principal.

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionVoid test

Como consecuencia de que el mensaje es enviado al actor, ejecutándose en un segundo plano, el hilo principal no es capaz de saber si ha ocurrido un error en la ejecución. Si se produce una excepción no será recogida desde la llamada al método.

El test anterior permite hacer esta comprobación y es bastante didáctico.

Cuando un método devuelve un futuro

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testFutureEcho test

Cuando se llama a un método de un actor tipado que devuelve un futuro, el comportamiento sería el mismo que si se enviara un mensaje de petición y respuesta no bloqueante. Es el equivalente al envío de un mensaje con ‘Patterns.ask(…)’ de un actor no tipado.

Por lo tanto la respuesta se recogerá cuando se resuelve el futuro y no desde la llamada al método. El hilo principal continuaría su ejecución sin esperar.

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionFuture test

Lo mismo pasaría si se produjera una excepción, sería devuelta en la resolución del futuro y no sería recogida en la llamada al método tipado. Esto entra dentro de lo lógico si pensamos que cuando se produce el error es en el momento en el que se procesa el mensaje por parte del actor.

Cuando un método devuelve un objeto

Test 1: Llamada normal

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpTest#testEcho test

Test 2: Cuando se produce una excepción

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.typed.TypedActorDummyImpExceptionsTest#testRuntimeExceptionString test

Cuando se llama a un método de un actor tipado que devuelve un objeto, el comportamiento es ‘parecido‘ al esperado. Y digo ‘parecido‘ porque en realidad lo que se está haciendo es enviando el mensaje al actor y esperando la respuesta (siguiendo un patrón de petición-respuesta bloqueante)

Por lo tanto desde la llamada al método de un actor tipado hace que hilo de ejecución principal espere la respuesta (aunque por detrás se esté enviando un mensaje ejecutándose en otro ‘hilo’). Por lo tanto el comportamiento es ‘el mismo’ al acostumbrado (ver el ejemplo 1). En este caso si se produce una excepción si será recogida en la llamada al método (Ver test 2)


Como conclusión final de esta serie de posts decir que aunque el modelo de actores y Akka presentan nuevos conceptos, estos una vez aprendidos son sencillos de asimilar.

A cambio ofrece un modo elegante y sencillo de codificar aplicaciones que soporten programación paralela  que sean escalables, robustas y  de alta disponibilidad.

Espero que os sirva.

M.E.

Akka por ejemplos. Sobre supervisión, bus de eventos, …

Esta es la segunda entrega de Akka por ejemplos. La primera trató sobre cual es el funcionamiento de la cola de mensajes de un actor, que es un router y como se envían mensajes entre actores.

Ahora se tratarán temas como el control de fallos y la supervisión de actores, el bus de eventos de Akka y sobre los ‘Dead Letters’

Entrada anterior: Akka por ejemplos

Sin más vamos con los ejemplos.

Todo el código fuente relacionado con esta serie de posts está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures


Control de fallos: Supervisión y monitorización.

[Supervisión padre-hijo en Akka]

[Supervisión padre-hijo en Akka]

En Akka la robustez a fallos se basa en la supervisión de actores con jerarquía padre-hijo. El actor que delega tareas en los actores que crea es el que ‘supervisa‘ y decide que hacer cuando se produce un fallo en alguno de sus hijos.

Se crea así una jerarquía en forma de árbol en la que la que los actores padres supervisan a los actores hijos. El actor ‘user‘ de Akka será el padre de primera generación de actores que hayamos creado.

Esto es realmente lo que te da la robustez (‘resilence‘)  que un sistema reactivo necesita. Esta robustez se pierde cuando se intenta en vez de tener esta jerarquía, ir a un esquema con una mentalidad más tradicional de inyección de dependencias y se cae en la tentación de inyectar actores a otros actores.

Cuando un actor falla y se produce una excepción, su supervisor puede hacer, o bien reiniciar el actor, parar el actor, escalar la excepción o absorber la excepción y continuar con la ejecución.

El sistema de supervisión de Akka permite tener la posibilidad de diferente respuesta del supervisor dependiendo del tipo de excepción y si esta afecta a todos los actores supervisados o sólo al que ha fallado. Esto junto con lo anterior permite implementar fácilmente patrones,  por ejemplo de tipo ‘circuit breaker‘, si uno de los actores falla.

Akka tiene la posibilidad de establecer eventos o disparadores en el ciclo de vida de un actor. Por ejemplo antes de crearlo, antes y después de reiniciarlo y cuando se para.

Ademas del concepto de supervisión, en Akka existe el de monitorización. Cualquier actor, puede ‘monitorizar‘ a cualquier otro, lo haya creado o no. El primero obtiene un mensaje ‘Terminated‘ cuando el monitorizado ha terminado. Esto permite modificar su comportamiento o cambiar su estado. En los ejemplos siguientes el actor supervisor también hace de ‘monitor‘ de sus hijos.

Para poder mostrar con ejemplos como es el comportamiento de las diferentes estrategias a seguir, he creado en el proyecto dos actores: ActorNoTypedDummyCheckLifeCycle y ActorNoTypedLetItCrash.

ActorNoTypedDummyCheckLifeCycle se utiliza para comprobar los eventos que se disparan y por los ‘estados‘ que pasa un actor cuando es supervisado con diferentes estrategias. Concatena en un atributo ‘state‘ los diferentes pasos por los ‘hooks‘ del ciclo de vida de un actor:

  • Método ‘aroundPreStart‘: Primer evento que se dispara cuando se inicia un actor. Sólo se ejecuta cuando se inicia un actor por primera vez.
  • Método ‘preStart’: Se lanzan cuando se inicia un actor o después de que se haya reiniciado.
  • Método ‘aroundPreRestart’: Cuando un actor va a ser reiniciado, se dispara antes de parada el actor.
  • Método ‘preRestart‘: También se ejecuta antes de parar el actor cuando va a ser reiniciado. La llamada es después de la del método ‘aroundPreRestart
  • Método ‘postStop‘: Evento que se llama, o bien cuando se para el actor, o bien antes de reiniciarlo (en este último caso justo después de que se llame al método ‘preRestart‘)
  • Método ‘postRestart‘: Se lanza después de reiniciar el actor.
  • Método ‘aroundPostStop‘: Se realiza la llamada justo antes de parar definitivamente el actor.

El actor ActorNoTypedLetItCrash es el que creará y hará de supervisor de ActorNoTypedDummyCheckLifeCycle. En su constructor,  permite definir por parámetro la estrategia de supervisión. Su comportamiento será en de hacer de proxy en el envío de mensajes a  ActorNoTypedDummyCheckLifeCycle hasta que este el actor hijo se pare o cuando el mismo se haya reiniciado.

Para mostrar el comportamiento de las diferentes estrategias y cual es el ciclo de vida especifico de los actores (cuando se llama a los diferentes ‘hooks‘) he codificado en el proyecto los siguientes ejemplos.

Estrategia de supervisión por defecto

Test: ActorLetItCrashTestDefault.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestDefault test

Si se produce un excepción en un actor hijo, la estrategia por defecto en Akka es la de reiniciar el actor hijo, excepto si es un error irrecuperable:

  •  cuando se ha producido una excepción al inicializar el actor (ActorInitializationException)
  • cuando ya se había parado el actor(ActorKilledException)

Esta estrategia cobra sentido cuando se quiere mantener un sistema estable. La idea subyacente es que cuando se produce un error el sistema debería volver a un estado consistente y esto se consigue reiniciando el estado del actor.

En este ejemplo, los pasos son:

  1. Se envía un primer mensaje ‘state‘ al actor ActorNoTypedLetItCrash. Este hará el reenvío del mensaje al actor hijo (ActorNoTypedDummyCheckLifeCycle) que devolverá la concatenación de los diferentes métodos por los que ha pasado hasta ese momento.
  2. Después se envía un mensaje con una excepción para que el actor hijo provoque la excepción.
  3. Por último se vuelve a enviar un mensaje ‘state‘ para ver por los eventos que se ejecutan cuando se reinicia el actor.
  4. Finalmente para poder ver todo el flujo, se para el actor.

El ejemplo permite comprobar el flujo completo del paso de los diferentes eventos a lo largo de la vida del actor hijo. En este caso con la estrategia de supervisión por defecto, es este:

Se llama al constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPreRestart
     => Llamada a preRestart
      => Llamada a postStop
       => Llamada al constructor (Se vuelve a crear el actor)
        => Llamada a aroundPostRestart
         => Llamada a postRestart
          => Llamada a preStart
           => Llamada a aroundPostStop
            => Llamada a postStop

Estrategia de supervisión: Escalar la excepción

Test: ActorLetItCrashTestEscalate.java

Commando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestEscalate test


¿Qué ocurre cuando se elige una estrategia de supervisión de tipo ‘escalate‘? En este caso la excepción en el actor hijo provoca el error también en el actor supervisor. El comportamiento final depende entonces de la propia estrategia de supervisión de este último.

El ejemplo puede ayudar a verlo más claro. En este caso se configura el supervisor (ActorNoTypedLetItCrash) para que la estrategia de supervisión sea la de escalar la excepción. Cuando se provoca una excepción en el actor supervisado, el resultado es el mismo que si se hubiera producido en el supervisor.

El este caso el supervisor tiene la estrategia de supervisión por defecto, que lo reinicia, volviéndose a crear el actor hijo.

En el test se comprueba este hecho cuando se valida todo el ciclo de vida del actor hijo. Se arranca y después de la excepción, se para, para después volver a arrancar sin reinicio. Esto último provocado porque al reiniciarse actor supervisor, el hijo se para y se vuelve a crear:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop
      => Llamada al constructor (Se vuelve a crear el actor)
       => Llamada a aroundPreStart
        => Llamada a preStart
        => Llamada a aroundPostStop
         => Llamada a postStop

Estrategia de supervisión ‘resume’: ‘Absorber’ la excepción.

Test: ActorLetItCrashTestResume.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestResume test

Si el supervisor adopta una estrategia de ‘resume‘ si se produce un error la excepción no produce ni el reinicio, ni la parada del actor supervisado. Aunque se haya producido el error, sigue levantado a la espera de procesar nuevos mensajes.

El test ayuda a comprender este tipo de supervisión. Se comprueba que cuando se produce una excepción al procesar un mensaje, no se hace ninguna llamada a los métodos del ciclo de vida, ni tampoco se escala la excepción. El siguiente mensaje lo procesa correctamente.

El ciclo de vida del actor supervisado con este tipo de supervisión será:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Estrategia de supervisión ‘stop’: Parar el actor supervisado.

Test: ActorLetItCrashTestStop.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.supervisorstrategy.ActorLetItCrashTestStop test

En este caso, se para el actor supervisado cuando al procesar un mensaje ocurre una excepción.

En el ejemplo se fuerza esta situación. Si se provoca una excepción en el actor supervisado se comprueba que el actor no se vuelve a reiniciar. De hecho si se le vuelve a enviar un mensaje de estado, este se envía a la cola de ‘Dead Letters‘ porque la referencia al actor ya no apunta a un actor válido.

El ciclo de vida del actor es el siguiente:

Llamada a constructor
 => Llamada a aroundPreStart
  => Llamada a  preStart
   => [[exception]] Se provoca una excepción
    => Llamada a aroundPostStop
     => Llamada a postStop

Los mismos pasos que con la estrategia ‘resume‘. Pero en este caso no ha sido necesario parar el actor en el test porque ‘muere‘ después de provocarse la excepción.

Bus de eventos interno de Akka

Test: PublishSimpleSuscribeTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.PublishSimpleSubcribeTest test

Akka poseé un bus interno que permite el envío de mensajes siguiendo el patrón publicador-suscriptor. Un ‘publicador‘ envía un mensaje sin saber quien van a ser los receptores. Los actores que quieran recibir ese tipo de mensajes deberán suscribirse a esa publicación.

[Bus de eventos de Akka]El paradigma cambia. En vez de enviar un mensaje a un actor concreto, es decir, “(Por favor) haz esto”, cuando se publica un mensaje en el bus se está diciendo “(A quien pueda interesar) ha ocurrido esto

En este caso el ejemplo muestra un uso sencillo del bus de Akka para mostrar este patrón.

Se levantan dos actores suscriptores (del tipo ActorNoTypedLogEvent) que se suscribirán a mensajes de tipo Integer. La implementación de este actor es sencilla: registra los mensajes del tipo a los que está suscrito y si se le envía un mensaje ‘lastMessage‘ devolverá el último mensaje que ha registrado.

En el test después de levantar a los dos suscriptores se envía un mensaje al bus de Akka. Después se comprueba que el mensaje le ha llegado a ambos.

Dead letters

Test: DeadLettersTest.java

Comando maven
mvn -Dtest=com.logicaalternativa.examples.akka.bus.DeadLettersTest test

Un ‘dead letter‘ se produce cuando no se ha podido entregar un mensaje a un actor. Un caso típico es cuando el actor receptor del mensaje ya no existe. El ‘dead letter‘ contiene el mensaje enviado, la referencia al actor que lo envía y la del que lo iba a recibir.

Por defecto Akka informa en el log de la aplicación los dead letters que se producen (esto es configurable). También pública esta información a través del bus de eventos de Akka, lo que permite que una aplicación tenga la posibilidad de una gestión específica de estos mensajes perdidos.

En el ejemplo para poder provocar un dead letter se crea un actor del tipo ActorNoTypedDummy pararlo para a continuación enviarle un mensaje. Este mensaje ‘se pierde‘ y es recogido como ‘dead letter‘.

Por otra parte en el ejemplo se está utilizando un actor del tipo ActorNoTypedLogEvent configurado para que suscriba en el bus de eventos de Akka los mensajes del tipo DeadLetter.

Cuando se manda un mensaje de ‘lastMessage‘ al actor ActorNoTypedLogEvent este devolverá la información del mensaje perdido en forma de DeadLetter.

Como comprobación final del test se validará la información contenida en el objeto DeadLetter: el mensaje y la referencia al actor receptor.


Hasta aquí este segundo artículo de Akka por ejemplos. El próximo y último artículo de esta serie será sobre actores tipados.

Espero que os sirva.

M.E.

Akka por ejemplos

«Akka representa muchos conceptos nuevos que al principio cuesta asimilar. Para poder entenderlo mejor, he ido creando, poco a poco, una serie de ejemplos que me han permitido comprender mejor el paradigma que conlleva.

[Akkapor ejemplos]

Este artículo trata sobre esto, intentar tener una prueba de código de cada nuevo concepto que permita ver cual es su comportamiento y función.»

Entrada siguiente: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Akka es un framework basado en el modelo de actores que permite dar solución al problema de la programación concurrente. Además de formar parte de Scala de manera nativa existe como librería en Java.

Permite diseñar aplicaciones que sean escalables horizontalmente de manera transparente, con alta toleracia a fallos y basada en eventos que permite cumplir el ‘manifiesto reactivo‘.

Este será el primer de una seríe de artículos explicando conceptos clave que se utilizan en Akka mediante ejemplos. En esta primera parte trataré como funciona las colas de mensajes de un actor, que es un router y las diferentes maneras de como se pueden enviar mensajes entre actores.

En próximas entregas trataré sobre el sistema de supervisión de los actores en Akka, como funciona el bus de eventos y que son los actores tipados.

Esta entrada es eminentemente práctica, te invito a descargarte el proyecto y a que eches un vistazo y ejecutes los ejemplos. Se entenderá mejor lo que quiero explicar en este artículo. Todo el código fuente relacionado con esta serie de post está disponible en mi repositorio de GitHub

[Logo GitHub] AkkaActorsAndFutures

Sobre los test

La idea fundamental a la hora de realizar los test ha sido la de realizar implementaciones dummy y ‘ad hoc‘ y, gracias a ellas, montar test que permitieran ver con facilidad cual es el funcionamiento de la pieza que interesa.

Por otra parte, he buscado que el código incluido en los test puedan servir de ejemplo uando se quiera implementar ese mismo concepto en una aplicación real.

Es por esto por lo que he evitado utilizar el framework de Akka de test ‘akka-testkit’ y en algunos momentos puede parecer que me he complicado la vida realizando las validaciones cuando se completan los futuros y utilizando agentes de Akka para compartir estados entre actores.

Mucha de la funcionalidad común a todos los actores, como crear el sistema de actores y métodos de utilidad se ha llevado a test base (TestBaseTestBaseTypedActor ) de los que heredan todos los test.

Prólogo: Los agentes

Ya que en los test utilizo agentes, antes de entrar a explicar los test, intentaré hacer una breve introdución de lo que es un agente en Akka.

Un agente de Akka permite almacenar un valor y actualizarlo sin problemas de concurrencia. Tienen la particularidad que la actualización se realiza de manera asíncrona, pero se puede leer el valor de manera síncrona.

Su funcionamiento es similar a un mailbox de un actor. Se basa en encolar los nuevos valores de tal manera que el valor interno se va actualizando en orden de llegada. No existe concurrencia y por eso su actualización es asíncrona.

Hay que tener en cuenta que cuando se pide su valor de manera síncrona devuelve el valor ‘actual‘ no el valor ‘futuro‘ que tendrá cuando se procesen todos los valores encolados hasta ese momento.

Vamos entonces con los test.


Como funciona la cola de mensajes de un Actor

Test: ActorQueueTest.java

Commando maven:
mvn  −Dtest=com.logicaalternativa.examples.akka.queue.ActorQueueTest test

[Un actor, un mailbox]

Un actor, un mailbox

El modelo de actores nos asegura que no puede haber más de una ejecución concurrente de un actor. Es decir, no puede haber más de un hilo ejecutando el código de actor. Los mensajes que se envían al actor se encolan en su ‘inbox‘ de tal manera que se ejecutan de uno en uno.

En este ejemplo se está levantando dentro del sistema de actores, un actor del tipo ActorNoTypedDummy. Este tiene una lógica muy sencilla: si se envía un mensaje tipo Long la ejecución se espera los milisegundos indicados en el valor del mensaje. Si el mensaje es de tipo String devuelve un eco del mensaje.

En el test ActorQueueTest se envía un primer mensaje tipo Long para que se realice una espera y después 10 mensajes de tipo String.

En en la ejecución del test, se puede observar de que aunque se envían todos los mensajes sin esperar la ejecución del actor, en realidad estos se encolan. El actor no procesa el siguiente mensaje hasta que no ha terminado la ejecución anterior.

El resultado es que los mensajes son procesados por orden de llegada ya que este actor tiene la implementación por defecto de ‘mailbox‘ (existen otras implementaciones que permiten prioridades de mensajes). Con lo que realiza la espera del primero de ellos y después el eco del resto.

En este test para comprobar el orden de los mensajes que se están ejecutando en el actor se está utilizando un agente de Akka para guardar el estado de manera asíncrona.  El agente almacena la concatenación de los mensajes tipo cadena que se envían al actor.

Para verificar que el orden de los mensajes enviados es el mismo orden de los mensajes que se han procesado se comprueba que estas dos cadenas son iguales.

Cómo funciona un Router

Test: ActorQueueRouteRoundRobinTest.java

Commando maven
mvn  −Dtest=com.logicaalternativa.examples.akka.queue.ActorQueueRouteRoundRobinTest test

Akka permite el concepto de ‘Router‘. Esto permite asociar en una misma referencia de un actor envolver un grupo de actores del mismo tipo.

Se basa en el mismo concepto que tenemos todos en mente de que es un Router: un frontal al que se envían los mensajes y que se encarga de reenviarlos a sus ‘routees‘ para que estos los procesen y devolver la respuesta.

Permite un procesamiento en paralelo mayor, al existir más instancias de un actor, pero con la comodidad de tener una referencia única a la que enviar los mensajes.

[Concepto de router]

Router

Cada miembro del router es de hecho un actor y tiene su propia cola. La estrategia del envío de los mensajes a los miembros del enrutador se define al crear este. En el test de ejemplo se está utilizando la estrategia de envío secuencial de mensajes (‘RoundRobinPool’): se envía un mensaje a un actor del grupo, el siguiente al siguiente actor y así sucesivamente. En la documentación de Akka puedes ver que existen y se pueden utilizar otras estrategias.

El ejemplo levanta un sistema de actores. Se crea un router de 5 actores del tipo ActorNoTypedWhoIam. Este actor tiene una implementación muy sencilla. Se limita a responder en un Map con el mismo mensaje que le envían y su nombre de actor.

Al router se le envían 10 mensajes. En la resolución de cada futuro de respuesta se comprueba que el mensaje es el mismo que se ha enviado. Por otra parte, gracias a la nombre del routee, se guarda la información de que routee ha procesado el mensaje.

Por último se comprueba que a cada actor del grupo del router le ha llegado el mismo número de mensajes (estrategía de envío RoundRobinPool). En este caso son 2 ya que el router lo forman 5 actores y se mandan 10 mensajes.

En las trazas se puede comprobar que el actor con el nombre ‘a‘ le llegan los mensajes ‘0‘ y ‘5‘, al ‘b‘ el ‘1‘ y el ‘6‘ y así sucesivamente.

Como se pueden enviar mensajes entre actores

Test: ActorProxyTest.java

Comando maven
mvn  -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest test

Fundamentalmente los actores se pueden enviar mensajes de dos maneras diferentes: tipo ‘fire & forget‘ (dispara y olvida) utilizando la función ‘tell‘ o bien seguir un esquema petición-respuesta utilizando la función ‘ask‘.

Por otra parte un actor puede crear otros actores a los que necesita enviar mensajes. Es muy común que existan actores cuya tarea sea la de orquestar o supervisar el trabajo de los actores que ha creado (‘actores hijos’), y que una parte de esta tarea sea la de reenviar a sus hijos los mensajes que les llegan. Para estos cosos es muy útil utilizar la función ‘forward

El ejemplo se crea un actor ActorNoTypedProxy que crea un actor hijo del tipo ActorNoTypedDummy. Recordemos que este último devuelve un echo de los mensajes que se le envían.

ActorNoTypedProxy hará de proxy para mostrar las diferentes formas de enviar y reenviar mensajes entre actores. Recibe los siguientes mensajes tipo cadena:

forward‘, redirigir el mensaje

Commando maven test 'forward'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testForward test

Cuando recibe un mensaje de este tipo ejecuta llamada al método ‘forward‘ del actor hijo, con el mismo mensaje. El actor hijo (ActorNoTypedDummy) recibirá el mensaje como si el emisor hubiera sido el que emitió el mensaje al actor ActorNoTypedProxy.

redirect‘ dispara y olvida

Comando maven test redirect
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testRedirectMessageToChild test

El actor que hace de proxy redirecciona el mensaje llamando a la función ‘tell‘ del hijo indicando que el remitente es el del mensaje original que le llega al proxy. Aquí también el actor hijo (ActorNoTypedDummy) recibirá el mensaje como si el emisor hubiera sido el que emitió el mensaje a ActorNoTypedProxy.

[forward o 'redirect']

forward o ‘redirect’

 ‘future‘, petición-respuesta no bloqueante y asíncrona

Comando maven test 'future'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testFutur test

Este es un ejemplo de comportamiento no bloqueante y asíncrono utilizando los futuros de Scala que ofrece Akka. ActorNoTypedProxy utiliza la función ‘ask‘ para con el mismo mensaje que le ha llegado, preguntar al actor hijo ActorNoTypedDummy y obtener el futuro de la respuesta. Este futuro se envía al remitente del mensaje original.

Al ser este un futuro, si fuera necesario, se puede desde el actor que hace de proxy, operar con él o realizar cualquier tipo de transformación. Por ejemplo se puede registrar un callback, realizar alguna transformación operando con el de manera funcional, etc…

Para simplificar en el test se espera el resultado de la respuesta y como esta también es un futuro, se espera también a este para obtener el resultado.

 ‘await‘, petición-respuesta bloqueante y síncrona

Comando maven test 'await'
mvn -Dtest=com.logicaalternativa.examples.akka.message.ActorProxyTest#testAwaitFutur test

Sigue el mismo esquema que el test anterior pero esperado la respuesta de una manera síncrona.

En el actor proxy realiza la misma llamada ‘ask‘ y a continuación se utiliza la función ‘Await‘ que espera la resolución del futuro. Se obtiene así un comportamiento bloqueante y síncrono de petición-respuesta.


Hasta aquí llega esta primera parte de esta serie de artículos centrados en explicar como funciona Akka con ejemplos. Conceptos como la supervisión entre actores, el bus de eventos y que son los actores tipados serán material de futuras entregas.

Espero que os sirva.

M.E.

Entrada siguiente: Akka por ejemplos. Sobre supervisión, bus de eventos, …

Mocks… o el TDD y yo

… segunda Parte de TDD is dead? … o yo y el TDD

[Mock y test]Este es el segundo y último artículo de la serie que completa el anterior post TDD is dead? … o yo y el TDD.

Trataré de explicar como defino y codifico mis propios objetos ‘mock‘, y de como los uso tanto para pruebas unitarias, como también en pruebas de integración entre clases.

Y siendo más especifico mostrar como se pueden codificar tres tipos de mock utilizados habitualmente:

  •  Simular la capa de persistencia a base de datos.
  •  El que se utiliza para comprobar que se ha llamado a la interfaz que representa desde el objeto que nos interesa probar.
  • El utilizado simplemente para poder pasar las pruebas y que no nos interesa su comportamiento.

Y como dijo el maestro:

“… hablar es barato, vamos a ver un poco de código…”

Demo

Para ilustrar el ejemplo utilizaré una aplicación web que mediante un formulario html sencillo llamará con ajax a un servicio REST. Consiste en dar de alta códigos de promoción de una web.

[Pantallazo de la Demo Ejemplo Mock]

[Pantallado de la demo]

Los datos que se piden son la promoción, el nombre, el correo electrónico y el código de promoción. Se validará que el correo electrónico no esté ya utilizado y si todo es correcto se enviará el correo a la persona y se mostrarán los datos de los códigos ya dados de alta.

La demo es completamente operativa y se puede usar. Se puede descargar el código aquí:

[Logo GitHub]MoksExample en GitHub

Los detalles de como funciona y como se puede probar están en el archivo README.md

La parte de servicios REST es Java, montada sobre Spring. En el ecosistema de Spring, Spring-Data es el mediador con la capa de persistencia de datos. En el ejemplo se usará como interfaz con la base de datos. Como framework de tests unitarios usaré Junit. Maven será la herramienta de compilación, ejecución de test y construcción del proyecto. Como es una demo para estos fines se usa Hsqldb, base de datos en memoria.

Simular la capa de persistencia de BBDD

En la demo existen dos entidades PROMOTION y PROMOTION_CODE. La primera es el maestro de promociones y en la segunda se almacenarán todos los códigos de promoción relacionados con las primeras. Los objetos de negocio que las definen son los beans: Promotion y PromotionCode

Spring-Data se basa en el patrón repositorio. A grandes rasgos y simplificando, Spring-Data implementa la interfaz de las operaciones CRUD y el resto de consultas que se pueden realizar para cada entidad de la capa de persistencia (usualmente una tabla de una base de datos).

Existen por tanto dos interfaces definidos en el pakage com.logicaalternativa.ejemplomock.repository cuya misión es definir las operaciones CRUD de las entidades

En este caso los dos extienden del interfaz de Spring-Data JpaRepository.

Con Spring-Data sólo tienes que definir la interfaz con las diferentes operaciones de consulta, inserción y modificación que se van a realizar de la entidad y este se encarga de implementar la interfaz. Esto hace que resulte muy fácil codificar tus propios mocks. Después para los test se inyectarán por inversión de control al objeto de negocio.

Para los test he implementado los dos mock de cada uno de los interfaces. Están en el package com.logicaalternativa.ejemplomock.repository.mock .

Las dos clases son muy similares y siguen la misma línea. Sólo se ha implementado las operaciones necesarias para realizar los test. La idea es esa codificar sólo lo estrictamente necesario. Se añadirá o se modificará código cuando toque, si para un futuro test es necesario implementar algún otro método más.

Centrándome por ejemplo en el mock PromotionCodeRepositoryMock, el ‘quid de la cuestión‘ está en que he definido un atributo lista de tipo PromotionCode.

1
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
2
   private List<PromotionCode> promotionCode;
3
...
4
}

Este es accesible mediante los métodos públicos:

1
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
2
...
3
   public List<PromotionCode> getPromotionCode()
4
...
5
   public void setPromotionCode(PromotionCode...promotionCode)
6
...
7
}

He codificado los métodos CRUD para que operen con esta lista. Por ejemplo, así he codificado el método que sirve para obtener un código de promoción a través de su clave primaria.

01
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
02
...
03
  public PromotionCode findOne( final String email ) {		
04
    int index = findIndex( email );		
05
    if ( index != -1 ) {
06
      return clone( getPromotionCode().get( index ) ); 
07
    }	
08
    return null;
09
  }
10
...
11
}

Que lo que hace es encontrar el índice de la lista de códigos de promoción con el mismo email. Si lo encuentra devuelve una copia de ese objeto. Para entrar más en detalle te invito a revisar los métodos findIndex, clone y el resto de métodos que he implementado de PromotionCodeRepositoryMock

Otro ejemplo es el método saveAndFlush:

01
public class PromotionCodeRepositoryMock implements PromotionCodeRepository {
02
...
03
  public <S extends PromotionCode> S saveAndFlush(S promotionCode ) {
04
    if ( getPromotionCode() == null ) {
05
     this.promotionCode = new ArrayList<PromotionCode>();
06
     getPromotionCode().add( promotionCode );
07
     return promotionCode ;
08
    }
09
    final String email = promotionCode != null ? promotionCode.getEmail() : null;
10
    int index = findIndex( email ) ; 
11
    if ( index == -1 ) {
12
     getPromotionCode().add( promotionCode );
13
    } else {
14
     getPromotionCode().set( index, promotionCode );
15
    }
16
    return promotionCode;
17
  }
18
...
19
}

Que busca en la lista el objeto con el mismo email. Si lo encuentra actualiza el objeto de la lista y sino, lo añade a la lista.

¿Cómo se usa?

El test AddCodeBusinessImpTest prueba el objeto de negocio AddCodeBusinessImp.

La clase de negocio (AddCodeBusinessImp) comprueba que existe el código de promoción en la BBDD y utiliza para ello PromotionRepository. En el método setUp() del test se inicializa un objeto PromotionRepositoryMock con el objeto Promotion deseado y este mock se inserta por inversión de control a la instancia de AddCodeBussinessImp.

01
public class AddCodeBusinessImpTest {
02
  ...
03
  private AddCodeBusinessImp addCodeBusinessImp;
04
  ...
05
  private PromotionRepositoryMock promotionRepositoryMock;
06
  private PromotionCodeRepositoryMock promotionCodeRepositoryMock;	
07
  private Promotion promotion;
08
  ...
09
  @Before
10
  public void setUp() throws Exception {
11
    promotion = new Promotion();
12
    promotion.setIdPromotion( 1 );
13
    ...    
14
    promotionRepositoryMock = new PromotionRepositoryMock();
15
    promotionRepositoryMock.setPromotions( promotion );
16
    ...  
17
    addCodeBusinessImp = new AddCodeBusinessImp();
18
    addCodeBusinessImp.setPromotionRepository( promotionRepositoryMock );
19
    ...
20
  }
21
  ...
22
}

promotion, promotionRepositoryMock, addCodeBusinessImp son atributos privados de AddCodeBusinessImpTest.

Internamente AddCodeBusinessImp llama al método findOne de PromotionRepository con el identificador de la promoción (el del maestro de promociones) del nuevo código que se quiere insertar.

Si queremos testear que ocurre si no encuentra la promoción en la BBDD, simplemente se hace lo que en el método testPromotionNotBbDd de AddCodeBusinessImpTest:

01
public class AddCodeBusinessImpTest {
02
  ...
03
  @Test
04
  public void testPromotionNotBbDd() {
05
    try {
06
      promotionRepositoryMock.setPromotions( ( Promotion[] ) null ); 
07
      addCodeBusinessImp.validateAndAdd( promotionCode );
08
      ...
09
  }
10
  ...
11
}

Si la lista de promociones en PromotionRepositoryMock es nula no se podrá encontrar la promoción (El método findOne devolverá nulo).

En este mismo test también se utiliza PromotionCodeRepositoryMock. Inyectado también por inversión de control a la instancia de AddCodeBusinessImp, en este caso, sirve para comprobar que se ha insertado el código de promoción. Se hace en el test testOk

01
public class AddCodeBusinessImpTest {
02
  ...
03
  @Test
04
  public void testOk() {
05
    try {
06
      addCodeBusinessImp.validateAndAdd( promotionCode );
07
      final List<PromotionCode> promotionCodeBbDCodes = promotionCodeRepositoryMock.getPromotionCode();
08
      boolean result = promotionCodeBbDCodes != null
09
                && promotionCodeBbDCodes.size() == 1
10
                && promotionCode.equals( promotionCodeBbDCodes.get( 0 ) )
11
               ;
12
      ...
13
  }
14
  ...
15
}

Para tener una visión más clara de cual es la idea, lo mejor es revisar cada uno de los test Junit de AddCodeBusinessImpTest Creo que puede ser de gran ayuda para tener una visión global de lo que quiero plantear . He intentado que sean claros y autoexplicativos.

Mock de comprobación de llamada a interfaz y datos correctos.

Lo que interesa en este caso es comprobar que un objeto de negocio hace la llamada a un interfaz con los datos correctos. Lo que se hace es ‘mockear‘ esa interfaz capturando los datos de la llamada para comprobar después de que estos son correctos.

En la demo existe un objeto de negocio, SendMailCodePromotionImp, que a partir de una dirección de correo manda el código de promoción por email. Este objeto de negocio realiza internamente una llamada a la interfaz JavaMailSender que implementa Spring (JavaMailSenderImpl) para enviar el correo electrónico.

JavaMailServerMock, que implementa también el interfaz JavaMailServer, es el mock que va a recoger los datos de la llamada. En este caso sólo me interesaba saber la dirección de correo a la que se envía el correo electrónico. Para ello he implementado el método send:

01
public class JavaMailServerMock implements JavaMailSender {
02
  ...
03
  private String sendTo;
04
  ...
05
  @Override
06
  public void send( MimeMessage mimeMessage ) throws MailException {
07
    String[] to = null;
08
    try {
09
      to = mimeMessage.getHeader("To");
10
    } catch (MessagingException e) {
11
      logger.error( "[send] ".concat( e.getMessage() ), e );  
12
      to = null;      
13
    }
14
    setSendTo( to != null && to.length > 0 ? to[0] : null );
15
  }
16
  ...
17
  public String getSendTo() {
18
    return sendTo;
19
  }
20
  public void setSendTo(String sendTo) {
21
    this.sendTo = sendTo;
22
  }
23
}

Se recoge del argumento de entrada la cabecera “To” para almacenarla en un atributo de la clase.

¿Cómo se usa?

En el test SendMailCodePromotionImpTest se utiliza este Mock. En el método setUp(), se instancia y se inserta por inversión de control al objeto SendMailCodePromotionImp.

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  private SendMailCodePromotionImp sendMailCodePromotionImp;
04
  ...
05
  private JavaMailServerMock javaMailServerMock;
06
  ...
07
  @Before
08
  public void setUp() throws Exception {
09
    ...
10
    javaMailServerMock = new JavaMailServerMock();
11
    ...    
12
    sendMailCodePromotionImp = new SendMailCodePromotionImp();
13
    ...
14
    sendMailCodePromotionImp.setJavaMailSender( javaMailServerMock );
15
    ...
16
  }
17
  ...
18
}

El test testOk de SendMailCodePromotionImpTest sirve como ejemplo para comprobar si se ha realizado correctamente la llamada:

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  public void testOk() {
04
    try {
05
      sendMailCodePromotionImp.sendMailCodePromotion( email, locale );
06
      final String sendTo = javaMailServerMock.getSendTo();
07
      boolean res = sendTo != null
08
              && sendTo.equals( nameUser.toUpperCase() + " <" + email +">"  );
09
    ...
10
  }
11
  ...
12
}

Donde después de hacer la llamada al método sendMailCodePromotion del objeto de negocio se obtiene el atributo de sendTo del mock para comprobar que se envía a la misma dirección de correo electrónico.

En este mock sólo se comprueba la cabecera ‘To‘. También se podría comprobar el texto del mensaje o cualquier otro dato enviado desde el objeto de negocio.

Mock para pasar las pruebas

En la demo he codificado MessageSourceMock que implementa el interfaz MessageSource, utilidad que tiene Spring para la internacionalización. Este mock sólo me interesa para poder probar otras funcionalidades. Ha sido necesario codificado porque el objeto de negocio lo necesitaba, pero, en este caso, el resultado de su llamada era irrelevante. Solamente se ha codificado el método getMessage :

1
public class MessageSourceMock implements MessageSource {
2
  ...
3
  @Test
4
  public String getMessage(String arg0, Object[] arg1, Locale arg2) throws NoSuchMessageException {
5
    return arg0;
6
  }
7
  ...
8
}

Que como puedes comprobar, devuelve directamente la entrada.

¿Cómo se usa?

En el test SendMailCodePromotionImpTest se utiliza este Mock. En el método setUp()Se instancia y se inserta por inversión de control al objeto
SendMailCodePromotionImp.

01
public class SendMailCodePromotionImpTest {
02
  ...
03
  private SendMailCodePromotionImp sendMailCodePromotionImp;
04
  ...
05
  private MessageSourceMock messageSourceMock;
06
  ...
07
    @Before
08
  public void setUp() throws Exception {
09
    ...
10
    messageSourceMock = new MessageSourceMock();
11
    sendMailCodePromotionImp = new SendMailCodePromotionImp();
12
    ...
13
    sendMailCodePromotionImp.setMessageSource( messageSourceMock );
14
  }
15
  ...
16
}

Ya ahora al hacer la llamada getSendTo del objeto de negocio no aparece la tan temida NullPointerException 😉

Conclusiones

Como se puede ver, con un poco de ingenio es relativamente sencillo crearte tus propios objetos mock sin tener que recurrir a Frameworks. La creación de los mock me ayudan a comprender mejor como funciona la aplicación y ver las clases involucradas como verdaderas cajas negras. Esta es la gracia del paradigma de la orientación a objetos.

No necesariamente tiene que llevar demasiado tiempo el codificarlos. Sólo se debería ‘picar’ lo que necesitas cuando lo necesitas y mucho es reaprobechable. Al final del proyecto seguro que tienes un buen juego de objetos mock para pruebas.

Otra ventaja, es que no hay reflexión, no existe bbdd en memoria para los test, ni ha sido necesario levantar un entorno para pruebas… el resultado es que los test van ‘volaos‘.

M.E.

P.D.: Para esta demo, de esto que te vas liando y liando… y poco a poco me ‘currado’ un framework MVC hecho en JavaScript. Cuando lo organice un poco será material para próximos post.

Aprendiendo Grunt a partir de Ant

Prólogo

Hace unos años, unos 8 ya …

[Grunt logo]En un proyecto me tocó realizar una ‘builtool‘. Era una herramienta común que utilizarían todos los demás proyectos no importando su tecnología, PHP,.Net, Java, etc. Obtenía el código del sistema de control de versiones compilaba, paquetizaba y subía la build compilada a otra rama del control de versiones. En realidad era un pre-Maven porque obligaba a una cierta estructura de directorios en los proyectos pero no tenía ni su control de dependencias, ni sus arquetipos para nuevos proyectos. La herramienta estaba hecha en Ant.

Realmente nunca me llegó a apasionar ese proyecto, siempre me ha gustado más programar. Pero me ayudó a tener conciencia de la importancia de saber montar el ‘Control de la configuración‘ de un proyecto y también, como podéis imaginar, a tener bastante soltura con Ant.

Capitulo I

… en la actualidad

Para el Front del nuevo proyecto, con mucha carga de JavaScript, teníamos que generar la build  y realizar el despliegue. Para hacer menos pesada y más rápida la descarga necesitamos comprimir html, jasvascript y css y en el caso de estos dos últimos unificarlos en un sólo fichero.  Este proceso también lo  utilizaríamos para hacer despliegue continuo en nuestro entorno de preproducción, utilizando Jenkins.

Grunt se ajustaba perfectamente a nuestras necesidades y además se unificaba las tecnologías. La elección de Grunt en vez de Gulp, otra herramienta similar, fue porque el primero está incluido en Yeoman, que viene a ser en Javascript lo que Maven es a Java. Una herramienta de gestión de dependencias, arquetipos, generación de buidls, test, etc.., que al igual que Maven permite gestionar todo el ciclo de vida de las builds. Elegí Grunt como un primer paso del camino que muy probablemente nos lleve a Yeoman.

Me enfrente al reto aprendiendo algo nuevo desde la perspectiva de algo conocido. Utilizando como punto de apoyo, sin que lo conocido conllevara  a perjuicios iniciales. Estas son las semejanzas, las diferencias y las conclusiones a las que he llegado.

En que se parecen…

Ant tiene ya mucho recorrido, o dicho de otra manera ya es bastante ‘viejuno‘. En cierta forma fue la respuesta de Java al Make de C. Surgió de la necesidad de crear una herramienta que pudiera compilar, generar ejecutables y que no dependiera del sistema operativo donde se ejecutara. Permite también la generación de test, despliegue, generación de documentación, etc.

Grunt está dentro del ecosistema Javascript, es un ‘ejecutor de tareas‘ y se usa fundamentalmente para realización de builds, su testeo y su despliegue.

Arquitectura y configuración

Para utilizar Ant es necesario primero tener instalado Java y después la distribución de Ant. Algo similar ocurre con Grunt para poder usarlo es requisito tener instalado node.js y el cliente de Grunt.

Tanto en Ant como en Grunt la configuración de la build del proyecto se hace a través de un archivo. Su nombre por defecto en ‘build.xml‘ en Ant y ‘Gruntfile.js‘ en Grunt

Tareas y objetivos

En esencia tanto en Ant como en Grunt se utilizan las tareas disponibles (‘tasks‘) para definir objetivos (‘target‘). Los objetivos contienen la configuración de nuestro proyecto utilizando estas tareas… ‘Copia estos ficheros‘, ‘borra los ficheros de este tipo‘, etc..

En Ant un target pueden depender de otros. Se ejecutarán los targets de los que depende antes que él y lo harán en el orden indicado. Esto permite crear un flujo de ejecución de tareas.

1
<project name="Ejemplo de build" default="ejecutar">
2
...
3
 <target name="ejecutar" depends="clean,crearDistro,crearWar"/>
4
...
5
</project>

En este caso ‘ejecutar‘ sería el target por defecto.

En Grunt se definen ‘alias‘ para el mismo resultado.

1
...
2
grunt.registerTask('default', ['clean', 'copy','uglify', 'concat','cssmin']);
3
..

Eso no significa que no puedas ejecutar targets individuales. Por ejemplo en Ant para lanzar el target clean sería, ejecutando en el directorio donde está el ‘build.xml

1
$ ant clean

o en Grunt, ejecutado en el directorio donde está el ‘Gruntfile.js

1
$ grunt clean

Variables externas

Tanto en Ant como en Grunt se pueden pasar variables al archivo de configuración desde línea de comandos, lo que resulta muy útil a la hora de configurar varios entornos del mismo proyecto en el Jenkins.

En Ant

1
$ ant −DdirEntorno=prepro

Usando así la variable en el buid.xml

1
<target name="clean">	
2
 <delete dir="${dirEntorno}"/>
3
</target>

En Grunt:

1
$ grunt −−dirEntorno=prepro

Y el Gruntfile.js

1
clean: {
2
 main: {
3
  src: ['<%= dirEntorno %>']
4
 }
5
}

… y en que se diferencian

Xml o Json/Javascript

Ant utiliza xml para definir la configuración. Esto hace que, sobre todo al principio, y con archivos de build complejos, que sea bastante rígido y engorroso.

Grunt en este aspecto utiliza json, un formato mucho más liviano. Además está embebido en un archivo javascript permitiendo utilizar este lenguaje con toda su potencia. Este aspecto le da mucho más flexibilidad que Ant. Aquí es donde se le notan los años a Ant y como muestra Gant,una alternativa en el mundo Groovy que ‘pasa’ del xml

Gestión de dependencias de las tareas

La filosofía de las dependencias de las tareas es completamente diferente. Ant ,de serie, trae diferentes tareas que ya se pueden usar. Esto no significa que se puedan utilizar otras tareas de terceros. Para esto se usa la tarea ‘typedef‘.

La gestión de dependencias de las librerías que son necesarias para ejecutar estar tareas es completamente ‘a mano’. No te queda otra que bajarte la librería he incluirla, o bien en tu distribución de ant (en el directorio ‘lib’) o bien dentro de tu home (en el directorio ‘.ant/lib‘)

En esto Grunt si que gana por goleada. Por defecto no viene con ninguna tarea predefinida, por lo que eres el que elige cual vas a utilizar, seleccionandola de su página de plugins. Probablemente existan varias posibilidades a la tarea que estás buscando. Después, para poder utilizarla, Grunt utiliza la potencia del gestor de paquetes de node.js, npm.

Por ejemplo, para instalar la tarea ‘uglify‘ que se utiliza para comprimir archivos js, se ejecuta el siguiente comando en el directorio donde este el Grutfile.js

1
$ npm install grunt−contrib−uglify −−save−dev

Esto incluye las dependencias en el ‘package.json‘ (Este fichero se crea al iniciar el proyecto ejecutando ‘npm init’)

Y para pode usar la tarea hay que añadir al Gruntfile.js:

1
...
2
grunt.loadNpmTasks('grunt−contrib−uglify');
3
...

Fácil y cómodo, aunque tampoco falto de problemas. Por ejemplo la tarea clean de repente dejo de funcionar en Windows, mientras que el Linux no había problema. El problema, una de las dependencias subió de versión… y dejo de funcionar. La solución fue añadir la dependencia a la versión que funcionaba directamente en el archivo ‘package.json‘. Espero tener tiempo para explicarlo mejor en otro post.

Epílogo, Conclusiones

Si eres de Back ,tienes algo de experiencia en Ant y quieres montar tu control de configuración para el Front que está basado en Javascript, trabajar con ‘Grunt’ te va a resultar muy familiar.

Son tecnologías diferentes, algunas tareas serán similares y otras más específicas  no encontrarás en Ant, pero la esencia es la misma, así que sin miedo.

Espero que os sirva.

M.E.

Vert.x: Mucho más que trabajar en Java como en node.js.. y en groovy, ruby,…

Prueba de concepto: Gateway con websockets y Gtalk utilizando Vert.x

[Vert.x Logo]La primera vez que oí hablar de Vert.x fue en la charla sobre el nuevo lenguaje Ceylon basado en la JVM que dio Gavin King  (la mente pensante detrás de Hibernate) el pasado febrero en MadridJUG. Comentó que para la web estaban enfocando sus esfuerzos en un framework asíncrono basado en Vert.x.

«¿Asíncrono…?» Ya se me levantó la ceja a lo ‘Sobera’ .. y lo que me dio ya la puntilla es cuando se puso a picar en directo un servidor web (puro live coding :-)) me olía todo tenía un aire a como se trabaja con node.js,.. Así que me dije…»esto de Vert.x me lo tengo que mirar«.

He de reconocer que con el título del post me he pasado… He estado dándole vueltas a uno que tuviera ‘punch‘… y me parece que he tirado por lo fácil. En realidad Vert.x es mucho más que un servidor web… Su ‘misión‘, ‘visión‘ y ‘valores‘ es soportar millones de conexiones concurrentes usando un número mínimo de hilos del sistema operativo (¿¿?? así lo asegura en su documentación), imposibles en un esquema multihilo típico.

¿Qué es Vert.x?

Vert.x es un framework basado en eventos que corre en la máquina virtual de Java. Hecho para que sea fácil de escalar y soporte a tolerancia a fallos. Pensado para que existan de una manera sencilla varios cores en diferentes JVM y que se intercomuniquen entre ellos. Vert.x resuelve la concurrencia siguiendo el modelo de actores y además asegura que no existirán bloqueos entre hilos. Otra de sus características es su ‘bus de eventos‘ que permite desacoplar tu aplicación en módulos y comunicarse entre ellos a través de mensajes. Y todo de manera asíncrona.

Vert.x es ‘Políglota‘, soporta JavaScript, Ruby, Groovy, Java o Python y con vista a soportar Scala, Clojure e incluso PHP. Ejecuta código fuente por lo que, por ejemplo, existe la posibilidad de arrancarlo con ficheros ‘.java’ sin necesidad de compilarlos.

Simple hilo ó multihilo

Llegaréis a la conclusión y la compartiré de que con el título lo he simplificando demasiado ¿Pero porque he hecho esta comparación? Porqué Node.js y Vert.x tienen funcionamientos similares.

En JavaScript no existe la concurrencia. Aunque esta afirmación pueda ser no del todo cierto, porque en html5 y en el cliente existe los workers, en JavaScript sólo existe un hilo y las operaciones que bloquean se ejecutan con llamadas asíncronas.

Y quizás esto, lo que parece su debilidad, es su virtud es esto lo que hace que node.js este valorado como un servidor con poca latencia cuando existe mucha carga .

La diferencia fundamental entre node.js (o Vert.x) y un sistema tradicional multihilo es que la máquina virtual de node utiliza un sólo hilo para atender todas las peticiones. El hilo se limita a recibir la petición y realizar llamadas asíncronas. No espera el resultado de la petición y continua con la siguiente. Más tarde recogerá el resultado para devolverlo al cliente.

Por el contrario en un sistema multihilo, por ejemplo en un despliegue tradicional de Java, existe un hilo para cada petición. Este se queda bloqueado mientras espera el resultado de una operación. Esto hace que bajo mucha carga existan muchos hilos y parte de ellos esperando, lo que repercute en la latencia.

Vert.x trabaja de igual manera, en este caso utilizando el modelo de actores en el que cada uno de los actores será un ‘verticle‘. En la documentación lo definen con una partícula de Vert.x y en la práctica es la manera de definir el código desplegado. Los ‘verticles‘ se pueden agrupar en módulos (lo más usual cuando la aplicación deja de ser trivial) y estos se pueden reutilizar.

…Y la prueba de concepto

Con Vert.x es muy sencillo crear servidores y clientes socket, ssl, http y websocket.

Necesitaba poder familiarizarme con la herramienta y tenía que hacer algo. Es entonces cuando recordé la presentación y demo muy, muy chula que hizo Iván López en MadridGUG utilizando una cuenta de Gtalk como boot. Así que basándome en esa idea he creado una prueba de concepto realizando un Gateway con WebSockets y Gtalk utilizando Vert.x. El proyecto es un proyecto Java.

Se utiliza una cuenta de Gtalk para poder crear una sala de chat entre usuarios que se conectan por Gtalk y usuarios que se conectan con un navegador mediante websockets.

Este ejemplo no explota todas las posibilidades  de Vert.x como el escalado y el bus de eventos pero si que despliega servidores web y de websocket. Me ha permitido conocer como se genera, se configura y se ejecuta un módulo. En definitiva, ha conseguido mi objetivo que como he dicho más arriba era familiarizarme con el framework

El proyecto lo he subido a GitHub y que es lo que hace y como está explicado en el README.md .

[Logo GitHub] Prueba de concepto: Gateway WebSockets y Gtalk utilizando Vert.x

README.md

Espero que os sirva.

M.E.

Java versus JavaScript

Java versus JavaScript, reflexiones

Con la aparición de Node.js y la posibilidad de programar JavaScript en servidor se palpa entre los “javeros” cierta, no se encontrar la palabra, …¿preocupación?. La sensación es de “…nos están cambiando el agua…” y el comentario más oído es “… parece que es lo que se lleva ahora, no me gusta, pero habrá que aprenderlo…

A este desasosiego no ayudan post como los de PayPal (enlace ) en el que en resumen dicen que se pasan a JavaScript entre otras cosas porque es más rápido, necesitan menos gente y además se tira menos código. En respuesta a este post ha habido otros que han salido en defensa de Java y para poner coherencia en el tema (enlace)… y es que es lo que tienen casi todos los benchmark que pecan de partidistas.

En todas las ingenierías, pero mucho más en informática, tienes que estar en continua formación y estar al tanto de lo que se está haciendo. Es cierto que no podemos negar que también va todo un poco por modas y que es todo es cíclico. Parece que más tarde o más temprano siempre volvemos al mismo sitio que nos estamos moviendo en un circulo cerrado. Yo prefiero verlo más como una espiral… si la ves verticalmente parece que estás en el mismo punto,… pero que si la ves horizontalmente te das cuenta que estás en un nivel superior. Un ejemplo de esto son las nuevas bases de datos NOsql. Puede parecer que vuelven a las bases de datos pre-relacionales pero en realidad aportan muchas más cosas (escalabilidad, rapidez, big data y su explotación).

Pasa lo mismo con JavaScript hace mucho mucho tiempo que ha dejado de ser un lenguaje que sirve para poco más que hacer validaciones y hacer las “cosas bonitas” en la capa de presentación.

El gran problema de los “javeros” que dan sus primeros pasos en JavaScript, entre los que me incluyo, es que a la hora de enfrentarse al nuevo lenguaje piensan “… al final será algo como Java, con tipado dinámico y bueno con callbacks... ” y nada más lejos de la realidad, JavaScript es otra filosofía y en realidad casi casi comparte con Java poco más que el nombre y algunas palabras reservadas.

Creo que en el aprendizaje hay que enfrentarse con una actitud diferente y positiva. Me parece muy interesante el trabajo que ha realizado Micael Gallego en su blog (enlace), en el que explica su viaje en el aprendizaje del lenguaje desde el punto de vista de un programador Java y como a lo largo de los diferentes artículos va entendiendo la filosofía de JavaScript. A mi me ha ayudado mucho su lectura, así que no puedo más que recomendarla.

Reconozco que no soy experto en JavaScript y no puedo opinar en profundidad. Pero desde fuera creo que lo bueno y lo malo de JavaScript es que debido a su dinamismo, se pueden hacer las cosas de varias maneras. En Java por el contrario que es todo más cuadriculado.

De todas maneras creo que lo mejor es ser práctico, intentar conocer las debilidades y las fortalezas de cada lenguaje… Por ejemplo no me platearía hacer una aplicación de escritorio para Widonws en Java, para eso creo que es mucho mejor .NET. Por la misma razón me encontraría más a gusto, en aplicaciones de Backend en un proyecto con un equipo de trabajo numeroso, en un arquitectura Java que en una JavaScript, ya que al ser Java más “estricto” el código tendería ser más uniforme.

Lo que es cierto es que JavaScript permite hacer nuevas arquitecturas muy escalables y derivando gran parte de la responsabilidades al cliente. Angular.js es un framework que sigo muy de cerca. Sé que en algunos aspectos puede ser limitado pero prefiero la seguridad de basarme en algo estándar para montar una arquitectura MVC en el cliente.

Además JavaScript, junto con HTML5 se está convirtiendo en la única opción en la parte de navegador. Debido a las restricciones de seguridad que se están poniendo a los applets de java y a las extensiones y plugins. Son un autentico quebradero de cabeza por los agujeros de seguridad encontrados. Un ejemplo, Firefox a partir de su versión 26 no vienen habilitados por defecto los plugins excepto el de Flash.

Por eso en cosas “especiales” en la capa de cliente que por inercia antes te planteabas hacerlas con un applet o una extensión ahora enfocas tus esfuerzos en hacerlas en JavaScript… y se pueden hacer cosas muy, muy chulas.

Espero que os sirva.

M.E.

Configuración de entornos flexible en Spring utilizando SpEL

Introducción

En general cuando desarrollas una aplicación de cualquier tipo te enfrentas al reto de:

1) Configurar la aplicación de una manera sencilla

La configuración tiene que ser cómoda de modificar y tiene que estar centralizada (evitando que este desperdigada en multitud de ficheros de configuración las rutas, parámetros de conexión etc…)

2) Que un mismo ejecutable (jar o war en el caso de java) sirva para diferentes entornos.

Evitar tener que hacer un build para diferentes entornos (Además probablemente en un entorno corporativo no tengas acceso a las contraseñas y a las rutas de los recursos, etc.. de producción) A esto es a lo que me refiero con externalizable.

Spring es una poderosa y elegante herramienta que permite configurar una aplicación y establecer las dependencias entre sus clases a través de anotaciones o mediante archivos xml.

Pero esta potencia también puede llevar al peligro de que si no somos cuidadosos tengamos los parámetros de conexión, contraseñas, URL y rutas desperdigadas en varios archivos.

Para esto Spring ofrece herramientas que permiten cargar propiedades y valores de archivos ‘.properties‘ y además estos archivos pueden encontrase fuera del jar o del war e incluso pueden estar cifrados. Con esto se soluciona la centralización y la externalización.

El problema

Hecha la introducción paso a explicar el problema: Había que configurar una aplicación web en Spring en diferentes entornos en una misma máquina (un entorno en un Jetty y otro en un Tomcat), por lo que había que externalizar la configuración y además al estar en la misma máquina no servía que la ruta al fichero de configuración fuera fija (de estilo ‘/home/usuario/aplicacion.properties‘)

La solución

Ha sido utilizar el bean ‘PropertyPlaceholderConfigurer‘ de Spring y utilizar SpEL (Spring Expression Language) de esta forma:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
08
  <property name="locations" value="#{systemProperties['aplicacion.config'] != null ? 'file:' + systemProperties['aplicacion.config'] :'classpath:'}application.properties"/>
09
 </bean>
10
 ...
11
 </beans>

Código 01. Configuración xml de ‘propertyConfigurer’

La clave está en la línea 8. Si está definida la propiedad del sistema ‘aplicacion.config‘ buscará en el sistema de ficheros, el archivo de configuración ‘aplicacion.properties‘ en la dirección que indica su valor. Si no, busca el ‘aplication.properties‘ en el classpath (es decir dentro del war), por lo que este sería el archivo de configuración de la aplicación por defecto.

Un ejemplo del contenido de ‘aplicacion.properties‘ podría ser

1
...
2
aplicacion.config.pathfiles=/home/miguel/aplicacion/tmp
3
...

Código 02. Ejemplo de contenido de aplicacion.properties

Y la manera de usarlo dentro de la configuración xml de Spring sería:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="utilFichero" class="com.logicaalternativa.ejemplo.UtilFicheroImp"> 
08
  <property name="directorio" value="${aplicacion.config.pathfiles}"/>
09
 </bean>
10
 ...
11
 </beans>

Código 03. Ejemplo de como se utilizan los valores definidos en el archivo de configuración

Ya sólo me queda indicar como se define esa propiedad. En el Tomcat un buen sitio es el ‘catalina.properties de su directorio ‘config‘. Se definiría así:

1
...
2
aplicacion.config=/home/miguel/config-aplicacion-tomcat/
3
...

Código 04. Configurando el Tomcat

O directamente definiendo la propiedad al arrancar la máquina virtual. Por ejemplo si tu proyecto tiene configurado el plugin,  arrancando el jetty embebido de mvn de la siguiente manera:

1
mvn -Daplicacion.config=/home/miguel/config-aplicacion-jetty/ jetty:run

Código 05. Ejemplo al arrancar el jetty de mvn

En los ejemplos en los dos directorios ‘/home/miguel/config−aplicacion−jetty/‘ y ‘/home/miguel/config−aplicacion−tomcat/‘ se encontrarían sendos archivos ‘aplicacion.properties‘ cada uno configurados con los valores para cada entorno.

Espero que os sirva.

M.E.

De despliegue continuo y de responsabilidad personal

Despliegue continuo con Jenkins, Maven, Selenium y Junit

Están surgiendo nuevos conceptos como el despliegue continuo y la responsabilidad personal que están cambiando la forma de desplegar en un entorno de producción.

Digamos que la “manera tradicional” es decidir que funcionalidades van a ir en cada versión codificarlas, probar esa versión y por fin el despliegue en producción. Quién se haya enfrentado a esto sabe el estrés que produce el despliegue de una nueva versión sobre todo si conlleva bastantes cambios, …si ya sabemos que todo está probado, que no va a pasar nada, pero el mal trago del despliegue no te lo quita nadie … “¿irá todo bien? ¿no irá?

Despliegue continuo

¿Cómo están haciendo las cosas empresas como Facebook? … pues simplemente no hay versiones. Sigue leyendo

Hibernate 4: obtener el objeto Connection relacionado con la sesión

Una nota rápida de un problema con el que me he pegado hace poco.

Necesitaba lanzar una función de BBDD (Oracle) desde Hibernate manteniendo la transacción.  Para lanzar la función desde jdbc, en las versiones anteriores de Hibernate era muy intuitivo obtener el objeto Connection relacionado con la sesión pero en Hibernate 4 ha cambiado el interface Session. Sigue leyendo

Cambio de color a barra de progreso en Android

AndroidLa duración de manga de motocross se mide en minutos + 2 vueltas. A nivel regional son 20 minutos + 2 vueltas, a nivel nacional 30 minutos + 2 vueltas, etc… Entrenando lo normal es hacer mangas de la misma duración, o de menos tiempo (mejorando la rapidez) o de más (mejorando el fondo). Las motos de cross no tienen instrumentación y obliga a que una persona desde fuera indique al piloto cuanto le queda de manga.

¿Qué por qué cuento esto? Desde hace bastante tiempo mi hermano y yo corremos motocross a nivel regional. Bueno en realidad mi hermano es el “quemao” y siempre andaba quejándose de que sus entrenos no podían ser de calidad porque no sabía el tiempo que llevaba, no sabía cuando apretar, cuando regular, bla, bla, bla…

Ahí salió el “hermano informático”, surgió el problema de cambiar el color a una barra de progreso y echarme a la cara el peor ‘stakeholder‘ que he tenido en mi vida … Sigue leyendo