lunes, 8 de enero de 2018

Consumiendo API del tiempo OpenWeatherMap con WSO2 en Cuba


Hola a todos. En esta ocasión la entrada es particular para mi país, con poca penetración de internet en nuestro hogares.

El post ampliado lo pueden ver en mi blog de cubava.

En resumen es una pequeña solución usando 2 conectores del WSO2 ESB para obtener los datos de la temperatura en mi ciudad en mi buzón de correo cada 1h. Algo útil para estos días de frio. 

Aquellos que tienen internet en sus celulares no la necesitan pues los gadgets del tiempo dan esa información actualizada casi que en tiempo real, pero quien no tiene internet si la puede ver útil.

En lo particular me sirvió para probar el conector de openweathermap, que no lo había probado antes y para detectar un bug en el uso del payloadfactory de conjunto con el mediador iterate desde un proxy y desde un API, en el caso del consumo del iterate desde el API hay un problema con el namespace del body que usa el de soap12 y no el de soap11 por lo que no funciona como se espera...tuve que mirar bien los mensajes generados por el payloadfactory para darme cuenta y hacer el ajuste necesario.

Saludos.

jueves, 7 de diciembre de 2017

WSO2 EI:Escribir y leer en el registro interno



Se puede dar un escenario muy común donde tenemos algunas propiedades guardadas en el registro interno del WSO2 EI o el WSO2 ESB, y necesitamos ser capaces de leer la información y además de escribirla o actualizarla. En esta entrada veremos como escribir y leer del registro en el WSO2 EI.

Digamos que el escenario es el siguiente:
Tenemos un fichero de configuración en XML donde guardamos direcciones IP y puertos a donde debemos enviar determinada información.
Su estructura puede ser la siguiente:

<ListaEP xmlns:ns1="http://ejemplos.softdevelop.org/consultarEP">
 <EP>
  <IP>192.168.1.1</IP>
  <Puerto>8080</Puerto>
 </EP>
 <EP>
  <IP>192.168.1.2</IP>
  <Puerto>8081</Puerto>
 </EP>
 <EP>
  <IP>192.168.1.3</IP>
  <Puerto>8082</Puerto>
 </EP>
</ListaEP>

Se necesita:
  1. Un proxy que escriba el XML anterior en el registro interno. Aquí no veremos de donde viene la información, así que usaremos un payloadfactory para crear la estructura, pero el xml puede venir de la invocación de un servicio de datos o de cualquier otra fuente de información.
  2. Un proxy que lea el XML almacenado en el registro y pueda consultar las IP y los puertos.
En el WSO2 EI tenemos la estructura inicial creada en el registro:
image


Así que necesitamos primero el proxy para que escriba en ella. Este proxy se muestra a continuación:


<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="EscribirXMLPS"
       transports="https http"
       startOnLoad="true"
       statistics="enable"
       trace="enable">
   <description/>
   <target>
      <inSequence>
         <payloadFactory media-type="xml">
            <format>
               <ListaEP xmlns="http://ejemplos.softdevelop.org/consultarEP">
                  <EP>
                     <IP>192.168.4.1</IP>
                     <Puerto>8080</Puerto>
                  </EP>
                  <EP>
                     <IP>192.168.4.2</IP>
                     <Puerto>8081</Puerto>
                  </EP>
                  <EP>
                     <IP>192.168.4.3</IP>
                     <Puerto>8082</Puerto>
                  </EP>
               </ListaEP>
            </format>
            <args/>
         </payloadFactory>
         <property name="bodyEntradaESB"
                   expression="$env/*[local-name()='Body']"
                   scope="default"
                   type="OM"/>
         <property xmlns:ns1="http://ejemplos.softdevelop.org/consultarEP"
                   name="dataValida"
                   expression="$ctx:bodyEntradaESB/ns1:ListaEP"
                   scope="default"
                   type="STRING"/>
         <log level="custom">
            <property name="IMPRIMIR" value="Mensaje a guardar"/>
            <property name="BODY" expression="$ctx:bodyEntradaESB"/>
           <property name="Data" expression="$ctx:dataValida"/>
         </log>
         <script language="js">
importPackage(Packages.org.apache.synapse.config);
mc.getConfiguration().getRegistry().newResource("gov:/endpoints/ListaEP.xml",false);
mc.getConfiguration().getRegistry().updateResource(
  "gov:/endpoints/ListaEP.xml", mc.getProperty("dataValida").toString());
</script>
         <respond/>
      </inSequence>
   </target>
</proxy>

Al ejecutar el servicio proxy vemos la respuesta usando el Try it.
image


Y en el registro vemos que se ha creado el fichero con el XML.
image


Y su contenido es:
image


Ahora si queremos leer dicho XML usaremos el siguiente proxy:

