jueves, 25 de septiembre de 2014

Introducción al ESB de WSO2 a través de ejemplos prácticos.V

En esta entrada quiero mostrarles una pequeña implementación motivada a partir de una pregunta lanzada en StackOverFlow.
Basicamente se quiere obtener a partir de la consulta de un servicio de datos un listado de IDs y con ese listado se desea iterar sobre el mismo y por cada elemento lanzar una llamada a otro servicio de acceso a datos, y las respuestas obtenidas unirlas para devolver una única respuesta al cliente.
Veamos como se hace.

El servicio proxy queda como sigue:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="AddressProxy"
       transports="https,http"
       statistics="disable"
       trace="disable"
       startOnLoad="true">
   <target>
      <inSequence>
         <property xmlns:p="http://www.example.org/Address/"
                   name="clientid"
                   expression="//p:getAddress/clientid"
                   scope="default"
                   type="STRING"/>
         <sequence key="conf:/sequencesStackOverFlow/getmpartybranch"/>
      </inSequence>
      <outSequence>
         <aggregate>
            <completeCondition>
               <messageCount min="-1" max="2"/>
            </completeCondition>
            <onComplete xmlns:add="http://ws.wso2.org/dataservice"
                        expression="//add:Addresses/add:Address">
               <send/>
            </onComplete>
         </aggregate>
      </outSequence>
   </target>
   <publishWSDL key="conf:/wsdls/Address.wsdl"/>
   <description/>
</proxy>



Como pueden ver en la secuencia de entrada primero guardo en una property el valor del clientid que es la entrada del servicio proxy, y luego hago una llamada a la secuencia getmpartybranch, que está en el registro del ESB y que veremos a continuación.


<sequence xmlns="http://ws.apache.org/ns/synapse">
   <payloadFactory media-type="xml">
      <format>
         <dat:getmpartybranch xmlns:dat="http://ws.wso2.org/dataservice">            
            <dat:clientid>$1</dat:clientid>         
         </dat:getmpartybranch>
      </format>
      <args>
         <arg xmlns:ns="http://org.apache.synapse/xsd" expression="get-property('clientid')" evaluator="xml"></arg>
      </args>
   </payloadFactory>
   <send receive="conf:/sequencesStackOverFlow/iterOvermpartybranch">
      <endpoint>
         <address uri="http://127.0.0.1:9765/services/mpartybranch"></address>
      </endpoint>
   </send>
</sequence>



En esta secuencia creo un nuevo mensaje para consultar el servicio de acceso a datos que me dará dado el clientid el listado sobre el cual deberé iterar. Este resultado lo obtengo de invocar al servicio http://127.0.0.1:5555/services/mpartybranch y será enviado a la secuencia iterOvermpartybranch, que veremos a continuación.


<sequence xmlns="http://ws.apache.org/ns/synapse">
   <iterate xmlns:ns="http://org.apache.synapse/xsd" xmlns:ds="http://ws.wso2.org/dataservice" expression="//ds:DataCollection/ds:Datalist" id="iterate1" sequential="true">
      <target>
         <sequence>
            <property name="partybranchid" expression="//ds:partybranchid/text()" scope="default" type="STRING"></property>
            <property name="clientid" expression="//ds:clientid/text()" scope="default" type="STRING"></property>
            <log>
               <property name="PARTYID" expression="get-property('partybranchid')"></property>
               <property name="CLIENTID" expression="get-property('clientid')"></property>
            </log>
            <payloadFactory media-type="xml">
               <format>
                  <dat:getselect_addresses xmlns:dat="http://ws.wso2.org/dataservice">                     
                     <dat:objectid>$1</dat:objectid>                     
                     <dat:clientid>$2</dat:clientid>                  
                  </dat:getselect_addresses>
               </format>
               <args>
                  <arg expression="get-property('partybranchid')" evaluator="xml"></arg>
                  <arg expression="get-property('clientid')" evaluator="xml"></arg>
               </args>
            </payloadFactory>
            <log level="full"></log>
            <send>
               <endpoint>
                  <address uri="http://127.0.0.1:9765/services/getAddress" format="soap12"></address>
               </endpoint>
            </send>
         </sequence>
      </target>
   </iterate>
