Spring Integration: Ejemplo completo.

Spring Integration: Ejemplo completo.

 

0. Índice de contenidos.

1. Introducción

Como vimos en el anterior tutorial Spring Integration es la implementación de una plataforma de integración propuesta por Spring Framework. En este tutorial vamos a ver un ejemplo de uso más complejo en el que consumiremos diferentes servicios, transformaremos datos y gestionaremos el flujo de los mensajes en función de su contenido.

2. Entorno.

El tutorial está escrito usando el siguiente entorno:
  • Hardware: Portátil MacBook Pro 15′ (2.2 Ghz Intel Core I7, 8GB DDR3).
  • Sistema Operativo: Mac OS Snow Leopard 10.6.7
  • Spring Integration 2.0.5.
  • Spring 3.0.5.
  • Apache JMeter 2.4.

3. El problema.

El escenario que proponemos es el siguiente. Trabajamos con tres entidades bancarias, cada una de las cuales tiene un servicio que devuelve las cuentas y saldo de un cliente de dicha entidad. Para que el servicio devuelva las cuentas y saldos debe recibir el identificador del cliente para esa entidad. Además, disponemos de un servicio que, recibiendo un NIF de un usuario devolverá las entidades bancarias y el identificador del usuario de cada una de las entidades con las que tiene cuentas abiertas el usuario. Nuestra plataforma de integración (Spring Integration) deberá hacer lo siguiente. Recibirá peticiones via Web-Service recibiendo el NIF de un usuario. Con ese NIF consumirá el servicio de entidades por cliente. Con lo que responda ese servicio, irá a cada uno de los servicios de las distintas entidades con las que trabaja el cliente a por las cuentas y saldos del cliente en esa entidad. Devolverá una respuesta con los datos de todas las cuentas y saldos que tiene el cliente en todas las entidades. Además dejaremos un registro en un fichero (log) por cada petición que reciba la plataforma. Las características de los servicios son las siguientes:
  • Servicio de consulta de entidades/identificadores de cliente por entidad: Este es el servicio que devuelve las entidades e indentificadores de cliente por entidad. Recibe un NIF. Es un Servicio WEB.
  • Servicio de consulta de cuentas de usuario en la entidad 1 (código de entidad 088): Servicio Web que recibe peticiones con el identificador del cliente para dicha entidad y devuelve sus cuentas con su saldo.
  • Servicio de consulta de cuentas de usuario en la entidad 2 (código de entidad 767): Servicio REST que recibe peticiones con el identificador del cliente para dicha entidad y devuelve sus cuentas con su saldo.
  • Servicio de consulta de cuentas de usuario en la entidad 3 (código de entidad 955): Clase Java a la que se invoca pasando el identificador del cliente para dicha entidad y devuelve una lista (Collection) con las cuentas y saldo.
Gráficamente hay que hacer esto:

4. Los Servicios Web.

Como hemos comentado, dos de los servicios son Web-Services. El servicio que recibe un NIF y devuelve los identificadores del cliente para cada una de las entidades bancarias con las que tiene cuentas debe recibir un elemento “usuario” que contendrá un nodo hijo “NIF”. Devolverá una “respuesta” con una lista de “clienteEntidad” tal y como se aprecia en el esquema del siguiente .wsdl: El servicio que recibe el identificador del usuario de la entidad 088 y devuelve la lista de cuentas con saldos debe recibir un elemento “cliente” que contendrá un nodo hijo “ID”. Devolverá un elemento “cuentas” con una lista de “cuentaSaldo” tal y como se aprecia en el esquema del siguiente .wsdl:

5. Paso 1: Recibiendo las peticiones del cliente.

Una vez presentado el escenario, lo primero que haremos será configurar nuestra plataforma de integración para que sea capaz de recibir peticiones del cliente. El cliente nos enviará el NIF del usuario del que queremos obtener sus cuentas y saldos. Añadimos lo siguiente en el fichero de configuración de Spring. Lo que estamos haciendo es definir un gateway de entrada vía Web-Service “wsInboundGateway” que hará pasar las peticiones por el canal de entrada “inputChannel” el cual tiene un Service-Activator “usuarioEndpoint” que procesará dichas peticiones y las enviará al siguiente canal “idsUsuarioChannel”. El Service-Activator sería el siguiente: El Service-Activator recibe en su método handleRequest un DOMSource (XML de la petición) y lo transforma a un objeto Usuario. Dicho objeto será la entrada del siguiente canal “idsUsuarioChannel”. Es muy parecido al ejemplo que vimos en el anterior tutorial. Nótese que esta tranformación podría haberse hecho usando otro componente distinto a un Service-Activator, como podría ser un Transformador.

6. Paso 2: Trazando la petición y obteniendo el identificador del usuario por cada entidad bancaria.

Bien, una vez recibidos los datos de entrada, el siguiente paso será trazar la petición en un fichero de log y conectar con el servicio que nos dará el identificador de cliente por cada una de las entidades bancarias con las que tenga cuentas abiertas el usuario. Añadimos lo siguiente en nuestro fichero de configuración de Spring:   Recordemos que en el paso anterior vimos que el Service-Activator enviaba los datos al canal idsUsuarioChannel. Pues bien, a este canal le añadimos un logging-channel-adapter “loggingChannel” que añadirá a un fichero de logs cada mensaje (payload) de entrada que pase por este canal. Por otro lado, tenemos un gateway que conectará con el Servicio Web de consulta de identificadores por entidad y envía los datos a un canal llamado “clienteEntidadSplitterChannel”. La transformación de los datos la delega en UsuarioToClienteEntidadMarshaller. El método marshal recibirá los usuarios entran por el canal y los transforma en el XML necesario para enviárselo al WS de identificador de cliente por entidades. El método unmarshal recibe la respuesta del servicio (XML) y la transforma en una lista de UsuarioEntidad (contiene id de usuario e id entidad).