<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
       name="ConsultarXMLPS"
       transports="https http"
       startOnLoad="true"
       statistics="enable"
       trace="enable">
   <description/>
   <target>
      <inSequence>
         <property name="ListadoEP"
                   expression="get-property('registry','gov:/endpoints/ListaEP.xml')"
                   scope="default"
                   type="OM"/>
         <log level="custom">
            <property name="Registro:=====" expression="$ctx:ListadoEP"/>
         </log>
         <foreach xmlns:nm="http://ejemplos.softdevelop.org/consultarEP"
                  id="FE1"
                  expression="$ctx:ListadoEP//nm:EP">
            <sequence>
               <log level="custom">
                <property name="Registro" value="Accediendo a un registro"/>
                <property name="IP:" expression="//nm:EP/nm:IP"/>
                <property name="Puerto:" expression="//nm:EP/nm:Puerto"/>
               </log>
            </sequence>
         </foreach>
         <respond/>
      </inSequence>
   </target>
</proxy>

Al probar este proxy nos responde con un success pero nada más, pues no le inyectamos una respuesta que devolver. Pero si podemos ver en la consola como se accede a la información del XML.

image

Y ya con estos 2 proxy tenemos la funcionalidad deseada.
Espero les sea de utilidad.

lunes, 4 de diciembre de 2017

Tiene WSO2 futuro dentro de Cuba? I.


Alguien hace poco me hizo la pregunta del asunto al conocer que una buena parte de mis habilidades se centran en esta suite, y mi respuesta fue: obvio

Y claro, aproveché para enumerarle una buena cantidad de escenarios donde veía la necesidad/utilidad imperiosa del uso de una suite para temas de integración e interoperabilidad en nuestro país, y que aprovecho para compartir con la comunidad.


image

WSO2 es una empresa de Sri Lanka que se especializa en el desarrollo de una suite (colección de herramientas con un fin relacionado) para temas de integración e interoperabilidad o más concretamente centrada en temas de SOA y BPM. Sus desarrollos son completamente Open Source bajo licencia Apache v2, o sea 0 $, y se prestan para casi cualquier escenario que imaginemos.

Posee varias oficinas, y en Latinoamérica tiene en Brasil:
image


Además se encuentra muy bien posicionada según Gartner y The Forrester Wave:
image


Por lo que no estamos hablando de una empresa incipiente o con poca presencia en el mercado. Ya que cuenta con más de 250 clientes bien posicionados y que le dan una buena visibilidad.
image


Desde hace unos meses su larga lista de productos, pues son más de 20, la han concentrado en 3 direcciones fundamentales: Integración, Gestión de APIs y Seguridad.
image


Y lo interesante del caso es que hace unos 5 años atrás, por ahí por el 2012 propusimos algo similar para desarrollar acá en Cuba, lo que lamentablemente llegamos a oídos sordos y falta de $$, pero nuestra propuesta era:

image


Llegado este punto, cualquiera que tenga un 1% de interés en saber de que va WSO2 lo invito a ver su lista de casos de éxito pues por ahí es por donde se sabe si es buena o no una suite de este tipo.
Pero volviendo al inicio. Les dejo a continuación algunos de los escenarios que le describí a quien dudaba del futuro de WSO2 y en particular en el mercado cubano


