Jul 17

Puñetitas con SpringBoot y RestTemplateBuilder

Cuando en Spring Boot queremos hacer un cliente REST, podemos usar RestTemplate. Esta clase permite hacer llamadas REST al servidor.
Para evitar en todas las llamadas poner la URL completa, se puede poner la URL base de esta forma

RestTemplateBuilder builder = new RestTemplateBuilder();
RestTemplate restTemplate = builder.rootUri(“http://loquesea.com/”).build();

// y a partir de aqui, para una llamada GET por ejemplo
restTemplate.getForObject(“/entidad”, ….);

En getForObject() no hace falta poner la URL completa, basta empezarla con / y el rootUri que añadiemos anteriormente se añade al principio.

Pues bien, esto funciona bien, pero cuando hice mi primera prueba, iluso de mí, se me ocurrió poner esto

RestTemplateBuilder builder = new RestTemplateBuilder();
builder.rootUri(“http://loquesea.com/”)
RestTemplate restTemplate = builder.build();

peeero … ¡¡eso no funciona!!. ¿Por qué?. Metiéndome en el código del método rootUri() me asombra ver

/**
* Set a root URL that should be applied to each request that starts with {@code ‘/’}.
* See {@link RootUriTemplateHandler} for details.
* @param rootUri the root URI or {@code null}
* @return a new builder instance
*/
public RestTemplateBuilder rootUri(String rootUri) {
return new RestTemplateBuilder(this.detectRequestFactory, rootUri,
this.messageConverters, this.requestFactorySupplier,
this.uriTemplateHandler, this.errorHandler, this.basicAuthorization,
this.restTemplateCustomizers, this.requestFactoryCustomizers,
this.interceptors);
}
}

Lo advierte el comentario, devuelve una nueva instancia, por lo que la rootUri no se guarda en la instancia actual. Así que esta llamada solo funciona si se pone todo seguido como en el primer ejemplo rootUri(..).build(), o si nos guardamos en una nueva variable lo que devuelve rootUri() para luego llamar a buld() de lo devuelto.

En fin, despista un poco.

Jun 16

Comunicación Consola Servidor : Hazelcast, Vert.x, REST

Logo HazelcastEn el mismo proyecto del post anterior, estaba replanteandome como hacer que la interfaz de usuario (consola, aplicación java de escritorio) se conecte con el servidor (ejecutable java que no es servidor web ni de aplicaciones). Habitualmente abrimos un socket TCP/IP y definimos la mensajería. Tenemos librerías ya preparadas para esto, es eficiente y lleva muchos años funcionando. Pero a todos nos gusta jugar. Para este proyecto, me estoy planteando usar algún otro tipo de comunicación.

En otros proyectos que he visto (uno de los cuales lo he heredado), usan servicios web REST para todo lo que sea petición/respuesta desde la consola al servidor. Cuando el servidor quiere enviar algo de motu propio a todas las consolas, se usa ActiveMQ como cola de mensajes. Como el proyecto está con Spring Framework, hay soporte para las dos cosas haciendo fácil su codificación. Este mecanismo también está funcionando sin problemas.

Pero lo dicho, quiero seguir jugando.

Lo del servicio REST … ¿podemos eliminarlo usando sólo colas de mensajes o algo parecido? ¿Y en vez de una cola de mensajes ActiveMQ podemos usar algo más sencillo y ligero?

Pues me plantee hacerlo primero todo con Hazelcast. Si pongo modelos compartidos entre consola y servidor y con el mecanismo que tiene Hazelcast de publicación/suscripción a base de topics, quizás me bastaría sólo Hazelcast para reemplazar los web services REST y a ActiveMQ.

Pues no. Por un lado, Hazelcast no ofrece un mecanismo de petición/respuesta. Si uso un topic como petición de forma que el servidor se suscribe a ese topic de petición y cuando la consola quiere algo, publica en ese topic qué quiere, el servidor no tiene forma de responder. Habría que crear un topic temporal de respuesta, de forma que la consola que ha hecho la petición se suscribe a ese topic temporal y recoge la respuesta. Esto lo ofrece ActiveMQ de forma transparente, pero con Hazelcast habría que currárselo.

Y me surgió un segundo tema. Si en base de datos tenemos guardadas una serie de cosas y la consola las quiere, lo normal es pedírselas al servidor y el servidor en respuesta las devuelve. ¿Cómo lo hace en el caso de Hazelcast? Tendría que meterlo en algún tipo de colección de Hazelcast en memoria. ¿Y qué pasa sin son muchos datos?. Pues que hay que cargarlos todos en memoria, o inventar un mecanismo de cargas parciales, con paginados, etc, etc.

Así que descarté el uso exclusivo de Hazelcast. Lo he dejado, pero principalmente porque me vale para el modelo “vivo” de datos. En la aplicación se verá un mapa con barcos moviéndose. Estos barcos moviéndose en lo que llamo modelo “vivo” de datos, los datos que actualmente se presentan en todas las consolas y que el servidor se encarga de ir actualizando para todas. Esto es una ventaja frente a lo que teníamos. Sin Hazelcast (o un equivalente), el servidor tenía que enviar todos los cambios de ese modelo “vivo” a través de eventos por socket TCP/IP o ActiveMQ y las consolas debías actualizar su copia de dicho modelo en base a esos eventos. Con Hazelcast, el servidor toca la colección compartida y la consola ve dicha colección actualizada en todo momento. Es Hazelcast el que se “come” por debajo todo el tema de eventos de cambios del modelo y la actualización en el lado de la consola. La consola puede suscribirse a cambios en esa colección compartida, hazelcast ofrece esa posibilidad, pero para hacer otras cosas que necesite, como borrar el icono del barco en el mapa o desplazarlo, pero no para actualizar esa misma colección de barcos que ya está actualizada

Bien, no me vale Hazelcast para todo. ¿Qué tal Vert.x?. Tiene un EventBus, más sencillo de manejar que ActiveMQ, contempla la petición/respuesta, usa (o puede usar) Hazelcast por debajo por lo que encaja con el Hazelcast que me he planteado usar. Así que eso me planteé. Dejo Hazelcast para el modelo vivo y usar EventBus de Vert.x para peticion/respuesta y publicación/suscripción con Topics.

Me pongo a hacer mis pruebas y … ¡¡Sorpresa!!. Vert.x no garantiza el orden en la entrega de los eventos. Si garantiza que si un publicador envía eventos, un suscriptor concreto los recibe en el orden que el publicador los ha enviado. Pero no garantiza nada más. Si un publicador publica en varios topic y cada topic tiene un suscriptor distinto, los suscriptores pueden recibir los eventos en cualquier orden, no necesariamente en el orden en que el publicador los ha enviado. Y eso me hizo polvo. Para petición/respuesta a veces se necesita que las cosas vayan en orden, que no me contesten antes a lo que he pedido después. Así que que para petición/respuesta descarté Vert.x, seguro que puedo hacer apaños para garantizar el orden, pero va en contra de la filosofía de Vert.x y me parece una fuente importante de bugs si los desarrolladores se despistan.

¿Y para publicación/suscripción con topics, sin respuesta?. Bien, tengo Hazelcast que también lo hace. No voy a meter un framework por encima sólo para eso. Lo dejo aparcado por si en un momento dado Hazelcast se me queda cojo en este asunto y Vert.x me lo solucionara, pero lo dicho, queda aparcado.

¿Cómo hago al final lo de petición/respuesta?. Pues al final he dejado los web services REST.

¿Qué creo que he ganado con todo este cambio aparte de jugar y aprender? Principalmente el tema del modelo “vivo”. La colección compartida de Hazelcast entre consola y servidor me ahorra enviar eventos de cambios en ese modelo en el servidor, recogerlos en la consola y reconstruir en consola con código el mismo modelo que tiene el servidor.

En cuanto a topics, AciveMQ frente a Hazelcast, desde luego es mucho más potente y con más posibilidades ActiveMQ, pero es más complejo y no necesito todas esas posibilidades, tiro de momento por la opción más simple de Hazelcast.

 

Jun 10

Estructura de Plugins con OSGI / Spring Boot

osgi

spring boot

Estoy empezando una aplicación java, de escritorio, desde cero. Una de las cosas que pretendo hacer es que tenga plugins que se puedan instalar de forma adicional, no solo en el lado de la consola (javax.swing), sino también funcionalidades en el lado del servidor (java de escritorio).

Me he planteado dos opciones. Una es usar OSGI, que es el framework más estándar y conocido para hacer una aplicación modular con plugins. Pero aunque no está pensado para ello, se me ha ocurrido otra forma de hacerlo usando Spring Boot (por ir a lo más moderno).

Con OSGI, cada jar lleva un fichero de manifiesto donde indica qué paquetes java exporta a otros jar y qué paquetes java necesita de otros jar. Si el fichero de manifiesto no exporta o importa paquetes, el desarrollador no puede usar los paquetes que no han sido exportados/importados, el mismo IDE debidamente montado no le deja.

Con Spring Boot no hay esta opción de importar y exportar paquetes, pero se puede “apañar” con disciplina. Debemos montar una estructura de proyectos/subproyectos donde haya jar que sólo tengan interfaces o estructuras de datos. Los demás jar donde está el código sólo pueden depender de estos jar de interfaces/estructuras de datos. Esto se puede montar correctamente con maven/gradle. Puede quedar quizás una estructura de proyecto/subproyectos un poco engorrosa, pero si organizada y que impide al desarrollador usar en un proyecto cosas que no debe de otro (siempre que no se líe a tocar dependencias maven/gradle)

Para enganchar las distintas clases/servicios entre si de distintos jar, OSGI ofrece lo que llama Declarative Services. Cada jar registra en OSGI los servicios que ofrece (clases que implementan una interfaz java y que ofrecen alguna funcionalidad) y cada jar pide a OSGI los servicios que necesita (servicios a través de interfaces java y que necesita que alguien se las dé ya implementadas) . OSGI se encarga de “enganchar” en el arranque, automáticamente, a unos con otros en función de lo que ofrecen y necesitan.

Con Spring Boot, está el mecanismo que tiene de inyección de dependencias y anotaciones. Si una clase necesita un servicio, le basta con poner un atributo con la interfaz de ese servicio anotada con @Autowired. Si Un jar ofrece un servicio, basta que le ponga a la clase que lo ofrece la anotación @Service (o cualquiera de las alternativas, como @Component u otras). Spring Boot se encarga de ver qué servicios se ofrecen e inyectarlos en las clases que lo necesitan.

De una forma o de otra, el mecanismo de plugin sería que la aplicación principial definiera la interfaz que deben implementar los plugins y los servicios que deben ofrecer para integrarse correctamente en la aplicación. Por ejemplo, en la interfaz de usuario la interfaz que deben implementar los plugins pueden tener métodos como getActions() para añadir dichas acciones a un menú o barra de herramientas, getIcon() para poner el icono de dicho plugin en algún sitio, getPanel() para que el plugin pueda proporcionar su propio panel visual, etc. La aplicación principal pediría al framework todas las clases que ofrezcan este servicio (implementen esta interfaz) y los plugin presentes registrarían sus servicios en el framework.

¿Qué ventajas/inconvenientes tiene cada mecanismo?

OSGI es el estándar para plugins, y además permite el añadir plugins en caliente. Debidamente configurado, bastaría situar el jar con el plugin en un directorio concreto de la aplicación que está en ejecución y el plugin se cargaría automáticamente, inyectando en caliente los servicios que ofrece al que los necesite. Sin embargo, la pega de OSGI es es que es algo retorcido a la hora de desarrollar. Su objetivo es limitarnos para obligarnos a hacer el desarrollo modular y esas limitaciones a veces son un poco engorrosas.

Spring Boot por otro lado es muy sencillo de usar. Un par de anotaciones (@Autowired y @Service) y está todo apañado (por supuesto, siempre hay peguillas en el mundo real y casos extraños). Las pegas son que no permite el despliegue de plugins en caliente y que no obliga a desarrollo modular limitando visibilidad, por lo que tenemos que obligar a ese desarrollo modular a bases de subproyectos maven/gradle debidamente configurados.

Otra posible pega de Spring Boot es que en el arranque busca por todas las clases las anotaciones mencionadas para hacer el enganche. Si es un proyecto grande con muchas clases, el proceso de escaneo de todas las clases y sus anotaciones puede volverse lento. OSGI no tiene ese problema, porque cada jar, con código (o un xml si optamos por esa opción), pide o registra servicios en OSGI, no es OSGI el que se dedica a recorrer todo el código.

Y una ventaja clara de Spring Boot sobre OSGI es la cantidad de funcionalidades adicionales que de forma sencilla nos vienen de regalo. Por ejemplo, montar web services o soporte con bases de datos en Spring Boot es casi inmediato. En OSGI, aunque existe algo, es muy, muy engorroso de poner en marcha. Si conoces ambos frameworks, pero no has levantado nunca web services con ellos, en Spring Boot puedes buscar un tutorial y tener tu web service “hola mundo” en 10 minutos. Con OSGI, te puedes pasar una o dos semanas buscando los plugins que te dan soporte para crear web services y tenerlos funcionando, sin haber implementado todavía tu hola mundo. Spring Boot es seguramente más pesado, pero si quieres funcionalidad adicional es mucho más fácil.

¿Mi elección?

Para este proyecto que estoy empezando y que no tiene ningún requisito (ni visos de tenerlo) de despliegue de plugins en caliente, me he tirado por Spring Boot. Por su sencillez y porque voy a usar web services para comunicación entre consola y servidor, aunque sea java de escritorio.

Dec 17

Por qué me está gustando IntelliJ IDEA

 Hace ya un porrón de años tuve que elegir un IDE para trabajar con Java. Miré Eclipse y Netbeans, de aquella no existía IntelliJ y me acabé decantando por eclipse. Y desde entonces, más de 10 años ya, trabajando con eclipse.

Sin embargo, algunos compañeros míos usan IntelliJ y están muy contentos con él. También encontré unas estadísticas en las que IntelliJ se estaba usando cada vez más mientras que Eclipse parece que cada vez menos, aunque actualmente andan muy a la par.

Así que me decidí a probar IntelliJ …. y de momento me está convenciendo.

Me está costando acostumbrarme a los atajos de teclado o encontrar los comandos del IDE que quiero hacer, pero sólo es por la costumbre y poco a poco me voy haciendo a los nuevos atajos. Aparte de esto ¿por qué me está gustando?

Lo primero es el auto-compilar. Eclipse auto-compila siempre. IntelliJ por defecto no lo  hace, pero es una opción que se puede poner. El autocompilado de eclipse a veces hace el trabajo lento o pesado. En eclipse me veía frecuentemente esperando por barras del progreso de cosas que el eclipse estaba haciendo por debajo. En IntelliJ de momento no me está pasando.

Soy fan del editor vi. IntelliJ lo lleva por defecto, pero se puede activar/desactivar. Siempre tengo el gvim instalado en windows para determinadas tareas, ahora parece que no me va a hacer falta.

IntelliJ lleva la ventana de comandos del sistema empotrada por defecto. Habitualmente me gusta ejecutar los comandos de gradle, maven, git y subversion desde línea de comandos, porque me da la impresión de tener más control de lo que estoy haciendo. Lo de tener la ventana de comandos integrada en el IDE me está ayudando mucho. Sí, eclipse tiene un plugin opcional para poner.

Otra ventaja que resulta más o menos interesante es que el autocompletar de IntelliJ es más inteligente. Incluso autocompleta el nombre de la variable que estamos declarando, ofreciéndonos sugerencias. Por ejemplo, si tengo una clase MiClase y despues de poner el tipo MiClase le digo a IntelliJ que me diga el posible nombre de variable, me pone miClase.

Pero todo esto no dejan de ser detalles (bueno, quizás lo de las esperas de eclipse no sea tan tonto). Una de las cosas que me ha convencido totalmente de IntelliJ es que IntelliJ entiende por separado los classpath de test y de main. Tanto en gradle como en maven, hay directorios src/main/java y src/test/java y hay dependencias de compilado y dependencias de test. Tanto gradle como maven no incluyen para nada las dependencias de test en compilado o runtime, salvo que se estén haciendo test. Pues bien, eclipse no hace esta distinción en absoluto. En tu código de src/main/java puedes usasr clase que sean de test o de dependencias de test. En eclipse va, pero al compilar luego fuera de eclipse con gradle o maven, da error. IntelliJ sin embargo sí tiene en cuenta esta separación. Tiene su "classpath" de "proyecto_main" y "proyecto_test".

En fin, llevo ya un par de semanas con IntelliJ y me está gustando más que eclipse. Es posible que tenga que volver a eclipse cuando quera utilizar alguna cosa que no venga en la edición gratuita de IntelliJ.

Dec 10

Qué es Spring Boot

Hace unos meses estuve jugueteando con Spring Boot, pero el ponerme a hacer código a lo loco mirando la documentación y algunos tutoriales, no me dio una idea de lo que realmente es Spring Boot.

La idea de Spring Boot es que podamos hacer aplicaciones Spring, pero con cero configuración. No tenemos que hacer ningún fichero de configuración, ni ficheros XML. A Spring Boot, usando una herramienta propia, le decimos qué tipo de aplicación queremos (web, con jpa, con postgres, etc) y él solo nos genera una proyecto maven/gradle con todo lo necesario y que se autoconfigura en el arranque.

Por ejemplo, si decimos que queremos una aplicación web, Spring Boot automáticamente nos embebe un Tomcat y nos lo configura con el servlet de Spring. Por supuesto, si no nos gusta la configuración por defecto (no queremos Tomcat, por ejemplo), sí podemos cambiar cosas para usar jetty, jboss o el que nos guste.

¿y cómo hace esta magia Spring Boot?

Pues añadiendo en nuestro proyecto Maven/Gradle dependencias estilo "spring-boot-starter-****". Por ejemplo, si añadimos la dependencia "spring-boot-starter-web", es la que se encarga de añadir todo lo necesario para embeber un Tomcat y el que nos crea (sin que ni siquiera lo veamos en nuestro proyecto) el fichero web.xml de nuestra aplicación correctamente configurado para Spring. Si añadimos "spring-boot-starter-data-jpa" junto con la dependencia de algún driver de base de datos, como por ejemplo h2, es Spring Boot el que automáticamente en el arranque nos configurará automáticamente los DataSource para esa base de datos y todo lo necesario para acceder a esa base de datos usando JPA.

La magia de Spring Boot va incluso más allá. Una vez añadida la dependencia "spring-boot-starter-data-jpa" y la del driver de nuestra base de datos, sólo tenemos que crear nuestras clases de base de datos con las consabidas anotaciones @Entity, @Id, etc …  y una interfaz (adecuadamente anotada) que herede de la interfaz de Spring CrudRepository<MyBean, Long>, siendo MyBean la clase persistente que nos hemos creado y cuyo id es un Long. Y listo, no tenemos que implementar la interfaz, Spring Boot lo hace por nosotros en tiempo de ejecución, dándonos todos los métodos típicos de consulta/inserción/modificación y borrado de MyBean en base de datos.

Dentro de nuestro proyecto Spring Boot, en src/main/resources hay un fichero, en principo vacío, de nombre applicacion.properties. En ese fichero podemos poner properties propias de Spring Boot para cambiar las configuraciones por defecto de Spring Boot. Un ejemplo tiípico es cambiar el puerto por defecto 8080 de tomcat por otro. Basta añadir en ese fichero la linea server.port=8000 siendo 8000 el puerto que queremos en vez de 8080. Aquí tienes todas las posibles propiedades a poner y valores por defecto.

 

En fin, estoy con ello todavía, pero promete mucho y merece la pena echarle un ojo. Lo comentado aquí es un pequeño resumen de lo que se dice en este vídeo

 

 

Nov 29

git flow

git-flow

( Imagen de Our Workflow: git-flow

Hace poco, viendo un vídeo, descubrí git-flow.

Siempre había oído, tanto en git como en subversion, que hay que tener una rama de desarrollo, una rama para versiones estables, hacer ramas para cada nueva funcionalidad que se va a implementar, etc, etc. Pero siempre me ha parecido muy lioso. Los comandos de crear ramas y juntarlas tanto en subversion como en git, si bien no son especialmente complicados, si son varios comandos a ejecutar para cada una de esas tareas a hacer y requieren que todos los del equipo seamos muy rigurosos para hacerlo bien.

Pues bien, hay una herramienta para git, llamada git-flow, que justamente nos facilita la ejecución de esos comandos, haciendo que el proceso de crear las ramas para cada nueva funcionalidad, para cada nueva release, para corregir bugs, sea bastante más sencilla.

Con git-flow hay dos ramas principalmente. La rama master, en la que están las versiones estables de nuestro software, convenientemente etiquetadas, y la rama development, en la que se hace el desarrollo. La creación de estas ramas es muy sencilla una vez instalado git-flow, basta ejecutar

$ git flow init

Si queremos empezar a trabajar en una nueva funcionalidad, debemos crear una rama para ella que parte de la rama development. Nuevamente, con git-flow es inmediato

$ git flow feature start NOMBRE

donde NOMBRE es el nombre que queramos para la rama. Yo suelo poner el número de tarea de jira. El comando de git-flow crea la rama feature/NOMBRE y nos hace el checkout de ella para que podamos empezar a trabajar. Podemos subirla al servidor si queremos que más desarrolladores trabajen en ella, o dejarla en nuestro git local si sólo vamos a trabajar nosotros. Una vez terminada y probada la funcionalidad, hay que llevarla a la rama development, que se hace con el siguiente comando

$ git flow feature finish NOMBRE

Esto hace el merge de nuestra funcionalidad sobre la rama de desarrollo … y borra la rama de la funcionalidad, es decir, se borra la rama feature/NOMBRE, aunque los commit que hicimos en ella se han pasado a la rama de desarrollo.

Si quisieramos hacer una nueva entrega de nuestro software, es decir, pasar una nueva versión de la rama de desarrollo a la rama estable master, el comando de git-flow es

$ git flow release start VERSION

Esto crea una nueva rama release/VERSION donde podemos tener congelada este nuevo candidato a versión, hacer los cambios que consideremos necesarios para pasar a nueva versión (por ejemplo, cambiar en número de versión en los ficheros pom.xml o build.gradle, cambiar niveles de log, ficheros de configuración o lo que sea). Una vez que nuestra nueva versión está "fetén", para llevarla a la rama master el comando es

$ git flow release finish VERSION

Esto lleva los cambios de release/VERSION tanto a la rama master como a la rama de desarrollo. Etiqueta la rama master con una etiqueta que nos pide y que puede ser en número de versión o lo que queramos. Y finalmente, borra la rama release/VERSION.

Finalmente, si en la rama estable master encontráramos un bug que hubiera que corregir, git flow permite crear una rama directamente sobre la master para corregir el bug. El comando sería

$ git flow hotfix start BUG

Esto crea una rama hotfix/BUG para que corrijamos el bug. Una vez corregido, hay que llevar los cambios a master y suele ser buena idea llevarlos también a la rama de desarrollo, para que el bug quede corregido definitivamente. El comando es

$ git flow hotfix finish BUG

Esto lleva los cambios del bug tanto a master como a development, y borra la rama del bug.

Y esto es lo básico, bastante sencillo. Hay más comandos de git flow, y con opciones, pero con lo comentado aquí, así de sencillo, se tiene ya un flujo de trabajo sobre git bastante completito.

 

Dec 13

Un poquito decepcionado con los ESB

esb image  Hace tiempo que oí hablar de los Enterprise Service Bus (ESB) y con ellos he estado jugueteando por mi cuenta algún tiempo, leyendo e informándome en general, hasta que ha llegado la posibilidad de aplicarlo en un proyecto real.

En mi proyecto real, antes de tomar la decisión de si meter o no ESB y cual de ellos meter, decidí hacer algunas pruebas más en serio con los casos concretos que me iba a encontrar.

El primer punto son sockets TCP/IP con protocolo propio, es decir, mensajes binarios con su propia cabecera y forma de delimitar los mensajes dentro del flujo de bytes que es un socket TCP/IP. Mi primera opción de ESB, por supuesto, los gratis y más conocidos, en concreto, Apache Servicemix, Así que con él voy a hacer la prueba. Lo primero, es que si el protocolo es binario y no un simple protocolo de texto delimitado por retornos de carro, te tienes que hacer una clase java que sea capaz de hacer este trabajo por Apache Servicemix. De acuerdo, me puse a ello y conseguí hacerla…. pero me costó un buen rato de investigación. La documentación es escasa y en ningún sitio pone cómo hacerlo. Al final rebuscando por los ejemplos y fuentes del propio Apache Servicemix encontré cómo hacerlo. Esa ha sido mi primera pega/decepción con este ESB, la documentación es bastante pobre.

Y una vez conseguido, me pongo a probar y me encuentro una segunda pega. Un ESB implementa los Enterprise Integration Patterns (EIP), Y en ellos, hay dos posibles flujos de mensajes: En los que uno sólo envía y el otro sólo recibe, es decir, una única dirección, o bien los petición/respuesta, es decir, uno pide y el otro responde, por cada mensaje de ida debe haber uno de vuelta. Y eso a mí no me vale, en mi proyecto necesito que cualquiera de los dos lados, de modo espontáneo, puedan enviar o recibir, sin necesidad de haber enviado o recibido previamente una petición.

Bien, podría convivir con eso y seguramente encontraría algún tipo de solución.

Y se me ocurre probar lo que en EIP se llama controlbus, es decir, la posibilidad de parar y re-arrancar un flujo de datos a voluntad. Pues bien, Apache Servicemix lo soporta, da métodos start y stop para parar definitivamente el canal y pause/resume para pararlo temporalmente. Casualmente, con el componente camel-netty (que es el que nos proporciona socket TCP/IP), no funciona el suspend/resume. 🙁

Y finalmente, decido hacer otra prueba que también necesito, socket multicast. Pues bien, aunque teóricamente están soportados por Apache Servicemix, no es cierto, símplemente no funcionan. Hay dos componentes que nos pueden dar esta funcionalidad: camel-mina y camel-netty. Camel-Mina directamente dice que no lo soporta. Camel-netty sí, pero si lo pones, salta una excepción de "bind" y no funciona. Y no, no es que el puerto ya esté ocupado. Te pones a rebuscar en el código de camel-netty y ves que el test de JUnit que verifica el multicast directamente está deshabilitado. Y si lo habilitas, falla.

Así que decido pasar de Apache Servicemix, ya que me está dando demasiados problemas: falta de documentación para tus propios desarrollos, no funcina multicast… 

Y me busco otro ESB gratis, voy por jboss-fuse, y lo descarto casi inmediatamente. Tanto Apache Servicemix como JBoss Fuse se basan por debajo en la librería apache camel y la documentación de jboss es casi una copia de la de Servicemix. Así que mismos problemas … con uno añadido. Una de las cosas que aporta Jboss fuse en un eclipse "tuneado" para Jboss fuse, que permite definir gráficamente las rutas que quieres crear en el ESB… y que falla más que una escopeta de feria al menos con el componente camel-netty. Pongo el componente gráfico, relleno los formularios que salen …. y en el xml por debajo me genera mal la URL del punto de conexión. La arreglo a mano, y en cuento me descuido, me la vuelve a estropear.

Así que voy por otro ESB. El siguiente en la lista es Mule ESB. Este está mucho más guay, mucho mejor documentado, mis pruebas fueron bien a la primera, sin demasiada complicación …. pero me da la impresión de que es un ESB de pago. Creo que  me he bajado el trial de 30 días….

Con todo esto, ya casi he desistido de poner un ESB en el proyecto. Voy a darle un vistazo a wso2, que tiene muy buena pinta, la documentación parece buena y tiene pinta de ser gratis. A ver qué tal.

He visto por encima otros como OpenESB, Talend, y Synapse, pero son quizás menos conocidos y en todos ellos, mirando por encima la documentación, he visto alguna cosilla que no me acaba de convencer.

Estoy seguro que los ESB funcionan bien, ya que son bastante conocidos y aparentemente muy usados. Pero me da la impresión de que funcionan muy bien si te atienes a los protocolos para los que están pensados, en concreto y sobre todo, Web Services, JMS, HTTP, FTP, etc.

May 30

Autocompletar en los IDE

autocompletar en javascriptPara trabajar siempre me gustan más los lenguajes estáticamente tipados que los dinámicamente tipados y entre otras ventajas, una de ellas es la de autocompletar de los IDE. Pero siempre que digo esto, alguien me comenta que si el IDE está correctamente configurado, los dinámicamente tipados también tienen autocompletar.

Bien, esto es cierto, pero sólo parcialmente. Imagina el siguiente trozo de código en un lenguaje estáticamente tipado, como java

public void metodo ( UnaClase parametro) {
   parametro.???
}

Cuando empezamos a teclear en la zona de ???, el IDE sabe que parámetro es de tipo UnaClase, porque se ve claramente, así que es perfectamente capaz de darnos los métodos y atributos públicos de parámetro para que elijamos uno.

Sin embargo, en un lenguaje dinámicamente tipado, si tenemos el código equivalente

function unaFuncion (parametro) {
   parametro.???
}

aquí el IDE no tiene ni idea de qué tipo es parámetro y de hecho, no puede saberlo, porque parámetro puede ser de cualquier tipo cuando el código se esté ejecutando, se puede llamar a unaFuncion() pasándole un entero, una cadena de texto, un objeto propio que hayamos creado o cualquier otro tipo que se nos ocurra. Así que el IDE aquí es totalmente incapaz de ofrecernos opciones, salvo que el lenguaje tenga algo común en todos sus tipos.

¿Cómo se apaña entonces para autocompletar?. Bien, un caso como el que acabamos de mostrar es imposible, pero los IDEs tienen sus trucos para ofrecernos opciones de autocompletar cuando es posible. Por ejemplo, en el caso anterior, si tenemos

function unaFuncion (parametro) {
   parametro.funcion1();
   parametro.funcion2();
   var a = parametro.atributo1;
   parametro.???
}

aquí el IDE ve qué cosas usamos de parámetro, así que cuando lleguemos a los ??? nos ofrecerá las funciones y atributos que ya hemos usado (funcion1, funcion2, atributo1), sean o no correctos y de hecho, pueden no ser correctos porque nos hemos equivocado al teclear o simplemente porque en tiempo de ejecución alguien nos pasa como parámetro algo que no tenga esas funciones ni atributos.

Otro truco usado por los IDE es el siguiente

function unaFuncion () {
   var b = new UnaClase()
   b.???
}

en este caso, se ve claramente qué contiene la variable b, aunque no tenga tipo definido, ya que estamos haciendo un new de una clase concreta y metiéndola en la variable. Si el IDE es capaz de encontrar en nuestro código la definición de UnaClase, será capaz de ofrecernos sus métodos/funciones y atributos … es justo el caso de la imagen.

Así que sí, los IDE pueden autocompletar en lenguajes dinámicamente tipados, pero con ciertas limitaciones.

May 16

ESB vs MQ vs DDS

Ando últimamente mirando herramientas estilo Enterprise Service Bus (ESB), de colas de Mensajes (MQ) y Data Distribution Systems (DDS). La primera vez que oyes hablar de ellas te preguntas ¿qué son exactamente? ¿Para que sirven?. La primera explicación que encuentras en la Web de cualquiera de ellas es la habitual : "Una herramienta maravillosa que con poco trabajo te resuelve todos tus problemas y te va a hacer el más feliz de los programadores". Si profundizas un poco más, llegas a las definiciones técnicas que nadie entiende, como "Es la implementación del estándar JSR x33, bájate y lee el estándar de dos mil páginas para saber de qué estamos hablando".

Aquí va un "pequeño" resumen de qué son y para qué sirven, según lo he entendido tras andar investigando y jugando con algunas de ellas.

¿Cual es el problema que pretenden resolver?

Todas ellas pretenden resolver más o menos el mismo problema, pero lo hacen con diferentes aproximaciones, siendo más o menos intrusivas en nuestro desarrollo.

Imagina un sistema complejo en el que varios ejecutables están corriendo en varios ordenadores. Estos ejecutables colaboran entre sí enviándose mensajes unos a otros, compartiendo datos, repartiendo tareas, etc. El esquema podría ser similar al de la siguiente figura, donde hay tres ordenadores (las cajas cuadradas), con siete ejecutables A,B,C… y las comunicaciones entre ellos

Problema que pretende resolver ESB, MQ y DDS

Cada ejecutable conoce a los demás ejecutables con los que está trabajando y establece las conexiones que necesita para colaborar con ellos. Esta aproximación tiene varios problemas:

  • Cada ejecutable debe saber las IP/hosts y puertos donde están los otros ejecutables con los que colabora
  • Los ejecutables deben ponerse de acuerdo en el formato en el que se envían los datos.
  • Si más adelante queremos ampliar o modificar el sistema añadiendo, quitando o moviendo de sitio ejecutables, tendremos que tocar todos los ejecutables afectados. Por ejemplo, imagina que añadimos un cuarto servidor con ejecutables H y J que quieren colaborar con algunos de los ya existentes, casi seguro que tendremos que tocar los ya existentes para que admitan a los nuevos.
  • ¿Y qué pasa si alguno de esos ejecutables existentes no podemos tocarlo porque es un producto comercial, nos lo hizo otra empresa o se ha ido el desarrollador que lo concoce? (triste, pero real como la vida misma, a veces se va el que lo ha hecho y nadie más se atreve a tocarlo).

Dar flexibilidad a este tipo de montajes y facilitar la conexión con nuevos ejecutables es lo que pretenden resolver todo este tipo de herramientas ESB, MQ y DDS. Empezamos a ver la solución que propone cada una de ellas, empezando de la menos intrusiva (la que nos oblgaría a hacer menos cambios en nuestros ejecutables ya existentes) a la más intrusiva (que nos obligaría prácticamente a diseñar el sistema pensando en ella).

Enterprise Service Bus (ESB)

 Hay varias herramientas gratuitas de este tipo, como Apache Service Mix, Mule ESB, JBoss Fuse, WSO2 Enterprise Service Bus.La solución que proponen estas herramientas es arrancar uno o varios ejecutables ESB de forma que todas las aplicaciones se conecten al ESB en vez de unas con otras. Es en este ESB donde configuramos las rutas de las conexiones, diciendo por ejemplo, que lo que mande el ejecutable A se debe enviar al ejecutable B. El esquema sería parecido al siguiente

Enterprise Service Bus

Las bondades de esta solución son las siguientes

  • En el ESB se establecen las rutas de qué ejecutables hablan con qué ejecutables. De esta forma, el conocimiento de qué ejecutables hay y dónde están queda centralizado en el ESB, en vez de repartido por los distintos ejecutables de nuestra aplicación.
  • Estas rutas se pueden crear, modificar y eliminar en caliente, por lo que sería posible, por ejemplo, añadir un nuevo ejecutable a nuestro sistema y establecer las rutas en caliente para que este ejecutable sea capaz de enviar/recibir de los que ya están arrancados.
  • Las rutas pueden tener "inteligencia", de forma que pueden enviar un mensaje procedente de un ejecutable a varios ejecutables a piñón fijo, o bien seguir algún tipo de criterio para decidir a cual enviarlo, filtrar para enviar unos mensajes sí y otros no, etc, etc. Por supuesto, esta "inteligencia" se puede cambiar en caliente.
  • Como parte de la "inteligencia", las rutas pueden modificar los mensajes, siendo uno de los casos más habituales el cambio de formato de mensaje. Si un ejecutable usa el protocolo FTP y el otro HTTP, la ruta podría hacer la conversión correspondiente para, por ejemplo, coger ficheros de un servidor FTP y subirlos a una web con HTTP o al revés. Si los protocolos son estándar (FTP, HTTP, SNMP, XML, …) los ESB saben tratarlos y convertir entre ellos. Si no son estándar, podemos añadir nuestro trozo de código dentro del ESB para hacer las conversiones a nuestro gusto.
  • Otra ventaja adicional es que estas herramientas permiten de alguna forma monitorizar las rutas, de forma que podemos ver qué mensajes pasan por ellas, si se utilizan o no, si hay fallos, etc.
  • Las posibilidades que implementan las rutas suelen conocerse como "Enterprise Integration Patterns" o EIP. Siguiendo el enlace puedes ver todos estos patrones que suelen implementar.

Este es el mecanismo menos intrusivo porque nuestros ejecutables siguen siendo tal cual y enviando/recibiendo los mensajes en los formatos que ya tienen. Únicamente debemos cambiar la IP/host de conexión para que sea contra ESB en vez de unos con otros y nos queda el trabajo de configurar rutas en el ESB y darles la lógica que sea necesaria (conversiones de datos, filtros y en general cualquier EIP de la lista anterior).

Colas de Mensajes MQ

 Hay varias herramientas de colas de mensajes gratuitas, siendo ActiveMQ posiblemente la más conocida. Otras son RabbitMQ o Apache Kafka. La solución planteada es similar a ESB en el sentido de que debemos arrancar uno o más ejecutables MQ y nuestras aplicaciones deben conectarse a ellos. Sin embargo, es más intrusiva que ESB en el sentido de que debemos conectarnos con el protocolo que establece MQ, no podemos seguir conectándonos usando nuestros propios protocolos.

A MQ le enviamos mensajes en el formato que admite y cualquier otro ejecutable que tenga interés puede recibirlos. El esquema de trabajo sería como el siguiente

 Message Queue

Dentro de MQ se definen "topic" y "queue" con nombres, tantos como queramos. Los ejecutables envían mensajes a estos topic o queue. Otros ejecutables se suscriben a estos topic y queue de forma que recibirán los mensajes. La diferencia entre un topic y un queue es que un topic entregará sus mensajes a todos los ejecutables que se hayan suscrito, mientras que un queue sólo lo entregará a uno de los suscriptores. Un queue se utiliza más como un reparto de tareas.

Esta aproximación me parece más sencilla y elegante que la de los ESB, pero tiene el inconveniente de que nuestros ejecutables deben estar pensados para enviar y recibir mensajes a MQ, por lo que puede ser un trabajo modificar un ejecutable existente para adaptarse a MQ.

O quizás no. Los ESB suelen entender los mensajes de los MQ, de hecho, Apache Service Mix (un ESB) lleva integrado ActiveMQ (un MQ) Nuestra aplicación puede conectarse con su protocolo normal contra ESB y en ESB podemos establecer una ruta para convertir los mensajes en el formato de la aplicación a mensajes en el formato de MQ y enviarlos a MQ. Por otro lado, en otro sitio, haremos una ruta que recoja estos mensajes MQ, los convierta al protocolo que necesite la aplicación receptora y se los despache en el formato que ella entienda.

 Data Distribution Service DDS

De este tipo de aplicaciones hay menos gratuitas, pero tenemos por ejemplo OpenDDS y OpenSplice DDS. El concepto aquí es similar a las MQ, pero va más allá. Debemos arrancar uno o más ejecutables DDS y nuestras aplicaciones deben conectarse a ellos. La diferencia con MQ es que en DDS debemos definir todos nuestros tipos de datos y nuestros datos. Por ejemplo, si nuestra aplicación controla una flota de camiones, debemos indicar a DDS que tenemos un tipo camión con los campos matrícula, carga máxima, año de fabricación, modelo, marca, etc. y debemos indicar a DDS que vamos a tener una lista de camiones en revisión, una lista de camiones en recorrido, etc, etc.

A partir de aquí, nuestros ejecutables se conectan a DDS y en formato DDS van alimentando estos datos. Cualquier ejecutable puede a su vez suscribirse a los datos para enterarse de cambios en ellos. El esquema sería el siguiente

Data Distribution Service DDS

Esta solución como se puede intuir es la más intrusiva de todas, ya que no solo nos obliga a adaptarnos al protocolo de DDS, sino que de alguna forma dejamos en DDS la responsabilidad de mantener nuestros datos. Hasta cierto punto, DDS hace las veces de una base de datos (de hecho, suele tener una base de datos detrás que respalda nuestros datos), pero con la posibilidad de suscribirse a cambios. DDS suele además poder trabajar "distribuido". Varios ejecutables DDS interconectados entre sí, de forma que si metemos datos por uno de ellos, podemos retirarlo en cualquiera de los otros.

La principal ventaja de DDS es que está pensado para ser muy eficiente, por lo que no es raro encontrarlo en sistemas de tiempo real, defensa , espacio, transporte.

May 09

He leído “ActiveMQ in Action”

ActiveMQ in actionHe leído ActiveMQ in Action, una forma de enterarse de qué va ActiveMQ. El libro en sí no me ha gustado demasiado, se hace pesado de leer. Explica un concepto (eso sí es útil), te dice que el ejemplo de código de ese concepto está en tal sitio web, que para ejecutarlo uses tal comando y luego te planta dos páginas de libro viendo el log de salida del programa. Así una y otra vez.

Sin embargo, como yo soy más de enterarme bien de los conceptos que de andar mirando el detalle del código, el libro me ha servido para saber de qué va ActiveMQ y sus posibilidades.

ActiveMQ ofrece un servicio de mensajería entre distintas aplicaciones, o incluso para distintas partes dentro de una misma aplicación. Una aplicación o una parte de ella puede enviar mensajes a ActiveMQ y otra aplicación u otra parte de la misma pueden recoger esos mensajes. Aparte de esto, las características que mas me han llamado la atención de ActiveMQ son las siguientes:

Los mensajes pueden ser persistentes, es decir, se guardan automáticamente en ficheros o base de datos, según configuremos, de forma que si paramos la aplicación ActiveMQ y la volvemos a arrancar más adelante, los mensajes no entregados cuando paramos la aplicación, se recuperan y se pueden entregar en cuanto alguien los recoja.

Tiene posibilidad de arrancar varios ActiveMQ para trabajar colaborando, bien en forma de cluster, bien en configuración maestro-esclavos. En la configuración de cluster, los ActiveMQ se interconectan entre sí, de forma que si entregamos un mensaje en uno de ellos, se puede recoger en cualquiera de los otros. La configuración de cluster es muy sencilla, tiene posibilidad de "autodescubrimiento" de forma que según se vayan arrancando aplicaciones ActiveMQ en la red local se incorporan automáticamente al clustter, o bien podemos indicar las IPs concretas donde está cada ActiveMQ, para formar un cluster fijo. En cuanto a la configuración maestro-esclavo, es también sencilla. Un ActiveMQ es el que hace de maestro y es al que se conectan las aplicaciones. Los esclavos únicamente van guardando réplicas de los mensajes. Si el maestro se cae, uno de los esclavos entra en funcionamiento y las aplicaciones deben re-conectarse al nuevo maestro. Las librerías para clientes de ActiveMQ se pueden configurar de forma que hagan esta reconexión automáticamente.

Y lo que más me ha gustado, embeber un ActiveMQ dentro de nuestra propia aplicación es casi inmediato. Si ponemos la dependencia del jar adecuado (activemq-broker y activemq-client), basta con que nuestra aplicación establezca una conexión contra ActiveMQ usando el protocolo "vm://un-nombre" y automáticamente se creará una instancia de ActiveMQ con nombre "un-nombre" dentro de nuestra aplicación, disponible para cualquier parte de ella. Si además, a esa instancia le creamos una conexión adicional  "tcp:….", otros programas externos podrán conectarse a nosotros para recibir nuestros mensajes o enviarnos los suyos propios. También podemos crearle conexiones de red adicionales, de forma que nuestra instancia embebida de ActiveMQ forme parte de un cluster externo de ActiveMQ.

En resumen, me ha gustado la herramienta, es bastante simple de poner en marcha, de montar clusters e incluso de embeberla en nuestras aplicaciones. No me ha gustado que el envío de mensajes es relativamente tedioso: hay que crear la conexión, de la conexión una sesión, de la sesión un destino que no es más que un nombre, del destino crear una cola o un topic (son dos posibles formas de distribución del mensaje), un producer (el que envía el mensaje), construir el mensaje y enviarlo. Muchos de estos pasos se pueden dejar preparados para no repetirlos muchas veces, pero no deja de ser "un pelín" engorroso. Con la recepción algo similar.

De todo esto han salido algunos tutoriales de ActiveMQ en la Chuwiki.