</sequence>



En  el mediador iteramos para llegar a cada nodo //ds:DataCollection/ds:Datalist y obtenemos las propiedades que vamos a utilizar, estas las imprimimos en consola para comprobar que efectivamente el servicio está funcionando. Algo que es muy útil cuando lo estamos desarrollando.


Luego creamos otro mensaje usando el mediador payload factory y lo enviamos al servicio de datos correspondiente. En base de datos tengo 2 tuplas en mi ejemplo, así que se realizaría 2 recorridos y se consultaría 2 veces al servicio http://127.0.0.1:9765/services/getAddress


La respuesta de esta secuencia entraría por la secuencia de salida del servicio proxy, la cual pueden ver en la definición del servicio. En la secuencia se usa el mediador aggregate para agregar las respuestas. Solo queda pendiente realizar una transformación para cumplir con el formato del mensaje de salida. Esto lo veremos en la siguiente entrada.

jueves, 11 de septiembre de 2014

WSO2 Identificando y solucionando errores.


Cuando se comienza a trabajar en soluciones de integración usando un ESB el tema de Troubleshooting es fundamental tenerlo claro.

Para aquellos que se enfrenta a desarrollos de este tipo usando la suite de WSO2 y su ESB les recomendamos descargar este PDF, que les dará una guía muy útil sobre como identificar los problemas y proceder a resolverlos eficientemente.

Los principales puntos que aborda son:


  • Troubleshooting Techniques
    1. Debug logs
      Trace logs
  • Monitoring Messages
    1. TCPMon
      Wire Logs
  • Solutions for Commonly Occurring Exceptions
  • Troubleshooting Timeout Issues
  • Mediation Fault Handling

Esperamos que les sea de utilidad.

Tomado de: http://wso2.com/library/articles/2014/05/wso2-esb-a-guide-to-troubleshoot/

miércoles, 3 de septiembre de 2014

WSO2 con un IDE en la Nube.


WSO2 no deja de sorprendernos y como parte de su solución en la nube "WSO2 Cloud" tenemos la  funcionalidad de poder editar nuestro código y subir los cambios desde un repo temporal de git en la nube hacia el repo remoto. Nos provee de un autocompletamiento de código que si no está al nivel de los IDEs a los que estamos acostumbrados, si para realizar un trabajo rápido o un cambio menor cumple con las espectativas.

Para llegar a esta pantalla del IDE nos vamos a un proyecto en la solución Cloud y seleccionamos del menú de la derecha la opción "Repos & Builds".

De ahí vamos al final y damos clic en el botón "Edit Code", y ya con esto tendremos acceso al IDE y poder realizar los cambios que queramos.

Espero les sea de utilidad y les agilice el desarrollo, es una buena opción para aquellos que se dan cuenta de un cambio a última hora y no tienen a mano su PC o Laptop con su IDE de preferencia. :-D

martes, 2 de septiembre de 2014

WSO2 ESB y el manejo de los logs para la detección de errores

En esta entrada quisieramos mostrarles algo que es básico en cualquier suite para desarrollar soluciones de integración y es la forma en que capturamos los logs generados por los eventos que ocurren con los servicios desplegados.

En el WSO2 ESB existen 3 formas de capturar los logs de los servicios proxy:

  1. Usando el mediador log, dentro de la misma configuración del servicio proxy, algo muy útil durante el desarrollo y para los temas de troubleshooting.
  2. Generando los logs propios del servicio proxy en un fichero a parte del de los logs del propio ESB. A veces dada la cantidad de logs generados se hace un poco complicado seguirle la traza a lo que ocurre con determinado servicio. Esto es muy útil en los ambientes de producción.
  3. Extendiendo las funcionalidades del Synapse, framework base del WSO2 ESB, para incluir lo que se conoce como Observadores. Los cuales se programan para capturar la información que querramos y son adjuntados al servicio proxy en cuestión, especificando incluso el fichero de salida hacia donde se escribirán los logs.

