wso2
WSO2
Introducción
WSO2 es una compañía que desarrolla aplicaciones de software abierto enfocadas en proveer una arquitectura orientada a servicios (SOA) para desarrolladores profesionales. Fue fundada por Sanjiva Weerawarana, un conocido tecnólogo. WSO2 es un contribuyente clave en proyectos de servicios web de Apache.
Suite WSO2
La suite WSO2 consta de los siguientes módulos:
- WSO2 API Manager
Este módulo permite al usuario crear y publicar APIs para uso interno (intranet) o externo (extranet). Además, otros usuarios
pueden suscribirse a las APIs a través de aplicaciones creadas en esta herramienta; esto se realiza en el Store, donde se pueden ver todas las APIs publicadas. - WSO2 Identity Server (IS)
Se trata de un servicio de identidad. Se emplea para gestionar el Single Sign On (SSO), entre proveedores de servicio y como gestor de tokens de acceso a las APIs (con protocolo Oauth2). - WSO2 API Publisher y Store
Son herramientas web utilizadas para crear, publicar y suscribir las APIs. Este módulo es parte del API Manager. - WSO2 ESB
Es el proxy empleado para asegurar la comunicación entre componentes. Es un BUS empresarial, por lo que tiene más
funcionalidades como son: enriquecer mensajes, redireccionarlos a distintos puntos finales, hacer de balanceador, acceder a bases de datos y otros servicios a través de llamadas RestFul. - WSO2 Message Broker
Se emplea para gestionar las colas creadas en el ESB. Dichas colas se utilizan para guardar mensajes durante algún tiempo hasta que el punto final, al que van destinadas, es capaz de procesarlos.
WSO2 EI
WSO2 Enterprise Integrator (EI) es una solución de integración que, además del bus (ESB) para flujos de corto plazo sin estado, tiene un perfil de proceso de negocio (Business Profile) para flujos a largo plazo con estado; también incluye un perfil de análisis (Analytics) para monitorizar estadísticas, un perfil para mensajería confiable (Message Broker) y un perfil de integración de microservicios (MSF4J).
WSO2 Enterprise Integrator es un único paquete que está compuesto por:
- Enterprise Service Bus (ESB)
- Data Services Server (DDS)
- Business Process Server (BPS)
- Message Broker (MB)
- Business Rules Server (BRS)
- Microservices Framework for Java (MSF4J)
- Micro Integrator
- Herramientas de integración y análisis
Estos productos aportan:
- Un bus de servicios potente y robusto.
- Capacidad para acceder a cualquier tipo de datos y exponerlo como un servicio.
- Entrega de mensajes garantizada y gestión de proceso de negocio.
- Analíticas integradas de monitorización.
WSO2 EI es la evolución de WSO2 ESB, incluyendo toda la tecnología de integración en un único paquete. Permite integrar perfectamente aplicaciones, servicios, datos y procesos de negocio.
Los beneficios de WSO2 EI son:
- Alto rendimiento
- Completo
- Interoperabilidad
- Extensible y escalable
- Medible: equipado con analíticas
- Bajo coste: open source
- Contenedores nativos y facilidad para trabajar con microservicios
- Flexibilidad de despliegue:
- nube pública/privada
- local
- híbrido
WSO2 MI
A partir de la versión 7, la suite WSO2 pasa de ser Enterprise Integration a Microservices Integration
Apache Synapse
Apache Synapse es el motor asíncrono de mediación que utiliza WSO2.
Su configuración se hace en el fichero `passthru-http.properties
Apache Axis2
Es el motor de servicios web que utiliza WSO2.
Su configuración se hace en el fichero axis2.xml
[!NOTE] Nota
Todo mensaje que llega al WSO2, sea del tipo que sea, se transforma en un mensaje SOA antes de procesarse.
Alternativas a WSO2 EI
- Dell Boomi
- MuleSoft
- Tibvo BusinessWorks
- IBM WebSphere
SOA
SOA con WSO2
La infraestructura WSO2 para SOA es la siguiente:
WSO2 es el centro de la infraestructura SOA, con los siguientes componentes:
- WSO2 Data Services Server.
Permite exponer datos desde distintas fuentes como servicios web o recursos REST, sin necesidad de codificar. - WSO2 Message Broker.
Agente de mensajes que soporta el modelo de publicación/suscripción, JMS y el protocolo avanzado de encolamiento de mensajes. - WSO2 Business Process Server.
Es el motor de proceso de negocio.
Los procesos de negocio son un nivel mayor de abstracción llamado BPM (Business Process Management).
En estos componentes faltaría el registro UDDI, que WSO2 lo ofrece dentro del WSO2 Governance Registry. Este componente además de un registro UDDI provee un catálogo de servicios y un repositorio para todos los elementos relativos a la administración, como políticas, documentos, esquemas y descriptores de servicios web.
Puntos de entrada de mensajes
REST
Diseño de APIs
Estrategias de diseño
Integración RESTful con WSO2
- Exposición de interfaces REST mediante APIs
- Exposición de servicios HTTP
- Fijado de un contexto URL fijado para tener varios recursos
- API ligera y no gestionada
REST tiene tres vías:
- Verbos - recursos API y puntos finales HTTP.
- Nombres - puntos finales HTTP y plantillas URI.
- Formatos y tipos de datos - XML/JSON.
Soporte de WSO2 a la integración RESTful
- Transformaciones JSON
- Los mediadores PayloadFactory soportan todas las combinaciones posibles de transformaciones de JSON y XML.
- Enrutado JSON basado en el contenido
- Expresiones JSONPath
- Alta eficiencia de procesado JSON
- Librería Staxon
- Sin canonicalización (es decir, no es necesaria la conversión JSON -> SOAP -> JSON)
APIs
- Hay integración RESTful con las APIs
- Las APIs están ancladas a un contexto URL:
GET /customer/name/{customerName}
GET /customer/id/{customerId}
La mayor diferencia entre APIs y proxies es que los proxies usan el protocolo SOAP, mientras que las APIs usan el protocolo REST. Por esta razón, las APIs son más sencillas de desarrollar (no necesitamos crear el WDSL para el servicio) y tienen mejor rendimiento y escalabilidad que los servicios SOAP.
La sintaxis de una API es la siguiente:
<api name="NOMBRE_API"
context="URI_API"
[hostname="NOMBRE_SERVIDOR"]
[port="PUERTO"]>
<resource [methods="GET|POST|PUT|DELETE|OPTIONS|HEAD|PATCH"]
[uri-template="URI_TEMPLATE"|url-mapping="URL_MAPPING"]>
<inSequence>
...
</inSequence>?
<outSequence>
...
</outSequence>?
<faultSequence>
...
</faultSequence>?
</resource>
</api>
Donde context es el endpoint de la API, que debe ser único.
Cuando se diseña un recurso dentro de un API se puede elegir entre mapeo de URL o plantilla URL.
Mapeo de URL
Si se usa mapeo de URL hay que especificar un patrón para el recurso y solo las peticiones que lo satisfagan pasarán a través del servicio API.
Se pueden usar tres tipos de patrones:
- Mapeo de ruta: Se atenderán las peticiones que comiencen con el recurso y/o la ruta; por ejemplo,
/recurso/*
. - Mapeo de extensión: Solo se atenderán las peticiones que tengan la misma extensión; por ejemplo,
*.jag
. - Mapeo exacto: Solo se atenderán las peticiones que coincidan exactamente con el patrón; por ejemplo,
/recurso
.
Para leer el parámetro de entrada para todos los tipos anteriores se puede usar una de las siguientes expresiones:
POST:json-eval($.nombreParametro)
GET:$ctx:query.param.nombreParametro
Ejemplo
A continuación se tiene un API de mapeo exacto:
<api xmlns="http://ws.apache.org/ns/synapse"
name="UrlMappingAPI"
context="/urlmappingapi">
<resource methods="GET"
url-mapping="/getParam">
<inSequence>
<log>
<property name="Valor del parametro param con GET"
expression="$ctx:query.param.param"/>
</log>
<respond/>
</inSequence>
</resource>
<resource methods="POST" url-mapping="/postParam">
<inSequence>
<log>
<property name="ValOR del parametro param con POST"
expression="json-eval($.param)"/>
</log>
<respond/>
</inSequence>
</resource>
</api>
Este API se puede probar con curl
:
curl http://localhost:8280/urlmappingapi/getParam?param=PRUEBA
(cambiando localhost por el nombre o ip apropiados)
y en la consola de WSO2 EI se verá algo como
INFO {org.apache.synapse.mediators.builtin.LogMediator} -
To: /urlmappingapi/getParam?param=GetParam,
MessageID: urn:uuid:912f3abc-f84b-4ccc-a60b-374cc7ee1f23
correlation_id : 959bae55-2b96-4c8e-a5b2-f5e12ec80489,
Direction: request,
Valor del parametro param con GET = PRUEBA
Para probar el método con POST se haría:
curl -H "Content-Type: application/json" \
-X POST -d {"param":"PRUEBA"} \
http://localhost:8280/urlmappingapi/postParam
con el que se obtendría una salida similar a la anterior.
Plantilla URI
En este caso es necesario definir patrones y variables para cada recurso, de forma que solo las peticiones que cumplan el patrón lanzarán el recurso.
La forma de definir parámetros de entrada o variables es con llaves, de la forma:
/recurso/{param1}{param2}
Para leer los parámetros definidos en la plantilla se puede usar la expresión:
get-property{'uri.var.nombreParametro'}
Ejemplo
Se crea un recurso que se puede consumir con métodos GET y POST y que espera dos parámetros de entrada:
<api xmlns="http://ws.apache.org/ns/synapse"
name="UriTemplateAPI"
context="/uritemplateapi">
<resource methods="POST GET"
uri-template ="/resource/{param1}/{param2}">
<inSequence>
<log>
<property name="Valor de param1"
expression="get-property('uri.var.param1')"/>
<property name="Valor de param2"
expression="get-property('uri.var.param2')"/>
</log>
<respond/>
</inSequence>
</resource>
</api>
Para probarlo se pueden usar los siguientes comandos:
-
Método GET:
curl http://localhost:8280/uritemplateapi/resource/P1/param2
-
Método POST:
curl -X POST http://localhost:8280/uritemplateapi/resource/P1/param2
En el log aparecerá algo como:
LogMediator To: /uritemplateapi/resource/P1/param2,
MessageID: urn:uuid:252608a9-42aa-4fb0-b9ee-49263c1cdc5a
correlation_id : ffa9facd-bbd5-4691-92f8-60e5448c3d6e,
Direction: request,
Valor de param1 = P1,
Valor de param2 = param2
ESB
Bus de Integración
Un Enterprise Service Bus (ESB) es un patrón de diseño que intermedia entre el cliente y el servicio y que es, al mismo tiempo, capaz de cambiar el formato y el protocolo de comunicación de los datos para conseguir que los dos extremos de la conversación se entiendan. Un ESB permite que distintas aplicaciones, servicios y sistemas puedan hablar, interactuar y realizar transacciones entre sí. Actúa como la columna vertebral de la mensajería en cualquier arquitectura orientada a servicios (SOA).
De la misma forma que en hardware se utiliza un bus en las placas para interconectar microprocesadores, memoria o discos duros; en software el ESB es el bus que interconecta aplicaciones.
En las figuras se muestra la diferente arquitectura de interconexión al utilizar o no un ESB.
El ESB es un middleware donde se despliegan y publican servicios SOA que están disponibles para su consumo por otros sistemas.
Principales funcionalidades de un ESB
- Intermediación de mensajes. Manipula el contenido del mensaje, dirección, destino y protocolos.
- Virtualización de servicios. Encapsula los sistemas existentes con nuevas interfaces de servicio.
- Conversión de protocolos. Hace de puente entre diferentes protocolos. Por ejemplo, JMS a HTTP.
- Soporte de EIP. EIP es el estándar de facto para la Integración Empresarial.
- Quality of Service. Aplica seguridad, throttling (estrangulamiento) y cacheo.
- Conexión con sistemas propietarios y legacy.
- Conexión con servicios y APIs en la nube.
- Dirigido por la configuración. Las funcionalidades se pueden configurar sin necesidad de escribir código.
- Extensible.
Diferencias entre ESB y Middleware
Un ESB es una de las herramientas de la subcategoría integración dentro de un middleware. Un ESB contribuye a la integración de
numerosas aplicaciones jugando un papel de intermediario mediante el enrutado, el filtrado, la mediación y la transformación de mensajes.
Un middleware incluye desde herramientas de integración hasta gestión de contenidos y documentos, pasando por portales web, gestión de procesos de negocio o servidores de aplicaciones.
La plataforma de middleware de WSO2 es WSO2 Carbon.
WSO2 ESB
WSO2 ESB es parte de la plataforma middleware WSO2, que aparte del ESB provee capacidades como gestión API, gestión de identidades, servicios de datos, estadísticas, etc.
A continuación se muestra la arquitectura de WSO2 ESB utilizada para implementar los flujos de integración.
El diagrama muestra cómo una petición se propaga hasta su verdadero endpoint a través del ESB. La gestión de la respuesta sería la operación inversa.
Ejemplo
Veremos cómo funciona WSO2 a partir del siguiente ejemplo:
Se quiere integrar un servicio de backend, que es un servicio web basado en SOAP, con una aplicación web que utiliza JSON. Para ello, el ESB se encargará principalmente de convertir el formato del mensaje.
La petición JSON de la aplicación móvil al ESB es:
{
"getFinancialQuote": { "company": "WSO2" }
}
Mientras que el servicio Web espera un mensaje SOAP como:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://services.samples">
<soapenv:Header/>
<soapenv:Body>
<ser:getSimpleQuote>
<ser:symbol>WSO2</ser:symbol>
</ser:getSimpleQuote>
</soapenv:Body>
</soapenv:Envelope>
Los pasos principales para implementar esta integración son los siguientes:
- Construir un interfaz/servicio HTTP virtual que acepte la petición JSON del cliente Web y responda con una respuesta JSON.
- En el control de la respuesta del interfaz/servicio HTTP virtual, debe convertir el mensaje entrante JSON a un mensaje SOAP y enviarlo al servicio web backend.
- En la respuesta el interfaz/servicio HTTP virtual necesita convertir la respuesta SOAP entrante a un mensaje JSON y devolverlo al cliente.
Características principales
Enrutado
Cuando WSO2 procesa mensajes individuales de los clientes puede enrutar los mensajes basándose en su contenido.
Filtrado
El filtrado permite lógica más compleja mediante la cual los mensajes se pueden filtrar y enviar a diferentes flujos de mediación.
Transformación
La transformación incluye manipular mensajes en cualquier forma requerida, añadiendo/borrando contenido de los mensajes, convirtiendo el formato del mensaje en otro completamente distinto e incluso validando los mensajes según su formato.
Conmutación de protocolo
Otra característica es la posibilidad de cambiar los protocolos. Esto hace posible, por ejemplo, que un mensaje que llega vía HTTP se pueda reenviar a una cola JMS.
Componentes funcionales
El flujo de alto nivel de mensajes de WSO2 ESB comprende tres componentes lógicos principales:
- Puntos de entrada de mensajes: Reciben las peticiones de los clientes.
- Unidades de proceso de mensajes: Contienen la lógica de mediación1 para procesar peticiones de cliente, las peticiones que el ESB envía al servidor, la lógica de proceso de respuesta del servidor, y la respuesta que el bus devuelve al cliente.
- Puntos de salida de mensajes: Puntos de integración con los servicios de backend.
Puntos de entrada de mensajes
WSO2 ESB tiene tres puntos de entrada de mensajes principales:
- Servicio proxy: Interfaz de servicio web expuesta desde el ESB.
- APIs REST/HTTP: Interfaz HTTP anclada en una URL de contexto URL.
- Puntos finales de entrada: Fuente de mensajes con capacidad de escucha o sondeo (polling).
Los puntos de entrada de mensajes son los principales componentes responsables de manejar la transferencia de mensajes de los sistemas externos al ESB. Los mensajes que vienen a través de alguno de estos puntos de entrada se encaminan a unidad de proceso de mensajes.
Unidad de proceso de mensajes
El procesamiento del mensaje se lleva a cabo en los componentes conocidos como secuencias. Una secuencia dada puede contener una secuencia de componentes que pueden procesar un mensaje dado. Estos componentes se denominan mediadores.
Puntos de salida de mensajes
El punto final de salida (o punto final) es el punto de salida del mensaje en WSO2, que lógicamente representa un punto final de servicio
de backend externo.
En la figura se muestra cómo está configurado el flujo de mensajes para implementar la integración. Los puntos clave de este flujo son los siguientes:
- Ofrecer una interfaz HTTP al cliente móvil.
- Anclar un servicio API/HTTP.
- Configurar una secuencia de mediación.
- El primer mediador es un mediador de payload que se utiliza para convertir el JSON entrante al formato SOAP y extraer los valores necesarios para le petición JSON original.
- Se debe configurar una acción SOAP como cabecera antes de enviar el mensaje fuera del ESB.
- Después se necesita un mediador de llamada que pueda enviar el mensaje fuera del ESB.
- Configurar en punto final de salida.
- Configurar la secuencia de mediación de respuesta.
- Definir una secuencia de mediación en caso de error.
En la figura se muestra otra forma de implementar este flujo de mensajes.
Bloques de construcción
Se tienen los siguientes bloques de construcción:
- Secuencias
- Definen la lógica para gestionar peticiones y respuestas
- Consisten en una lista de mediadores y el orden en que se tienen que ejecutar.
- Mediadores
- Realizan una acción en el mensaje.
- Puntos finales (endpoints)
- Definen el destino externo -normalmente un servicio- para un mensaje.
- Transportes
- Transportan el mensaje en un formato específico.
Las secuencias son el componente de configuración de los mediadores, permiten organizar los mediadores para implementar tuberías y filtros.
Los mediadores son unidades de proceso que ejercen una función específica, como enviar o filtrar mensajes. WSO2 incluye una librería de mediadores que provee funcionalidad para implementar ampliamente patrones de integración (EIPs). También se pueden escribir mediadores personalizados que provean funcionalidad adicional utilizando tecnologías como Java, scripts y Spring.
Los puntos finales definen un destino externo --como, por ejemplo, un servicio-- para un mensaje. Un punto final puede especificarse como una dirección, un WSDL, un balanceador, etc. El punto final se define independientemente del transporte, permitiendo utilizar el mismo punto final con múltiplos transportes. Cuando se configura una secuencia de mediación para un mensaje o un servicio web para manejar el mensaje entrante, se especifica el transporte a usar y el punto final al que se enviará el mensaje.
Lenguaje de configuración de WSO2
Como el proceso de desarrollo de un escenario de integración de WSO2 está completamente dirigido por la configuración todos los puntos de entrada, unidades de proceso y puntos de salida está configurados utilizando un lenguaje de configuración basado en XML.
Existen editores gráficos de flujos de mensajes para WSO2.
A continuación se muestra la implementación del ejemplo para aceptar un mensaje JSON de la aplicación móvil:
<api xmlns="http://ws.apache.org/ns/synapse"
name="ShoppingInfo"
context="/ShoppingInfo"> <!-- [1] -->
<resource methods="POST">
<inSequence> <!-- [2] -->
<payloadFactory media-type="xml">
<format>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://services.samples">
<soapenv:Header></soapenv:Header>
<soapenv:Body>
<ser:getSimpleQuote>
<ser:symbol>$1</ser:symbol>
</ser:getSimpleQuote>
</soapenv:Body>
</soapenv:Envelope>
</format>
<args>
<arg evaluator="json" expression="$.getFinancialQuote.company"></arg>
</args>
</payloadFactory>
<header name="Action" value="urn:getSimpleQuote"></header>
<call>
<endpoint> <!-- [3] -->
<address uri="http://localhost:9000/services/SimpleStockQuoteService"
format="soap11">
</address>
</endpoint>
</call>
<property name="messageType" value="application/json"
scope="axis2" type="STRING"> <!-- [4] -->
</property>
<respond/> <!-- [5] -->
</inSequence>
</resource>
</api>
- Ancla un servicio HTTP/API en el contexto /
ShoppingInfo
como punto de entrada del mensaje. - Procesa el mensaje petición.
- Configura un servicio web de backend como punto de salida.
- Procesa el mensaje de respuesta, cambia el formato de respuesta a JSON.
- Envía la respuesta de vuelta al cliente.
Extensión de WSO2 ESB
Existen muchos puntos de extensión soportados por el perfil ESB de WSO2 Enterprise Integrator:
- Script Mediator
- Class Mediator y mediadores personalizados
- Manejadores API
- Tareas personalizadas
- Conectores
- Endpoints de entrada personalizados
- Almacenes de mensajes personalizados
- Procesadores de mensajes personalizados
- Funciones XPath personalizadas
- Controladores de Synapse
- Controladores de Axis2
- Módulos de Axis2
- Formateadores y constructores de mensajes
- Listeners y emisores de mensajes
Scripts
Se pueden usar distintos lenguajes de script para procesar el payload y obtener información o hacer una transformación. Esos lenguajes son JavaScript, Groovy y Ruby.
La sintaxis de script en línea es:
<script language="js">
<![CDATA[
//script code
]]>
<script/>
Y la sintaxis de script en registro es:
<script key="ruta/al/script"
language="(js | groovy | rb)"
[function="nombreFuncion"]>
[<include key="cadena"/>]
</script>
Los métodos disponibles son:
getPayloadXML()
: devuelve el contenido del XML.setPayloadXML(payload)
: establece el contenido del XML según el parámetro payload.addHeader(mustUnderstand, content)
: añade una nueva cabecera SOAP.getEnvelopeXML()
: devuelve todo el payload.setTo(valor)
: establece el valor de la cabeceraTo
(destinatario).setToFault(valor)
: establece el valor de la cabeceraFaultTo
.setFrom(valor)
: establece el valor de la cabeceraFrom
(remitente).setReplyTo(valor)
: establece el valor de la cabeceraReplyTo
.getPayloadJSON()
: devuelve el contenido del JSON.setPayloadJSON(payload)
: establece el contenido del JSON según el parámetro payload.getProperty(nombre)
: obtiene el valor de la propiedad nombre.setProperty(clave, valor)
: crea o actualiza el contenido de la propiedad del primer parámetro con el valor del segundo.
Por ejemplo, el siguiente script imprime el valor actual de una propiedad y establece un nuevo valor:
<script language="js">
<![CDATA[
var property = mc.getProperty("static");
print("propiedad: " + property);
mc.setProperty("static", "newValue");
]]>
</script>
Tareas
Con la programación de tareas se puede configurar la ejecución de un servicio en fecha y hora específicos y periódicamente durante un número determinado de veces.
En WSO2 Enterprise Integrator nos encontramos con tres tipos de tareas:
- Tareas de Servicios de datos
- Tareas ESB
- Tareas personalizadas
Configurando el servidor
Para utilizar las tareas, el servidor usa un fichero de configuración llamado tasks-config.xml
, que está alojado en <EI_HOME>/conf/etc
.
Servicios de datos
La programación de tareas de servicios de datos se hace desde Main > Manage > Services > Add > Data Service > Scheduled Tasks .
Otros servicios
Las tareas asociadas al resto de servicios se programan desde Main > Manage > Service Bus > Scheduled Tasks .
Desde aquí se pueden crear tareas para lanzar proxies, secuencias, endpoints y otros. Las tareas se pueden programar de tres formas:
-
Especificando el número de veces (si no se quiere que termine se indica -1) y el intervalo.
Ejemplo:
<task name="IntervalTask" class="org.apache.synapse.startup.tasks.MessageInjector"> <trigger interval="3" count="5"/> </task>
se ejecutará cada 3 segundos 5 veces.
-
Configurando una expresión cron.
Ejemplo:
<task name="CronTask" class="org.apache.synapse.startup.tasks.MessageInjector"> <trigger cron="0 0 8 * * ?"/> </task>
se ejecutará todos los días a las 08:00 AM.
-
Diseñando una tarea que se ejecutará solo cuando se arranque el servidor.
Ejemplo:
<task name="OnceTask" class="org.apache.synapse.startup.tasks.MessageInjector"> <trigger once="true"/> </task>
Conectores
Los conectores permiten al perfil ESB de WSO2 EI interactuar con servicios de terceros como Twitter, Google Docs, JIRA, etc.
Los conectores proveen acceso a las APIs.
Se pueden descargar de la Tienda WSO2 e instalarlos en WSO2.
También se pueden crear conectores personalizados.
Endpoints de entrada
Para crear servicios en WSO2 Enterprise Integrator además de utilizar proxies y APIs se pueden usar puntos finales de entrada.
Tanto los proxies como las APIs usan la capa axis2 y aunque se pueden configurar los puertos entrantes, estos son estáticos y se aplican globalmente para todos los servicios desplegados en el servidor. Además, tras cada cambio en la configuración es necesario reiniciar el servidor para aplicar los cambios.
Sin embargo, con los endpoints de entrada esto es distinto ya que no usan la capa axis2, sino que directamente toman el mensaje de la capa de transporte y lo envían a la capa de mediación. WSO2 tiene cuatro tipos diferentes de endpoints de entrada:
- Listening
- Polling
- Event-Based
- Custom
Listening
En los puntos finales de entrada de escucha, configuramos un puerto específico en el que el servidor estará esperando para la petición entrante. Se pueden utilizar distintos protocolos como HTTP, HTTPS, HL7, CXF, WebSocket y Secure WebSocket.
Por ejemplo, se puede definir un punto final de entrada HTTP, llamado HttpInboundEndpoint, que escuche en el puerto 8765 y que lance la secuencia principal según se ve en la figura.
WSO2 abrirá dinámicamente dicho puerto y permanecerá a la escucha de una petición para lanzar la secuencia principal.
Para probarlo es suficiente con hacer una petición a dicho puerto con curl:
curl http://localhost:8765
Polling
Este tipo de endpoints finales sondea continuamente por los datos según el intervalo de tiempo configurado. Cuando los datos están disponibles lanzará una secuencia específica con los datos originales como payload.
WSO2 tiene tres tipos de sondeo:
- File: para conexiones FTP, SFTP y FILE.
- JMS: para el protocolo Java Message Service.
- Kafka: para el protocolo Apache Kafka.
Por ejemplo, se puede configurar un endpoint que esté sondeando en un directorio local por un fichero específico para procesarlo en una secuencia.
Para probarlo es suficiente con crear el fichero C:\Temp\pollingInboundEndpoint.txt
.
Event based
Este tipo de endpoint establece la conexión con el servidor configurado cuando se crea y permanece esperando a un evento específico.
Se puede implementar mediante los protocolos Message Queue Telemetry Transport (MQTT) y RabbitMQ.
Monitorización y gestión de errores
Logging
El registro en ficheros de log (logging) es una de las herramientas de monitorización más importante.
El log de WSO2 está basado en log4j.
Existen dos tipos de logs:
- Logs de sistema. Registra eventos de todo el sistema de manera integral.
- Logs de aplicación. Permiten elegir una aplicación o un servicio en particular para ver sus registros.
Para monitorizar los mensajes dentro de una secuencia se utiliza el Log mediator, pudiendo especificar con exactitud qué propiedades se quieren registrar.
Configuración de log4j
El log se puede configurar o bien desde la consola de WSO2, o bien desde el fichero log4j.properties
en <EI_HOME>/conf
.
Por defecto, los ficheros de log se almacenan en <EI_HOME>/repository/logs.
Logs de depuración
Para habilitar los logs de depuración:
- Se para el servidor.
- En
conf/log4j.properties
se indicalog4j.category.org.apache.synapse=DEBUG
- Se arranca el servidor.
Logs de traza
Los logs de traza rastrean la ruta completa cuando un mensaje viaja a través de una secuencia de mediación.
La traza se puede habilitar tanto para un proxy como para una secuencia, para ello se añade el atributo trace="enable"
en la configuración del proxy o secuencia. Una vez habilitada la traza ésta se puede ver en el fichero wso2-ei-trace.log
.
Monitorización de mensajes
Los mensajes se pueden monitorizar con las siguientes herramientas:
- TCPMon
- WireLogs
- Wireshark
TCPMon
WSO2 tiene un TCPMon incluido, para habiltarlo hay que ejecutar <wso2>/bin/tcpmon.sh
.
Hay dos conexiones:
- Conexión Cliente---Servicio proxy
- Conexión Proxy---Servidor de backend
TCPMon tiene dos importantes limitaciones:
- Solo puede monitorizar conexiones HTTP (no HTTPS)
- Es difícil usarlo en sistemas en producción
WireLogs
WireLogs tiene las siguientes ventajas sobre TCPMon:
- Puede monitorizar mensajes por HTTPS.
- No necesita cambiar la configuración de synapse
Para habilitar WireLogs se hace lo siguiente:
- Se apaga el servidor.
- Se descomenta en
<wso2>/conf/log4j.properties
la línealog4j.logger.org.apache.synapse.transport.http.wire=DEBUG
- Se arranca el servidor.
En los logs con WireLog hay que tener en cuenta que la dirección del mensaje se identifica de la siguiente forma:
DEBUG - wire >>
. Representa el mensaje entrando en el EI desde el wire.DEBUG - wire <<
. Representa el mensaje llegando al wire desde EI.
WireShark
WireShark2 es un analizador de protocolos de red. Captura paquetes en tiempo real y los muestra en un formato legible.
Puede monitorizar tanto peticiones HTTP como HTTPS y no necesita realizar cambios en la configuración.
Manejo de errores
La secuencia de error se encarga de lanzar mensajes en caso de error (por ejemplo guardar el error en un log, enviar mensajes al cliente o notificar a los administradores).
El mediador de error habilita el envío apropiado de mensajes de error al cliente.
Manejo de errores en Endpoints
Cuando ocurre un error, si no se ha configurado WSO2 para gestionar dicho error, se marcará el endpoint como fallido, lo que conllevará un fallo en la mensajería. Por defecto, el endpoint se marca como fallido por un largo período de tiempo y debido a este error los mensajes siguientes se pueden perder.
Para evitar la pérdida de mensajes se debe configurar el manejo de errores a nivel de endpoint. También se deberían lanzar pruebas de carga para descubrir posibles errores y configurar los endpoints correctamente.
En un momento dado, el estado de un endpoint puede ser uno de los siguientes:
- Activo. El endpoint está en ejecución y gestionando peticiones.
- Timeout. El endpoint ha encontrado un error pero todavía puede enviar y recibir.
- Suspendido.
- Erróneo.
Despliegue de aplicaciones
Para desplegar aplicaciones entre entornos se siguen los pasos:
- Se crea el Composite Application Project (C-App) desde un proyecto de configuración del ESB.
- Se exporta el C-App como un fichero Composite Application Archive (CAR).
- Se sube el fichero CAR a la instancia WSO2 necesaria.
Inquilinos (tenants)
Los tenants sirven para separar datos y lfujos de información. Se pueden utilizar los tenants para hacer distintos perfiles por departamento, localización, etc.
Con los tenants se tienen entornos completamente aislados donde no se comparte nada entre distintos tenants salvo la estructura general.
Si accedemos a la consola ESB con el superusuario admin vemos la siguiente pantalla:
Sin embargo si entramos como un tenant vemos:
Mensajería
Las aplicaciones se comunican unas con otras intercambiando mensajes por la red utilizando sistemas de mensajería empresarial. Estos sistemas de mensajería aplicación-aplicación se conocen como MoM (Message Oriented Middleware).
JMS (Java Message Service) se refiere a los MoM que proveen una API Java de intercambio de mensajes. Sirve para intercambiar mensajes entre aplicaciones Java.
Cuando se quiere intercambiar mensajes de una aplicación Java a otro tipo de aplicación, JMS no nos sirve. En este caso se utiliza AMQP (Advanced Message Queuing Protocol)3.
MQTT (Message Queuing Telemetry Transport) es un protocolo de contectividad entre máquinas para IoT (Internet of Things).
Kafka es un sistema de mensajería distribuida, que se utiliza principalmente en sistemas Big Data.
Arquitectura de la mensajería
Desencadenamiento de mensajes
Los mensajes se pueden introducir en las secuencias a través de los siguientes disparadores:
- Servicios proxy. WSO2 puede actuar como un servicio virtual delante del verdadero servicio de backend, permitiendo transformar los mensajes antes de enviarlos al destino.
- Secuencia principal. Todos los mensajes que no se envían a un servicio proxy se envían a la secuencia principal.
- APIs. Las APIs pueden aceptar mensajes REST que permiten a los clientes dar información adicional sobre cómo gestionar el mensaje.
- Tareas programadas. Las tareas pueden desencadenar en secuencias para su proceso.
Servicios proxy
Los servicios proxy son servicios virtuales que reciben mensajes y opcionalmente los procesan antes de reenviarlos a un servicio a un endpoint dado. Esto permite realizar las transformaciones necesarias e introducir funcionalidad adicional sin cambiar el servicio existente.
Las respuestas que vuelven del servicio pueden, a su vez, ser procesadas antes de reenviarlas a los clientes.
Son similares a los proxy HTTP tradicionales.
Por ejemplo, si se necesita un servicio para gestionar mensajes en diferentes formatos, se puede crear un proxy para transformar las peticiones y las respuestas basándose en transformaciones XSLT.
Los servidores proxy están compuestos de secuencias.
Secuencia principal
Todos los mensajes que no se envían a un API, un servicio proxy o un endpoint de entrada se envían a través de la secuencia principal. Por defecto, la secuencia principal simplemente envía un mensaje sin mediación; si se quiere añadir mediación a los mensajes hay que añadir mediadores y/o secuencias a la secuencia principal.
APIs
Las APIs en WSO2 pueden aceptar mensajes REST que permiten a los clientes añadir información adicional sobre cómo gestionar el mensaje.
Las APIs pueden gestionar múltiples URLs, y pueden gestionar parámetros en la URL.
Cada API está anclada en un contexto de URL definido por el usuario, de la misma forma que una aplicación web desplegada en un contenedor de servlet está anclada en una URL fija.
Cada API solo podrá procesar peticiones que caigan bajo su contexto URL. Por ejemplo, si una API está anclada en el contexto /prueba
solo atenderá las peticiones HTTP cuya URL comience con la ruta /prueba
.
También es posible enlazar una API dada con un nombre de servidor dado o un puerto específico.
Creación de APIs
Un recurso se puede asociar mediante mapeo de URL o una plantilla URI.
El mapeo URL puede ser cualquier mapeo de servlet válido, es decir, puede ser de uno de estos tipos:
- Mapeo de ruta. Por ejemplo,
/prueba/*
. - Mapeo de extensión. Por ejemplo,
*.jsp
. - Mapeo exacto. Por ejemplo
/prueba/test2
.
Una plantilla URI representa una clase de URIs utilizando patrones y variables. Ejemplos de plantillas URI válidas son /order/{orderId}
y /centro/identificadorCentro
.
Los identificadores entre llaves se consideran variables. Por ejemplo, la plantilla /order/{orderId}
procesaría /order/A001
, de forma que a la variable orderId
se le asignaría el valor A001
.
Con get-property
se recuperan los valores:
<property name="Word" expression="get-property('uri.var.word')"/>
Cada API se debe especificar con un único nombre y con un único contexto URL. Para identificar cada API se utiliza la etiqueta <api>
.
Tareas programadas
Las tareas permiten la configuración de trabajos programados en WSO2 para ejecutar comandos tanto internos como externos. Consisten en inyectar un mensaje en un servicio proxy, la secuencia principal o una secuencia dada.
La implementación por defecto inyecta un mensaje al WSO2 en un intervalo programado. Por defecto el mensaje va a la secuencia principal, pero también se puede configurar para que vaya a una secuencia cualquiera o a un servicio proxy.
También podemos escribir una tarea propia creando una clase Java que implemente la interfaz Task.
Endpoints entrantes
Un endpoint entrante es un mensaje fuente que se puede configurar dinámicamente.
El entorno de un endpoint entrante puede ser:
- Escuchar
- Dividir
- Basado en eventos
Los endpoints entrantes proveen coordinación. Se utilizan en escenarios de clientes múltiples.
Con endpoints entrantes HTTP se pueden cambiar dinámicamente los puertos en los que el cliente accede a los servicios.
Flujo de la mensajería
WSO2 Enterprise Integrator es el middleware entre un servicio y un cliente que requiere dicho servicio.
Los mensajes navegan entre el cliente y el servicio a través de secuencias construidas en WSO2.
Existen tres secuencias principales:
- Secuencia de entrada (In Sequence)
- Secuencia de salida (Out Sequence)
- Secuencia de error (Fault Sequence)
El flujo de un mensaje es el siguiente:
- Un cliente envía una petición a un servicio.
- El mensaje fluye a través de la secuencia de entrada.
- El mensaje se entrega al servicio.
- El servicio genera una respuesta.
- Las respuesta se envía a través de la secuencia de salida.
- El mensaje se entrega al cliente.
La secuencia de error se puede utilizar para capturar errores. Por defecto, la secuencia de error registra en el log el mensaje, el payload y cualquier error o excepción que se encuentra, y le indica al drop mediator que deje de procesar. Se debería configurar la secuencia de error para que maneje el error correctamente en lugar de simplemente lanzar mensajes.
Mediadores
En WSO2, un mediador es un trozo de código que tiene un comportamiento lógico y un propósito final para usarlo, con una estructura XML. Por defecto, existe una lista de mediadores que podemos utilizar; además se pueden desarrollar mediadores personalizados para ampliar la funcionalidad básica.
Los mediadores básicos son:
- Log Mediator. Registra todo o parte del mensaje, según los niveles (traza, debug, etc.).
- Sequence Mediator. Invoca una secuencia existente. El nombre de la secuencia puede ser estático o dinámico.
- Send Mediator. Envía un mensaje de salida, utilizando información estática o un endpoint definido.
- Callout Mediator. Realiza una invocación a un servicio externo de bloqueo.
- Switch Mediator. Evalúa el contenido del mensaje mediante expresiones regulares e invoca al mediador correspondiente (
switch-case-default
). - Validate Mediator. Valida el mensaje, o una parte, contra un esquema XML (el esquema puede ser local o estar en el registro).
- Drop Mediator. Termina de procesar el mensaje actual.
- Fault Mediator. Transforma el mensaje actual en un mensaje de fallo personalizado.
Log Mediator
Se tienen 6 categorías para registrar errores:
- Trace
- Debug
- Info
- Warn
- Error
- Fatal
También se tienen cuatro niveles de log:
- Custom. Muestra las propiedades configuradas dentro.
- Full. Las cabeceras Show To, From, WSAction, SOAPAction, ReplyTo y MessageID y el payload actual.
- Headers. Registra todas las cabeceras SOAP.
- Simple. Registra las cabeceras Log To, From, WSAction, SOAPAction, ReplyTo y MessageID.
Por ejemplo, para archivar todo el contenido del mensaje se usa:
<log level="full" />
Para archivar una propiedad personalizada:
<log category="INFO" separator=",">
<property name="dynamicProperty"
expression="//xpathExpression" />
</log>
Nota: por defecto, el log se ubica en
<WSO2_HOME>/repository/log/wso2carbon.log
Sequence Mediator
El mediador de secuencia lanza el proceso de una secuencia con nombre o de una secuencia del registro.
La sintaxis para una secuencia con nombre es:
<sequence key="nombreSecuencia"/>
Y para una secuencia del registro:
<sequence key="conf:/ruta/a/la/secuenciaDelRegistro"/>
Invocación de servicio
Send Mediator
El mediador de envío se usa para hacer una solicitud sin bloqueo a un backend con el payload actual. El backend está configurado con los endpoints. Los endpoints se pueden configurar de forma implícitamente, en línea, por nombre o almacenada en el registro.
La sintaxis implícita es:
<send/>
Con definición en línea sería:
<send>
<endpoint>
<address uri="http://localhost:8280/services"/>
</endpoint>
</send>
Y con un endpoint referenciado por nombre:
<send receive="OutSequence">
<endpoint key="CreditEpr"/>
</send>
Respond Mediator
El mediador de respuesta deja de procesar el mensaje actual y envía el payload al cliente que hizo la solicitud al servicio.
La sintaxis es:
<respond/>
Call Mediator
Sin mediadores después del envío/respuesta
Loopback Mediator
El mediador de loopback mueve el mensaje actual a la secuencia de salida.
Su sintaxis es:
<loopback/>
Drop Mediator
El drop mediator para el procesamiento del mensaje actual. En el caso de estar configurado en la secuencia de entrada enviará un HTTTP 202
de respuesta aceptada al cliente.
Su sintaxis es:
<drop/>
Enrutado
El enrutado se realiza con el Switch Mediator, que:
- Permite enrutado basado en el contenido.
- Evalúa el XPath o JSONPath y devuelve una cadena. La cadena es evaluada mediante una expresión regular para cada caso declarado.
- Si se encuentra un caso, no se evalúan más. Si no se encuentra ninguno, se ejecutará uno por defecto.
Transformación
Se puede hacer vía:
- Data Mapper Mediator
- Payload Factory Mediator
- XSLT Mediator
- FastXSLT Mediator
- Smooks Mediator
- XQuery Mediator
Data Mapper Mediator
El Data Mapper Mediator se puede utilizar para convertir y transformar datos visualmente. Se puede utilizar para:
- Transformar desde/hacia JSON, XML y CSV.
- Integrar fácilmente en secuencias de mediación como un mediador
- Aplicar operaciones
El Data Mapper Mediator consiste en tres ficheros de configuración principales:
- Esquema de entrada.
- Esquema de salida.
- Configuración de mapeo.
Payload Factory Mediator
Con el Payload Factory Mediator se puede:
- Transformar o reemplazar el contenido de un mensaje.
- Configurar el formato de una petición o respuesta y mapearla según los argumentos.
Intercambio de protocolo
Permite transformar el mensaje de un protocolo a otro.
Por ejemplo, un mensaje http se puede transformar en un mensaje JMS.
Intercambio de formato de mensajes
Permite la traducción de mensajes entre formatos comunes.
Por ejemplo, si un cliente envía una petición JSON pero el servicio existente utiliza XML SOAP, es necesario traducir el mensaje tanto en la petición como en la respuesta.
Servicio de encadenamiento
El servicio de encadenamiento consiste en:
- Una colección de mediadores que permiten exponer múltiples servicios como si fueran uno único.
- Orquesta las respuestas de un servicio y las usa para alimentar las entradas de otros servicios.
Property mediator
Una propiedad (property) es una variable que almacena alguna información durante un tiempo que depende del alcance (scope) en el que se haya configurado.
Hay tres tipos de propiedades:
-
Estática. Toma un valor estático en la creación:
<property name="color" value="rojo" />
-
Dinámica. Toma un valor dinámico:
<property name="dinamica" expression="//xpath//" />
-
Acción. Realiza una acción con una propiedad existente:
<property name="To" action="remove"/>
Las propiedades pueden tener siete alcances distintos:
- Axis2. Es el alcance más corto y solo se usa para enviar parámetros al motor Axis2.
- Axis2-client. La misma duración que synapse, pero la propiedad se puede leer a través de mediadores personalizados.
- Synapse. La propiedad se mantendrá viva en la secuencia. Es el alcance por defecto.
- Operation. Es el alcance más grande; la propiedad se mantendrá viva hasta el final del servicio a través de las diferentes secuencias.
- Registry. Se usa para obtener propiedades del registro.
- System. Para obtener propiedades del sistema Java.
- Transport. La propiedad se enviará como una cabecera de transporte.
Secuencias
Una secuencia es una lista de mediadores procesados ordenadamente uno detrás de otro. Por defecto, el Enterprise Integrator tiene dos secuencias: principal (main) y error (fault), pero se pueden crear todas las secuencias que se crea necesario, conteniendo una combinación de mediadores.
Secuencia principal
Esta secuencia se lanza cuando la llamada al servidor EI no corresponde con un servicio axis2. Por ejemplo, si se hace una petición a la URL
http://localhost:8280/services/ServiceNoExistente
la secuencia devuelve un código HTTP 202 de aceptación y loguea el mensaje entrante por la consola, a menos que exista un servicio de ejemplo:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="main" xmlns="http://ws.apache.org/ns/synapse">
<in>
<!-- Log all messages passing through -->
<log level="full"/>
<!-- ensure that the default configuration only
sends if it is one of samples -->
<!-- Otherwise Synapse would be an open proxy
by default (BAD!) -->
<filter regex="http://localhost:9000.*"
source="get-property('To')">
<then>
<!-- Send the messages where they have been
sent (i.e. implicit "To" EPR) -->
<send/>
</then>
<else/>
</filter>
</in>
<out>
<send/>
</out>
<description>The main sequence for the
message mediation</description>
</sequence>
La secuencia de error
Se usa para capturar excepciones cuando no hemos configurado una secuencia de error personalizada.
Esta secuencia loguea el código de error y el payload actual y entonces borra el mensaje:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="fault"
xmlns="http://ws.apache.org/ns/synapse">
<!-- Log the message at the full log level with
the ERROR_MESSAGE and the ERROR_CODE-->
<log level="full">
<property name="MESSAGE"
value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<!-- Drops the messages by default if there is a fault -->
<drop/>
</sequence>
Secuencias personalizadas
Además de las dos secuencias definidas por defecto (main y fault) en WSO2 Enterprise Integrator se pueden definir las secuencias personalizadas que se necesite. La idea principal de las secuencias es que sean todo lo genéricas que sea posible, para que cada secuencia pueda utilizarse desde diferentes servicios, sean estos SOAP o REST, un Proxy o una API.
La sintaxis de una secuencia personalizada es:
<sequence name="string"
[onError="string"]
[key="string"]
[trace="enable"]
[statistics="enable"]>
mediator*
</sequence>
- El atributo
onError
indica qué otra secuencia se lanzará si existe algún problema al procesar la secuencia, en lugar de utilizar la secuencia de error por defecto. - statistics habilita o deshabilita la recogida de estadísticas con el número de mensajes procesados y el tiempo de proceso.
- trace habilita o deshabilita las trazas del mensaje en cada paso de mediación.
Plantillas
Las plantillas son prototipos de puntos finales o secuencias que se pueden utilizar como para nuevos objetos. Son de los siguientes tipos:
- Plantillas URI.
- Plantillas de secuencia.
Almacenamiento y reenvío
El mecanismo de almacenamiento y reenvío se utiliza para garantizar la entrega usando el almacén de mensajes y el procesador de mensajes del perfil integrador de WSO2 EI.
Almacenes de mensajes
Permiten almacenar temporalmente mensajes antes de que se consiga entregarlos en destino mediante un procesador de mensajes.
Procesadores de mensajes
Se usan para entregar mensajes que se han almacenado temporalmente en un almacén de mensajes.
Transformando el contenido del Payload
El payload se refiere al cuerpo de los mensajes donde se obtiene la información más importante para la lógica y los requisitos.
Creando nuevo contenido
En este caso el mensaje no tiene todavía contenido. Se da cuando tenemos un servicio REST que solo se activa con un endpoint URL con parámetros, pero necesita un payload para consumir un servicio de backend. Otro caso es el inverso, en el que el servicio de backend no da una respuesta, pero nuestro servicio necesita responder con un mensaje al cliente que hizo la petición.
En ambos casos se pueden utilizar PayloadFactory mediator, Enrich mediator o Script mediator.
PayloadFactory mediator
Define nuevo contenido para el payload, configurando una plantilla para el nuevo mensaje dentro de la etiqueta <tag>
y los valores dinámicos dentro de las etiquetas <arg>
.
Ejemplo
Supongamos que tenemos un servicio REST que recibe los aeropuertos origen y destino y una fecha, y devuelve información sobre las distintas compañías y hora.
Servicio WSO2:
- Request
- Endpoint:
/flights/get
- Parámetros URL:
- from=London
- to=Liverpool
- date=15/12/2017
- Response
<flights> <flight> <company>PacktAir</company> <time>10:30</time> <price>£ 300</price> </flight> </flights
Servicio Backend:
- Request
<flight> <from>Londo</from> <to>Liverpool</to> <date>15/12/2017</date> </flight>
- Response
<flights> <flight> <company>PacktAir</company> <time>10:30</time> <price>£ 300</price> </flight> </flights
Como vemos, en nuestro servicio no tenemos un payload en la petición, pero el backend lo está esperando con la información relativa al vuelo. Para construir un payload con estos datos a partir de los parámetros de la url usamos el mediador PayloadFactory:
<api xmlns="http://ws.apache.org/ns/synapse"
name="flights"
context="/flights">
<resource methods=POST
uri-template="/get?from={from}&to={to}&date={date}">
<inSequence>
<payloadFactory media-type="xml">
<format>
<flight>
<from>$1</from>
<to>$2</to>
<date>$3</date>
</flight>
</format>
<args>
<arg evaluator="xml"
expression="get-property(‘uri.var.from’)">
</arg>
<arg evaluator="xml"
expression="get-property(‘uri.var.to)">
</arg>
<arg evaluator="xml"
expression="get-property(‘uri.var.date)">
</arg>
</args>
</payloadFactory>
[...]
Script mediator
Ejemplo
Para resolver el mismo ejemplo que hemos hecho anteriormente con PayloadFactory mediante Script Mediator sería:
<api xmlns="http://ws.apache.org/ns/synapse"
name="flights"
context="/flights">
<resource methods="POST"
uri-template="/get?from={from}&to={to}&date={date}">
<inSequence>
<script language="js">;
<![CDATA[
var from = mc.getProperty("uri.var.from");
var to = mc.getProperty("uri.var.to");
var date = mc.getProperty("uri.var.date");
mc.setPayloadXML(
> <flight>
<from>{from}</from>
<to>{to}</to>
<date>{date}</date>
</flight>
);
]]>
</script>
[...]
En el ejemplo los parámetros de la URL se incluyen directamente en el script mediante la función mc.getProperty("uri.var.nombreParametro")
. Después, se define el payload con el mensaje XML mediante la función mc.setPayloadXML(nuevoPayload)
.
Cambiando el formato del contenido
La mejor forma de cambiar el contenido es con el uso de Message type.
Message type
Message type es una propiedad de synapse que define el formato del mensaje del payload actual. La sintaxis es la siguiente:
<property name="messageType" value="string" scope="axis2"/>
Ejemplo
Si en el ejemplo de los vuelos queremos devolver la misma información del backend, pero en formato JSON en vez de XML es suficiente con añadir la siguiente propiedad en la secuencia de salida:
<property name="messageType"
value="application/json"
scope="axis2">
</property>
XQuery mediator
El mediador XQuery nos permite hacer transformaciones XQuery sobre el payload.
La sintaxis es:
<xquery key="string"
[target="xpath"]>
<variable name="string"
type="string"
[key="string"]
[expression="xpath"]
[value="string"]/>
</xquery>
Ejemplo
Ahora suponemos que el backend nos devuelve la respuesta en JSON y queremos obtener un XML.
En la secuencia de salida, añadimos el XQuery mediator:
<xquery key="gov:/xquery/flights.xq">
<variable name="payload" type="ELEMENT"/>
</xquery>
El fichero flights.sq
se debe guardar en el registro, conteniendo la siguiente transformación:
<x>
<![CDATA[
declare variable $payload as document-node() external;
<flights>
<flight>
<company>{$payload//company/child::text()}</company>
<time>{$payload//time/child::text()}</time>
<price>{$payload//price/child::text()}</price>
</flight>
</flights>
]]>
</x>
Enriqueciendo el mensaje
En este caso ya tenemos el mensaje en el formato correcto, pero no tiene la estructura que necesitamos.
Enrich mediator
Puede procesar el payload actual para llevar a cabo diferentes acciones como reemplazar o añadir partes del mensaje, como el sobre, el cuerpo o una propiedad.
La sintaxis es
<enrich>
<source [clone=true|false]
[type=custom|envelope|body|property|inline]
xpath=""
property="" />
<target [action=replace|child|sibiling
[type=custom|envelope|body|property|inline]
xpath="" property="" >
</enrich>
Ejemplo
Siguiendo con el ejemplo de los vuelos supongamos que ahora el backend necesita un nuevo parámetro con la fecha actual.
Podemos hacer esta modificación gracias al enrich mediator:
<api xmlns=”http://ws.apache.org/ns/synapse”
name=”flights”
context=”/flights”>
<resource methods=”POST”
uri-template=”/get?from={from}& to={to}&date={date}”>
<inSequence>
<enrich>
<source clone="false"
type="inline">
<currentDate xmlns=""></currentDate>
</source>
<target action="child"
type="custom"
xpath="//flight">
</target>
</enrich>
<property name="date"
scope="default"
expression="get-property('SYSTEM_DATE','yyyy.MM.dd')" />;
<enrich>
<source clone="false"
type="property"
property="date"/>
<target action="child"
type="custom"
xpath="//currentDate">
</target>
</enrich>
[...]
Con el primer enrich mediator del ejemplo se añade a <flight>
el elemento hijo <currentDate>
para tener la estructura correcta. Con el segundo enrich mediator lo que se hace es añadir en ese nuevo elemento la fecha actual.
Rutas condicionales
Una de las mayores utilidades de un ESB es procesar las peticiones entrantes a nuestro servicio (proxy, API, endpoint, ...) y a partir de cierta información como URL, paylod, parámetros, etc. encaminar el servicio a una u otra secuencia y llevar a cabo distintas acciones según necesite para el mensaje en concreto.
Validación de XML
El mediador de validación (Validate Mediator) por defecto evalúa el contenido dentro de la etiqueta soapBody, pero también se puede especificar una expresión XPath para evaluar una parte concreta del payload. La sintaxis completa del mediador es:
<validate [source="xpath"]>
[<property name="validation-feature-id" value="true|false"/>*]
[<resource location="string" key="string"/>+]
<schema key="string"/>+
<on-fail>
mediator+
</on-fail>
</validate>
Donde schema referencia al fichero XSD para validar el mensaje.
Ejemplo
Se hace una validación de todo el contenido del payload contra el fichero XMLSchema.xsd
. Si el mensaje no fuera correcto crea un log con la descripción del error, formatea un mensaje de error SOAP y lo devuelve al cliente que haya hecho la petición al servicio.
<validate>
<!-- Specify the XSD schema -->
<schema key=" conf:/XMLSchema.xsd"/>
<on-fail>
<!-- Log the error in the server log -->
<log level="custom">
<property name="ERROR" value="Invalid Request"/>
</log>
<!-- Create a SOAP Fault message -->
<makefault>
<code value="tns:Receiver"
xmlns:tns="http://www.w3.org/2003/05/soap-envelope"/>
<reason value="Invalid Request"/>
</makefault>
<!-- Return message to the client -->
<respond/>
</on-fail>
</validate>
Validación de JSON
El mediador de validación también se puede utilizar para validar un payload JSON o una ruta específica sobre un esquema JSON.
La sintaxis en este caso es:
<validate [source="JSONPath"]>
[<resource location="string" key="string"/>+]
<schema key="string"/>+
<on-fail>
mediator+
</on-fail>
</validate>
En este caso schema referencia al fichero JSON para validar el mensaje.
Ejemplo
Siguiendo el ejemplo anterior, se registra y se crea un mensaje descriptivo de respuesta para devolverlo al cliente:
<validate source="json-eval($.rootElement)">
<!-- Specify the JSON schema -->
<schema key=" conf:/JSONSchema.json"/>
<on-fail>
<!-- Log the error in the server log -->
<log level="custom">
<property name="ERROR" value="Invalid Request"/>
</log>
<!-- Create a error message -->
<payloadFactory media-type="json">
<format>{"Error":"Invalid Request"}</format>
</payloadFactory>
<!-- Configure the HTTP code of the response -->
<property name="HTTP_SC" value="500" scope="axis2"/>
<!-- Return to the client -->
<respond/>
</on-fail>
</validate>
Filtro booleano
En los servicios se pueden comprobar condiciones booleanas de forma muy sencilla con el mediador filtro (filter mediator) que realiza acciones con una estructura del tipo if...else
. Se puede usar tanto para mensajes XML o JSON.
La sintaxis es la siguiente:
<filter (source="[XPath|json-eval(JSONPath)]" regex="string") |
xpath="[XPath|json-eval(JSONPath)]">
<then [sequence="string"]>
mediator+
</then>
<else [sequence="string"]>
mediator+
</else>
</filter>
Ejemplo
Tenemos una REST API que expone el mismo recurso mediante métodos GET y POST. Podemos usar el mediador filtro para comprobar si la petición se hace sobre GET o POST y obtener los valores de los parámetros, ya que cada método tiene su forma específica de hacerlo.
<filter xpath="boolean($axis2:HTTP_METHOD = 'POST' )">
<then>
<log>
<property name="Method" value="POST"></property>
</log>
<property name="flightID"
expression="json-eval($.flightID)"/>
</then>
<else>
<log>
<property name="Method" value="GET"></property>
</log>
<property name="flightID"
expression="$ctx:query.param.flightID"/>
</else>
</filter>
Filtrado múltiple
Cuando se tienen más de dos parámetros para comparar en lugar de usar el mediador filtro usaríamos el switch mediator, que funciona de una forma similar al filtro pero en vez de trabajar con 2 alternativas lo hace con N.
La sintaxis es la siguiente:
<switch source="[XPath|json-eval(JSON Path)]">
<case regex="string">
mediator+
</case>+
<default>
mediator+
</default>?
</switch>
Ejemplo
Hay un servicio que recibe, entre otra información, el nombre de un país. Se toma el código identificativo del país y se envía al servicio de backend. Necesitamos crear una expresión que procese el nombre del país del mensaje entrante y usar el mediador switch creando etiquetas case con el código de los diferentes países que tenemos, para guardar la información del código para cada país.
<switch source="//Country/name">
<case regex="Spain">
<property name="code" value="ES"/>
</case>
<case regex="UK">
<property name="code" value="GB"/>
</case>
<case regex="Germany">
<property name="code" value="DE"/>
</case>
[...]
<default>
<property name="code" value="UNKNOWN"/>
</default>
</switch>
Encaminamiento avanzado
WSO2 tiene otros dos mediadores para enrutar que son más potentes y complejos:
- Conditional router mediator
- Rule mediator
Estos mediadores permiten crear diferentes reglas para los mensajes y redirigir el flujo del servicio a una secuencia existente con la lógica para cada condición particular.
Mediador de encaminamiento condicional
Su sintaxis es
<conditionalRouter continueAfter="(true|false)">
<conditionalRoute breakRoute="(true|false)">
<condition ../>
<target ../>
</conditionalRoute>+
</conditionalRouter>
Ejemplo
Si tenemos una única condición que verifica si el servicio es flight y la operación es get, se puede comprobar la URL de la solicitud con:
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false">
<condition>
<match xmlns="" type="url" regex="/flights/get.*"/>
</condition>
<target sequence="flights_IN_SEQ"/>
</conditionalRoute>
</conditionalRouter>
En el siguiente ejemplo incluimos la condición de verificar que la solicitud tiene una cabecera llamada company con el valor PacktAir:
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false">
<condition>
<and xmlns="">
<match type="url" regex="/flights/get.*"/>
<match type="header" source="company"
regex="PacktAir"/>
</and>
</condition>
<target sequence="PacktAir_IN_SEQ"/>
</conditionalRoute>
</conditionalRouter>
Ahora se añade la condición para comprobar si tiene un parámetro llamado company aunque no se cumpla la primera regla:
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false">
<condition>
<and xmlns="">
<match type="url" regex="/flights/get.*"/>
<match type="header" source="company"
regex="PacktAir"/>
</and>
<or>
<equal type="param" source="company" value="PacktAir"/>
</or>
</condition>
<target sequence="PacktAir_IN_SEQ"/>
</conditionalRoute>
</conditionalRouter>
Por último también comprobamos que la petición no incluya un parámetro específico:
<conditionalRouter continueAfter="false">
<conditionalRoute breakRoute="false">
<condition>
<and xmlns="">
<match type="url" regex="/flights/get.*"/>
<match type="header" source="company"
regex="PacktAir"/>
</and>
<or>
<equal type="param" source="company"
value="PacktAir"/>
</or>
<not>
<equal type="param" source="next24Hr"
value="false"/>
</not>
</condition>
<target sequence="PacktAir_IN_SEQ"/>
</conditionalRoute>
</conditionalRouter>
Mediador de reglas
Es similar al anterior, pero ofrece más opciones y procesos. Su sintaxis es:
<rule>
<ruleset>
<source [ key="xs:string" ]>
[ in-Lined ]
</source>
<creation>
<property name="xs:string" value="xs:string"/>*
</creation>
</ruleset>
<session type="[stateless|stateful]"/>*
<facts>
<fact name="xs:string" type="xs:string"
expression="xs:string" value="xs:string"/>+
</facts>
<results>
<result name="xs:string" type="xs:string"
expression="xs:string" value="xs:string"/>*
</results>
[<childMediators>
<mediator/>*
</childMediators>]
</rule>
Ejemplo
Leemos el país de la petición entrante y obtenemos el código asociado:
<rule xmlns="http://wso2.org/carbon/rules">
<source>soapBody</source>
<target action="replace"
resultXpath="//country::text()">$country</target>
<ruleSet>
<properties/>
<rule resourceType="regular" sourceType="inline">
<![CDATA[
rule "Country ES" no-loop true
when
country: String()eval(country.equals("Spain"))
then
update(drools.getWorkingMemory()
.getFactHandle(country),"ES");
end
rule "Country GB" no-loop true
when
country: String()eval(country.equals("UK"))
then
update(drools.getWorkingMemory()
.getFactHandle(country),"GB");
end
rule "Country DE" no-loop true
when
country: String()eval(country.equals("Germany"))
then
update(drools.getWorkingMemory()
.getFactHandle(country),"DE");
end
]]>
</rule>
</ruleSet>
<input wrapperElementName="flights">
<fact elementName="country" type="java.lang.String"
xpath="//country::text()"/>
</input>
<output wrapperElementName="flights">
<fact elementName="country" type="java.lang.String"/>
</output>
</rule>
Mediator Debugger
El Mediator Debugger permite depurar el flujo de mensajes en el WSO2 Enterprise Integrator. Con el Mediator Debugger se pueden añadir puntos de ruptura o saltar puntos de los mediadores cuando se necesite depurar.
La depuración es útil para:
- Asegurarse de que las unidades independientes de mediación funcionan como se espera.
- Asegurarse de que la combinación de unidades funciona como se espera.
- Inspeccionar propiedades del mensaje en puntos intermedios.
- Inyectar propiedades al mensaje durante el flujo.
Integración de datos
Introducción
La integración de datos ofrece todas las operaciones CRUD como servicios.
Las operaciones CRUD son:
- C. Creación (create)
- R. Lectura (read)
- U. Actualización (update)
- D. Borrado (delete)
WSO2 EI dispone de las siguientes capacidades para la integración de datos:
- Exposición de datos como SOAP/REST.
- Soporte de datasources predefinidos.
- Soporte de datasources personalizados.
- Solicitudes por lotes.
- Federación de datos.
- Acceso transaccional a datos.
- Transformación y validación de datos.
- Securización y gestión del acceso a datos.
Servicios de datos
WSO2 EI nos permite construir servicios web que gestionen tablas de nuestras fuentes de datos. Estos servicios se denominan servicios de datos o data services.
WSO2 soporta cualquier tipo de datos, como sistemas gestores de base de datos relacionales (RDBMS), CSV, Excel, ODS, Cassandra, Google Spreadheets, RDF, cualquier página web. Respecto a bases de datos soporta MsSQL, DB2, Oracle, OpenEdge, TeraData, MySQL, PostgreSQL/EnterpriseDB, H2, Derby y cualquier base de datos con driver JDBC.
Para crear un servicio de datos se siguen estos pasos:
- Definir Servicio de datos (Data Service).
- Añadir datasource.
- Escribir consulta.
- Añadir operaciones asociadas a la consulta.
- Exponerlo como un servicio SOAP (operación), o exponerlo como un recurso REST.
Los servicios de datos se pueden crear tanto desde la consola de gestión de WSO2 como desde Integration Studio. La forma más rápida y sencilla es desde la consola, pero se recomienda hacerlo desde Integration Studio para poder añadirlo como parte de un despliegue en la forma de fichero .car y poder llevar un control de versiones.
Fuentes de datos
En lugar de definir cada data source en cada data service lo mejor es definir el data source en la consola WSO2 y añadir la referencia al data source en la definición del data service.
Los data sources se crean en la consola WSO2 desde Configure > Datasources.
Otra forma de crear los datasources es en el sistema de ficheros en forma de XML, se deben situar en $WSO2_HOME/conf/datasources
.
Consultas
Lo normal es tener una consulta por operación o recurso. Estas consultas se consumirán vía servicio SOAP (operación) o vía servicio REST (recurso).
En el diseño de la consulta se deben definir:
- Consulta y fuente de datos sobre la que se va lanzar.
- Parámetros de entrada según los parámetros de la consulta.
- Parámetros de salida según las columnas resultantes de la consulta.
El formato de la salida de consultas puede ser XML (al que se puede aplicar XLST) o JSON.
Calidad del servicio
No es suficiente con crear servicios, estos deben ser de calidad, para ello se deben configurar con seguridad, throttling y cacheo para crear servicios con mejor rendimiento.
Los principios básicos de seguridad son:
- Autenticación: verificar que un usuario es realmente quien dice ser.
- Disponibilidad: los servicios deben estar disponibles cuando se necesiten.
- Confidencialidad: los servicios solo deben estar disponibles para los usuarios que tienen permiso para consumirlos.
- Integridad: los datos no se pueden modificar de forma no autorizada o no detectada.
- No repudio: el consumidor del servicio no puede negar haber recibido respuesta del servicio o denegar la respuesta.
Throttling se refiere a las distintas políticas que aplicar a las peticiones entrantes para evitar cargas pesadas que ocasionen problemas de rendimiento en el servidor, y también a restringir el acceso a un servicio por IP o dominios.
El cacheo es una herramienta que permite mejorar el rendimiento de los servicios de WSO2.
Seguridad
Escenarios de seguridad
A continuación se explican los 16 escenarios de seguridad que provee WSO2. Se pueden crear políticas de seguridad personalizadas si es necesario.
Las políticas se crean desde Integration Studio y después se despliegan en el servidor.
Autenticación con token con nombre de usuario
Es el escenario más simple y más utilizado. El usuario envía el UsernameToken en el mensaje, y se valida contra el almacén de usuarios configurado en el servidor.
No repudio
Los clientes deben tener un certificado X.509 para firmar los mensajes con su clave privada; luego el receptor puede verificar al cliente utilizando la clave pública del cliente.
Integridad
El cliente genera una clave simétrica y firma el mensaje con dicha clave. Después encripta la clave simétrica con la clave pública del servicio y la envía dentro del mensaje SOAP. De esta forma el único que puede desencriptar la clave simétrica y verificar la firma del mensaje es el servicio, usando su clave privada.
Confidencialidad
El cliente genera una clave simétrica y encripta el mensaje con dicha clave. Después encripta la clave simétrica con la clave pública del servicio y la envía dentro del mensaje SOAP. El servicio desencripta la clave simétrica usando su clave privada, y con esta clave simétrica desencripta el mensaje.
Firma y encriptación con autenticación X509
El cliente encripta el mensaje usando la clave pública del servicio y lo firma usando su clave privada. El servicio desencripta el mensaje usando su clave privada y verifica la firma contra la clave pública del cliente.
Tanto el cliente como el servidor necesitan tener el certificado público de la otra parte en su almacén de claves.
Firma y encriptación desde clientes anónimos
El cliente genera una clave simétrica y encripta y firma el mensaje con dicha clave. Entonces, encripta la clave simétrica con la clave pública del servicio y la envía dentro del mensaje SOAP. El servicio desencripta la clave simétrica usando su clave privada y entonces, con la clave simétrica, desencripta el mensaje y verifica la firma.
Encriptación y autenticación con token de nombre de usuario
Este escenario es una mezcla entre Token de nombre de usuario y Confidencialidad.
El cliente genera una clave simétrica y encripta el mensaje con dicha clave. Entonces encripta la clave simétrica con la clave pública del servicio y la envía dentro del mensaje SOAP. El servicio desencripta la clave simétrica usando su clave pública y, con esta clave simétrica, desencripta el mensaje. El usuario envía el UsernameToken en el mensaje y es validado contra los almacenes de usuario configurados en el servidor.
Firma, encriptación y autenticación con token de nombre de usuario
Este escenario es una mezcla entre Token de nombre de usuario y Firma y encriptación desde clientes anónimos.
El cliente genera una clave simétrica y encripta y firma el mensaje con dicha clave. Entonces encripta la clave simétrica con la clave pública del servicio y la envía dentro del mensaje SOAP. El servicio desencripta la clave simétrica usando su clave privada y, con la clave simétrica, desencripta el mensaje y verifica la firma. El usuario envía el UsernameToken en el mensaje, y es validado contra el almacén de usuarios configurado en el servidor.
Conversación segura con autenticación X509. Firma
Este escenario establece un canal seguro entre el cliente y el servicio usando certificados X509. Todas las comunicaciones en el canal seguro están firmadas usando las claves del canal seguro.
Conversación segura con autenticación X509. Encriptación
Es el mismo escenario que el anterior, con la diferencia de que los mensajes dentro del canal seguro se encriptan en vez de firmarse. Así el entorno es más seguro porque el mensaje no es visible por terceras partes.
Conversación segura con autenticación X509. Firma y encriptación
Este escenario es mezcla de los dos anteriores. Todos los mensajes dentro del canal son firmados y también encriptados. Éste es el más seguro de los tres escenarios.
Conversación segura con clientes anónimos. Firma
Aquí también se comparte un canal seguro entre el cliente y el servicio, pero el cliente no tiene un certificado X.509, por lo que el canal se establece usando una clave simétrica.
Todas las comunicaciones en el canal seguro se firman usando las llaves del canal seguro.
Conversación segura con clientes anónimos. Encriptación
Igual que en el escenario anterior, pero los mensajes en vez de firmarse se encriptan.
Conversación segura con clientes anónimos. Encriptación y autenticación con token
Igual que el anterior, con la diferencia de que el usuario se autentica con el token de usuario cuando se establece el canal seguro.
Conversación segura con clientes anónimos. Firma, encriptación y autenticación con token
Como el anterior, pero los mensajes además de firmarse se encriptan.
Seguridad basada en Kerberos
En este caso necesitamos un Centro de distribución de claves, Key Distribution Center (KDC) y un servidor de autenticación al que conectar nuestros servicios.
En WSO2 se dispone de los siguientes ficheros para la configuración de este escenario:
<EI_HOME>/repository/conf/security/krb5.conf
: configuración del servidor KDC.<EI_HOME>/repository/conf/security/jass.conf
: configuración del servidor de autorización.
Securizando el transporte
La primera medida para proveer seguridad a nuestros servicios es securizar la capa de transporte, ya que nuestra red puede ser vulnerable a ataques como man in the middle, spoofing, poisoning, etc.
Para la comunicación segura se utilizan los protocolos Secure Sockets Layer (SSL) y Transport Layer Security (TLS), que encriptan los mensajes entre el emisor y el receptor, restringiendo el acceso a la información a un tercero no autorizado.
Creando un certificado para el Servidor WSO2
Por defecto, todos los servidores WSO2 están configurados con un certificado para localhost. Este certificado se puede usar para pruebas en un entorno local, pero no se puede utilizar en un entorno de producción.
Para crear un certificado válido para el servidor se puede utilizar la aplicación keytool, que es parte del Java Development Kit (JDK).
Configurando el transporte por HTTPS
Una vez creado el certificado, tenemos que decir al WSO2 EI que lo utilice.
Para hacerlo se modifican las propiedades keystoreFile
y keystorePass
del fichero <WSO2_HOME>/conf/tomcat/catalinaserver.xml
dentro del conector con el puerto 9443.
Además, es necesario añadir el certificado creado al almacén truststore.jks.
Por último, tenemos que configurar las propiedades transportReceiver
y transportSender
del fichero <WSO2_HOME>/conf/axis2/axis2.xml
para utilizar el nuevo almacén.
Securizando aplicaciones REST
Por defecto, WSO2 no provee ningún método de autenticación para APIs REST, así que es necesario crear un programa Java con la lógica de la autenticación, generar un proyecto .jar, desplegarlo en el directorio <WSO2_HOME>/lib
y configurar las APIs para usar este proyecto como handler.
Autenticación básica
El consumidor envía usuario y contraseña en la cabecera Authorization de la request. Esta cabecera tiene la estructura username:password
codificada en formato base64. En la clase java se recuperan las credenciales así:
String authHeader = (String) headersMap.get("Authorization");
String credentials = authHeader.substring(6).trim();
String decodedCredentials =
new String(new Base64().decode(credentials.getBytes()));
String userName = decodedCredentials.split(":")[0];
String password = decodedCredentials.split(":")[1];
En el API hay que configurar el handler con el paquete java y la clase que contiene la lógica para llevar a cabo la autenticación básica, como en el siguiente ejemplo:
<api xmlns="http://ws.apache.org/ns/synapse" name="flights"
context="/flights">
<resource methods="POST"
uri-template="/get?from={from}&to={to}&date={date}">
<inSequence>
mediators...
</inSequence>
</resource>
<handlers>
<handler class="org.wso2.rest.BasicAuthHandler"/>
</handlers>
</api>
Autenticación contra el WSO2 Identity Server
WSO2 EI tiene un mediador que permite comprobar las credenciales contra el WSO2 Identity Server usando el protocolo OAuth.
Securizando proxies SOAP
La creación de un proxy SOAP seguro se hace desde el Integration Studio, para ello hay que configurar tres proyectos diferentes:
- ESB Config Project: este proyecto contendrá la definición del proxy.
- Registry Resources Project: para la política de seguridad.
- Composite Application Project: este proyecto sirve para crear el fichero
.car
a desplegar en el servidor.
Para crear la política se elige Registry Resource y como plantilla WS-Policy. Esta política nos ofrece un asistente donde se puede elegir el escenario de seguridad a aplicar a la política.
Invocando backend seguros
Autenticación básica
Para invocar un backend seguro usando autenticación básica tenemos que enviar una cabecera llamada Authorization en la petición, conteniendo usuario y contraseña unidos por :
y codificado en Base64:
<!-- Define the username -->
<property name="username" value="USERNAME_OF_BACKEND"
scope="default"
type="STRING" xmlns="http://ws.apache.org/ns/synapse"/>
<!-- Define the password -->
<property name="password" value="PASSWORD_OF_BACKEND"
scope="default"
type="STRING" xmlns="http://ws.apache.org/ns/synapse"/>
<!-- Configure the header with the above parameters -->
<property expression="fn:concat('Basic ',
base64Encode(fn:concat($ctx:username,':',$ctx:password)))"
name="Authorization" scope="transport" type="STRING"
xmlns="http://ws.apache.org/ns/synapse"/>
Autenticación OAuth
El proceso es similar al anterior, pero con la diferencia de que es necesario enviar el token en lugar de las credenciales:
<!-- Define the Oauth token -->
<property name="token" value="OAUTH_TOKEN" scope="default" type="STRING"
xmlns="http://ws.apache.org/ns/synapse"/>
<!-- Configure the header with the above parameters -->
<property expression="fn:concat('Bearer ',$ctx:token)" name="Authorization"
scope="transport" type="STRING" xmlns="http://ws.apache.org/ns/synapse"/>
Servicios Web Seguros
Cuando tenemos un servicio SOAP seguro en el backend es necesario especificar la política a aplicar y configurar el endpoint para usar esta política en la comunicación:
<!-- Define the security policy -->
<localEntry key="securityPolicy" src="path/to/policy"/>
<!-- Define the security policy -->
<send>
<address uri="http://enterpriseintegrator:8280/flights/list"
format="soap11">
<enableAddressing/>
<enableSec policy="securityPolicy"/>
</address>
</send>
En la secuencia de salida tenemos que borrar la cabecera de seguridad:
<header
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
name="wsse:Security"
action="remove"/>
Throttling
WSO2 EI tiene un mediador llamado throttle que es útil para restringir el uso de los servicios o dar prioridad a determinados grupos de usuarios según sus IPs o dominios.
La sintaxis es
<throttle [onReject="string"] [onAccept="string"] id="string">
(<policy key="string"/> | <policy>..</policy>)
<onReject>..</onReject>?
<onAccept>..</onAccept>?
</throttle>
Cacheo
El principal objetivo del mediador cache es evitar que el servidor pierda tiempo y tenga sobrecarga por procesar una petición que ya haya sido recibida y procesada con anterioridad.
Su sintaxis es
<cache [id="string"] [hashGenerator="class"] [timeout="seconds"]
[scope=(per-host | per-mediator)] collector=(true | false)
[maxMessageSize="in-bytes"]>
<onCacheHit [sequence="key"]>
(mediator)+
</onCacheHit>?
<implementation type=(memory | disk) maxSize="int"/>
</cache>
Patrones de integración
Los patrones de integración o Enteprise Integration Patterns (EIP) recogen las mejores prácticas en mediación e integración, abarcando un amplio espectro de escenarios comunes de integración.
El catálogo de patrones de integración está disponible en eaipatterns.com.
WSO2 y los patrones de integración
WSO2 da cobertura a todos los EIPs publicados. Los EIPs se habilitan utilizando bloques de construcción individuales llamados Mediadores.
Tipos de patrones de integración
- Enrutado basado en contenido (Content-based Router).
- Filtrado de mensajes (Message Filter).
- División de mensajes (Message Splitter).
- Agregador de mensajes (Message Aggegator).
Sistemas de mensajería
La mensajería es uno de los estilos de integración. Se utiliza para conectar varias aplicaciones de manera asíncrona y poco acoplada.
La mensajería desacopla las aplicaciones de la transferencia de datos, para que las aplicaciones se puedan concentrar en los datos y la lógica relacionada, mientras que el sistema de mensajería maneja la transferencia de datos.
Canales de mensajería (Message Channels)
Permite comunicar una aplicación con otra mediante mensajería.
Los canales de mensajería facilitan la comunicación entre aplicaciones. Un emisor envía un mensaje por un canal en concreto. Un receptor puede leer este mensaje. Los canales permiten a emisor y receptor sincronizarse.
Ejemplo de los canales de mensajería en WSO2
Se solicita un presupuesto por una aplicación cliente desde un servicio.
Este escenario se puede configurar en el ESB con:
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="message-channel-proxy" startOnLoad="true" transports="http https">
<target>
<inSequence>
<sequence key="message-channel-sequence" />
</inSequence>
<outSequence>
<log level="custom">
<property name="sending response to" value="client" />
</log>
<respond />
</outSequence>
<faultSequence />
</target>
</proxy>
<sequence name="message-channel-sequence">
<log level="custom">
<property name="sending request to" value="axis2 server" />
</log>
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService" />
</endpoint>
</send>
</sequence>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: es el servicio proxy que se deberá invocar para ejecutarlo.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.<sequence>
: secuencia externa que se invoca por el proxy.<send>
: el mediador send enruta el mensaje al endpoint indicado por la dirección URI.
Mensaje (Message)
Cómo dos aplicaciones conectadas por un canal de mensajería intercambian información.
Cuando se conectan dos aplicaciones distintas mediante un canal de mensajería la información se debe empaquetar en un conjunto de datos (data set) y el patrón mensaje se utiliza como medio de transmisión.
Un mensaje tiene dos partes: una cabecera (header) y un cuerpo (body). La cabecera tiene información sobre el tipo de datos a transmitir, su origen y su destino; el cuerpo tiene los datos en sí.
Ejemplo de mensaje en WSO2
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://services.samples"
xmlns:xsd="http://services.samples/xsd">
<soapenv:Header />
<soapenv:Body>
<ser:getQuote>
<ser:request>
<ser:symbol>foo</ser:symbol>
</ser:request>
</ser:getQuote>
</soapenv:Body>
</soapenv:Envelope>
Tuberías (pipes) y filtros (filters)
Sirven para llevar a cabo procesamientos complejos de un mensaje manteniendo independencia y flexibilidad.
El patrón de tuberías y filtros rompe una gran tarea en un conjunto de pequeñas subtareas independientes y encadenadas. El objetivo principal de usar este patrón es mantener la independencia y la flexibilidad en cada paso del proceso.
Ejemplo de tuberías y filtros en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- Sender will invoke the following Sequence -->
<sequence name="PipesAndFilters">
<log level="full"
xmlns="http://ws.apache.org/ns/synapse"/>
<!-- Checks For the User Name -->
<filter xmlns:m0="http://services.samples"
source="//m0:credentials/m0:name" regex="UserName">
<!-- If the filtered condition is satisfied -->
<then>
<!-- Checks for the User ID -->
<filter xmlns:m1="http://services.samples"
source="//m1:credentials/m1:id" regex="001">
<then>
<!-- The filtered message will be routed to the end point -->
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</then>
<else>
<drop/>
</else>
</filter>
</then>
<!-- If the condition was not satisfied -->
<else>
<drop/>
</else>
</filter>
</sequence>
<!-- Will be triggered first -->
<proxy name="pipes-and-filters-proxy"
startOnLoad="true" transports="http https">
<target>
<inSequence>
<!-- Will direct an incoming request to the specified sequence -->
<sequence key="PipesAndFilters"/>
</inSequence>
<outSequence>
<respond/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: es el servicio proxy que se deberá invocar para ejecutarlo.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.<sequence>
: secuencia externa que se invoca por el proxy.<filter mediator>
: este mediador filtra un mensaje entrante basándose en las restricciones especificadas en la expresión regularregex
.<then>
: acciones a llevar a cabo si las condiciones del filtro se satisfacen.<else>
: acciones a tomar cuando no se satisfacen las condiciones.
Enrutador de mensajes (Message Router)
División del proceso en pasos individuales para que los mensajes se puedan pasar por distintos filtros según las condiciones.
El enrutador de mensajes lee el mensaje y según su contenido lo enruta al destinatario apropiado.
Ejemplo de enrutador en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- Receiving sequence which will be the message router -->
<sequence name="message-router-sequence">
<!-- Would analyze the data for filtering -->
<switch xmlns:m0="http://services.samples"
source="//m0:getQuote/m0:request/m0:symbol">
<!-- If the content is "foo" -->
<case regex="foo">
<!-- Sends the information to the fooOutQueue -->
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService?wsdl"/>
</endpoint>
</send>
</case>
<!-- If the content is "bar" -->
<case regex="bar">
<!-- Sends the information to the barOutQueue -->
<send>
<endpoint>
<address uri="http://localhost:9001/services/SimpleStockQuoteService?wsdl"/>
</endpoint>
</send>
</case>
<default>
<property name="symbol" expression="fn:concat('Normal Stock - ',
//m0:getQuote/m0:request/m0:symbol)"/>
</default>
</switch>
</sequence>
<proxy name="message-router-proxy"
startOnLoad="true" transports="http https">
<target>
<inSequence>
<!-- Will call the message router -->
<sequence key="message-router-sequence"/>
</inSequence>
<outSequence>
<respond/>
</outSequence>
<description>Message Router</description>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: es el servicio proxy que se deberá invocar para ejecutarlo.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.<sequence>
: secuencia externa que se invoca por el proxy.<send>
: el mediador send enruta el mensaje al endpoint indicado por la dirección URI.<case>
: cuando el contenido filtrado coincida con la expresión regular especificada.<default>
: si no coincide con ninguna condición el mensaje se desviará a este caso por defecto.
Traductor de mensajes
Comunicación entre sistemas que utilizan diferentes formatos de datos utilizando mensajería.
Ejemplo de traductor en WSO2
El formato de petición del cliente es:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://services.samples"
xmlns:xsd="http://services.samples/xsd">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
<ser:Code>foo</ser:Code>
</soapenv:Body>
</soapenv:Envelope>
El formato compatible con el destinatario es:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://services.samples"
xmlns:xsd="http://services.samples/xsd">
<soapenv:Header/>
<soapenv:Body>
<ser:getQuote>
<!--Optional:-->
<ser:request>
<!--Optional:-->
<ser:symbol>foo</ser:symbol>
</ser:request>
</ser:getQuote>
</soapenv:Body>
</soapenv:Envelope>
La traducción se consigue con:
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- Will trigger when a request is sent to the
ESB profile of WSO2 EI -->
<proxy name="message-translator-proxy"
startOnLoad="true" transports="http https">
<target>
<inSequence>
<!-- Will transform the incoming message
to the format specified below -->
<payloadFactory>
<format>
<m:getQuote xmlns:m="http://services.samples">
<m:request>
<m:symbol>$1</m:symbol>
</m:request>
</m:getQuote>
</format>
<args>
<arg xmlns:m0="http://services.samples"
expression="//m0:Code"/>
</args>
</payloadFactory>
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<respond/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.<send>
: el mediador send enruta el mensaje al endpoint indicado por la dirección URI.<main sequence>
: la secuencia predeterminada que se activa al invocar el ESB.<payload factory>
: transforma el mensaje al formato indicado por el mediador.
Punto final de mensaje (Message Endpoint)
Cómo una aplicación se conecta a un canal de mensajería para enviar y recibir mensajes.
Este patrón encapsula el sistema de mensajería dentro de una aplicación, después personaliza una API de mensajería general para una aplicación y tarea específicas. De esta forma se puede cambiar al API de mensajería simplemente cambiando el código del endpoint, lo que mejora la mantenibilidad de las aplicaciones.
Ejemplo de punto final de mensaje en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- Will trigger when the message is sent to message-endpoint-proxy -->
<proxy name="message-endpoint-proxy"
startOnLoad="true" transports="http https">
<target>
<inSequence>
<!-- Sends the message to the specified service -->
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<respond/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: es el servicio proxy que se deberá invocar para ejecutarlo.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<endpoint>
: destino al que se va a enviar el mensaje.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.
Canales de mensajería
Un canal de mensajería es un patrón arquitectónico básico de un sistema de mensajería, se utiliza fundamentalmente para intercambiar datos entre aplicaciones.
Una aplicación puede usar un canal para hacer accesible un tipo específico de datos para cualquier otra aplicación que necesite consumir este tipo de datos.
Canal punto a punto (point-to-point channel)
Asegura al que emisor que el receptor recibirá el documento o se completará la llamada.
El patrón Canal Punto a Punto garantiza que tan solo un único receptor consuma un mensaje (cuando hay varios receptores esperando para consumir el mensaje).
Ejemplo del canal punto a punto en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PointToPointProxy"
transports="http https" startOnLoad="true">
<target>
<inSequence>
<send>
<endpoint>
<!-- Channel With Multiple Endpoints Load Balancer
Will Ensure that only one will receive it -->
<loadbalance>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService/" />
</endpoint>
<endpoint>
<address uri="http://localhost:9001/services/SimpleStockQuoteService/" />
</endpoint>
<endpoint>
<address uri="http://localhost:9002/services/SimpleStockQuoteService/" />
</endpoint>
</loadbalance>
</endpoint>
</send>
</inSequence>
<outSequence>
<respond/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: es el servicio proxy que se deberá invocar para ejecutarlo.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<send>
: el mediador send enruta el mensaje al endpoint indicado por la dirección URI.<load balance>
: administra la colección de servicios definidos en el endpoint. Envía la solicitud solo a una instancia cada vez, que se selecciona según el algoritmo dado.<outSequence>
: esta secuencia se lanza después de la ejecución de<inSequence>
.
Canal publicación--suscripción (publish--subscribe channel)
Cómo el emisor transmite un evento a todos los receptores interesados.
El patrón canal de publicación--suscripción recibe mensajes del canal de entrada que divide y transmite a sus suscriptores a través del canal de salida. Cada suscriptor tiene un único canal de salida.
Ejemplo del canal publicación--suscripción en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="PublishSubscribeChannel"
startOnLoad="true" transports="http,https">
<target>
<inSequence>
<event topic="PublisherSubscriber"/>
</inSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<main sequence>
: la secuencia predeterminada que se activa al invocar el ESB.<event>
: permite definir un conjunto de receptores.
Canal de tipo de datos (datatype channel)
Cómo envía la aplicación un elemento de datos de forma que el receptor sepa cómo procesarlo.
El patrón crea un canal separado para cada tipo de datos de forma que todos los mensajes de un canal dado contengan el mismo tipo de datos. El emisor, que conoce el tipo de datos, debe elegir el canal apropiado por el que enviar el mensaje. El receptor identifica el tipo de datos de un mensaje según el canal por el que lo esté recibiendo.
Ejemplo del canal tipo de datos en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<endpoint name="StockQuoteReceiver">
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<sequence name="MarketActivity">
<log level="custom">
<property name="Messaging_Channel" value="MARKET_ACTIVITY"/>
</log>
<send>
<endpoint key="StockQuoteReceiver"/>
</send>
</sequence>
<sequence name="FullQuote">
<log level="custom">
<property name="Messaging_Channel" value="FULL_QUOTE"/>
</log>
<send>
<endpoint key="StockQuoteReceiver"/>
</send>
</sequence>
<sequence name="StockQuote">
<log level="custom">
<property name="Messaging_Channel" value="STOCK_QUOTE"/>
</log>
<send>
<endpoint key="StockQuoteReceiver"/>
</send>
</sequence>
<proxy name="datatype-channel-proxy"
startOnLoad="true" transports="http https">
<target>
<log/>
<inSequence>
<switch source="get-property('Action')">
<case regex="/*urn:getQuote/*">
<sequence key="StockQuote"/>
</case>
<case regex="/*urn:getFullQuote/*">
<sequence key="FullQuote"/>
</case>
<case regex="/*urn:getMarketActivity/*">
<sequence key="MarketActivity"/>
</case>
</switch>
</inSequence>
<outSequence>
<respond/>
</outSequence>
</target>
</proxy>
</definitions>
Canal de mensaje inválido (invalid message channel)
Cómo un receptor gestiona apropiadamente un mensaje que no tiene sentido.
Este patrón permite a los administradores definir una indicación de error que aparezca cuando un endpoint falle en el proceso de una solicitud.
Ejemplo del canal de mensaje inválido en WSO2
<!-- Invalid Message Chanel Proxy-->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="InvalidMessageChannelProxy">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<inSequence>
<log level="full" />
</inSequence>
<outSequence>
<log level="full" />
</outSequence>
<faultSequence>
<log level="full">
<property name="MESSAGE" value="Failure Message..."/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop />
</faultSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/proxy/sample_proxy_1.wsdl"/>
</proxy>
</definitions>
Canal de papel mojado (dead letter channel)
Qué tiene que hacer el sistema de mensajería con un mensaje que no puede entregar.
Debido a errores en los sistemas y en la red o a fallos en el receptor, los mensajes a veces no pueden llegar a su destino. En estos casos, el sistema de mensajería puede entregar los mensajes a un DLC (Dead Letter Channel. En el DLC se pueden implementar distintos mecanismos que se ocupen de entregar el mensaje a su destinatario. Un método es reintentar el reenvío de forma periódica. Otra opción es la persistencia del mensaje, que asegura que los mensajes se entregan a sus destinatarios cuando se reinicia el sistema, incluso cuando el sistema de mensajería falla.
Ejemplo de dead letter channel en WSO2
La arquitectura del DLC en WSO2 es la siguiente:
Además de los dos tipos de almacenamiento que propone WSO2 (memoria y JMS), se pueden definir soluciones propias de almacenamiento.
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<proxy name="StockQuoteProxy" transports="https http"
startOnLoad="true" trace="disable">
<description/>
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<inSequence>
<log level="full"/>
</inSequence>
<outSequence>
<log level="full">
<property name="MSG" value="Response...."/>
</log>
<send/>
</outSequence>
<faultSequence>
<log level="full">
<property name="MSG" value="++++++++++FAULT---------...."/>
</log>
<property name="target.endpoint" value="SimpleStockQuoteService"/>
<store messageStore="test-msg-store"/>
</faultSequence>
</target>
<publishWSDL uri="http://localhost:9000/services/SimpleStockQuoteService?wsdl"/>
</proxy>
<endpoint name="SimpleStockQuoteService">
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<log level="full"/>
<filter source="get-property('To')" regex="http://localhost:9000.*">
<send/>
</filter>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
<messageStore name="test-msg-store"/>
<messageProcessor
class="org.apache.synapse.message.processors.forward.
ScheduledMessageForwardingProcessor"
name="test-msg-processor"
messageStore="test-msg-store">
<parameter name="interval">1000</parameter>
<parameter name="max.deliver.attempts">100</parameter>
</messageProcessor>
</definitions>
Se tienen los siguientes elementos:
<faultSequence>
: secuencia por defecto. El servicio proyx StockQuoteProxy se ejecuta en el caso de un fallo o error.<store>
: el mediador store carga el mensaje almacenado definido en la línea
<messageStore name="test-msg-store"/>
<messageStore>
: define el almacenamiento de mensajes a usar, que se tiene que haber creado con la consola de gestión del ESB.<messageProcessor>
: define el algoritmo de procesamiento, el periodo para intentar reenviar el mensaje en caso de fallo y el máximo número de reintentos.
Entrega garantizada (guaranteed delivery)
Cómo el emisor se asegura la entrega del mensaje, incluso cuando falla el sistema de mensajería.
Este patrón garantiza la entrega del mensaje almacenándolo localmente y enviándolo al almacén de datos del receptor. Incluso cuando el destinatario está offline el patrón asegura que el mensaje llegará cuando vuelva a estar online.
Ejemplo de entrega garantizada en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="GuranteedDeliveryProxy"
transports="http https" startOnLoad="true">
<target>
<inSequence>
<sequence key="delivery_seq"/>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
<endpoint name="StockReqEndPoint">
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<sequence name="delivery_seq" onError="delivery_fail">
<property name="FORCE_SC_ACCEPTED" value="true" scope="axis2"/>
<property name="OUT_ONLY" value="true"/>
<enrich>
<source type="envelope" clone="true"/>
<target type="property" property="mssg"/>
</enrich>
<send>
<endpoint key="StockReqEndPoint"/>
</send>
</sequence>
<sequence name="delivery_fail">
<log level="full"/>
<enrich>
<source type="property" clone="true" property="mssg"/>
<target type="envelope"/>
</enrich>
<property name="target.endpoint" value="StockReqEndPoint"/>
<store messageStore="JMStore"/>
</sequence>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<log/>
<drop/>
</sequence>
<messageStore class="org.apache.synapse.message.store.impl.jms.JmsStore"
name="JMStore">
<parameter name="java.naming.factory.initial">
org.wso2.andes.jndi.PropertiesFileInitialContextFactory</parameter>
<parameter name="store.jms.cache.connection">false</parameter>
<parameter name="java.naming.provider.url">
repository/conf/jndi.properties</parameter>
<parameter name="store.jms.JMSSpecVersion">1.1</parameter>
</messageStore>
<messageProcessor
class="org.apache.synapse.message.processors.
forward.ScheduledMessageForwardingProcessor"
name="ScheduledProcessor" messageStore="JMStore">
<parameter name="interval">10000</parameter>
</messageProcessor>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: este servicio permite abstraer la lógica de enrutado del cliente. Cualquiera que sea la petición, el cliente la envía solo al servicio expuesto.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<sequence>
: secuencia externa que se invoca por el proxy.<enrich>
: procesa mensajes basados en la configuración de origen y realiza la acción en la configuración de destino.<store>
: guarda el mensaje utilizando el almacén de mensajes definido por el nombre JMS Store.<messageStore>
: define el almacén de mensajería a utilizar y los parámetros necesarios para la conexión al almacén. En este ejemplo la conexión se hace a un almacenamiento JMS externo.<messageProcessor>
: define el algoritmo de procesamiento a usar, el período de tiempo para reintentar el reenvío de mensajes en caso de fallo y el máximo número de reintentos.
Adaptador de canal (channel adapter)
Cómo conectar una aplicación al sistema de mensajería para enviar/recibir mensajes.
El adaptador de canal accede a los datos de una aplicación y publica mensajes en un canal en función de esos datos. Además, recibe mensajes e invoca la funcionalidad dentro de la aplicación.
Puente de mensajería (messaging bridge)
Cómo se pueden conectar varios sistemas de mensajería para que los mensajes disponibles en uno también lo estén en los otros.
El puente de mensajería facilita la conexión entre los sistemas de mensajería y replica los mensajes entre ellos transformando el formato del mensaje de un sistema al otro.
Ejemplo de puente de mensajería en WSO2
<!-- Message Translator-->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<api name="MessageTranslate" context="/stockquote">
<resource methods="GET" uri-template="/view/{symbol}">
<inSequence>
<payloadFactory>
<format>
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol>$1</m0:symbol>
</m0:request>
</m0:getQuote>
</format>
<args>
<arg expression="get-property('uri.var.symbol')"/>
</args>
</payloadFactory>
<property name="SOAPAction" value="getQuote"
scope="transport"></property>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"
format="soap11"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
</api>
</definitions>
Se tienen los siguientes elementos:
<payloadFactory>
: crea la solicitud SOAP necesaria para el servicio de back-end. Utiliza el valor de la variable HTTP GET (de la solicitud REST realizada al ESB).<arg>
: lista de argumentos que se concatenarán en el mismo orden dentro de las etiquetas de formato (al modo de printf).
Bus de mensajes (message bus)
Una arquitectura que permite que aplicaciones separadas trabajen juntas de manera desacoplada, de modo que las aplicaciones se puedan agregar o quitar fácilmente sin afectar a las demás.
Este enfoque facilita el mantenimiento y las pruebas, ya que modificar o quitar una aplicación no afectará la funcionalidad de ninguna otra aplicación.
Construcción del mensaje
La construcción de mensajes involucra los patrones arquitectónicos de varias construcciones, funciones y actividades involucradas en la creación y transformación de un mensaje entre aplicaciones.
Mensaje de comando (command message)
Cómo se puede usar la mensajería para invocar un procedimiento en otra aplicación.
Ejemplo de mensaje de comando en WSO2
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="command-message-proxy"
startOnLoad="true" transports="http https">
<target>
<inSequence>
<callout
serviceURL="http://localhost:9000/services/SimpleStockQuoteService"
action="urn:getQuote">
<source
xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:s12="http://www.w3.org/2003/05/soap-envelope"
xpath="s11:Body/child::*[fn:position()=1] |
s12:Body/child::*[fn:position()=1]" />
<target
xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:s12="http://www.w3.org/2003/05/soap-envelope"
xpath="s11:Body/child::*[fn:position()=1] |
s12:Body/child::*[fn:position()=1]" />
</callout>
<respond />
</inSequence>
<outSequence>
<respond />
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<callout>
: este mediador especifica un método a invocar en el servicio de back-end. Esta invocación es bloqueante.<source>
: especifica el payload para la invocación del método usando expresiones XPath.<target>
: especifica la ubicación donde se debe encadenar la respuesta.
Mensaje de documento (document message)
Cómo usar la mensajería para transferir datos entre aplicaciones.
Mensaje de evento (event message)
Cómo usar la mensajería para transmitir eventos de una aplicación a otra.
Se utiliza para usar notificaciones de eventos confiables y asíncronas entre aplicaciones.
Petición--respuesta (request-reply)
Cómo una aplicación que envía un mensaje obtiene una respuesta del receptor.
El patrón petición-respuesta facilita la comunicación bidireccional al garantizar que el remitente reciba una respuesta del receptor tras enviar una petición.
Dirección de retorno (return address)
Cómo saber a dónde enviar una respuesta.
Este patrón facilita añadir una dirección de retorno a un mensaje de petición, que indica dónde enviar el mensaje respuesta.
Ejemplo de dirección de retorno en WSO2
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="main">
<in>
<log level="full"/>
<send/>
</in>
<out>
<log level="full"/>
<send/>
</out>
</sequence>
</definitions>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:To>http://localhost:9000/service/SimpleStockQuoteService</wsa:To>
<wsa:ReplyTo>
<wsa:Address>http://10.150.3.53:8200/axis2/services/anonService2/
</wsa:Address>
</wsa:ReplyTo>
<wsa:MessageID>urn:uuid:9aa8e783-2eb7-4649-9d36-a7fb3ad17abd
</wsa:MessageID>
<wsa:Action>urn:getQuote</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol>foo</m0:symbol>
</m0:request>
</m0:getQuote>
</soapenv:Body>
</soapenv:Envelope>
<send>
: el mediador send envía mensajes a la dirección implícita en el campo ReplyTo de forma predeterminada, a menos que se indique explícitamente que la respuesta se debe enviar una dirección especificada mediante un endpoint.
Identificador de correlación (correlation identifier)
Cómo un emisor que ha recibido una respuesta sabe a qué petición se refiere dicha respuesta.
Este patrón facilita un identificador único que indica a qué petición corresponde una respuesta dada.
WSO2 implementa este patrón añadiendo automáticamente un identificador numérico en el mensaje de cada petición. Cuando llega la respuesta, este mensaje se puede identificar unívocamente utilizando este número.
Secuencia de mensajes (message sequence)
Cómo la mensajería puede transmitir una cantidad arbitraria de datos.
Cuando se transmite un gran conjunto de datos, se puede dividir en pequeños trozos para mantener el rendimiento del sistema. El patrón secuencia de mensajes lo facilita enviando los datos como una secuencia de pequeños mensajes, marcando cada uno con campos identificativos de la secuencia.
WSO2 implementa este patrón dividiendo por defecto los mensajes grandes en pequeños trozos, mapeando cada trozo con un número identificador de la secuencia para no perder el orden.
Expiración de mensaje (message expiration)
Cómo un remitente indica cuándo un mensaje debe considerarse obsoleto y, por tanto, no debe procesarse.
Ejemplo de expiración de mensaje en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy xmlns="http://ws.apache.org/ns/synapse" name="MessageExpirationProxy"
transports="https,http" statistics="disable"
trace="disable" startOnLoad="true">
<target>
<inSequence onError="LogAndDropMessageFault">
<log level="full"/>
</inSequence>
<outSequence onError="fault">
<log level="full"/>
<send/>
</outSequence>
<endpoint name="TimeoutEndpoint">
<address uri="http://localhost:9000/services/SimpleStockQuoteService">
<timeout>
<duration>30000</duration>
<responseAction>fault</responseAction>
</timeout>
</address>
</endpoint>
</target>
<description></description>
</proxy>
<sequence name="LogAndDropMessageFault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
</definitions>
Se tienen los siguientes elementos:
<endpoint>
: define el servicio back-end al que se pasan los mensajes.<tiemout>
: define la duración del timeout en milisegundos, y también la acción a tomar (por defecto, o descartar) en el caso de un timeout en la respuesta.
Indicador de formato (format indicator)
Cómo se puede diseñar el formato de datos de un mensaje para permitir posibles cambios futuros.
Enrutado del mensaje
Un enrutador de mensajes es un patrón arquitectónico básico de un sistema de mensajería utilizado fundamentalmente para conectar diferentes canales de mensajería.
Un enrutador consume un mensaje de un canal de mensajes y lo vuelve a publicar en un canal diferente según las condiciones especificadas.
Enrutador basado en el contenido (content-based router)
Cómo manejar una situación cuando la implementación de una única función lógica se extiende a través de múltiples sistemas físicos.
El enrutador lee el contenido del mensaje y lo encamina a un destinatario específico según su contenido.
Ejemplo de enrutador basado en contenido en WSO2
<!-- The example use of content based routing -->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- The service which the sender will be invoking -->
<proxy name="ContentBasedRoutingProxy">
<target>
<!-- When a request arrives the following sequence will be followed -->
<inSequence>
<!-- The content of the incoming message will be isolated -->
<switch source="//m0:getQuote/m0:request/m0:symbol"
xmlns:m0="http://services.samples">
<!-- The isolated content will be filtered -->
<case regex="foo">
<!-- Will Route the content to the appropriate destination -->
<send>
<endpoint>
<address uri="http://localhost:9001/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</case>
<case regex="bar">
<send>
<endpoint>
<address uri="http://localhost:9002/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</case>
<default>
<!-- it is possible to assign the result of an XPath expression as well -->
<property name="symbol"
expression="fn:concat('Normal Stock - ',
//m0:getQuote/m0:request/m0:symbol)"
xmlns:m0="http://services.samples"/>
</default>
</switch>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: este servicio permite abstraer la lógica de enrutado del cliente. Cualquiera que sea la petición, el cliente la envía solo al servicio expuesto.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<switch>
: observa el mensaje y filtra su contenido según la expresión XPath.<case>
: el contenido filtrado coincidirá con la expresión regular especificada.<send>
: cuando se encuentra un caso coincidente, el mediador de envío enrutará el mensaje al punto final especificado en el URI de la dirección.<default>
: si no se encuentra ningún caso coincidente el mensaje se desviará al caso predeterminado.<outSequence >
: la respuesta de un endpoint se recibe a través de outSequence. El mensaje se reenviará de nuevo al remitente.
Filtro de mensajes (message filter)
Cómo un componente evita recibir mensajes que no le interesen.
Ejemplo de filtro de mensajes en WSO2
<!-- The example use of Mesage Filtering -->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="MessageFilterProxy">
<target>
<inSequence>
<filter xmlns:m0="http://services.samples"
source="//m0:getQuote/m0:request/m0:symbol" regex="foo">
<then>
<send>
<endpoint>
<address uri="http://localhost:9000/services/
SimpleStockQuoteService?wsdl"/>
</endpoint>
</send>
</then>
<else>
<drop/>
</else>
</filter>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
<proxy>
: este servicio permite abstraer la lógica de enrutado del cliente. Cualquiera que sea la petición, el cliente la envía solo al servicio expuesto.<inSequence>
: el servicio proxy recibe primero un mensaje y luego lo dirige a esta secuencia.<filter>
: filtra los mensajes entrantes descartando los que no cumplen los criterios.<send>
: cuando se encuentra un caso coincidente, el mediador de envío enrutará el mensaje al punto final especificado en el URI de la dirección.<outSequence >
: la respuesta de un endpoint se recibe a través de outSequence. El mensaje se reenviará de nuevo al remitente.
Enrutador dinámico (dynamic router)
Cómo evitar la dependencia de un router en todos los destinos posibles, manteniendo su eficiencia.
Es un router que se puede autoconfigurar según mensajes especiales de configuración desde los destinos involucrados. Para enviar estos mensajes de configuración desde los destinos se utiliza un canal de control.
Ejemplo de enrutador dinámico en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="ConfigA">
<value>foo</value>
<description/>
</localEntry>
<localEntry key="ConfigC">
<value>WSO2</value>
<description/>
</localEntry>
<localEntry key="ConfigB">
<value>bar</value>
<description/>
</localEntry>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="DynamicRouterProxy" startOnLoad="true"
statistics="disable" trace="disable" transports="http,https">
<target>
<inSequence>
<log level="full"/>
<switch source="get-property('To')">
<case regex="http://localhost:9000.*">
<filter xmlns:m0="http://services.samples"
xpath="get-property('ConfigA') =
//m0:getQuote/m0:request/m0:symbol/text()">
<then>
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</then>
<else>
<log level="custom">
<property name="MESSAGE"
value="Registry Value Doesn't Matched"/>
</log>
</else>
</filter>
</case>
<case regex="http://localhost:9001.*">
<filter xmlns:m0="http://services.samples"
xpath="get-property('ConfigB') =
//m0:getQuote/m0:request/m0:symbol/text()">
<then>
<send>
<endpoint>
<address uri="http://localhost:9001/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</then>
<else>
<log level="custom">
<property name="MESSAGE"
value="Registry Value Doesn't Matched"/>
</log>
</else>
</filter>
</case>
<case regex="http://localhost:9002.*">
<filter xmlns:m0="http://services.samples"
xpath="get-property('ConfigC') =
//m0:getQuote/m0:request/m0:symbol/text()">
<then>
<send>
<endpoint>
<address uri="http://localhost:9002/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</then>
<else>
<log level="custom">
<property name="MESSAGE" value="Registry Value Doesn't Matched"/>
</log>
</else>
</filter>
</case>
</switch>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
<description/>
</proxy>
</definitions>
Lista de destinatarios (recipient list)
Cómo enruta un mensaje a una lista de destinatarios especificados dinámicamente.
Procesa un mensaje entrante e identifica su lista de destinatarios. Una vez se identifica la lista, el mensaje se enviará a todos los canales receptores.
Ejemplo de lista de destinatarios en WSO2
<!-- Would Route the Message Based on the List of Recipients-->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.ESBRegistry">
<parameter name="root">file:repository/samples/resources/</parameter>
<parameter name="cachableDuration">15000</parameter>
</registry>
<proxy name="RecipientListProxy">
<target>
<inSequence>
<switch source="//m0:getQuote/m0:request/m0:symbol"
xmlns:m0="http://services.samples">
<!-- First the recipient list will be identified -->
<case regex="foo">
<send>
<!--Dynamic Recipient List-->
<endpoint>
<recipientlist>
<endpoint xmlns="http://ws.apache.org/ns/synapse">
<address uri="http://localhost:9000/services/
SimpleStockQuoteService"/>
</endpoint>
<endpoint xmlns="http://ws.apache.org/ns/synapse">
<address uri="http://localhost:9001/services/
SimpleStockQuoteService"/>
</endpoint>
</recipientlist>
</endpoint>
</send>
<drop/>
</case>
<case regex="WSO2">
<send>
<!--Dynamic Recipient List-->
<endpoint>
<recipientlist>
<endpoint xmlns="http://ws.apache.org/ns/synapse">
<address uri="http://localhost:9002/services/
SimpleStockQuoteService"/>
</endpoint>
<endpoint xmlns="http://ws.apache.org/ns/synapse">
<address uri="http://localhost:9003/services/
SimpleStockQuoteService"/>
</endpoint>
</recipientlist>
</endpoint>
</send>
<drop/>
</case>
<default>
<!-- Message Should Be Discarded -->
</default>
</switch>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
</definitions>
Separador (splitter)
Cómo procesar un mensaje con múltiples elementos, si cada uno de ellos habría que procesarlo de diferente forma.
El splitter divide el mensaje compuesto en una serie de mensajes individuales, conteniendo cada uno datos relacionados con un elemento.
Agregador (aggregator)
Cómo combinar mensajes individuales pero relacionados de forma que se puedan procesar como un todo.
Funciona como un filtro con estado, recolectando y almacenando mensajes individuales hasta que se haya recibido un conjunto completo de mensajes relacionados. Luego publica un solo mensaje extraído de los mensajes individuales.
Procesador de mensajes compuestos (composed message processor)
Cómo mantener el flujo general al procesar un mensaje que consta de múltiples elementos, cada uno de los cuales puede requerir un procesamiento diferente.
El procesador de mensajes compuestos divide el mensaje, enruta los sub-mensajes a los destinos apropiados y luego agrupa de nuevo las respuestas en un único mensaje.
Esparcir-recoger (scatter--gather)
Cómo mantener el flujo general cuando se necesita enviar un mensaje a varios destinatarios, cada uno de los cuales puede enviar una respuesta.
Ejemplo de esparcir-recoger en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy xmlns="http://ws.apache.org/ns/synapse" name="ScatterGatherProxy"
transports="https http" startOnLoad="true" trace="disable">
<description/>
<target>
<inSequence>
<clone>
<target>
<endpoint name="vendorA">
<address uri="http://localhost:9000/services/
SimpleStockQuoteService/"/>
</endpoint>
</target>
<target>
<endpoint name="vendorB">
<address uri="http://localhost:9001/services/
SimpleStockQuoteService/"/>
</endpoint>
</target>
<target>
<endpoint name="vendorC">
<address uri="http://localhost:9002/services/
SimpleStockQuoteService/"/>
</endpoint>
</target>
</clone>
</inSequence>
<outSequence>
<log level="full"/>
<aggregate>
<completeCondition>
<messageCount min="3"/>
</completeCondition>
<onComplete xmlns:m1="http://services.samples/xsd"
xmlns:m0="http://services.samples" expression="//m0:return">
<enrich>
<source xmlns:m1="http://services.samples/xsd" clone="true"
xpath="//m0:return[not(preceding-sibling::m0:return/m1:last
<= m1:last) and not(following-sibling::m0:return/m1:
last < m1:last)]"/>
<target type="body"/>
</enrich>
<send/>
</onComplete>
</aggregate>
</outSequence>
</target>
</proxy>
</definitions>
Se tienen los siguientes elementos:
-
<clone>
: el mediador clone hace tres copias de la petición, este mediador es similar al patrón splitter. Clona la petición entrante y pasa las peticiones en paralelo a varios endpoints. -
<log>
: todas las respuestas recibidas se registran antes de que el mediador aggregate las fusione. -
<aggregate>
: el mediador aggregate añade mensajas de respuesta a las solicitudes realizadas por los mediadores iterate o clone. La condición de finalización especifica el número mínimo o máximo de mensajes que se recopilarán. -
<onComplete>
: cuando se añaden todos los mensajes se ejecuta la secuencia onComplete del mediador aggregate. Esta secuencia se llama una vez que se reciben todas las respuestas o se cumple la condición de finalización especificada. Las respuestas se agregan en función del valor del elemento de retorno en la respuesta. -
<enrich>
: el mediador enrich se usa para extraer la mejor respuesta, para ello se usa la siguiente expresión XPath ://m0:return[not(preceding-sibling::m0:return/m1:last <= m1:last) and not(following-sibling::m0:return/m1:last < m1:last)]
que le dice al ESB que escoja la respuesta que tenga el último valor más bajo.
Hoja de enrutamiento (routing slip)
Cómo enrutar un mensaje a través de una serie de pasos consecutivos cuando la secuencia de los pasos no se conoce en el momento del diseño y puede variar para cada mensaje.
Ejemplo de hoja de enrutamiento en WSO2
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="RoutingSlipProxy" transports="http https"
startOnLoad="true">
<target>
<inSequence>
<!-- Will Attach The Routing Slip -->
<header xmlns:m1="http://services.samples"
name="m1:RoutingSlip" value="Process_A" />
<header xmlns:m1="http://services.samples"
name="m1:RoutingSlip" value="Process_C" />
<log level="full" />
<!-- Will Perform All The Steps Based on The Slip -->
<iterate xmlns:m0="http://services.samples"
preservePayload="true"
expression="//m0:RoutingSlip" sequential="true">
<target>
<sequence>
<switch xmlns:m2="http://services.samples"
source="//m2:RoutingSlip">
<case regex="Process_A">
<sequence key="process_a" />
</case>
<case regex="Process_B">
<sequence key="process_b" />
</case>
<case regex="Process_C">
<sequence key="process_c" />
</case>
<default>
<drop />
</default>
</switch>
</sequence>
</target>
</iterate>
</inSequence>
<outSequence>
<send />
</outSequence>
</target>
</proxy>
<sequence name="send_seq">
<send>
<endpoint name="simple">
<address uri="http://localhost:9000/services/
SimpleStockQuoteService" />
</endpoint>
</send>
</sequence>
<sequence name="process_c">
<log level="custom">
<property name="Process" value="C" />
</log>
<sequence key="send_seq" />
</sequence>
<sequence name="process_b">
<log level="custom">
<property name="Process" value="B" />
</log>
</sequence>
<sequence name="process_a">
<log level="custom">
<property name="Process" value="A" />
</log>
</sequence>
</definitions>
</definitions>
-
header
: el mediador Header añade un par clave/valor a la cabecera SOAP. En el ejemplo, añade un campo a la cabecera llamado RoutingSlip con el valorProcess_A
. Después añade otro campo RoutingSlip con el valorProcess_C
. -
iterate
: El mediador Iterate se usa para iterar sobre todos los nodos RoutingSlip en la cabecera.
Gestor de procesos (process manager)
Cómo enrutar un mensaje a través de múltiples pasos de procesamiento, cuando los pasos requeridos quizá no se conozcan en el momento del diseño y pueden no ser secuenciales.
Agente de mensajes (message broker)
Cómo desacoplar el destino de un mensaje del remitente y mantener el control central sobre el flujo de mensajes.
El agente de mensajes recibe mensajes desde múltiples remitentes, determina el destino correcto y enruta el mensaje al canal apropiado.
Resecuenciador (resequencer)
Cómo reordenar una secuencia de mensajes relacionados pero desordenados.
Transformación del mensaje
Los formatos de datos y sus mecanismos de almacenamiento varían entre diferentes sistemas. Un traductor de mensajes es un patrón arquitectónico que actúa como un filtro entre otros filtros o aplicaciones, transformando el mensaje adecuadamente según pasa a través del ESB.
Ensobrado (envelope wrapper)
Cómo los sistemas existentes participan en un intercambio de mensajes, que coloca requisitos específicos en el formato del mensaje, como campos de encabezado de mensaje o encriptación.
Mete los datos de la aplicación dentro de un «sobre» que cumple con la infraestructura de mensajería. El mensaje se saca del sobre cuando llega a su destino.
Ejemplo de ensobrado en WSO2
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="EnvelopeUnwrapProxy"
transports="https http" startOnLoad="true">
<target>
<endpoint>
<address uri="http://localhost:9000/services/
SimpleStockQuoteService" format="pox" />
</endpoint>
<outSequence>
<send />
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/
proxy/sample_proxy_1.wsdl" />
</proxy>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence" />
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')" />
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')" />
</log>
<drop />
</sequence>
<sequence name="main">
<send />
</sequence>
</definitions>
address
: la dirección del endpoint contiene el atributoformat='pox'
, que hace que el ESB convierta las peticiones entrantes a Plain Old XML. Otros formatos soportados como «sobre» son soap11, soap12, etc.
Enriquecedor de contenido (content enricher)
Cómo comunicarse con otro sistema si el creador del mensaje no tiene todos los datos necesarios disponibles.
Accede a una fuente de datos externa para añadir información perdida al mensaje.
Ejemplo de enriquecedor de contenido para WSO2
<!-- Content Enricher -->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="ContentEnrichProxy">
<target>
<inSequence>
<!-- Would Enrich the Value Based On the Number -->
<switch source="//m1:symbol"
xmlns:m0="http://services.samples"
xmlns:m1="http://services.samples/xsd">
<case regex="1">
<log level="full" />
<enrich>
<source type="inline" key="Location1" />
<target xmlns:m1="http://services.samples/xsd"
xpath="//m1:symbol/text()" />
</enrich>
</case>
<case regex="2">
<enrich>
<source type="inline" key="Location2" />
<target xmlns:m1="http://services.samples/xsd"
xpath="//m1:symbol/text()" />
</enrich>
</case>
</switch>
<!-- Will Send the Enriched Message -->
<send>
<endpoint>
<address uri="http://localhost:9000/services/
SimpleStockQuoteService" />
</endpoint>
</send>
<!-- <drop /> -->
</inSequence>
<outSequence>
<send />
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/
proxy/sample_proxy_1.wsdl" />
</proxy>
<localEntry key="Location1">
IBM
</localEntry>
<localEntry key="Location2">
WSO2
</localEntry>
</definitions>
Filtro de contenido (content filter)
Cómo simplificar la gestión de un mensaje grande cuando solo interesen algunos datos.
Elimina elementos sin importancia del mensaje y solo deja los importantes. Además de utilizarse para eliminar elementos no necesarios se usa para simplificar la estructura del mensaje.
<!-- Content Filter -->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.ESBRegistry">
<parameter name="root">
file:./repository/samples/resources/
</parameter>
<parameter name="cachableDuration">
15000
</parameter>
</registry>
<!-- define the request processing XSLT resource as a static URL source -->
<localEntry key="filter_data"
src="file:repository/samples/resources/transform/
split_message.xslt" />
<proxy name="ContentFilterProxy">
<target>
<inSequence>
<xslt key="filter_data" />
<log level="full" />
<send>
<endpoint>
<address uri="http://localhost:9000/services/
SimpleStockQuoteService" />
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full" />
<send />
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/
proxy/sample_proxy_1.wsdl" />
</proxy>
</definitions>
con <ESB_HOME>/repository/samples/resources/transform/split_message.xslt
:
<?xml version="1.0" encoding="ISO-8859-1"?>
<stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:m0="http://services.samples"
exclude-result-prefixes="m0 fn">
<output method="xml" omit-xml-declaration="yes" indent="yes" />
<template match="/">
<getQuote xmlns:m="http://services.samples">
<request>
<symbol>
<value-of select="//m0:getQuote/m0:request[1]" />
</symbol>
</request>
</getQuote>
</template>
</stylesheet>
localEntry
: entrada del registro local.xslt
: el mediador XSLT aplica una transformación XSLT al elemento especificado en el atributosource
, como en este caso no se ha especificado la transformación se aplica al primer elemento del mensaje.
Verificación de reclamo (claim check)
Cómo reducir el volumen de datos enviados sin sacrificar el contenido de la información.
Almacena el mensaje completo en la etapa inicial de una secuencia de procesamiento de mensajes, y solo extrae las partes requeridas por los siguientes pasos. Cuando se completa el procesamiento recupera el mensaje almacenado y realiza las operaciones apropiadas. Este patrón garantiza un mejor rendimiento.
Normalizador (normalizer)
Cómo gestionar mensajes semánticamente equivalentes pero que llegan en formatos distintos.
Enruta cada mensaje hacia el traductor de mensajes apropiado de forma que los mensajes resultantes tengan un formato común.
Ejemplo de normalizador en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- The proxy service to receive all kinds of messages -->
<proxy name="ServiceProxy" transports="https http"
startOnLoad="true" trace="disable">
<description />
<target>
<inSequence>
<log level="full" />
<!-- Filters incoming JSON messages -->
<filter xmlns:m0="http://services.samples"
xpath="//m0:getQuote/m0:request/m0:symbol">
<then>
<sequence key="sendSeq" />
</then>
<else>
<sequence key="jsonInTransformSeq" />
</else>
</filter>
</inSequence>
<outSequence>
<!-- Filters outgoing JSON messages -->
<filter source="get-property('TRANSFORMATION')"
regex="JSONtoSOAP">
<then>
<property name="messageType"
value="application/json" scope="axis2"
type="STRING" />
</then>
</filter>
<log level="full" />
<send />
</outSequence>
</target>
</proxy>
<localEntry key="in_transform">
<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/02/xpath-functions"
xmlns:m0="http://services.samples" version="2.0"
exclude-result-prefixes="m0 fn">
<output method="xml" omit-xml-declaration="yes" indent="yes" />
<template match="*">
<element name="{local-name()}"
namespace="http://services.samples">
<copy-of select="attribute::*" />
<apply-templates />
</element>
</template>
</stylesheet>
</localEntry>
<!-- Transform a JSON message -->
<sequence name="jsonInTransformSeq">
<xslt key="in_transform" />
<property name="TRANSFORMATION"
value="JSONtoSOAP" scope="default" type="STRING" />
<enrich>
<source clone="true"
xmlns:m0="http://services.samples"
xmlns:ns="http://org.apache.synapse/xsd"
xpath="//m0:getQuote" />
<target type="body" />
</enrich>
<header name="Action" scope="default" value="urn:getQuote" />
<sequence key="sendSeq" />
</sequence>
<!-- Normal flow of messages -->
<sequence name="sendSeq">
<send>
<endpoint>
<address uri="http://localhost:9000/services/
SimpleStockQuoteService" format="soap11" />
</endpoint>
</send>
</sequence>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence" />
<property xmlns:ns="http://org.apache.synapse/xsd"
name="ERROR_CODE"
expression="get-property('ERROR_CODE')" />
<property xmlns:ns="http://org.apache.synapse/xsd"
name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')" />
</log>
<drop />
</sequence>
<sequence name="main">
<log />
<drop />
</sequence>
</definitions>
filter
: busca una expresión XPATH en el mensaje entrante. Si la expresión se cumple entiende que es un mensaje SOPA o POX y el mediador continúa hacia la secuencia sendSeq. Si no se cumple la expresión entiende que es un mensaje JSON y el mediador continúa vía la secuencia jsonInTransformSeq.localEntry
: contiene una transformación XSL que convierte peticiones JSON a XML.xslt
: aplica la XSLT definida al payload.address
: define el servicio de back-end y el formato de mensaje que éste prefiere.
Modelo de datos canónicos (canonical data model)
Cómo minimizar dependencias cuando se integran aplicaciones que usan diferentes formatos de datos.
Puntos finales de mensajería
Los puntos finales (endpoints) se utilizan para conectar una aplicación a un canal de mensajería.
Pasarela de mensajería (messaging gateway)
Cómo encapsular el acceso al sistema de mensajería del resto de la aplicación.
Es una clase que proporciona llamadas a métodos específicos de mensajería y expone métodos específicos de dominio a la aplicación. Solo la pasarela de mensajería conoce la implementación real del sistema de mensajería, el resto de la aplicación llama a los métodos de la pasarela.
Ejemplo de pasarela de mensajería en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="StockQuoteProxy" startOnLoad="true">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<send/>
</outSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/proxy/sample_proxy_3.wsdl"/>
</proxy>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<log/>
<drop/>
</sequence>
</definitions>
endpoint
: define el endpoint del verdadero servicio de back-end con el que se conecta este servicio proxy.publishWSDL
: define el fichero WSDL que va a exponer este servicio proxy. Si no se da ningúnpublishWSDL
se expondrá el verdadero WSDL del servicio de back-end.
Mapeador de mensajería (messaging mapper)
Cómo mover datos entre objetos de dominio y la infraestructura de mensajería, mientras ambos se mantienen independientes entre sí.
Cliente transaccional (transactional client)
Cómo un cliente controla sus transacciones con el sistema de mensajería.
Hace la sesión del cliente del cliente con el sistema de mensajería transaccional de forma que el cliente pueda definir los límites de la transacción.
Ejemplo de cliente transaccional con WSO2
En muchos casos puede haber pérdida de datos debido a caídas del sistema y otros errores. En este ejemplo se muestra cómo los mensajes que tengan MESSAGE_COUNT=1
se supone que están provocando un error en la mediación, y cómo las transacciones garantizan que no se pierden los datos. Esta transacción se implementa mediante JMS.
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="StockQuoteProxy" startOnLoad="true" trace="disable">
<target>
<inSequence>
<!-- Setting MESSAGE_COUNT value -->
<class name="org.wso2.esb.client.MessageCounterMediator"/>
<log level="full">
<property name="MESSAGE*ID"
expression="get-property('MESSAGE_COUNT')"/>
</log>
<switch source="get-property('MESSAGE_COUNT')">
<case regex="1">
<!-- Undesired MESSAGE_COUNT value -->
<property name="SET_ROLLBACK_ONLY" value="true" scope="axis2"/>
<log level="custom">
<property name="Transaction Action" value="Rollbacked"/>
</log>
</case>
<default>
<log level="custom">
<property name="Transaction Action" value="Committed"/>
</log>
<send>
<endpoint name="proxy_endpoint">
<address uri="http://localhost:9000/services/
SimpleStockQuoteService"/>
</endpoint>
</send>
</default>
</switch>
<property name="OUT_ONLY" value="true"/>
</inSequence>
</target>
<publishWSDL uri="file:repository/samples/resources/proxy/
sample_proxy_1.wsdl"/>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/xml</default>
</rules>
</parameter>
</proxy>
<sequence name="main">
<log/>
<drop/>
</sequence>
</definitions>
Consumidor por encuesta (polling consumer)
Cómo una aplicación consume un mensaje cuando está lista.
Ejemplo de polling consumer en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="StockQuoteProxy" transports="jms">
<target>
<inSequence>
<property action="set" name="OUT_ONLY" value="true"/>
</inSequence>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<send/>
</outSequence>
</target>
<publishWSDL
uri="file:repository/samples/resources/proxy/sample_proxy_1.wsdl"/>
<parameter name="transport.jms.ContentType">
<rules>
<jmsProperty>contentType</jmsProperty>
<default>application/xml</default>
</rules>
</parameter>
</proxy>
</definitions>
Consumidor dirigido por eventos (event-driven consumer)
Cómo una aplicación consume mensajes automáticamente según están disponibles.
Este patrón también se conoce como receptor asíncrono.
Ejemplo de consumidor dirigido por eventos en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<log/>
<event topic="EventConsumerTopic"/>
</sequence>
</definitions>
event
: permite definir un conjunto de suscriptores para recibir mensajes, cuando se suscriban al topic.
Consumidores competidores (competing consumers)
Cómo un cliente de mensajería procesa múltiples mensajes simultáneamente.
En este patrón varios consumidores compiten entre sí para recibir una solicitud desde un canal punto a punto dado. Las solicitudes se manejan usando un algoritmo Round-Robin.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<send>
<endpoint>
<loadbalance
algorithm="org.apache.synapse.endpoints.algorithms.RoundRobin">
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService/"/>
</endpoint>
<endpoint>
<address
uri="http://localhost:9001/services/SimpleStockQuoteService/"/>
</endpoint>
<endpoint>
<address
uri="http://localhost:9002/services/SimpleStockQuoteService/"/>
</endpoint>
</loadbalance>
</endpoint>
</send>
</in>
<out>
<send/>
</out>
</sequence>
</definitions>
Despachador de mensajes (message dispatcher)
Cómo múltiples consumidores en un único canal coordinan su procesamiento de mensajes.
Consume mensajes de un solo canal los distribuye. Permite que múltiples consumidores en un solo canal coordinen el procesamiento de sus mensajes.
Ejemplo de despachador de mensajes en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<send>
<endpoint>
<loadbalance
algorithm="org.apache.synapse.endpoints.algorithms.WeightedRoundRobin">
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService/"/>
<property name="loadbalance.weight" value="1"/>
</endpoint>
<endpoint>
<address
uri="http://localhost:9001/services/SimpleStockQuoteService/"/>
<property name="loadbalance.weight" value="2"/>
</endpoint>
<endpoint>
<address
uri="http://localhost:9002/services/SimpleStockQuoteService/"/>
<property name="loadbalance.weight" value="3"/>
</endpoint>
</loadbalance>
</endpoint>
</send>
</in>
<out>
<send/>
</out>
</sequence>
</definitions>
Consumidor selectivo (selective consumer)
Cómo un consumidor de mensajes elige qué mensajes recibir.
Ejemplo de consumidor selectivo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="selective_criteria">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.apache-synapse.org/test"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
targetNamespace="http://services.samples">
<xs:element name="getQuote">
<xs:complexType>
<xs:sequence>
<xs:element name="request">
<xs:complexType>
<xs:sequence>
<xs:element name="stockvalue" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</localEntry>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<validate>
<schema key="selective_criteria"/>
<on-fail>
<makefault>
<code xmlns:tns="http://www.w3.org/2003/05/soap-envelope"
value="tns:Receiver"/>
<reason value="Invalid custom quote request"/>
</makefault>
<property name="RESPONSE" value="true"/>
<header name="To" expression="get-property('ReplyTo')"/>
<drop/>
</on-fail>
</validate>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService?wsdl"/>
</endpoint>
</send>
</in>
<out>
<send/>
</out>
</sequence>
</definitions>
Suscriptor duradero (durable subscriber)
Cómo un suscriptor evita los mensajes perdidos mientras no los está escuchando.
Ejemplo de suscriptor duradero en WSO2
<!-- Durable Subscriber Proxy-->
<definitions xmlns="http://ws.apache.org/ns/synapse">
<taskManager provider="org.wso2.carbon.mediation.ntask.NTaskTaskManager"/>
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PublishProxy"
transports="http"
statistics="disable"
trace="disable"
startOnLoad="true">
<target>
<inSequence>
<property name="FORCE_SC_ACCEPTED"
value="true"
scope="axis2"
type="STRING"/>
<clone>
<target sequence="DurableSubscriber"/>
<target sequence="NonDurableSubscriber"/>
</clone>
</inSequence>
<outSequence>
<drop/>
</outSequence>
</target>
<description/>
</proxy>
<!-- Error Sequences -->
<sequence name = "sub1_fails" >
<store messageStore="pending_subscriptions" />
</sequence>
<sequence name = "sub2_fails" >
<drop/>
</sequence>
<!-- Subscription List-->
<sequence name="DurableSubscriber" onError="sub1_fails"
xmlns="http://ws.apache.org/ns/synapse">
<in>
<property name="OUT_ONLY" value="true"/>
<send>
<endpoint name="Subscriber 1">
<address
uri="http://localhost:9000/services/SimpleStockQuoteService/"/>
</endpoint>
</send>
</in>
</sequence>
<sequence name="NonDurableSubscriber" onError="sub2_fails"
xmlns="http://ws.apache.org/ns/synapse">
<in>
<property name="OUT_ONLY" value="true"/>
<send>
<endpoint name="Subscriber 2">
<address
uri="http://localhost:9001/services/SimpleStockQuoteService/"/>
</endpoint>
</send>
</in>
</sequence>
<!-- Re Direction End Points -->
<endpoint name="DurableSubscriberEndpoint">
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<!-- Message Store And Process -->
<messageStore name="pending_subscriptions"/>
<messageProcessor class="org.apache.synapse.message.processor.impl.
forwarder.ScheduledMessageForwardingProcessor"
name="send_pending_message"
messageStore="pending_subscriptions">
<parameter name="interval">1000</parameter>
<parameter name="max.delivery.attempts">50</parameter>
<parameter name="target.endpoint">DurableSubscriberEndpoint</parameter>
</messageProcessor>
</definitions>
Receptor idempotente (idempotent receiver)
Cómo un receptor de mensajes maneja mensajes duplicados.
Activador de servicio (service activator)
Cómo una aplicación diseña un servicio para ser invocado a través de técnicas de mensajería y no mensajería.
Ejemplo de activador de servicio en WSO2
Gracias a la propiedad publishWDSL
se modifica el archivo WSDL para filtrar ciertos servicios específicos.
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="ServiceActivatorProxy" startOnLoad="true">
<target>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
<outSequence>
<send/>
</outSequence>
</target>
<publishWSDL
uri="file:repository/samples/resources/proxy/sample_proxy_1.wsdl"/>
</proxy>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in/>
<out>
<send/>
</out>
</sequence>
</definitions>
Administración del sistema
Los patrones de administración del sistema tienen como objetivo monitorizar la cantidad de mensajes enviados y sus tiempos de procesamiento sin analizar los datos del mensaje, a excepción de algunos campos en el encabezado del mensaje.
Purgador de canal (channel purger)
Elimina los mensajes no deseados de un canal.
También es útil cuando se necesita resetear un sistema de mensajería a un estado consistente.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<store messageStore="PurgedData"/>
</sequence>
<messageStore name="PurgedData"/>
</definitions>
Bus de control (control bus)
Administra un sistema de mensajería distribuido a través de múltiples plataformas y un área geográfica amplia.
Utiliza el mismo mecanismo de mensajería utilizado por los datos de la aplicación, pero se utilizan canales separados para transmitir datos que son relevantes para la gestión de los componentes involucrados en el flujo de mensajes.
Ejemplo de bus de control con WSO2
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<throttle id="A">
<policy>
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:throttle="http://www.wso2.org/products/wso2commons/throttle">
<throttle:ThrottleAssertion>
<throttle:MaximumConcurrentAccess>4</throttle:MaximumConcurrentAccess>
</throttle:ThrottleAssertion>
</wsp:Policy>
</policy>
<onReject>
<log level="custom">
<property name="text" value="Access Denied By Message System"/>
</log>
<makefault>
<code xmlns:tns="http://www.w3.org/2003/05/soap-envelope"
value="tns:Receiver"/>
<reason value="Access Denied By Messaging System"/>
</makefault>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send/>
<drop/>
</onReject>
<onAccept>
<log level="custom">
<property name="text"
value="Access Granted By Message System"/>
</log>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</onAccept>
</throttle>
</in>
<out>
<throttle id="A"/>
<send/>
</out>
</sequence>
</definitions>
throttel
: define una política de estrangulamiento (throttling) en WS-Policy.WS-Policy Assertion
: la aserciónthrottle:MaximumConcurrentAccess
define el número de conexiones concurrentes que se pueden hacer.onReject
: el elementoonReject
del mediador de estrangulamiento define qué hacer si se rechaza la política.onAccept
: ídem si es aceptada (en este ejemplo si no se superan las 4 conexiones concurrentes).
Desvío (detour)
Enruta un mensaje a través de pasos intermedios para realizar funciones de validación, prueba o depuración.
Tiene dos estados: en un estado, encamina los mensajes entrantes a través de pasos adicionales; en el otro, encamina directamente los mensajes al canal de destino.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="validate_schema">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://services.samples"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
targetNamespace="http://services.samples">
<xs:element name="getQuote">
<xs:complexType>
<xs:sequence>
<xs:element name="request">
<xs:complexType>
<xs:sequence>
<xs:element name="stocksymbol" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</localEntry>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<filter source="get-property('To')" regex=".*StockQuote.*">
<validate>
<schema key="validate_schema"/>
<on-fail>
<makefault>
<code xmlns:tns="http://www.w3.org/2003/05/soap-envelope"
value="tns:Receiver"/>
<reason value="Invalid custom quote request"/>
</makefault>
</on-fail>
</validate>
</filter>
<send/>
</in>
<send/>
</sequence>
</definitions>
Histórico del mensaje (message history)
Enumera todas las aplicaciones por las que pasó el mensaje desde su origen.
Ayuda a analizar y depurar el flujo de mensajes.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="sendSeq">
<property name="sendSeq"
value="*** At Sending Sequence ***"
scope="default"
type="STRING"/>
<log level="custom">
<property name="mainSeq" expression="get-property('mainSeq')"/>
<property name="seq1" expression="get-property('seq1')"/>
<property name="sendSeq" expression="get-property('seq1')"/>
</log>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</sequence>
<sequence name="seq1">
<property name="seq1"
value="*** At Sequence 1 ***"
scope="default"
type="STRING"/>
<sequence key="sendSeq"/>
</sequence>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<filter xmlns:ns="http://org.apache.synapse/xsd"
source="get-property('To')"
regex="http://localhost:9000.*">
<then>
<property name="mainSeq" value="** At Main Sequence**"/>
<sequence key="seq1"/>
</then>
<else/>
</filter>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
</definitions>
Almacenamiento del mensaje (message store)
Detalla la información del mensaje sin perturbar la naturaleza débilmente acoplada y transitoria de un sistema de mensajería.
Almacena un duplicado del mensaje entre cada flujo y captura la información del mensaje en una ubicación central.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="Location">foo</localEntry>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default "fault" sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<enrich>
<source type="inline" clone="true" key="Location"/>
<target xmlns:m1="http://services.samples/xsd" xpath="//m1:symbol/text()"/>
</enrich>
<store messageStore="CentralStorage"/>
<send>
<endpoint>
<address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</in>
<out>
<store messageStore="CentralStorage"/>
<send/>
</out>
</sequence>
<messageStore name="CentralStorage"/>
</definitions>
Proxy inteligente (smart proxy)
Rastrea mensajes en un servicio que publica mensajes de respuesta a la Dirección de retorno especificada por el solicitante.
Almacena la dirección de devolución proporcionada por el solicitante original y la reemplaza con la dirección del proxy inteligente. Cuando el servicio envía el mensaje de respuesta lo redirige a la dirección de devolución original.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<proxy name="SmartProxy" transports="http https" startOnLoad="true">
<target>
<inSequence>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in/>
<out/>
</sequence>
</definitions>
Mensaje de prueba (test message)
Asegura la salud de los componentes de procesamiento de mensajes al evitar situaciones como desviar mensajes salientes debido a un fallo interna.
Ejemplo de mensaje de prueba con WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<!-- Proxy for normal message flow -->
<taskManager provider="org.wso2.carbon.mediation.ntask.NTaskTaskManager"/>
<proxy name="ServiceProxy" transports="https http"
startOnLoad="true" trace="disable">
<target inSequence="sendSeq"/>
</proxy>
<!-- Normal flow of the messages -->
<sequence name="sendSeq">
<send receive="receiveSeq">
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</sequence>
<!-- Fault sequence handles failures -->
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default 'fault' sequence"/>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property xmlns:ns="http://org.apache.synapse/xsd"
name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<!-- Filter the failed Test Messages -->
<filter xmlns:ns="http://org.apache.synapse/xsd"
xmlns:m0="http://services.samples"
source="//m0:getQuote/m0:request/m0:symbol"
regex="TEST">
<then>
<log>
<property name="FAILURE"
value="*** Test Message Failed ***"/>
<property name="FAILED SERVICE"
value="*** localhost:9000/services/SimpleStockQuoteService ***"/>
</log>
</then>
<else/>
</filter>
<drop/>
</sequence>
<!-- Receiving messages from service -->
<sequence name="receiveSeq">
<log/>
<!-- Filter the Test Messages -->
<filter xmlns:ax21="http://services.samples/xsd"
xmlns:ns="http://org.apache.synapse/xsd"
source="//ax21:symbol"
regex="TEST">
<then>
<log>
<property name="TEST PASSED"
value="*** Test Message Passed ***"/>
<property name="TESTED SERVICE"
value="*** localhost:9000/services/SimpleStockQuoteService ***"/>
</log>
<drop/>
</then>
<else>
<send/>
</else>
</filter>
</sequence>
<!-- main sequence used as the test Message injector -->
<sequence name="main">
<in>
<sequence key="sendSeq"/>
</in>
<out>
<send/>
</out>
</sequence>
<!-- Task Scheduler act as Test data generator -->
<task name="Testing"
class="org.apache.synapse.startup.tasks.MessageInjector"
group="synapse.simple.quartz">
<!-- Interval between generating test messages,
Cron Expression are also allowed to use -->
<trigger interval="25"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="message">
<m0:getQuote xmlns:m0="http://services.samples">
<m0:request>
<m0:symbol>TEST</m0:symbol>
</m0:request>
</m0:getQuote>
</property>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="soapAction"
value="urn:getQuote"/>
<property xmlns:task="http://www.wso2.org/products/wso2commons/tasks"
name="to"
value="http://localhost:9000/services/SimpleStockQuoteService"/>
</task>
</definitions>
Wire tap
Inspecciona los mensajes que viajan en un canal punto a punto.
Ejemplo en WSO2
<definitions xmlns="http://ws.apache.org/ns/synapse">
<sequence name="fault">
<log level="full">
<property name="MESSAGE"
value="Executing default "fault" sequence"/>
<property name="ERROR_CODE"
expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE"
expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="main">
<in>
<log level="full"/>
<send>
<endpoint>
<address
uri="http://localhost:9000/services/SimpleStockQuoteService"/>
</endpoint>
</send>
</in>
<out>
<log level="full"/>
<send/>
</out>
</sequence>
</definitions>
WSO2 Integration Studio
Integration Studio es la herramienta de desarrollo de WSO2. Está basada en Eclipse.
Nota: En la versión 6.1 esta herramienta se llamaba WSO2 Enterprise Integrator Tooling. En otras versiones también se conoce como Developer Studio.
Proyectos carbon
Cuando se desarrolla una aplicación WSO2 se pueden crear distintos tipos de proyecto según la funcionalidad requerida. Todos estos proyectos se llaman proyectos carbon (.CAR
).
Tipos de proyecto
- ESB. Contiene todos los artefactos relacionados con la funcionalidad desarrollada en el ESB.
- Registry Resource. Se utiliza para añadir recursos como transformaciones XLS, ficheros WSDL y XSD al registro EI. Algunos artefactos que se usan para desarrollar nuestra aplicación requieren ficheros complementarios que se deben almacenar en el registro.
- Data Service. Para añadir los servicios de datos necesarios en nuestra aplicación.
- Composite Application. Genera el artefacto desplegable de nuestra aplicación. Detecta los artefactos existentes en todos los proyectos del workspace y nos permite elegir los que se empaquetarán en una aplicación que se desplegará en WSO2EI. - ESB Solution. No es un verdadero proyecto; se puede considerar como un asistente que permite crear los proyectos más comunes.
Todos estos proyectos utilizan tecnología Maven, por lo que tendrán su correspondiente pom.xml
.
Proyectos ESB
Este tipo de proyecto está centrado en servicios web y artefactos REST. Dentro de este proyecto crearemos todos los artefactos necesarios para desarrollar los servicios web o REST de nuestra aplicación.
Una vez creado un nuevo proyecto ESB se puede ver en el Project Explorer de Eclipse:
Ahora podemos añadir los artefactos necesarios para componer nuestra aplicación al proyecto. Los artefactos más comunes son:
- Servicios Proxy. Este artefacto se utiliza para crear cualquier tipo de servicio diferente de servicios REST. Por ejemplo, servicios web SOAP, servicios VFS, servicios JMS, etc.
- API REST. Con este artefacto se construyen servicios REST.
- Secuencias. Permiten estructura el flujo del servicio en pequeñas piezas que permiten que el código sea más entendible, reutilizable y fácil de leer.
- Endpoints. Con estos artefactos se define el destino al que podemos enviar mensajes.
Todos estos artefactos trabajan conjuntamente para abarcar todo nuestro servicio como se en la siguiente figura:
La flecha punteada muestra el camino seguido por un mensaje entrante hasta que llega al backend final, en este caso App 1. La flecha continua indica el camino de la respuesta.
En la figura se ven los siguientes pasos:
- El consumidor envía un mensaje al servicio que se puede implementar usando un Proxy (SOAP) o una API REST. En este elemento se especifica el interfaz con parámetros como el WSDL o el protocolo.
- Desde el Proxy / API REST se envía el mensaje a una secuencia donde se implementa la funcionalidad del servicio. La lógica del servicio se puede abstraer en varias secuencias que se pueden encadenar de la forma que se quiera. El flujo entrante termina enviando el mensaje a través de un ednpoint al backend, en este caso App 1. Se puede especificar una secuencia que procese la respuesta del endpoint, en caso contrario se utilizará la secuencia por defecto.
- El backend recibe el mensaje, lo procesa y envía la respuesta de vuelta a la secuencia de salida si se utiliza el el mediador de envío (send mediator), o al siguiente mediador en la secuencia si se utiliza el mediador de llamadas (call mediator). El endpoint enviará el mensaje a una secuencia para que se procese o se envíe de vuelta al proxy.
- El flujo de salida termina con el proxy contestando al consumidor con la respuesta.
Además, es necesario definir una secuencia que se ejecutará cuando ocurra algún error durante el proceso; esta secuencia se llama Fault Sequence. Lo habitual es que esta secuencia genere un mensaje de error y lo envíe al consumidor. Este flujo se muestra en la figura con una línea discontinua.
Este flujo refleja un escenario _síncrono_donde el consumidor espera una respuesta. Es el escenario más común, pero hay otros:
- Asíncrono. El consumidor no permanece en espera de la respuesta; la respuesta se puede recibir más tarde.
- Dispara y olvida (fire and forget). El consumidor no necesita una respuesta.
Proxy
El proxy se crea cuando necesitamos un servicio basado en un servicio web SOAP.
El proxy se crea desde:
Nos va a permitir crear los siguientes tipos de proxy:
- Pass Through Proxy. El servicio simplemente envía la información al endpoint sin procesar el contenido. El WSDL expuesto en este caso es uno genérico diferente del servicio web de backend.
- Custom Proxy. Es el que debemos escoger cuando ningún otro tipo resuelva nuestras necesidades.
- Transformer Proxy. El servicio modifica el contenido del mensaje mediante una transformación XLST (Extensible Stylesheet Language Transformation). Esta transformación se puede ejecutar sobre el flujo entrante, antes de enviarlo al backend, y/o sobre el flujo saliente, transformando la respuesta recibida del backend antes de enviarla al consumidor.
- Log Forward Proxy. Como Pass Through Proxy, pero con el log de los mensajes enviados y recibidos.
- WSDL Based Proxy. Similar al Pass Through Proxy, pero definiendo el WSDL del proxy. Puede ser el mismo del backend o uno personalizado. Se utiliza cuando tenemos un servicio con una definición WSDL, entonces crearemos el proxy con la información de este fichero.
- Secure Proxy. Igual que Pass Through Proxy, pero permite securizar el servicio web, añadiendo una política de seguridad al proxy. Se puede utilizar para securizar un servicio de backend que no tenga seguridad, de forma que el proxy seguro será el servicio disponible para el consumidor final en lugar del servicio de backend.
Una vez creado el proxy se puede modificar tanto de forma gráfica (arrastrando componentes), como editando el xml asociado.
El diseño del proxy tiene estas tres partes:
- Flujo de entrada (in flow). Aquí situamos la lógica que procesa los mensajes de entrada enviados al proxy.
- Flujo de salida (out flow). Aquí situamos la lógica para los mensajes salientes, son las respuestas recibidas desde un endpoint.
- Flujo de error (fault flow). Implementamos lo que queremos que se lance en caso de un error.
Es recomendable definir secuencias que definan la lógica necesaria; de forma que el proxy solo tenga definidas las secuencias, sin implementar lógica por sí mismo.
<?xml version="1.0" encoding="UTF-8"?>
<proxy name="proxy" startOnLoad="true"
transports="http https"
xmlns="http://ws.apache.org/ns/synapse">
<target>
<inSequence>
<sequence key="InSequence"/>
</inSequence>
<outSequence>
<sequence key="OutSequence"/>
</outSequence>
<faultSequence>
<sequence key="FaultSequence"/>
</faultSequence>
</target>
</proxy>
API REST
La API REST se crea de forma similar al proxy.
En la API nos va a preguntar por el contexto, que se refiere al contexto url donde estará accesible el API. Es decir, si el contexto es testApi la URL será del tipo http://localhost:8280/testApi
. El contexto debe empezar por /
.
También es recomendable definir secuencias de entrada, salida y error y poner en estas secuencias la lógica necesaria.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/api" name="api"
xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET">
<inSequence>
<sequence key="InSequence"/>
</inSequence>
<outSequence>
<sequence key="OutSequence"/>
</outSequence>
<faultSequence>
<sequence key="FaultSequence"/>
</faultSequence>
</resource>
</api>
Secuencias
La secuencias son bloques de construcción de nuestro servicio. Se crean de forma similar a los elementos anteriores. Presenta las siguientes opciones avanzadas:
- On Error Sequence: define qué secuencia queremos lanzar cuando ocurra un error en el flujo de la secuencia. Si no se especifica ninguna se lanzará la secuencia de error del proxy que esta ejecutando esta secuencia.
- Available Endpoints: podemos elegir un endpoint por defecto para enviar el mensaje.
- Make the sequence as Dynamic Sequence: en este caso la secuencia se almacenará en el registro de WSO2, permitiendo compartir y alojar la secuencia en dos localizaciones: Configuration y Governance4.
La lógica de la secuencia se define mediante mediadores que permiten modificar el contenido del mensaje.
Ejemplo de secuencia:
<?xml version="1.0" encoding="UTF-8"?>
<sequence name="Secuencia"
trace="disable"
xmlns="http://ws.apache.org/ns/synapse">
<log description="Log"/>
<send>
<endpoint>
<address uri="http://www.example.org/service"/>
</endpoint>
</send>
</sequence>
Endpoints
Lo creamos de forma similar a los anteriores, con los siguientes campos específicos:
- Tipo: lo habitual será utilizar Address Endpoint.
- Address: el endpoint del backend.
- Static o Dynamic: ídem secuencias.
Con estos campos ya no sería necesario añadir nada más, por lo que no aparece una edición gráfica como en los artefactos anteriores.
Proyectos de registro
Estos proyectos se utilizan para crear recursos para mediadores que proveen funcionalidades de utilidad, como validación de mensajes o transformaciones XSL. También los ficheros WSDL o XSD se tienen que subir al registro de WSO2.
La creación de estos proyectos se hace desde los tipos misceláneos.
Una vez creado un proyecto de tipo registro se le pueden añadir recursos de las siguientes formas:
- A partir de una plantilla.
- Importándola del sistema.
- Importando un volcado de registro del el sistema de ficheros.
- Descargándolo del registro.
Proyectos de Servicio de Datos
Los Data Service Project se utilizan para añadir data services que permiten acceder a múltiples fuentes de datos y exponer estos datos de una forma sencilla.
Una vez creado el proyecto se pueden añadir los Data Services.
Proyectos de Aplicaciones Compuestas
Los Composite Application Project se utilizan para generar el despliegue de los artefactos. Permite elegir entre los distintos artefactos del espacio de trabajo para incluirlo en el fichero de despliegue Carbon Application aRchive (CAR).
Una vez elegidos qué componentes, es suficiente con hacer click en el icono de la esquina superior izquierda para generar el CAR.
Una vez generado el CAR, el siguiente paso es desplegarlo en el servidor. Para ello es suficiente con acceder a la consola de gestión de WSO2 EI e ir a la opción de menú Main > Carbon Applications > Add.
Depuración
Depurando la mediación se puede hacer debug de nuestro servicio de una forma similar a como hacemos con las aplicaciones Java. Esta característica nos permite comprobar cómo cambia el mensaje tras cada pasa que sucede en nuestro servicio. De esta forma, podemos ver cómo una operación realizada por un mediador modifica el mensaje.
Para habilitar la mediación se siguen estos pasos:
- En el Integration Studio se elige Run > Debug Configurations.
- Elegir ESB Mediation Debugger.
- Ejecutar WSO2 EI en modo debug, añadiendo
-Desb.debug=true
. Por ejemplo en windows habría que ejecutarintegrator.bat –-run -Desb.debug=true
.
Lo habitual es hacer esta depuración en local, ya que carga mucho el servidor.
Pruebas
Probador incorporado
WSO2 EI provee un probador incorporado (buiitl-in tester) para probar servicios SOAP, incluyendo servicios proxy y servicios de datos.
Es una funcionalidad muy básica que no permite probar servicios REST.
Se puede acceder a esta funcionalidad desde la lista de servicios:
Que lleva a la siguiente ventana de pruebas:
Esta ventana muestra a la izquierda la lista de operaciones SOAP disponibles en el servicio. Pinchando en una de ellas se genera una plantilla de petición. Se puede elegir el Endpoint al que enviar la petición, modificar la plantilla según se quiera y enviar la petición, para ver la respuesta.
Pruebas con SOAPUI
Si necesitamos hacer una prueba compleja (o probar servicios REST) el probador incorporado no es suficiente, por lo que habría que utilizar una herramienta como SoapUI.
Creación de cliente de servicio web
SOAP
Para crear el cliente de un servicio web solo es necesario su contrato, es decir su WSDL. Se puede definir desde una URL o desde un fichero. El cliente se crea desde File > New SOAP Project
.
Entonces se crea el proyecto con la lista de operaciones disponibles (tanto en versiones SOAP 1.1 como SOAP 1.2). Eligiendo una de estas operaciones se muestra una ventana con la petición por defecto y la respuesta obtenida.
REST
Para probar una operación REST se hace de una forma similar a la anterior, dando la URI del servicio.
En la ventana de la petición se pueden cambiar todos los parámetros de la API, como método, endpoint, recurso y los parámetros. También se pueden modificar las cabeceras y la seguridad.
Si probamos un servicio de datos que necesite JSON, se puede añadir en la pestaña Header la propiedad Accept:application/json
.
Creación de un servicio simulado
Cuando se hace una prueba a menudo hay muchos servicios implicados, a alguno de estos servicios puede que no tengamos acceso. Para hacer las pruebas se puede crear un servicio simulado (mock service), en el que definiremos las peticiones y respuestas ejemplo del servicio.
El servicio simulado se crea desde New SOAP MockService
/ New REST MockService
en el menú contextual del proyecto.
Una vez creado ya se puede añadir la operación del proyecto que se quiera al servicio simulado (botón derecho desde la operación y Add ...
).
Creación de un caso de prueba
Los casos de prueba nos permiten crear un conjunto de pruebas sobre un servicio para validar que el servicio esté funcionando correctamente. También sirven para hacer pruebas de carga y pruebas de seguridad. Los casos de prueba se engloban en una Test Suite.
WSO2 BPM
Un proceso de negocio es una colección de actividades o tareas estructuradas o relacionadas que representan un caso de uso de negocio y producen un servicio específico o una salida. Durante la ejecución del proceso de negocio se ejecutan sus subprocesos de forma síncrona o asíncrona para producir la salida final. Durante la ejecución puede interactuar tanto con humanos como con máquinas.
Modelado de Procesos de Negocio
El Business Process Modeling o Modelado de Procesos de Negocio consiste en un diagrama que representa una secuencia de actividades.
Con este diagrama se representa:
- Cómo se procesan las actividades.
- Qué hacen las actividades.
- Cuándo y porqué son procesadas.
- Quién las procesa.
BPM (Business Process Management)
El BPM es un ciclo continuo que:
- Identifica los procesos frontera.
- Identifica las actividades y eventos.
- Identifica los recursos y sus entregas.
- Identifica el control de flujo.
WSO2 Business Process
BPMN
BPMN (Business Process Model and Notation) es un estándar para la implementación de workflows. Es un lenguaje basado en XML para modelar y ejecutar procesos de negocio.
Puertos de WSO2
Nota
Es recomendable deshabilitar HTTP en producción y utilizar únicamente HTTP.
Puertos comunes
Los siguientes puertos son comunes a todos los productos WSO2.
Consola de gestión
Los productos WSO2 que ofrecen una consola de gestión utlizan los siguientes puertos:
- 9443 - HTTPS
la URL por defecto de la consola de gestión es https://localhost:9443/carbon - 9763 - HTTP
WSO2 Enterprise Integrator utiliza los siguientes puertos para acceder a la consola de gestión:
- 9443 - HTTPS para el ESB
la URL por defecto de la consola de gestión del ESB es https://localhost:9443/carbon - 9445 - HTTPS para el EI
la URL por defecto de la consola de gestión del EI es https://localhost:9445/carbon - 9444 - Consola de gestión de EI-Analytics
LDAP
- 10389 - Servidor LDAP embebido
KDC
- 8000 - Servidor de claves Kerberos
JMX
Por defecto, JMX está habilitado en todos los productos. Se puede deshabilitar en el fichero <PRODUCT_HOME>/repository/conf/etc/jmx.xml
.
- 11111 - puerto RMIRegistry. Se utiliza para monitorizar Carbon remotamente.
- 9999 - puerto RMIServer. Se utiliza junto al puerto RMIRegistry cuando Carbon se monitoriza desde un cliente JMX que esté detrás de un cortafuegos.
Cluster
Para hacer cluster de una instancia Carbon se debe abrir uno de los siguientes puertos:
- 45564 - En caso de multicast
- 4000 - En caso de wka
Puertos aleatorios
Algunos puertos se abren de forma aleatorio en el arranque del servidor. El identificador de estos puertos cambiará cada vez que se arranque el servidor.
API Manager
- 5672 - Utilizado por el Message Broker interno.
- 7611 - Autentica los datos publicados cuando se usa Thrift.
- 7612 - Publica analíticas para el servidor API Manager Analytics.
- 7711 - Puerto para transporte seguro cuando se usa Thrift.
- 7711 - Puerto del servidor API Manager Analytics.
- 8280, 8243: puertos de transporte NIO / PT.
- 9611 - Publica datos para el Traffic Manager .
- 9711 - Autentica datos para el Traffic Manager .
- 10397 - Puertos Thrift cliente y servidor.
- 9099 - Puertos Web Socket.
BPS
- 2199 . Puerto de registro RMI (puerto de proveedor de acceso a datos).
ESB
Puertos de transporte HTTP/S no bloqueantes. Se utilizan para aceptar mensajes de mediación. Si se quiere enviar una solicitud a una API o a un servicio web se deben usar estos puertos.
Se configuran en el fichero <ESB_HOME>/repository/conf/axis2/axis2.xml
.
- 8243 - Passthrough o NIO sobre HTTPS
- 8280 - Passthrough o NIO sobre HTTP
De forma que llamando a
https://<servidor_wso2>:8243/services
o bien a
http://<servidor_wso2>:8280/services
se ven los servicios disponibles en el servidor y se puede acceder a los WSDL correspondientes.
Histórico de Versiones
Versión | Fecha | |
---|---|---|
0.0 | Lectura Beginning WSO2 ESB | Julio 2019 |
1.0 | Lectura documentación formación web WSO2 | Julio 2019 |
1.1 | Puertos WSO2 | 21/08/2019 |
1.2 | Patrones de integración (web WSO2) | 03/10/2019 |
2.0 | Lectura WSO2 Developer's Guide | 21/10/2019 |
2.1 | REST APIS (DZone) | 04/12/2019 |
2.2 | Lectura Pro RESTful APIs | |
2.3 | Incluido en Mkdocs | Enero 2021 |
2.4 | Corrección sintaxis | Mayo 2021 |
2.5 | Adaptación a Obsidian | Agosto 2023 |
Referencias
- Kasun Indrasiri - Beginning WSO2 ESB (2016) . Apress
- Fidel Prieto Estrada Ramon Garrido Lazaro - WSO2 Developer's Guide (2017). Packt
- Udemy - Learn Wso2 EI
1. En un ESB el procesamiento de peticiones o respuestas se conoce como mediación de mensajes.
2. WireShark anteriormente era conocido como Ethereal
3. Un proveedor de AMQP es RabbitMQ.
4. Los artefactos del registro de configuración se comparten por todos los nodos de un clúster WSO2, mientras que los artefactos del registro de «gobernanza» se comparten por todos los productos WSO2 de nuestro entorno.