w w w . c h a k r a y . c o m
Orquestar sevicios con el ESB de
WSO2 Iván Fontanals Este documente explica como usar el ESB como orquestador de varios servicios
desplegados en el AS o en el ESB como proxies, de forma que podamos ejecutar tareas o
grupo de tareas siguiendo un flujo de ejecución determinado por la orquestación a nivel de
WSO2 ESB.
2
Por Iván Fontanals IT Consultant
Índice
1. Qué es la orquestación de un servicio ..................................................................... 4 1.1 Estrategias de orquestación en SOA ................................................................. 4 1.2 Service Chaining ................................................................................................ 5 1.3 “Complex Service Chaining” con “Call Mediator” ............................................... 5
2. Caso de uso: Actualizar pedido una vez recibido el pago ....................................... 6 2.1. Definición del Proxy Service .............................................................................. 6 2.2. Definición de la secuencia ................................................................................. 7 2.2.1. Actualización del pedido ................................................................................. 7 2.2.2. Generación de la factura o PDF ..................................................................... 8 2.2.3. Envío del email ............................................................................................. 10 2.2.4. Envío de la respuesta al cliente .................................................................... 10 2.3. Código completo de la secuencia .................................................................... 11
Autor: ............................................................................................................................ 13
Revisado por: ............................................................................................................... 13
3
Por Iván Fontanals IT Consultant
4
Por Iván Fontanals IT Consultant
1. Qué es la orquestación de un servicio
Nos encontramos habitualmente con procesos de negocio complejos, donde la
respuesta de una llamada sirve como entrada de otro y que permita la invocación de
un servicio u otro.
La orquestación se puede realizar desde una herramienta BPM, pero en nuestro caso
usaremos directamente el ESB de WSO2 para definir un pequeño flujo que acabará
realizando lo que nos pide el negocio.
Para ello, usaremos distintos mediadores y patrones que comentaremos mas
adelante, pero vamos a explicar primero las dos alternativas que tuve sobre la mesa
justo antes de empezar a desarrollar el use case.
1.1 Estrategias de orquestación en SOA
Hay diferentes estrategias:
• Service Chaining 1 y/o Service Routing 2
o Básicamente, a través de diferentes “Mediators” podemos componer
la ejecución compleja y la secuenciación entre servicios mediante
sus EndPoints. Este documento trata de esto.
• Processes Orchestration
o Representa la composición y ejecución de grupo de actividades
llamados procesos usando un metalenguaje de alto nivel para definir
el orden de ejecución de las tareas que forman parte del proceso.
Por lo general, cada tarea está asociado a la ejecución de un
servicio.
1 Service Orchestration with WSO2 ESB: http://wso2.com/library/articles/2014/02/service-orchestration-with-wso2-esb 2 Lightweight Service Orchestration for Non-blocking Backend Services using WSO2 ESB: http://wso2.com/library/tutorials/2013/12/lightweight-service-orchestration-for-non-blocking-backend-services-using-wso2-esb
5
Por Iván Fontanals IT Consultant
1.2 Service Chaining
En este caso, la respuesta de un enpoint (usando el mediador SEND) sería la entrada
del siguiente proceso, usando para ello una Sequence distinta. Esto funciona
perfectamente, pero desde mi punto de vista, pierdes el control de lo que tu proceso
de negocio hace de forma global, ya que delegas a la sequence la finalización del
servicio, y desconoces a priori si esta sequence hace otra ejecución hacia otra
sequence.
1.3 “Complex Service Chaining” con “Call Mediator”
En este caso, se usa el “Call Mediator”, que permite realizar llamadas a distintos
EndPoints (EP) de forma ordenada y donde tenemos acceso al Payload del mensaje
antes y después de su invocación, de forma que no es necesario el uso de
inSequence / outSequence para controlar la composición del mensaje de retorno.
6
Por Iván Fontanals IT Consultant
Para el ejemplo que veremos a continuación, se ha usado esta segunda alternativa,
puesto que se ve de una forma más intuitiva la interacción con los diferentes servicios
(EPs), pudiendo usar también otros mediadores como Clones, Filters, etc.
2. Caso de uso: Actualizar pedido una vez recibido el pago
El caso de uso consiste en un proceso de negocio que permitirá actualizar un pedido
tras haber recibido el pago del mismo, enviando un email con la factura adjunta del
mismo. Así pues, tenemos identificados 3 servicios simples que serán:
• Actualización del pedido tras el pago
• Generación de la factura o PDF adjunto
• Envío del email al usuario
2.1. Definición del Proxy Service
El servicio no hace mas que iniciar la sequence previamente creada, que es donde
está toda la interacción de servicios. En este caso, la entrada del proxy será un XML
con la info del pedido:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.orders.chakray.com/"> <soapenv:Header/> <soapenv:Body> <ser:processOrderPaymentMock>
7
Por Iván Fontanals IT Consultant
<arg0> <amount>12</amount> <status>OK</status> <!--Optional:--> <txnId>ABXXX23423w234</txnId> </arg0> </ser:processOrderPaymentMock> </soapenv:Body> </soapenv:Envelope>
Y el Proxy creado en el ESB, será como el siguiente:
<?xml version="1.0" encoding="UTF-8"?> <proxy xmlns="http://ws.apache.org/ns/synapse" name="receivePayment" transports="https,http" statistics="disable" trace="enable" startOnLoad="true"> <target> <inSequence> <sequence key="receivePayment_SEQ"/> <send/> </inSequence> </target> <publishWSDL endpoint="OrdersService_EP"/> <parameter name="disableOperationValidation">true</parameter> <description/> </proxy>
2.2. Definición de la secuencia
Una vez el servicio recibe la petición (podemos usar SoapUI para realizar la invocación
cliente), se inicia la secuencia receivePayment_SEQ, que es quien realizará las
llamadas a los servicios simples tomando decisiones o reaprovechando la salida de
una llamada previa.
2.2.1. Actualización del pedido
Tal y como recibimos la llamada en el proxy, la reenviamos a nuestro servicio de
actualización que tenemos desplegado en el AS y configurado como enpoint
OrdersService_EP. Este servicio es quien recibirá el XML de entrada antes mostrado.
8
Por Iván Fontanals IT Consultant
<call> <endpoint key="OrdersService_EP"></endpoint> </call>
2.2.2. Generación de la factura o PDF
Despues de invocar al EP, el servicio devolverá el ID del pedido, Fase y estado del
pago que deberemos capturar. Esto se realizará con el mediator Property, que a través
de un XPath nos permitirá leer este valor y guardarlo como variable en el contexto del
flujo. Muy importante este punto si queremos reusar estas variables para futuras
invocaciones, tal y como es nuestro caso.
Una particularidad que tiene este ejemplo es que se generará la factura o PDF y se
enviará el email sólo si el pedido pertenece a una FASE I, lo que se realizará con el
mediator filter. De este modo conseguiremos también tener un ejemplo mas completo
donde se pueden ver interacciones con distintos mediadores.
<property xmlns:ns="http://org.apache.synapse/xsd"
xmlns:ser="http://service.orders.chakray.com/" name="ORDER_ID"
expression="//orderId"></property>
<property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="PHASE" expression="//phase"></property> <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="PAYMENT_STATUS" expression="//paymentStatus"></property> <filter xmlns:ns="http://org.apache.synapse/xsd" source="//phase" regex="FIRST"> <then> […] GENERACION_PDF ENVIO DE EMAIL […] </then> <else></else> </filter>
La invocación del servicio de generación de PDF requiere una modificación del
Payload de entrada, que se realizará con el mediator payloadFactory. En este caso, se
tiene que invocar al servicio pasándole cómo parámetro el ID del pedido.
9
Por Iván Fontanals IT Consultant
<payloadFactory media-type="xml"> <format> <gen:generateInvoice xmlns:gen="http://generator.services.chakray.com/"> <arg0 xmlns="">$1</arg0> </gen:generateInvoice> </format> <args> <arg expression="get-property('ORDER_ID')" evaluator="xml"></arg> </args> </payloadFactory> <call> <endpoint key="GeneratePdf_EP"></endpoint> </call>
10
Por Iván Fontanals IT Consultant
2.2.3. Envío del email
La invocación de este último paso es similar a la anterior…modificamos el payload e
invocamos al servicio.
<payloadFactory media-type="xml"> <format> <mail:sendEmailToCustomer xmlns:mail="http://mail.service.chakray.com/"> <arg0 xmlns="">$1</arg0> </mail:sendEmailToCustomer> </format> <args> <arg expression="get-property('ORDER_ID')" evaluator="xml"></arg> </args> </payloadFactory> <call> <endpoint key="EmailsService_EP"></endpoint> </call>
2.2.4. Envío de la respuesta al cliente
Para enviar la respuesta, generaremos nuestro mensaje a partir de la respuesta de los
anteriores servicios. Si no lo hacemos así, por defecto, devuelve como respuesta el
resultado del último servicio invocado.
<payloadFactory media-type="xml"> <format> <ns2:processOrderPaymentMockResponse xmlns:ns2="http://service.orders.chakray.com/"> <return> <orderId>$1</orderId> <paymentStatus>$2</paymentStatus> <phase>$3</phase> </return> </ns2:processOrderPaymentMockResponse> </format> <args> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:ORDER_ID" evaluator="xml"></arg> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:PAYMENT_STATUS" evaluator="xml"></arg> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:PHASE" evaluator="xml"></arg> </args> </payloadFactory>
11
Por Iván Fontanals IT Consultant
2.3. Código completo de la secuencia
<sequence xmlns="http://ws.apache.org/ns/synapse" name="receivePayment_SEQ"> <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="TXN_ID" expression="//txnId"></property> <call> <endpoint key="OrdersService_EP"></endpoint> </call> <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="ORDER_ID" expression="//orderId"></property> <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="PHASE" expression="//phase"></property> <property xmlns:ns="http://org.apache.synapse/xsd" xmlns:ser="http://service.orders.chakray.com/" name="PAYMENT_STATUS" expression="//paymentStatus"></property> <filter xmlns:ns="http://org.apache.synapse/xsd" source="//phase" regex="FIRST"> <then> <payloadFactory media-type="xml"> <format> <gen:generateInvoice xmlns:gen="http://generator.services.chakray.com/"> <arg0 xmlns="">$1</arg0> </gen:generateInvoice> </format> <args> <arg expression="get-property('ORDER_ID')" evaluator="xml"></arg> </args> </payloadFactory> <call> <endpoint key="GeneratePdf_EP"></endpoint> </call> <payloadFactory media-type="xml"> <format> <mail:sendEmailToCustomer xmlns:mail="http://mail.service.chakray.com/"> <arg0 xmlns="">$1</arg0> </mail:sendEmailToCustomer> </format> <args> <arg expression="get-property('ORDER_ID')" evaluator="xml"></arg> </args> </payloadFactory> <call> <endpoint key="EmailsService_EP"></endpoint> </call> </then> <else></else> </filter>
12
Por Iván Fontanals IT Consultant
<payloadFactory media-type="xml"> <format> <ns2:processOrderPaymentMockResponse xmlns:ns2="http://service.orders.chakray.com/"> <return> <orderId>$1</orderId> <paymentStatus>$2</paymentStatus> <phase>$3</phase> </return> </ns2:processOrderPaymentMockResponse> </format> <args> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:ORDER_ID" evaluator="xml"></arg> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:PAYMENT_STATUS" evaluator="xml"></arg> <arg xmlns:ns="http://org.apache.synapse/xsd" expression="$ctx:PHASE" evaluator="xml"></arg> </args> </payloadFactory> </sequence>
13
Por Iván Fontanals IT Consultant
Autor: Ivan Fontanals IT Consultant
Revisado por: Roger Carhuatocto IT Consultant Chakray Consulting S.L. www.chakray.com