Veamos ahora como podemos usar cada una de estas formas. Para ello usaremos el servicio JAX-WS desplegado en el WSO2 AS de la entrada anterior  y crearemos un servicio proxy.

El servicio JAX-WS lo pueden ver en la siguiente imagen:



El servicio proxy que creamos para la primera forma de captura de los logs lo pueden ver en la siguiente imagen.



Así los logs capturados se pueden ver en la consola o en el fichero de los logs en el ESB, como se muestra en la siguiente imagen.



La segunda forma de capturar los logs, aunque sería mejor decir que es de separar los logs que nos interesan de los logs propios de la ejecución del ESB, es modificar el fichero log4j.properties y añadir las siguientes líneas:

# Configuracion de appender para capturar los logs generados por el servicio UserCollectionProxy
log4j.category.SERVICE_LOGGER.UserCollectionProxy=INFO, PROXY_APPENDER
log4j.additivity.PROXY_APPENDER=false
log4j.appender.PROXY_APPENDER=org.apache.log4j.DailyRollingFileAppender
log4j.appender.PROXY_APPENDER.File=${carbon.home}/repository/logs/${instance.log}/wso2-esb-UserCollectionProxy${instance.log}.log
log4j.appender.PROXY_APPENDER.Append=true
log4j.appender.PROXY_APPENDER.layout=org.apache.log4j.PatternLayout
log4j.appender.PROXY_APPENDER.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%X{ip}-%X{host}] [%t] %5p %c{1} %m%


De esta manera se creará un fichero de nombre wso2-esb-UserCollectionProxy.log que tendrá los logs generados solo por el servicio proxy indicado.

La tercera variante es una implementación más general de la segunda. En la variante 2 para cada servicio debíamos realizar una modificación en el fichero log4j.properties y esto es conveniente cuando no nos interesa observar los logs de todos los servicios si no de algunos en particular. Pero cuando nos interesa observar los logs de todos los servicios, entonces la 3ra opción es la mejor.

Básicamente consiste en implementar un observer que extiende de la clase AbstractSynapseObserver de synapse y posee un método: private void setLogger(ProxyService proxy) throws IOException

Este método es donde se implementa el comportamiento tal y como se puede observar en la siguiente clase java.



package org.jorgesoftdev;

import org.apache.synapse.config.AbstractSynapseObserver;
import org.apache.synapse.core.axis2.ProxyService;
import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;

/**
 * Created by Jorge on 30/08/14.
 */
public class CustomSynapseObserverForLogging extends AbstractSynapseObserver  {

    private static final Log log = LogFactory.getLog(CustomSynapseObserverForLogging.class);

    public void proxyServiceAdded(ProxyService proxy) {
        try {
            setLogger(proxy);
        } catch (IOException e) {
            log.error("CustomProxyObserver could not set service level logger for the proxy : " + proxy.getName(), e);
        }
    }

    public void proxyServiceRemoved(ProxyService proxy) {
        try {
            setLogger(proxy);
        } catch (IOException e) {
            log.error("CustomProxyObserver could not set service level logger for the proxy : " + proxy.getName(), e);
        }
    }

    private void setLogger(ProxyService proxy) throws IOException {
        String filename = "repository/logs/" + proxy.getName() + ".log";
        String datePattern = "yyyy-MM-dd";
        String SYSTEM_LOG_PATTERN = "[%d] %5p - %x %m {%c}%n";
        PatternLayout layout = new PatternLayout(SYSTEM_LOG_PATTERN);
        DailyRollingFileAppender appender = null;
        appender = new DailyRollingFileAppender(layout, filename, datePattern);
        Logger proxyLogger = Logger.getLogger("SERVICE_LOGGER." + proxy.getName());
        proxyLogger.setLevel(Level.ALL);
        proxyLogger.setAdditivity(false);
        proxyLogger.addAppender(appender);
    }

}