Posibles escenarios de uso de WSO2 en Cuba:
    1. Visualización casi en tiempo real o en tiempo real, en un mapa, de múltiples eventos de salud. Por ejemplo, diariamente se generan y notifican de casos de dengue y demás enfermedades similares. Se podría tener visualizado el movimiento de la epidemia a nivel de país, provincia, municipio, etc….Desconozco si exista algo así pero sería una herramienta de mucha utilidad para todo cubano preocupado con su salud y para los decisores ni hablar…con WSO2 se podría recopilar la información de cualquier sistema de salud y usando una simple conexión telefónica transmitirla a un servidor central donde se tuviera un WSO2 DAS encargado del procesamiento de la información y su visualización en dashboard, además de que si se usa una herramienta como el WSO2 DAS se tiene ya las funcionalidades de un CEP para el manejo de eventos complejos y generación de alertas en tiempo real, algo que permitiera solo a manera de ejemplo identificar donde hay un potencia foco del aedes si en una cuadra se dan 3 brotes de la enfermedad en un plazo de 3 días...Muchos eventos de este tipo se podrían definir para tener notificaciones en tiempo casi real..
    2. Modernización de los sistemas de salud a nivel de las distintas instancias médicas. El estándar HL7 es ampliamente utilizado en el mundo entero para mover la información médica. Lograr la modernización e integración entre sistemas se puede realizar muy fácilmente con un WSO2 ESB pues tiene la capacidad para trabajar con HL7 y realizar las transformaciones necesarias para las integraciones, además de implementar 100% los patrones de integración empresarial. Y si se requiere exponer los datos de forma segura nada mejor que la combinación del WSO2 API Manager(AM) y un WSO2 Identity Server(IS). Con el AM las APIs se aseguran con OAuth y se lleva todo un ciclo de vida de las APIs, además de que se pueden monetizar y geolocalizar. Con estas dos funcionalidades se le podría dar facilidades a terceros para que desarrollen aplicaciones móviles relacionadas con la salud, abriendo todo un nuevo mercado verde verde en Cuba. Con el IS actuando como un bus de identidad, se lograría algo que dudo exista a nivel de país en cualquier instancia o nivel. Un repositorio centralizado de perfiles de usuarios con todos sus datos gestionados, con capacidad para gestionar además políticas de autorización a los sistemas, integrado con el resto de las soluciones, y con capacidad para brindar Single Sign On y actuar como puente entre proveedores de servicios y proveedores de identidad…Sería permitir la federación de identidades entre instituciones del sector de la salud.
    3. Salud desde la casa: Imagínense que se han comprado uno de esos reloj o pulseras que venden y que permiten monitorear diferentes variables de de nuestro cuerpo (ritmo cardíaco, calorías, ejercicios físicos realizados, horarios de sueño, etc) y que pudieran sincronizar esta información con alguna aplicación a la cual tuvieran acceso y por lo tanto esta información se guardara en servidores externos a su dispositivo. Y que además pudieran vincular esta información con su historia clínica, de tal manera que las personas enfermas tuvieran un chequeo constante por ejemplo de su ritmo cardíaco. Así si alguien padece del corazón y a media noche le sube mucho o le baja el ritmo cardíaco se lanzaría automáticamente una alerta que iniciaría todo un procedimiento de chequeo del estado de salud del paciente y quien quita que no se llame automáticamente a una ambulancia.
    4. Historia clínica: Que aunque me digan que eso ya está implementado, que está hecho, que existe, y demás cosas tratando de reafirmarme que si que ya se puede usar. Que hasta que no llegue a la consulta con mi doctor y este me enseñe mi historia clínica en digital con todos mis análisis y no el file lleno de papeles que siempre me saca, pues sencillamente para mi no existe, es ciencia ficción. Y lo digo porque esto tiene que ser de beneficio de los pacientes y que se vea el beneficio. Y si a esto le sumamos que tampoco puedo tener acceso a ella cuando es mía, son mis análisis, mis resultados, vaya que más ciencia ficción es. Y si a esto le sumamos que si un día tengo un accidente la gente del SIUM (los de la ambulancia acá en Cuba) no van a conocer mi tipo de sangre ni mis alergías, aunque la información esté en mi “historia clínica digital" pero ellos no tienen acceso, ummm….para mi lo que hay hoy no tiene utilidad. Y eso es una mala muy mala gestión de cara a la población en general. Y es que sería tan fácil tener un API, bien asegurada con los niveles de acceso y trazabilidad adecuada, que de información oportuna en función del rol y usuario que la solicite, sería genial para que se desarrollaran aplicaciones que consumieran dicha información y brindaran utilidad a la misma. Y ahí es donde se ve si la tecnología facilita la vida o no de nuestro pueblo. Entiendo que la infraestructura para realizar lo anterior es cara, pero estamos hablando del beneficio de la población y que dicho beneficio se puede extender en soluciones que se pueden vender bastante caras en otros países, por menos precio que que la competencia.


  • Sector financiero/bancario:
    1. Desarrollo de una pasarela de pago: Algo tan necesario en estos días y que tenemos o no tenemos, pero que la realidad es que en 2017 sin una pasarela de pago todo lo que dependa de un intercambio de dinero a nivel digital está detenido. Con WSO2 se cuenta con herramientas que permitirían muy fácilmente implementar una pasarela de pago. Estas son: WSO2 ESB para todo lo que tenga que ver con conexión, transformación de mensajes, ruteo, balanceo de carga, enriquecimiento de mensajes, etc…WSO2 API Manager para exponer funcionalidades de la pasarela a través de servicios REST lo que permitiría el desarrollo de aplicaciones de terceros que aprovecharan las funcionalidades de la pasarela de pago.
    2. Integración entre los bancos: Ahora en el 2018 se adoptará en Europa un nuevo estándar para los temas bancarios, el PSD2. Que será de obligatorio cumplimiento, algo como esto no lo tenemos en Cuba ni a nivel legislativo ni regulatorio ni tecnológico. Y al menos con WSO2 podríamos lograr la parte técnica muy rápidamente.
  • Sector Educativo:
    1. Integración de soluciones. Durante mi tiempo como profesor en la Universidad de las Ciencias Informáticas, mi mayor desencanto fue tener una suite como WSO2, ver los problemas diarios relacionados con las tecnologías en una universidad llena 100% de informáticos, y no poder darle un uso adecuado a la suite. Los problemas de integración estaban en donde quiera que se mirara, fundamentalmente cuando se iba a la página de la intranet (los sistemas no se conectaban entre si, no eran interoperables, se caían cada 2 por 3, se repetían funcionalidades, se usaba PHP para implementar cualquier cosa, se desconocían los patrones de integración empresariales, etc, etc, etc)…Hoy por hoy en cualquier universidad del mundo deben de existir más de 10 sistemas que necesitan comunicarse entre si. Lograr una gestión centralizada de los usuarios, una autenticación única, tener una capa de servicios expuestos hacia aplicaciones de gestión internas y a aplicaciones a través de un portal web. Tener monitorizados los eventos que se producen en la institución, como por ejemplo el nivel de desaprobados en un examen en particular para alertar que algo anda mal, serían solo escenarios puntuales que se podrían implementar usando la suite de WSO2.
    2. Interconexión entre universidades: Hoy los usuarios de una universidad no pueden disfrutar de servicios de otra universidad, pues sus usuarios no se autentican. Algo tan simple de lograr con una federación de identidades con el WSO2 IS.

  • Sector Industrial.
    • En nuestras industrias tenemos muchos procesos industriales, que llevan sensores, estos sensores generan información constantemente. Esta información debe ser recopilada, procesada, visualizada. Y es donde el WSO2 DAS juega su papel, pues puede hacer todo lo anterior y generar alertas en tiempo real, además de permitir la visualización en dashboard del estado de diferentes situaciones. Además tiene incorporado un framework de machine learning que nos acerca aun más a la internet de las cosas o IoT.

  • Sector de Gestión Empresarial.
    1. Trámites: Y aquí hay que hacer una parada bien grande, pues los trámites en Cuba es un punto y aparte. Se empieza por un problema que necesita tramitarse, y para resolver ese problema, debes como mínimo ausentarte entre 2 o 3 o 4 días al trabajo, en lo que inicias el trámite, buscas los documentos necesarios, vuelves y te dicen que te falta esto o aquello, que se perdieron los papeles, que el director no está, que le falta una firma, en fin el día a día de cualquiera enredado en un trámite. Un escenario muy simple de solución sería automatizar lo más que se puedan los trámites a través de un motor de procesos como puede ser el WSO2 Business Process Server, o como puede ser Intalio, Bonita o jBPM…Tener servicios por debajo que apalanquen los procesos, implementados como microservices, reglas de negocio con el WSO2 Business Rule Server(BRS), servicios de acceso a datos con el WSO2 Data Service(DSS) o proxys con el WSO2 Enterprise Services(ESB) y una buena capa de presentación web y móvil para que los usuarios puedan iniciar el trámite desde la comodidad de una conexión a la intranet cubana vía web o a través de su dispositivo móvil. Que además recibiera notificaciones o que pudiera consultar el estado de su trámite y aqui esto sería genial, pues hoy perdí varias horas pasando a recoger un documento, que no sabía si ya estaba listo o no, y claro, faltaba la firma del jefe RRRRRRR…Si hubiera podido consultar el estado de dicho trámite habría visto que aun estaba pendiente y me habría ahorrado dinero, tiempo y esfuerzo.
    2. Automatización de procesos a cualquier escala y en cualquier lugar: pues los procesos están en todas partes y pueden ser automatizados claro está. A nivel de gobierno, empresarial, gerencial, interno en las empresas, en trámites a la población, etc, etc…Un ejemplo sencillo es la reserva de pasajes para viajar, ya sea en ómnibus o en avión…Un dolor de cabeza, pues mínimo debes ausentarte un día solo para averiguar si hay pasaje o no, si hay felicidades, puede ser que tengas la suerte y lo reserves ese mismo día. Pero si no hay, ya sabes que te toca volver a perder otro día.

    jueves, 5 de enero de 2017

    Axis2: Seguridad en WSO2 AS 5.3.0

    image

    Ayer revisando StackOverflow me he topado con una pregunta sobre como establecer la seguridad para un servicio axis2 desplegado en el WSO2 AS 5.3.0 y la verdad es que desconocía que esta funcionalidad, muy buena por cierto, había sido removida de la interfaz web.
    Realmente no me ha gustado que se removiera, pues de una manera muy fácil permitía a los desarrolladores definir la seguridad para los servicios axis2, pero son cosas de la compañía WSO2 que habría que revisar los pro y los contras.

    La respuesta a la pregunta está en el enlace que puse más arriba pero lleva un trabajo adicional a lo que se hacía antes a través de la UI. Se necesita:
    • Identificar el XML que define la política que queremos usar. En mi respuesta usé la más sencilla, UsernameToken over HTTPs.
    • Incluir en el fichero services.xml del servicio axis2, que está dentro del fichero .aar la referencia al módulo de rampart. Que es el que define la seguridad para el framework axis2.
    • Definir cómo se vinculará la política con las distintas operaciones del servicio y donde será adjuntada.
    • Definir algunas configuraciones propias de rampart dentro de la política para la encriptación y uso de los usuarios del WSO2 AS y también una configuración extra para el carbon definiendo los roles que tendrán permiso de acceso al servicio.
    Una vez que se tiene un ejemplo resulta más fácil establecer la seguridad para cualquier servicio axis2 pero para aquellos que no dominan el framework puede llevarle horas o días dar con la configuración correcta. De ahí que me decidiera a compartir un ejemplo sencillo que les sirva a los que se enfrente a este pequeño problema.

    miércoles, 14 de septiembre de 2016

    Tareas programadas en WSO2 ESB.

    Aunque este es un tema simple de implementar desde versiones anteriores, puede ser que varios iniciados en estos temas al tratar de reproducir el post How to Schedule a Task Using WSO2 ESB 4.9.0 se encuentren con que no funciona del todo para WSO2 ESB 5.0.0.
    El problema es basicamente de namespaces así que a continuación les dejo la secuencia con los ajustes realizados y el payload que se manda a través de la tarea.

    La secuencia:

    <?xml version="1.0" encoding="UTF-8"?>
    <sequence xmlns="http://ws.apache.org/ns/synapse" name="iterateSequence">
       <iterate xmlns:ns="http://org.apache.synapse/xsd"
                xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"
                xmlns:ns3="http://org.apache.synapse/xsd"
                xmlns:m0="http://services.samples"
                preservePayload="true"
                attachPath="//m0:getQuote"
                expression="//m0:getQuote/m0:request">
          <target>
             <sequence>
                <call>
                   <endpoint>
                      <address uri="http://localhost:9000/services/SimpleStockQuoteService"/>
                   </endpoint>
                </call>
                <log level="custom">
                   <property xmlns:ax21="http://services.samples/xsd"
                             name="Stock_Quote_on"
                             expression="//m0:getQuoteResponse/m0:return/ax21:lastTradeTimestamp/child::text()"/>
                   <property xmlns:ax21="http://services.samples/xsd"
                             name="For_the_organization"
                             expression="//m0:getQuoteResponse/m0:return/ax21:name/child::text()"/>
                   <property xmlns:ax21="http://services.samples/xsd"
                             name="Last_Value"
                             expression="//m0:getQuoteResponse/m0:return/ax21:last/child::text()"/>
                </log>
             </sequence>
          </target>
       </iterate>
    </sequence>

    El payload:

    <m0:getQuote xmlns:m0="http://services.samples" xmlns:m1="http://services.samples/xsd">
     <m0:request>
     <m1:symbol>IBM</m1:symbol>
     </m0:request>
     <m0:request>
     <m1:symbol>MSTF</m1:symbol>
     </m0:request>
     <m0:request>
     <m1:symbol>WSO2</m1:symbol>
     </m0:request>
    </m0:getQuote>

    Los logs se pueden ver en la siguiente imagen:

    image

    martes, 13 de septiembre de 2016

    Mantén actualizado tu WSO2.

    wum

    Entre versión y versión de cualquier producto de la suite de WSO2 aparecen soluciones a bugs, parches de seguridad y varias mejoras que puede ser que te las pierdas si no estás al pendiente todo el tiempo. Eso era antes. WSO2 como siempre sorprendiéndonos se apareció con una solución que de una manera muy fácil nos permite actualizar antes de empezar a usar determinada herramienta de su suite.

    La herramienta WUM, que actualmente se encuentra en una versión beta, permite en pocos pasos mantenernos actualizados cuando queramos.

    De momento está en pruebas para las siguiente herramientas y versiones, pero todos esperamos que en breve esté para más versiones.
    • WSO2 Enterprise Service Bus 5.0.0
    • WSO2 Enterprise Service Bus 4.9.x
    • WSO2 Enterprise Service Bus Analytics 5.0.0
    • WSO2 API Manager runtimes and analytics 2.0.0
    NOTA: tener en cuenta que las soluciones actualizadas con esta herramienta no tiene la misma licencia open source, pues no está permitido su uso en producción. Tal parece que para eso habrá que pagar Sad smile

    Pero veamos como usarla:
    • Paso 1: La descargas de aquí y la instalas.
    • Paso 2: Valida que la instalaste correctamente, ejecutando wum en una consola.
    wum1

    • Paso 3: Ejecutamos wum init, si es la primera vez nos pedirá usuario y contraseña con los que nos autenticamos en el sitio de wso2.
    image

    • Paso 4: Buscamos las herramientas que pueden ser actualizadas usando esta vía: wum search
    image

    • Paso 5: Agregaremos ahora una herramienta que ya tenemos descargada:
    image

    • Paso 6: Procedemos a instalar la última actualización.
    image


    Y así de una manera muy fácil podemos ir actualizando las herramientas que utilizamos en nuestro día a día.

    Espero les sea de utilidad.

    martes, 23 de agosto de 2016

    Cuando falla un JSP en WSO2


    A veces nos topamos con errores como el mencionado en esta pregunta de stackoverflow, donde la razón no es evidente.

    Es una instalación fresca del WSO2 API Manager 1.10 y al tratar de ver los roles de un usuario salta el siguiente error:
    
    
    2016-08-23 09:26:05,638 [-] [http-nio-443-exec-2] ERROR JspTilesRequestContext JSPException while including path '/user/edit-user-roles.jsp'. 
    javax.servlet.jsp.JspException: ServletException while including page.
    
    Caused by: org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.jsp.user.edit_002duser_002droles_jsp
    
    Caused by: java.lang.ClassNotFoundException: org.apache.jsp.user.edit_002duser_002droles_jsp
        at java.net.URLClassLoader.findClass(Unknown Source)
        at org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:132)
        at org.apache.jasper.servlet.JasperLoader.loadClass(JasperLoader.java:63)
        at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:121)
        at org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:172)

    La solución es realmente fácil y es la siguiente:

    Editar el fichero wrapper.conf que se encuentra en [WSO2_HOME]\bin\yajsw\ y agregar estas 2 líneas:
    
    
    wrapper.java.additional.18 = -Dcomponents.repo=${carbon_home}\\repository\\components
    wrapper.java.additional.26 = -Dorg.apache.jasper.compiler.Parser.STRICT_QUOTE_ESCAPING=false

    La explicación la pueden encontrar en la misma respuesta dada en stackoverflow.

    jueves, 14 de abril de 2016

    WSO2 ESB. Orquestando APIs con Iterate/Aggregate

    Revisando en el sitio de stackoverflow me he topado con una duda ya respondida y aproveché para hacerle algunos cambios y adaptarla a un demo de uso de APIs en el WSO2 ESB que contempla lo siguiente:
    1. Se tienen 2 APIs que tienen cableadas las respuestas en JSON. Esos serían nuestros backend.
    2. Se tiene además otra API que debe implementar la invocación a la primera API que devuelve el listado de personas, luego debe iterar por cada persona para obtener un ID y con ese ID consultar a la segunda API. Dentro de cada iteración debe crear un nuevo mensaje que incluya tanto la respuesta de la primera API como de la segunda y retornarlo para que sea capturada en el flujo de salida. 
    3. La respuesta será entonces la unión de las respuestas de las 2 APIs generada a partir de la iteración y agregación de los mensajes finales.
    Veamos como se hace:

    Primero la imagen de la implementación en el WSO2 Developer Studio.
    image

    Lamentablemente WSO2 hizo su diseño gráfico hacia un costado y no hacia abajo como lo tiene Oracle así que es dificil fijar la imagen en una página, por lo que iremos presentando pedazos para que se vea bien.
    Primero la definición de la API:

    <?xml version="1.0" encoding="UTF-8"?>
    <api context="/services/userdetails" name="UserDetailsAPI" xmlns="http://ws.apache.org/ns/synapse">
      <resource methods="GET" protocol="http">
        <inSequence>
        ....
        </inSequence>
        <outSequence>
        ....
        </outSequence>
        <faultSequence>
     ....
        </faultSequence> 
      </resource>
    </api>  

    Dentro de la secuencia de entrada las acciones son las siguientes:

    Invocar al API que devuelve el listado de personas:
    image 

    <call description="invocacion al BE para obtener las personas">
    <endpoint>
      <http method="get" trace="disable" uri-template="http://localhost:8281/services/users"/>
    </endpoint>
    </call>

    Para ello usamos el mediador call e invocamos al API correspondiente usando el método GET.
    La respuesta de esta invocación será la siguiente:
    {
            "persons":
            [
                {
                    "person":
                    {
                        "Id": "1",
                        "givenName": "ajith",
                        "lastName": "vitharana",
                        "age": "25",
                        "contactInfos":
                        [
                            {
                                "InfoId": "1",
                                "department": "1",
                                "contactType": "email",
                                "value": "ajith@abc.org"
                            },
                            {
                                "InfoId": "2",
                                "department": "1",
                                "contactType": "mobile",
                                "value": "111111111"
                            },
                            {
                                "InfoId": "3",
                                "department": "1",
                                "contactType": "home",
                                "value": "Magic Dr,USA"
                            }
                        ]
                    }
                },
                {
                    "person":
                    {
                        "Id": "2",
                        "givenName": "shammi",
                        "lastName": "jagasingha",
                        "age": "30",
                        "contactInfos":
                        [
                            {
                                "InfoId": "1",
                                "department": "1",
                                "contactType": "email",
                                "value": "shammi@abc.org"
                            },
                            {
                                "InfoId": "2",
                                "department": "1",
                                "contactType": "mobile",
                                "value": "2222222222"
                            },
                            {
                                "InfoId": "3",
                                "department": "1",
                                "contactType": "home",
                                "value": "Magic Dr,USA"
                            }
                        ]
                    }
                }
            ]
        }


    Iterar sobre el listado de personas devueltas:
    image 

    <iterate attachPath="//jsonObject/persons"
    description="iterador sobre cada elemento person"
    expression="//jsonObject/persons/person" id="it1"
    preservePayload="true" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <target>
      <sequence>
     <property expression="$body/jsonObject/persons/person/Id"
       name="uri.var.Id" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
     <property expression="$body//jsonObject//person"
       name="response1" scope="default" type="STRING" xmlns:ns="http://org.apache.synapse/xsd"/>
     <enrich>
       <source clone="true" xpath="$body//jsonObject//person"/>
       <target property="Person" type="property"/>
     </enrich>
     <call description="Se invoca al BE para obtener los roles usando el ID del elemento person correspondiente">
       <endpoint>
      <http method="get" trace="disable" uri-template="http://localhost:8281/services/roles/{uri.var.Id}"/>
       </endpoint>
     </call>
     <!--Aqui se enriquece el mensaje sobre el que se itera 
         para incluirle la respuesta de la call con los roles -->
     <enrich>
       <source clone="true" xpath="$body//jsonObject//roles"/>
       <target action="child" xpath="$ctx:Person"/>
     </enrich>
     <enrich>
       <source clone="true" xpath="$ctx:Person"/>
       <target type="body"/>
     </enrich>
      </sequence>
    </target>
    </iterate>

    Los aspectos más interesantes dentro de cada iteración son:
    1. Se hace una copia del objeto person a una propiedad llamada Person. Esto con el objetivo de salvar ese objeto al realizar un call.
    2. Se invoca a la segunda API pasándole como parámetro el ID de la persona.
    3. De dicha invocación se obtiene un objeto usando el xpath $body//jsonObject//roles que es agregado como un hijo al contenido de la propiedad Person.
    4. Finalmente la propiedad Person es usada para reemplazar el contenido del body actual. Y con esto ya la respuesta está creada.

    Lo último que se hace en la secuencia de entrada es mover el mensaje para la secuencia de salida usando el mediador LoopBack.

    image

    En la secuencia de salida los pasos son los siguientes:
    image


    Crear una propiedad que contenga el elemento padre sobre el cual se van a agregar las respuestas.

    <property name="per" scope="default">
      <ns:Personas xmlns:ns="www.personas.org"/>
    </property>

    Luego hacemos uso del mediador Aggregate para agregar las respuestas que fueron direccionadas a la secuencia de salida.

    <aggregate id="it1">
    <completeCondition>
      <messageCount max="-1" min="-1"/>
    </completeCondition>
    <onComplete enclosingElementProperty="per" expression="$body/*[1]">
      <log>
     <property
       expression="json-eval($.Personas.person[0].givenName)" name="NOMBRE PERSONA: "/>
      </log>
      <send>
    </onComplete>
    </aggregate>

    Dentro del onComplete ponemos un ejemplo de como se captura un valor del JSON, aunque no es necesario y luego incluimos el mediador send para enviar el mensaje de vuelta al cliente.
    Y eso es todo. La respuesta final del API es la siguiente:
    {
            "Personas":
            {
                "person":
                [
                    {
                        "Id": 2,
                        "givenName": "shammi",
                        "lastName": "jagasingha",
                        "age": 30,
                        "contactInfos":
                        [
                            {
                                "InfoId": 1,
                                "department": 1,
                                "contactType": "email",
                                "value": "shammi@abc.org"
                            },
                            {
                                "InfoId": 2,
                                "department": 1,
                                "contactType": "mobile",
                                "value": 2222222222
                            },
                            {
                                "InfoId": 3,
                                "department": 1,
                                "contactType": "home",
                                "value": "Magic Dr,USA"
                            }
                        ],
                        "roles":
                        [
                            {
                                "personRoleId": 1,
                                "personKey": 2,
                                "role": "Manager"
                            },
                            {
                                "personRoleId": 2,
                                "personKey": 2,
                                "role": "QA"
                            }
                        ]
                    },
                    {
                        "Id": 1,
                        "givenName": "ajith",
                        "lastName": "vitharana",
                        "age": 25,
                        "contactInfos":
                        [
                            {
                                "InfoId": 1,
                                "department": 1,
                                "contactType": "email",
                                "value": "ajith@abc.org"
                            },
                            {
                                "InfoId": 2,
                                "department": 1,
                                "contactType": "mobile",
                                "value": 111111111
                            },
                            {
                                "InfoId": 3,
                                "department": 1,
                                "contactType": "home",
                                "value": "Magic Dr,USA"
                            }
                        ],
                        "roles":
                        [
                            {
                                "personRoleId": 1,
                                "personKey": 1,
                                "role": "Developer"
                            },
                            {
                                "personRoleId": 2,
                                "personKey": 1,
                                "role": "Engineer"
                            }
                        ]
                    }
                ]
            }
        }
    Como pueden ver se ha realizado sin mucha complicación una orquestación simple dentro del WSO2 ESB. Les dejo el código fuente que lo pueden importar en el WSO2 Developer Studio.

    viernes, 22 de enero de 2016

    WSO2 Data Service Server NPE con REST y JSON.

    image

    Haciendo algunas pruebas para un servicio de datos a manera de demo, estuvimos revisando sus facilidades para exponer funcionalidades de manera RESTful. Una vez configurada una operación de insersión que recibía varios datos y enviar el JSON que imaginamos debía enviarse nos topamos con un error NPE.

    Probamos con POX desde el RESTClient en firefox y sin problema.

    image

    Pero con JSON, convirtiendo el XML a JSON usando http://codebeautify.org/xmltojson no funcionaba.
    image


    En la consola se muestra el siguiente error:
    image


    Hicimos el cambio que pedía en el JSON:
    image

    Y sin problema. Faltaba incluirle al inicio del elemento raiz el string   _post.

    lunes, 11 de enero de 2016

    WSO2 DAS: fallo de autenticación en admin-dashboard

    image

    He estado trabajando en un escenario de integración que incluye las siguientes herramientas:
    • WSO2 Identity Server 5.0.0 como key manager y gestión de usuarios.
    • WSO2 API Manager 1.9.1 para la gestión de las APIs.

    La integración se hace bastante rápida y existe un manual bien detallado al respecto en la documentación oficial.

    Para ver el uso de las APIs quise integrar además el WSO2 Dashboard Application Server 3.0.0 a esta fiesta de herramientas así que me fui al manual del WSO2 API Manager y seguí los pasos descritos.

    Al intentar acceder al Admin Dashboard con las credenciales por defecto admin/admin me topo que no me permite autenticarme. Pruebo autenticarme en el WSO2 IS y funciona, en el DAS también funciona, en el Publisher y en el Store pues también funciona, así que ya es algo extraño.

    Activo el modo debug y a bucear en los logs y esto es lo que me encuentro.

    Invocación del WSO2 DAS al WSO2 IS para autenticar al usuario vía servicios web:
    Request:
    <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
                   xmlns:aut="http://authentication.services.core.carbon.wso2.org">
        <soap:Header/>
        <soap:Body>
            <aut:login>
                <aut:username>admin</aut:username>
                <aut:password>admin</aut:password>
                <aut:remoteAddress>localhost</aut:remoteAddress>
            </aut:login>
        </soap:Body>
    </soap:Envelope>
    Response:
    <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
        <soapenv:Body>
            <ns:loginResponse xmlns:ns="http://authentication.services.core.carbon.wso2.org">
                <ns:return>true</ns:return>
            </ns:loginResponse>
        </soapenv:Body>
    </soapenv:Envelope>


    Invocación para obtener el listado de roles del usuario y validar si se le permite el acceso:
    Request:
    <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
        <soapenv:Body>
            <ser:getRoleListOfUser xmlns:ser="http://service.ws.um.carbon.wso2.org">
                <ser:userName>admin</ser:userName>
            </ser:getRoleListOfUser>
        </soapenv:Body>
    </soapenv:Envelope>
    Response:
    <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
        <soapenv:Body>
            <ns:getRoleListOfUserResponse xmlns:ns="http://service.ws.um.carbon.wso2.org"
                    >
                <ns:return>Internal/admin</ns:return>
                <ns:return>Internal/subscriber</ns:return>
                <ns:return>Internal/WSO2.ORG_admin_DefaultApplication_PRODUCTION</ns:return>
                <ns:return>Internal/WSO2.ORG_admin_DefaultApplication_SANDBOX</ns:return>
                <ns:return>Internal/everyone</ns:return>
            </ns:getRoleListOfUserResponse>
        </soapenv:Body>
    </soapenv:Envelope>

    Como pueden apreciar el listado de roles que se devuelve es el siguiente:
    • Internal/admin
    • Internal/subscriber
    • Internal/WSO2.ORG_admin_DefaultApplication_PRODUCTION
    • Internal/WSO2.ORG_admin_DefaultApplication_SANDBOX
    • Internal/everyone

    Cuando  reviso el fichero donde se definen los roles con permito a admin-dashboard, el fichero site.json  aparece lo siguiente:
    Roles permitidos:
    • admin
    • subscriber
    {
        "theme" : {
            "base" : "default",
            "subtheme" : "modern"
        },
        "context" : "/admin-dashboard",
        "request_url":"READ_FROM_REQUEST",
        "tasksPerPage": 10,
        "allowedRole":"admin",
        "allowedRoles":"admin,subscriber",
        "workflows":{
         "applicationWorkFlowServerURL": "https://localhost:9446/services/",
         "subscriptionWorkFlowServerURL": "https://localhost:9446/services/",
         "signupWorkFlowServerURL": "https://localhost:9446/services/",
         "appRegistrationWorkFlowServerURL": "https://localhost:9446/services/"
    
        },
        "ssoConfiguration" : {
            "enabled" : "false",
            "issuer" : "API_WORKFLOW_ADMIN",
            "identityProviderURL" : "https://localhost:9448/samlsso",
            "keyStorePassword" : "",
            "identityAlias" : "",
            "responseSigningEnabled":"true",
            "keyStoreName" :""
        }
    }
    Tuve que adicionar el rol Internal/admin  al listado de allowedRoles para que mediera acceso a la aplicación.

    De esa manera ya tuve acceso y pude terminar la integración con el DAS. En próximas entradas estaré posteando la integración entre estas 3 herramientas.

    Espero les sea de utilidad.