7. Paso 3: descomponiendo el mensaje.

Llegados a este punto ya tenemos una lista con los identificadores de cliente para cada una de las entidades con las que trabaja. Lo que tenemos que hacer ahora con ese mensaje (lista de pares identificador/entidad) es descomponerlo en mensajes identificador/entidad para que sean procesados de manera independiente. La descomposición del mensaje en mensajes más simples será responsabilidad del componente splitter, el cual enviará la salida al canal “usuarioEntidadRouterChannel” que recibirá la lista de mensajes.

8. Paso 4: Enrutando los mensajes en función de su contenido.

Bueno, pues ya tenemos cada identificador de usuario para cada entidad con la que trabaja en mensajes independientes. Ahora lo que debemos hacer es conectar con el servicio de cada entidad bancaria, pero antes, debemos saber qué mensajes irán por el canal que comunicará con cada entidad. Tendremos 3 canales: uno por el que pasarán los mensajes que vayan a la entidad 1 (088), otro por el que pasarán los que irán a la entidad 2 (767) y otro por el que pasarán los de la entidad 3 (955). Por tanto necesitamos enviar los mensajes, en función de su contenido a su canal correspondiente. Usaremos un enrutador. Creo que se entiende perfectamente, pero lo explico un poco. Este canal contiene un router que, en función del contenido del mensaje (recordemos que en este canal los mensajes entrantes son de tipo UsuarioEntidad), en concreto en función del valor del atributo entidad (método getEntidad) que nos dirá la entidad bancaria del cliente, enviamos el mensaje por un canal u otro.

9. Paso 5: obteniendo las cuentas del cliente para la entidad 088.

Vale, pues vamos a configurar el canal por el que pasarán los mensajes con los clientes de la entidad 088. Recordemos que debemos conectar con un WS para obtener las cuentas y saldos del cliente de dicha entidad. Este caso es muy parecido a cuando conectamos con el WS que devolvía los ids de usuarios en función de su NIF en el paso 2. El marshaller es muy parecido al del caso anterior. En este caso, con la respuesta del servicio devolverá una lista de CuentaSaldo (clase que nos hemos creado para guardar esos datos).

10. Paso 6: obteniendo las cuentas del cliente para la entidad 767.

Recordemos que para obtener las cuentas de un usuario de la entidad bancaria 767 debemos consumir un Servicio REST mediante una petición GET. El responsable de convertir los datos de respuesta en una lista de CuentaSaldo será entidad767Converter:

11. Paso 7: obteniendo las cuentas del cliente para la entidad 955.

Y nos queda hacer lo mismo con la entidad 955. Recordemos que en este caso es una clase quien nos devolverá la lista de cuentas y saldos, por tanto, con un simple Service-Activator nos valdrá. En este ejemplo la clase corre dentro de la misma aplicación que Spring Integration (CuentasCliente955.java) pero si estuviese en otro entorno bastaría una invocación RMI. Nuestro Service-Activator:

12. Paso 8: agregar todos los resultados y devolver la respuesta.

Bueno, pues ya queda poco. Lo único que nos falta es agrupar todos los resultados que nos han devuelto los servicios de las entidades bancarias y devolver los datos. Para ello haremos uso de un agregador (juntará todas las respuestas en un único mensaje) y un Service-Activator (devolverá la respuesta). El agregador recibe la lista de respuestas de todos los servicios anteriores y las une en un único mensaje (Cuentas): El Service-Activator recibe los resultados unificados en el bean Cuentas y prepara la respuesta:

13. Probando el ejemplo.

Hemos colgado todo el código fuente del ejemplo: tanto servicios como la plataforma con Spring Integration en un repositorio público https://github.com/autentia/esb-tutorial, para que se lo descargue quien quiera. Para probarlo arrancamos los Servicios Web (localhost:8081) y el Servicio REST (localhost:8081), así como la aplicación de Spring integration (localhost:8080). Todas las aplicaciones que hemos colgado en el repositorio tienen su correspondiente .jmx para que puedan ser probados con JMeter. Una vez tenemos todo arrancado enviamos la siguiente petición a la plataforma (aplicación con Spring Integration): Y la respuesta que nos devuelve es la esperada, la lista de todas las cuentas y saldos de todas las entidades bancarias del cliente.

14. Referencias.

15. Conclusiones.

Después de la introducción a Spring Integration hemos querido hacer un ejemplo mucho más completo para demostrar todo lo que se puede hacer, o al menos una parte, con este sistema de integración. Recordemos que Spring Integration nos provee de mucha más funcionalidad de la que hemos visto en este tutorial, pero creo que con este ejemplo, cualquiera se puede hacer una idea del alcance de Spring Integration y, en general, de las plataformas de integración. Espero que este tutorial os haya sido de ayuda. Un saludo. Miguel Arlandy marlandy@autentia.com Twitter: @m_arlandy