Para implementar la tercera variante he creado un proyecto maven con esta clase implementada, he generado el jar y lo he copiado en la carpeta [ESB_HOME]\repository\components\lib\

Luego he ido al fichero [ESB_HOME]\repository\conf\synapse.properties y he actualizado la línea:
synapse.observers=org.wso2.carbon.mediation.dependency.mgt.DependencyTracker

con la línea:

synapse.observers=org.jorgesoftdev.CustomSynapseObserverForLogging

Luego de reiniciar el servidor en el directorio [ESB_HOME]\repository\logs\ aparecen los ficheros [nombre_servicio_proxy].log con los logs de los respectivos servicios, cada uno por separado.


Cada variante depende de las necesidades de los desarrolladores,  del ambiente en el que se esté ejecutando el ESB, pero al menos a nuestro equipo para un ambiente de desarrollo una combinación de las variantes 1 y 3 es la mejor opción.

La información utilizada para esta entrada fue obtenida de aquí.

Esperamos les sea de utilidad.

lunes, 1 de septiembre de 2014

Introducción a WSO2 Cloud. Nueva propuesta de WSO2.

Hola a todos.

En junio, durante el evento WSO2 Con - Europe 2014 en Barcelona se lanzó la versión beta del servicio WSO2 Cloud de la empresa WSO2. Esta fue la nueva iniciativa luego de la entrega por parte de la empresa a Apache de la solución para la nube StratosLive.

Este nuevo servicio es sumamento fácil de usar. Si ya tienes una cuenta en wso2.com puedes usarla para acceder al mismo, en caso contrario y a través de esta pantalla puedes registrarte y acceder.


La primera prueba que hice fue pasar la implementación de un servicio web desarrollado en jax-ws para esta nueva plataforma y básicamente luego de autenticarse aparece la siguiente pantalla.


Ahí se selecciona App Cloud pues nuestro servicio web estará dentro de un war, ya cuando entramos a la UI debemos crear una aplicación web y esto automáticamente nos provee de un repositorio git y un espacio en jenkin para el despliegue de la aplicación.

Usando el proyecto Example3_JAX-WS expuesto en esta entrada hice los cambios necesarios en el mismo para moverlo al nuevo repo git, cuidando de no modificar los parámetros del pom.xml pues aunque les compile abajo, cuando se trate de subir al repo online les dará problemas.



En nuestro caso usamos SourceTree como cliente GIT para clonar el repo, implementamos los cambios en el servicio y automaticamente cuando se hace un commit al repo online se lanza la tarea en jenkin de compilar y desplegar la aplicación.

Ya con la aplicación desplegada y corriendo usamos el SOAPUI para crear un proyecto y probar el consumo del servicio web desarrollado con JAX-WS.

Para cerrar, revisando los blogs de los desarrolladores de WSO2 me encontré con esta entrada donde se hace un resumen de las principales funcionalidades de este servicio:

WSO2 App Cloud

  • Create applications from scratch - JSP, Jaggery, JAX-WS, JAX-RS
  • Upload existing web applications - JSP, Jaggery
  • Database provisioning for your apps
  • Life cycle management for your app - Dev, Test and Prod environments
  • Team work - A team can collaboratively work on the app
  • Issue tracking tool
  • A Git repository per each application and a build tool.
  • Cloud IDE - For your app development work
  •  And more...

WSO2 API Cloud

  • Create APIs and publish to API store (a store per tenant)
  • Subscribe to APIs in the API store
  • Tier management
  • Throttling
  • Statistics
  • Documentations for APIs