SlideShare una empresa de Scribd logo
1 de 21
Descargar para leer sin conexión
Proyecto: análisis de capacidades de
  transformación de mensajes en
            JBossESB

                       Informe final




                 Pablo Pazos Gutierrez

   Taller de Sistemas de Información 4, Instituto de Computación
        Facultad de Ingeniería, Universidad de la República
Resumen
Hoy en día los sistemas informáticos orientados al dominio de la salud han crecido en importancia,
tamaño y complejidad, siendo la interoperabilidad entre los sistemas existentes, y también con nuevos
sistemas que se generen, el problema a resolver. Para intentar resolver los problemas de
interoperabilidad entre estos sistemas informático-clínicos existen distintos estándares propuestos por la
industria, dentro de estos HL7 es un grupo de estándares para resolver la interoperabilidad entre sistemas
de registro clínico orientado al intercambio de mensajes. El presente proyecto intenta explorar una
solución de comunicación entre sistemas que son compatibles con HL7 y sistemas que no lo son y que
manejan su propio formato de mensajes para interoperar con otros sistemas. Esta solución se basará en
un middleware JBossESB en donde se resolverán las diferencias entre los formatos de mensajes que
soportan los sistemas que intentan interoperar, de modo de que no sea necesario modificar un sistema
existente para hacerlo compatible con mensajes HL7, si no que dicha “compatibilización” se hará dentro
del ESB.
Planteo del problema
El objetivo principal del presente proyecto es investigar distintas opciones para implementar la
comunicación entre sistemas que se comuniquen mediante mensajes y que utilicen distintos formatos
para dichos mensajes, en particular se buscará la interoperación entre sistemas cuyos mensajes sigan el
estándar HL7 (*) y sistemas que utilicen otro formato de mensajes distinto a HL7. El objetivo es que
ninguno de los sistemas deba adaptar su formato de mensajes al formato del otro sistema, es decir que la
conversión entre los distintos sistemas de mensajes será realizada dentro de un ESB. Dicho ESB
manejará los distintos aspectos referentes a la comunicación entre los sistemas. Este enfoque de manejo
de transformaciones entre distintos formatos de mensajes en el propio ESB permite que los sistemas
existentes no necesiten ser modificados para poder interactuar con otros sistemas compatibles con HL7.

El ESB que se estará probando es JBossESB, un subproyecto dentro de JBoss. Sobre JBossESB se
desea relevar y probar las distintas capacidades de transformación entre formatos de mensajes y también
relevar las distintas capacidades de ruteo de mensajes con las que cuente JBossESB.

La siguiente figura muestra opciones de transformación de mensajes entre sistemas. En la opción
“clásica” se agrega un componente dentro del mismo sistema para que realice la estandarización de sus
mensajes a HL7. En la opción centrada en “ESB” la estandarización de los mensajes se realiza en el ESB
y es transparente a ambos sistemas, este es el enfoque que se intentará seguir.




                         Figura 1: opciones de estandarización de mensajes entre sistemas

(*) HL7 es un conjunto de estándares de comunicación orientados a mensajes, para el dominio de la salud. Los
mensajes están basados en el modelo de referencia de HL7 llamado RIM por sus siglas en inglés. Estos mensajes se
utilizan para comunicar información clínica y demográfica de pacientes entre sistemas, como por ejemplo: resultados
de estudios, medidas de presión de sangre, datos personales, etc.
Introducción a JBossESB
JBossESB es la solución de middleware para comunicación del stack de proyectos JBoss. JBossESB
sirve como infraestructura de comunicación para otros proyectos como jBMP, la solución de BPM del
stack JBoss. Con JBossESB se pueden definir servicios que consisten en una serie de acciones que se
ejecutan en secuencia llamado “pipeline” de acciones. Estos servicios pueden tener diversos puntos de
entrada a los cuales se puede acceder mediante distintos protocolos de comunicación, por ejemplo
mediante mensajería JMS, FTP, o vía Web Services, entre otros. La siguiente imagen muestra un ejemplo
de un servicio con su pipeline de acciones al cual se accede mediante el protocolo FTP y termina
ejecutando lógica de negocio. [1]




                                 Figura 2: Acciones en un servicio del ESB


El pipeline de acciones se parece mucho al estilo de arquitectura “tubos y filtros”, donde un mensaje es
pasado por cada acción, las cuales realizan algún tipo de transformación en los datos del mensaje, y el
resultado queda disponible para la siguiente acción. Es necesario diferenciar los conceptos de “mensaje
del ESB” [2] y “mensaje”. El ESB utiliza un mensaje interno para transportar los mensajes que le son
enviados, ese es el “mensaje del ESB”. El “mensaje del ESB” podría transportar múltiples mensajes
distintos dentro del ESB, y las acciones podrías acceder a diferentes mensajes para obtener datos o
modificarlos. Por ejemplo, el mensaje del ESB podría contener varios mensajes XML distintos en su Body.
Para el caso del taller, el mensaje del ESB contendrá solo un mensaje XML en su Body.


El mensaje del ESB cuenta con los siguientes campos:

    •   Body: mantiene información arbitraria que puede ser agregada y modificada por el usuario y por
        las acciones del canal.
    •   Attachment: contiene información extra a la que aparece en el Body.
    •   Context: el contexto es la sección del mensaje que contiene información para manejar la sesión,
        transacciones, seguridad, etc.
    •   Fault: sirve para especificar distintas fallas que se podrían dar en la comunicación y devolver un
        mensaje acorde (es similar a una excepción).
    •   Header: es el cabezal del mensaje.
    •   Properties: mantiene propiedades arbitrarias del mensaje en la forma de un mapa <String,
        Object>.


En la figura 3 se muestra la arquitectura de JBossESB, con las diversas opciones de puntos de entrada al
ESB y las opciones de comunicación con componentes de más bajo nivel (lógica de negocio).
Figura 3: Arquitectura de JBossESB
Alternativas de transformación de mensajes
JBossESB utiliza como principal componente de transformación al proyecto Smooks. Smooks es un
componente de transformación que “vive” dentro de otro proyecto mayor relacionado con el
procesamiento y transformación de datos, el proyecto Milyn (Data Transformation and Análisis). [5][6][7]

Smooks ofrece transformaciones entre distintos formatos de mensajes, por ejemplo brinda transformación
desde y hacia: XML, EDI, Java (*), CSV, JSON, entre otros. Los mecanismos de transformaciones que
ofrece Smooks y que pueden ser de utilidad para este taller son:

          Transformaciones Java
          Transformaciones XSLT
          Transformaciones FreeMarker
          Transformaciones basadas en modelos (model-driven transformations)
          Transformaciones Java-Java mediante configuración Smooks (Java Bindings)


Los tipos de transformación a analizar serían ente los siguientes formatos (**):

          Transformación Java-Java
          Transformación XML-XML
          Transformación XML-Java [7.2]
          Transformación Java-XML [7.3]


Los mecanismos de transformación indican “como” es que se lleva a cabo la transformación, los tipos de
transformación indican “entre que” formatos se está transformando, es decir que el “tipo” de
transformación es independiente del “mecanismo” que se aplique para implementar la transformación.
Por ejemplo, se podría hacer una transformación XML-XML mediante XSLT o FreeMarker, o una
transformación Java-Java basada en modelos o mediante configuración Smooks.


(*) Cuando se menciona que un mensaje se encuentra en formato Java, se refiere a que el mensaje es una instancia
en memoria de un modelo de datos particular.

(**) La notación de los tipos de transformación es: formato_origen – formato_destino, por ejemplo: XML-Java, es la
notación de una transformación que toma un mensaje en formato XML y devuelve un mensaje en formato Java.




Mecanismos de transformación
Transformación Java
Este mecanismo de transformación es implementada directamente con lógica Java. La configuración es
mínima y la lógica hace todo el trabajo de transformación, el tipo de transformación puede ser Java-Java
o XML-XML. La transformación Java puede hacerse dentro de Smooks o directamente como una acción
del pipeline de acciones de un canal del ESB. Para implementar una acción en el ESB, es necesario crear
una clase que extienda a org.jboss.soa.esb.actions.AbstractActionPipelineProcessor, si la clase que
implementa dicha acción se llama ActionProcessor, el segmento de configuración del ESB necesario para
agregar dicha acción al pipeline de acciones de un servicio del ESB sería similar al siguiente:

<actions>
  ...
  <action class="paquete.ActionProcessor" name="ContentFilter"/>
  ...
</actions>

La propia implementación de la transformación dependerá del formato del mensaje de entrada y del
formato del mensaje de salida. Este mecanismo puede ser ventajoso cuando se necesiten hacer
transformaciones muy particulares o que necesiten poco código para ser implementadas, comparando
con otros mecanismos que para algún caso particular necesiten más código que la implementación
directa en Java.
Transformación XSL
En la transformación XSL el trabajo de transformación se configura mediante reglas XSL en un
documento XML. La configuración de Smooks es mínima, solo se necesita decir donde está el archivo
XSL con la transformación, y el intérprete XSL es el que ejecuta la transformación. También se puede
poner la transformación XSL directamente dentro del mismo archivo de configuración de Smooks, por lo
que no es obligatorio tener un archivo XSL aparte.

Ejemplo de configuración de Smooks para una transformación XSL:

<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.0.xsd">
    <resource-config selector="$document">
        <resource>/ConversionXSL/transformacion.xsl</resource>
    </resource-config>
</smooks-resource-list>


En las últimas versiones de JBossESB se ha agregado también la posibilidad de realizar transformaciones
XSL nativas, es decir, sin necesidad de utilizar Smooks para dicho propósito. Entonces con
transformaciones XSL nativas se utilizaría el intérprete XSL de JBossESB en lugar del intérprete XSL de
Smooks.


Ejemplo de transformación XSL nativa:

Fue creada una clase llamada XSLActionProcessor extiende la clase AbstractActionPipelineProcessor,
esto es para poder ser llamada como una acción cuando se ejecute el pipeline de acciones del servicio en
el ESB. En XSLActionProcessor se implementa la configuración, carga de la transformación XSL y
ejecución de la transformación.

El constructor de la clase oficia de operación de configuración de la transformación, que previamente a
que el ESB ejecute la acción XSLActionProcessor en el pipeline de acciones, configura la acción para su
correcta operación obteniendo el nombre del archivo donde se encuentra la transformación y el mensaje
del ESB que contiene el mensaje XML a ser transformado.

Luego, automáticamente, el ESB invoca al método “process”, que es donde se ejecuta la lógica de la
acción, en este caso, es donde se carga la transformación XSL, donde se realiza la transformación y
donde se coloca el resultado en el mensaje del ESB para que pueda ser accedido por la próxima acción
del pipeline.

El método “getStylesheet” se utiliza como auxiliar para cargar el archivo XSL (con la transformación)
desde el sistema de archivos. Luego se creó la clase XSLTransformer, que es en la que se realiza
efectivamente la transformación XLS.

public class XSLActionProcessor
       extends AbstractActionPipelineProcessor {

  private static Map<String, String> cache = new HashMap<String, String>();
  private String xsl;
  private MessagePayloadProxy payloadProxy;

  public XSLActionProcessor(ConfigTree configTree) {
    xsl = configTree.getAttribute("xsl");
    payloadProxy = new MessagePayloadProxy(configTree);
  }

  public Message process(Message message) throws ActionProcessingException {
    try {
      XSLTransformer transformer = new XSLTransformer();

       System.err.println("XSLActionProcessor INPUT: " + message);

       byte[] bytes = ((String) payloadProxy.getPayload(message)).getBytes();
       ByteArrayInputStream input = new ByteArrayInputStream(bytes);
String theXSL = getStylesheet(xsl);
          ByteArrayOutputStream output =
                   (ByteArrayOutputStream) transformer.transform(input, theXSL);

          message.getBody().add(output);

          return message;
        }
        catch (Exception e) {
          throw new ActionProcessingException(e);
        }
    }

  /**
    * Carga hoja de estilo XSL de un archivo o del cache.
    *
    * @return
    * @throws IOException
    */
  private String getStylesheet(String stylesheetFileName)
  throws IOException {
      String result = null;
      synchronized (cache) {
        result = cache.get(stylesheetFileName);
        if (result == null) {
          File file = new File(stylesheetFileName);
          if(!file.exists()) {
            throw new IllegalArgumentException("Input message file [" +
file.getAbsolutePath() + "] not found.");
          }
          result = FileUtil.readTextFile(file);
          cache.put(stylesheetFileName, result);
        }
        else {
          System.err.println("Stylesheet retrieved from cache");
        }
        return result;
      }
  }
}

public class XSLTransformer {
  private static TransformerFactory tf = TransformerFactory.newInstance();

    /**
      * Ejecuta la transformacion XSL.
      *
      * @param input stream con datos de entrada
      * @param xsl transformacion XSL (no el nombre del archivo es el contenido)
      * @return La informacion transformada
      * @throws TransformerException
      */
    public OutputStream transform(InputStream input,
                   String xsl) throws TransformerException
    {
        if (input == null || xsl == null)
          throw new IllegalArgumentException("input cannot be null");

        Transformer t = tf.newTransformer( new StreamSource(
                                           new StringReader(xsl) ) );

        ByteArrayOutputStream output = new ByteArrayOutputStream(4096);
        t.transform(new StreamSource(input), new StreamResult(output));

        return output;
    }
}
Transformaciones Java-Java mediante configuración Smooks
Este mecanismo de transformación se utiliza cuando se tiene una instancia de un modelo Java y se
quiere generar una instancia de otro modelo con la información que tiene el primer modelo. Existen dos
conceptos importantes llamados “Binding” y “Wiring”. “Binding” se utiliza para generar las instancias
simples de las clases del modelo destino, a las cuales se les setean los datos del modelo origen. “Wiring”
se utiliza para generar relaciones entre las instancias simples del modelo destino para formar una
estructura de datos completa. Ambas tareas se realizan mediante reglas de configuración de Smooks
basadas en XML. [7.1]

Una característica interesante es que para seleccionar los valores de los atributos del modelo origen se
utilizan expresiones XPath sobre un XML. Dicho XML es generado internamente por Smooks, a partir del
modelo de entrada, mediante XStream. XStream es una librería que permite serializar cualquier instancia
de modelo de datos a XML y volver del XML a la instancia. Entonces es necesario saber que forma tiene
el XML generado a partir del modelo de entrada para poder escribir las expresiones XPath.

Este mecanismo de transformación tiene varias restricciones, sobre todo en el modelo destino. En el
modelo origen no existen restricciones particulares, ya que en realidad la transformación se realiza
tomando la serialización a XML del modelo origen y no el propio modelo.

Para la transformación Java-Java es necesario que el modelo destino se comporte según las siguientes
reglas:

    •    Debe tener un constructor simple (sin argumentos).
    •    Debe tener setters públicos para las propiedades de cada clase. No es necesario seguir algún
         formato de nombres particular para estos métodos, pero se aconseja seguir el estándar de
         nombres para setters de Java.
    •    Setear una propiedad de forma directa no está soportado, es necesario hacerlo invocando al
         setter de la propiedad.

Si no se siguen estas reglas, el transformador Smooks configurado mediante XML no sabrá como
establecer los valores, extraídos del modelo origen, en el modelo destino.

El problema que presenta esto, es que en la transformación de un modelo “custom” en el modelo de
referencia de HL7 (RIM), se debe utilizar alguna implementación de RIM. JavaSIG es una librería para
generar y consumir mensajes HL7, pero su implementación no sigue las reglas impuestas por este
mecanismo de transformación, por lo que no es posible utilizar dicha implementación. Se hizo una prueba
de esto, constatándose la imposibilidad de generar una instancia del RIM mediante este mecanismo de
transformación.


Para resolver este problema se plantearon las siguientes alternativas:

    1.   Probar la transformación generando el RIM a partir de esquemas XSD mediante JAXB y probar
         utilizar esas clases.
    2.   No hacer la transformación mediante configuración XML, si no hacer una transformación
         directamente implementada en Java.
    3.   Modificar el RIM implementado en JavaSIG para que las clases sigan las reglas antes
         mencionadas.


    1. Utilizando JAXB y transformación Java-Java:

Se pudo generar un modelo de clases a partir de los esquemas XSD para los mensajes CDA provistos
por la especificación de HL7 mediante la librería JAXB. En el anexo “Prueba transformación Java-Java
BindingAndWiring” se comenta cómo se generó el modelo a partir del XSD utilizando JAXB. Uno de los
problemas que tiene este modelo de clases es que para las colecciones no tiene un método del tipo “add
to collection”, que es lo que necesita Smooks para generar la colección y agregarle elementos, las clases
que tienen atributos de tipo colección tienen un método get para la colección y luego se invoca el “add”
directamente sobre la colección. Para poder ejecutar una transformación mínima se tuvo que modificar
algunas clases que tenían atributos de tipo colección, agregando un método “addXXX” donde “XXX” es el
nombre del campo de tipo colección.

Un tema a tener en cuenta es que Smooks sirve para colocar el modelo origen en un modelo destino,
pero no se puede generar más modelo. Por ejemplo, si el modelo destino tiene más información que el
mensaje original, este tipo de transformación no permite generar el modelo extra. Una posible solución es
la de agregar la información faltante en una etapa posterior a la transformación Java-Java, por ejemplo
utilizando transformaciones XSL o templates FreeMarker. Esto sucede cuando se tiene un modelo
“custom” y se quiere llevar a un CDA, se pueden colocar los valores presentes en el modelo “custom” que
se correspondan en la estructura CDA, pero CDA necesita mucha más información, porque tiene una
estructura más compleja y muchos atributos que no existen en el modelo “custom”, esto es porque CDA
agrega información para poder hacer una interpretación semántica de los documentos CDA. Por ejemplo
existen muchos atributos con valores fijos que no pueden ser generados directamente con este
mecanismo de transformación. En el caso inverso no habría problemas, es decir pasar CDA a el modelo
“custom”, porque se toman del CDA solo los valores que se necesiten, los demás valores no serían
utilizados para generar la instancia del modelo “custom”.

En conclusión, esta prueba necesita gran cantidad de código de configuración para poder hacer la
transformación Java-Java mediante Binding y Wiring, y las restricciones sobre el modelo de salida lo
hacen poco flexible. Además la configuración es como implementar la transformación directamente en
Java, lo que no solo llevaría menos código, si no sería más flexible, ya que puedo utilizar la API que me
provea el modelo destino sin ninguna restricciones sobre los métodos que debe proveer.

En el anexo “Prueba transformación Java-Java BindingAndWiring” están las referencias de
implementación de la transformación probada y los resultados obtenidos.


    2. Implementar la transformación directamente en Java:

Esta opción no fue probada por ser considerada la opción más simple, ya que lo único que se necesita
hacer es generar una instancia del modelo destino, e ir pidiendo los valores a la instancia del modelo
origen y setear dichos valores en la instancia destino. Esta opción no tendría inconvenientes con la API
del modelo destino, al contrario del mecanismo de Bindings y Wirings que pone estrictas reglas sobre
dicha API. De modo que esta es una solución más genérica que la antes mencionada y también necesita
escribir menos código para ser implementada, la diferencia es que mientras aquí se escribe código Java,
en la opción anterior se escribían reglas en formato XML. Como conclusión, esta sería una buena opción
si se tiene un modelo de datos destino con una API que no cumple con las restricciones del método
anterior, o también si la estructura es muy compleja, cuanto más compleja es la estructura más reglas
deben ser escritas y cada regla lleva en promedio 8 líneas de código, si en una implementación Java se
necesitaran menos líneas que estas, al agregar atributos o relaciones, se necesitaría mucho menos
código para implementar la misma transformación.


    3. Modificar JavaSIG

Esta puede ser la opción más costosa, ya que la API de la implementación del RIM de JavaSIG es muy
particular, no solo habría que modificar decenas de clases, si no que habría que escribir gran cantidad de
reglas para poder realizar la transformación. Esta opción no se llevó a cabo por las razones mencionadas.

En este caso, implementar la transformación directamente en Java sería una mejor opción.
Transformación FreeMarker
En la transformación FreeMarker, la información de la transformación se encuentra en la configuración de
Smooks (definido mediante reglas FreeMarker) o también puede estar en un archivo aparte (los archivos
FreeMarker tienen extensión .FTL por FreeMarker Template). El formato en el que se especifica es el
marcado por FreeMarker y se puede acceder aquí: http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd,
es declarativo como el XSL pero parece menos verboso que este último, o sea, con menos código se
hace lo mismo.

FreeMarker es una herramienta de “templating” o aplicación de plantillas que sirve para recorrer un
archivo de texto (estructurado o no), extrayendo su información y generando un nuevo archivo te texto
(estructurado o no) con un formato distinto. FreeMarker es soportado por los creadores de Smooks, los
cuales lo prefieren sobre XSL.

Comparándolo con XSL, FreeMarker está hecho para transformación de texto en general, mientras que
XSL solo sirve para procesar texto estructurado en forma de árbol, como ser un archivo XML. Por otra
parte, FreeMarker tiene constructores basados en programación imperativa, mientras que XSL los
constructores están basados en programación funcional, esto se refiere a la característica de poder definir
funciones y variables en cada una de las herramientas, los desarrolladores de FreeMarker afirman que
esto es una ventaja porque la mayoría de los desarrolladores conocen la programación procedural-
imperativa, mientras que pocos conocen la programación funcional. FreeMarker también apunta a que
sea más fácil de aprender y entender que XSL. Obviamente la principal diferencia entre ambas
tecnologías es que XSL es un estándar y tiene diversas implementaciones, y FreeMarker una herramienta
Java.

Si bien se realizó una implementación de transformación utilizando FreeMarker, sería interesante poder
comparar más a fondo las opciones de transformación utilizando FreeMarker y XSL, y verificar cual es la
opción más simple de utilizar, la que posee más funcionalidades que ayuden a realizar transformaciones
según las características particulares de las transformaciones que se necesiten, si es necesario escribir
más o menos reglas de transformación, y evaluar la capacidad, características y estabilidad de cada
herramienta. Lo que si se constató es que en las pruebas, para lograr el mismo resultado en la
transformación XML custom a XML CDA, el trabajo que tomó hacer funcionar la transformación XSL fue
aproximadamente una semana, mientras que el trabajo que tomó hacer funcionar la transformación
completa con FreeMarker fueron alrededor de cuatro horas. También se pudo ver que el código necesario
para especificar la transformación XSL es aproximadamente tres veces más que el código necesario para
especificar el template FreeMarker. Obviamente esta es una comparación en solo una transformación
particular, por lo que no se puede derivar un resultado general y decir que estas diferencias se dan en
otras transformaciones.

Se realizó una implementación de una transformación de un mensaje XML “custom” a un mensaje XML
CDA, la documentación se encuentra en el documento anexo “Prueba transformación XML-XML
FreeMarker”.



Transformación basada en modelo
Por último, para las transformaciones basadas en modelos, es necesario definir un modelo de datos
intermedio entre la entrada y la salida, al cual se pueda mapear la entrada y desde el cual se pueda
generar la salida. El único código Java a implementar es dicho modelo de datos y la transformación se
especifica en la configuración de Smooks, donde se definen las correspondencias del formato de entrada
al modelo y del modelo al formato de salida. La ventaja de este esquema es la posibilidad de definir
múltiples formatos de entrada y salida pudiendo hacer combinaciones de éstos sin necesidad de
especificar todas las combinaciones entrada-salida, solo se especifican las diferentes combinaciones
entrada-modelo y modelo-salida, luego automáticamente se obtienen todas las combinaciones entrada-
modelo-salida. Para la transformación Java-Java se utiliza la notación que se utiliza en la transformación
basada en modelos para especificar dicha transformación. Esta notación está basada en “bindings” que
toman un valor de la fuente y lo ponen en un lugar del destino, en el caso Java-Java, esto es hacer “gets”
en el modelo fuente y “sets” en el modelo destino.
Propuesta de transformación Java-Java híbrida
Si bien se analizaron varias opciones de transformación entre instancias de modelos Java, hasta ahora no
se analizó la posibilidad de mezclar otros mecanismos de transformación para lograrlo. Como se comentó
en la respectiva sección, para realizar la transformación Java-Java, Smooks internamente serializa la
instancia del modelo origen a un XML mediante la librería XStream.


Transformación Java-Java mediante FreeMarker + XStream

Esta opción utilizaría la transformación FreeMarker y la funcionalidad de convertir XML a una instancia y
viceversa de XStream, los pasos serían los siguientes:

    1.   Recibir una instancia del modelo origen.
    2.   Registrarla como bean en el mapa de beans del contexto de la transformación Smooks.
    3.   Tener un template FreeMarker que ejecuta la transformación obteniendo los datos desde el bean
         registrado con el modelo original y generando el XML del modelo destino, siguiendo el formato
         de XStream de una instancia válida de dicho modelo.
    4.   Mediante XStream, levantar el XML generado y convertirlo a la instancia del modelo destino en
         memoria.




                         Figura 4: Transformación Java-Java con FreeMarker+XStream


Aunque esta opción es similar a la prueba de transformación XML-XML mediante FreeMarker, los pasos
de transformación no son los mismos (por lo menos no en el mismo orden). La documentación completa
sobre la transformación XML-XML mediante FreeMarker se encuentra en el documento anexo llamado
“Prueba transformacion XML-XML FreeMarker”.

Otra opción sería teniendo una transformación XSL en lugar del template FreeMarker para generar el
XML de salida compatible con XStream para que este pueda generar una instancia del modelo de salida.

Distintas opciones de transformación se pueden generar mezclando los mecanismos ya vistos, también
se pueden utilizar otras herramientas como XStream, esto posibilita la realización de distintos pasos de
transformación de uno o más mensajes de forma simultánea, donde se pueden realizar distintas
transformaciones mediante distintos mecanismos para diferentes secciones de los mensajes que se
procesen.
Especificación Técnica de Implementación de HL7
Si bien todos los mecanismos vistos hasta el momento son válidos para definir transformaciones entre
distintos formatos de mensajes, siendo uno de los formatos HL7, la mayoría de los mismos no cumplen
con la especificación técnica de implementación de HL7 (ITS por sus siglas en inglés). La ITS es la forma
estándar en la que dos sistemas deberían interoperar utilizando mensajes HL7. En la misma se definen
una serie de transformaciones que son necesarias para que dos sistemas que tengan su propio modelo
de datos, lo puedan hacer corresponder en el RIM (modelo de referencia de HL7). Estas
correspondencias de su modelo de datos al RIM y viceversa garantiza que el intercambio de datos será
semánticamente correcto, y esto habilita a los sistemas para poder enviar y recibir mensajes HL7, que no
son más que instancias de RIM serializadas a XML. En la siguiente imagen se muestran los pasos
definidos por la ITS:




                             Figura 5: Especificación Técnica de Implementación


El escenario que plantea la ITS es el de dos sistemas, con un sistema emisor y otro receptor. Cada uno
con un modelo particular de datos, más algún mecanismo que ejecute transformaciones entre esos datos
e instancias de RIM. Los pasos que sigue la ITS son:

    1.   El sistema “emisor” tiene los datos que desea enviar al receptor en su propio modelo.
    2.   Mediante una transformación, genera una instancia de RIM a la cual le incluye los datos de su
         modelo.
    3.   Ahora se tiene una instancia de RIM con todos los datos que se quieren enviar. Esta instancia no
         es más que el mensaje que se va a enviar, en memoria.
    4.   Mediante algún mecanismo que serialice modelos RIM, se genera un mensaje XML válido según
         los esquemas XSD distribuidos por HL7 (dependiendo del tipo de mensaje, el XSD puede variar).
    5.   Ahora el mensaje en formato XML es enviado a través de un canal hacia el sistema “receptor”.
    6.   El “receptor” recibe el XML y reconstruye la instancia de RIM a partir del mensaje XML.
    7.   Se obtiene una instancia de RIM análoga a la que se obtuvo en el paso 3 dentro del sistema
         “emisor”.
    8.   A través de una transformación definida en el sistema “receptor”, se genera una instancia del
         modelo de datos de dicho sistema a partir de los datos contenidos en la instancia de RIM.
    9.   Se tiene la instancia del modelo de información del sistema “receptor”, que es semánticamente
         equivalente a la instancia del sistema de información del sistema “emisor” (la información que
         este sistema quería transmitir).
Propuesta de transformación siguiendo la HL7 ITS
Por lo mencionado anteriormente resulta interesante plantear una solución de transformación que cumpla
con la ITS y utilice el ESB para realizar las transformaciones necesarias.




                   Figura 6: Arquitectura del problema de envío y transformación de mensajes


En el caso de que el Sistema A (emisor) envíe mensajes “custom” al Sistema B (receptor) el cual los
recibe en formato HL7, donde las comunicaciones se realizan mediante Web Services, en el ESB se haría
el pasaje del modelo SOAP a una instancia del modelo de datos del Sistema A. Luego, dentro del ESB se
hace la conversión entre ese modelo de datos y el modelo RIM, por último se genera el XML a partir de la
instancia RIM obtenida (esta transformación es automática utilizando una librería como JavaSIG). Ese
XML es el que es enviado al Sistema B.

Para el caso inverso, donde el Sistema B envía un XML HL7 al ESB, el ESB lo transforma a una instancia
del RIM (esta transformación es automática utilizando una librería como JavaSIG). Luego, con los datos
del modelo RIM se genera el modelo de datos que espera recibir el Sistema A, ese modelo es enviado
directamente al Sistema A mediante Web Services SOAP (SOAP se encarga de hacer la serialización a
XML).
Relevamiento de opciones para ruteo de mensajes
El esquema general de procesamiento de un mensaje recibido es similar al estilo de arquitectura de
“tubos y filtro”, donde un mensaje es recibido por un filtro, procesado y luego puesto en un tubo hacia otro
filtro. En este esquema debe haber algún mecanismo que decida en que tubo se coloca la salida de cada
filtro, porque puede haber varios tubos distintos de donde elegir. La selección del tubo en el que se
colocará la salida del filtro es llamado “ruteo” del mensaje, y se realiza mediante la verificación de un
conjunto de condiciones, lo que permite tomar la decisión de cual será el tubo destino, entonces la ruta
del mensaje será el conjunto de tubos y filtros por los que ha pasado el mismo.

JBossESB ofrece cuatro tipos de ruteo:

    1.   Aggregator: es una implementación del patrón “Aggregator” de los “Enterprise Integration
         Patterns”, el mismo se utiliza para combinar información de varios mensajes distintos. [9]

    2.   Content Based Router (CBR): acción de ruteo basado en el contenido de los mensajes y la
         definición de reglas.

    3.   Static Router: versión simplificada del Content Based Router que no soporta reglas de ruteo
         basadas en contenido.

    4.   Notifier: envía notificaciones a una lista de destinos configurable. Está implementada como
         ejemplo, no debería ser usada directamente, si no que debería ser extendida por el usuario.


Considerando los casos de prueba planteados para realizar en el presente trabajo (*), el “Content Based
Router” podría ser de gran utilidad porque podría detectar que tipo de mensaje está recibiendo el ESB, y
en base a reglas que se definan, rutear el mensaje al servicio correcto que pueda procesarlo. El CBR
puede ser utilizado para enrutar el mensaje al próximo destino basándose en el contenido del mensaje.
Por defecto el ESB utiliza “JBossRules” como motor de evaluación de reglas, aunque puede ser
configurado para utilizar otro motor.

Para utilizar el CBR se debe levantar el servicio de CBR. Luego se deben definir un conjunto de reglas
(**). Para la definición de reglas sobre mensajes XML es conveniente utilizar evaluaciones basadas en
XPath, especialmente diseñado para poder extraer valores presentes en el XML de forma sencilla.

Una vez que se tiene el CBR andando, se le pueden enviar mensajes. Para esto se debe agregar dicho
envío como una acción en algún lugar del pipeline de acciones.


Luego existen tres modos de ejecución:

    1.   routeAndDeliver: rutea y entrega el mensaje al(los) destino(s)

    2.   route: rutea el mensaje y retorna un mensaje con una lista de destinos adjuntos a él.

    3.   deliver: simplemente entrega el mensaje, un mensaje ruteado previamente será entregado a
         su(s) destino(s).



(*) Los casos de prueba se mencionan en el documento “TSI4 Anexo 1 – Bitácora.doc”, en la sección “Etapa 2:
Definición de la arquitectura y casos de prueba”.

(**) Estas pueden ser creadas mediante JBossIDE [Eclipse+JBossTools] con el plugin de JBossRules.
Descripción del prototipo logrado
Para la implementación del prototipo se eligió la transformación XML-XML mediante XSL. El prototipo
define dos canales, uno que recibe un mensaje XML “custom”, mediante un punto de entrada expuesto
mediante Web Services, y genera un mensaje CDA que es enviado a un sistema externo mediante Web
Services, el otro recibe un mensaje CDA, mediante un punto de entrada expuesto mediante Web
Services, y genera un mensaje XML “custom” que es enviado a otro sistema mediante Web Services. El
prototipo fue implementado en el proyecto “ESBWS” incluido en el directorio de código de la entrega del
taller.

Los pipelines de acciones de ambos canales son similares:




                                    Figura 7: Canales en el ESB prototipo.


Lista de acciones y su funcionalidad:

    •    print-before: se encarga de mostrar en pantalla el mensaje entrante.

    •    ContentFilter: transforma el mensaje en el formato de entrada al formato de salida.

    •    print-after: muestra en pantalla el mensaje de salida.

    •    testStore: almacena el mensaje de salida en el filesystem.

    •    request-ws-processor: se encarga de preparar la llamada al Web Service, especificando que
         método del servicio será invocado y con que parámetros.

    •    soap-ws-client: esta acción invoca al Web Service.

    •    response-ws-processor: muestra en pantalla el resultado de la invocación al Web Service.


Algunas acciones tienen asociadas una clase Java que es la que implementa la acción, otras poseen una
implementación por defecto provista por el ESB, este último caso es el de las acciones: print-before, print-
after y soap-ws-client.
Descripción de la implementación de las acciones
Acción ContentFilter
Esta acción está asociada a la clase XSLActionProcessor, que es la clase en la que se implementó dicha
acción. La funcionalidad básica de esta clase es cargar la transformación XSL del filesystem, obtener el
mensaje XML a transformar (el cual se encuentra en el body del mensaje del ESB), y aplicar
efectivamente la transformación al mensaje. El mensaje XML resultante se coloca en el mensaje del ESB,
así la próxima acción en el pipeline de acciones puede acceder al mensaje transformado.

A continuación se presenta la implementación de la clase XSLActionProcessor, la cual ejecuta una
transformación XSL nativa sobre un mensaje XML. Esta acción es utilizada en ambos canales, al que se
envía un mensaje custom y al que se envía un mensaje HL7, como implementación de sus respectivas
acciones ContentFilter. Obviamente, en cada canal debe implementar una transformación distinta, esto se
lleva a cabo mediante la configuración de una transformación XSL distinta para cada caso.

Todas las acciones en el pipeline deben extender la clase AbstractActionPipelineProcessor [4], o su
superclase AbstractActionLifecycle [3], la cual define el método “process” que será descrito más adelante.

public class XSLActionProcessor
       extends AbstractActionPipelineProcessor {

El campo “cache” es utilizado para almacenar la transformación XSL que es levantada desde el
filesystem, de manera que se tenga que hacer una sola lectura del filesystem y en posteriores ejecuciones
se obtiene el XSLT desde el cache.

  private static Map<String, String> cache = new HashMap<String, String>();

El campo “xsl” es el que almacena el nombre del archivo XSL que deberá ser leído.

  private String xsl;

El campo “payloadProxy” se utiliza para acceder a los contenidos del mensaje del ESB.

  private MessagePayloadProxy payloadProxy;

El constructor recibe la configuración del ESB con toda la información necesaria para que la acción pueda
ejecutarse correctamente. Por ejemplo se extrae el nombre de la transformación XSL que hay que leer, y
trae el mensaje del ESB de donde se leerá el mensaje XML a ser transformado.

  public XSLActionProcessor(ConfigTree configTree) {
    xsl = configTree.getAttribute("xsl");
    payloadProxy = new MessagePayloadProxy(configTree);
  }

El método “process” es donde se realiza la transformación.

 public Message process(Message message)
        throws ActionProcessingException {


Aquí se crea la instancia del transformador, donde se realiza la transformación.

     try {
       SAXONTransformer transformer = new SAXONTransformer();
       System.err.println("XSLActionProcessor INPUT: " + message);


Se leen los bytes del mensaje XML de entrada y ponen dentro de la variable “input”.

    byte[] bytes = ((String) payloadProxy.getPayload(message)).getBytes();
    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
Se lee el archivo de la transformación del filesystem, o desde cache si ya fue cargado, y se pone su
contenido en la variable “theXSL”.

          String theXSL = getStylesheet(xsl);


Mediante el transformador, se ejecuta la transformación XSL sobre el input, obteniéndose el resultado en
la variable “output”.

          ByteArrayOutputStream output =
                  (ByteArrayOutputStream) transformer.transform(input, theXSL);

          System.err.println("XSLActionProcessor OUTPUT: " + output);


El mensaje obtenido se agrega al mensaje del ESB para que quede disponible para la siguiente acción
del pipeline.

          message.getBody().add(output);
          return message;
        }
        catch (Exception e) {
          throw new ActionProcessingException(e);
        }
    }


El método “getStylesheet” se utiliza para leer el archivo que contiene la transformación desde el
filesystem, o desde el cache si es que ya ha sido leído.

    private String getStylesheet(String stylesheetFileName)
                   throws IOException {

    String result = null;
    synchronized (cache) {


Se intenta obtener el contenido de la transformación desde el cache.

        result = cache.get(stylesheetFileName);

        if (result == null) {
          System.err.println("Loading stylesheet from file "+stylesheetFileName);


Se lee el archivo de disco.

          File file = new File(stylesheetFileName);
          if(!file.exists()) {
            throw new IllegalArgumentException("Input message file [" +
              file.getAbsolutePath() + "] not found.");
          }
          result = FileUtil.readTextFile(file);


Se agrega el contenido leído al cache para acelerar futuras cargas.

          cache.put(stylesheetFileName, result);
        }
        else {
          System.err.println("    Stylesheet retrieved from cache");
        }

        return result;
    }
}
Acción testStore
Esta acción almacena el mensaje transformado en el filesystem del sistema donde esté corriendo el ESB.
La misma está implementada en la clase StoreMessage.

Como toda acción del pipeline, la clase StoreMessage extiende la clase AbstractActionPipelineProcessor.

public class StoreMessage extends AbstractActionPipelineProcessor {
  private MessagePayloadProxy payloadProxy;

    public StoreMessage(ConfigTree config) {
      payloadProxy = new MessagePayloadProxy(config);
    }


El método “appendToFile” toma cualquier contenido en forma de String y lo agrega al final de un archivo,
conservando su contenido actual. El archivo es creado si es que no existe.

    public static void appendToFile(String dir, String fileName, String content)
    {
      BufferedWriter bw = null;
      try {
        bw = new BufferedWriter(new FileWriter(dir + "/" + fileName, true));
        bw.write(content);
        bw.newLine();
        bw.flush();
      } catch (IOException ioe) {
        ioe.printStackTrace();
      } finally {                       // always close the file
        if (bw != null) try {
                bw.close();
        } catch (IOException ioe2) { /* just ignore it */ }
      } // end try/catch/finally
    }


El método “process” genera un nombre de archivo basado en la fecha actual y una serie de números
random, de forma de generar un archivo diferente a los demás. Luego obtiene el contenido del mensaje a
almacenar, esto lo saca del mensaje del ESB a través del payloadProxy que se utiliza para acceder a los
datos del mensaje del ESB. Por último se llama al método “appendToFile” para generar el archivo con el
contenido obtenido.

    public Message process(Message message) throws ActionProcessingException
    {
      Date d = new Date();
      String name = ""+(d.getYear()+1900)+(d.getMonth()+1)+d.getDate();
      try {
        System.err.println("PayloadMessageClass: "+
            payloadProxy.getPayload(message).getClass());

          byte[] btextToStore = ((ByteArrayOutputStream)
                             payloadProxy.getPayload(message)).toByteArray();

         System.err.println( "textToStore: " + new String(btextToStore) );
         String textToStore = new String(btextToStore);
         appendToFile ("./", "message_"+name+"["+(Math.random()*5)+"].xml",
                       textToStore.toString());
        }
        catch (MessageDeliverException e) {
          throw new ActionProcessingException(e);
        }
        return message;
    }
}
Acción request-ws-processor
Esta acción se utiliza para preparar la llamada al Web Service al que se enviará el mensaje transformado,
esto está implementado en la clase MyRequestAction. Esta clase MyRequestAction extiende a la clase
AbstractActionLifecycle [3]. Antes se vio que las acciones extendían a la clase
AbstractActionPipelineProcessor, esto es porque AbstractActionPipelineProcessor a su vez extiende a
AbstractActionLifecycle.

public class MyRequestAction extends AbstractActionLifecycle {
  protected ConfigTree _config;
  private MessagePayloadProxy payloadProxy;

En el constructor se recibe la configuración del ESB y el estado actual del mensaje.

    public MyRequestAction(ConfigTree config) {
      _config = config;
      payloadProxy = new MessagePayloadProxy(config);
    }

El método “process” es quien obtiene el mensaje a enviar y configura los parámetros para la invocación al
Web Service. En este caso se obtiene el mensaje XML transformado, que está dentro del mensaje del
ESB. Luego se agrega a un mapa de parámetros mediante la clave “sendMessage.message”, esto quiere
decir que se va a invocar al método “sendMessage” del Web Service, en donde existe un parámetro
llamado “message” que tendrá como valor el mensaje XML transformado.

    public Message process(Message message) throws Exception {
      byte[] btext = ((ByteArrayOutputStream)
                  payloadProxy.getPayload(message)).toByteArray();

        String msgBody = new String(btext);
        HashMap requestMap = new HashMap();

        // add paramaters to the web service request map
        // Esto es: metodo.paramName
        requestMap.put("sendMessage.message", msgBody);
        message.getBody().add(requestMap);
        System.out.println("Request map is: " + requestMap.toString());

        return message;
    }
}

Acción response-ws-processor
Esta acción simplemente muestra en pantalla el resultado de la invocación al Web Service. Está
implementada en la clase MyResponseAction, la cual es análoga a la anterior, solo que en el método
“process” se obtiene el resultado de la invocación al Web Service desde el mensaje del ESB y se hace un
print del mismo a la consola.

public class MyResponseAction extends AbstractActionLifecycle {

    protected ConfigTree _config;

    public MyResponseAction(ConfigTree config) {
        _config = config;
    }

    public Message process(Message message) throws Exception {
      Map responseMsg = (Map)message.getBody().get(Body.DEFAULT_LOCATION);

        System.out.println("Response Map is: " + responseMsg);

        return message;
    }
}
Trabajo futuro y mejoras
    1.   Transformación XSL genérica: sería el generar una transformación XSL que sea equivalente al
         modelo CDA, de esa forma se podría consumir o producir cualquier CDA válido. Posteriormente
         a esta prueba se buscarían las conclusiones de si es posible crear tal transformación, de que tan
         costosa sería crearla (comparándola con otros tipos de transformaciones), verificar si tiene
         problemas de performance y probar varios casos con distintos CDA.
    2.   Ruteo del mensaje: si bien en el presente trabajo se relevaron las opciones de ruteo que ofrece
         JBossESB, no se agregó la funcionalidad de ruteo al prototipo. Sería interesante probar, por lo
         menos, el ruteo basado en contenido, de forma que si se recibe un mensaje CDA dependiendo
         de sus características sea enviado a un determinado canal del ESB (o a un servicio externo al
         ESB) para ser procesado total o parcialmente en dicho canal.
    3.   Solicitar información a servicios externos: un posible caso es que el mensaje entrante tenga
         menos información de la necesaria para generar el mensaje saliente, sería interesante que,
         basándose en la información que si se tiene, se consulten determinados servicios que provean la
         información faltante, de forma de contar con toda la información necesaria para generar el
         mensaje saliente.
    4.   Comparar en profundidad las alternativas de utilizar XSL y FreeMarker como opciones de
         transformación de mensajes, probando y comparando las funcionalidades que sean útiles según
         los casos particulares de prueba, con cual alternativa se necesita escribir menos código, cual es
         más sencilla de usar y aprender, etc.


Referencias
[1] Proyecto JBossESB
http://www.jboss.org/jbossesb/

[2] Mensaje de JBossESB
http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/message/package-
summary.html

[3] Clase AbstractActionLifecycle
http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/actions/AbstractActionLifecycle.
html

[4] Clase AbstractActionPipelineProcessor
http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/actions/AbstractActionPipelineP
rocessor.html

[5] Message Transformation on JBossESB
http://www.jboss.org/community/docs/DOC-11397

[6] Smooks User Guide
http://docs.codehaus.org/display/MILYN/Smooks+User+Guide

[7] Smooks Examples
http://www.smooks.org/documentation/documentation-smooks-1-1-x/examples

[7.1] Smooks Example JavaToJava:
http://docs.codehaus.org/display/MILYN/Smooks+Example+-+java-to-java

[7.2] Smooks Example XMLToJava:
http://docs.codehaus.org/display/MILYN/Smooks+Example+-+xml-to-java

[7.3] Smooks Example JavaToXML:
http://svn.codehaus.org/milyn/trunk/smooks-examples/java-to-xml/

[8] Componente Smooks de JavaBeans
http://milyn.codehaus.org/javadoc/v1.0/smooks-cartridges/javabean/

[9] Enterprise Integration Patterns
http://www.enterpriseintegrationpatterns.com/eaipatterns.html

Más contenido relacionado

Similar a Análisis de capacidades de transformacion de mensajes en jboss-esb

Modelado de sistemas software
Modelado de sistemas softwareModelado de sistemas software
Modelado de sistemas softwareJavier Ramírez
 
Diferencia entre html xml
Diferencia entre html xmlDiferencia entre html xml
Diferencia entre html xmlRobertLopezCh
 
Arquitectura de integración de servicios
Arquitectura de integración de serviciosArquitectura de integración de servicios
Arquitectura de integración de serviciosCoatzozon20
 
Web services-con-php
Web services-con-phpWeb services-con-php
Web services-con-phpLinkser SA.
 
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...Juan José Ogarrio
 
Guía estratégica de migración de WAS a JBoss
Guía estratégica de migración de WAS a JBossGuía estratégica de migración de WAS a JBoss
Guía estratégica de migración de WAS a JBossSergio Montoro Ten
 
Aplicaciones en capas1
Aplicaciones en capas1Aplicaciones en capas1
Aplicaciones en capas1mariana
 
FORMATO XML
FORMATO XMLFORMATO XML
FORMATO XMLLoncin
 
Windows communication foundation (wcf)
Windows communication foundation (wcf)Windows communication foundation (wcf)
Windows communication foundation (wcf)Vivi Marquez
 
Windows communication foundation (wcf)
Windows communication foundation (wcf)Windows communication foundation (wcf)
Windows communication foundation (wcf)Vivi Marquez
 
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptxFabianAndresNuezPinz
 

Similar a Análisis de capacidades de transformacion de mensajes en jboss-esb (20)

Modelado de sistemas software
Modelado de sistemas softwareModelado de sistemas software
Modelado de sistemas software
 
Diferencia entre html xml
Diferencia entre html xmlDiferencia entre html xml
Diferencia entre html xml
 
Programacion
ProgramacionProgramacion
Programacion
 
Arquitectura de integración de servicios
Arquitectura de integración de serviciosArquitectura de integración de servicios
Arquitectura de integración de servicios
 
Web services-con-php
Web services-con-phpWeb services-con-php
Web services-con-php
 
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...
Sio2009 Eq10 L10 Exp Gold Bernstein & Ruh Cap8 Information Integration Archit...
 
Guía estratégica de migración de WAS a JBoss
Guía estratégica de migración de WAS a JBossGuía estratégica de migración de WAS a JBoss
Guía estratégica de migración de WAS a JBoss
 
O9ebxml
O9ebxmlO9ebxml
O9ebxml
 
02 - Servicios SOAP.pptx
02 - Servicios SOAP.pptx02 - Servicios SOAP.pptx
02 - Servicios SOAP.pptx
 
Aplicaciones en capas1
Aplicaciones en capas1Aplicaciones en capas1
Aplicaciones en capas1
 
FORMATO XML
FORMATO XMLFORMATO XML
FORMATO XML
 
Windows communication foundation (wcf)
Windows communication foundation (wcf)Windows communication foundation (wcf)
Windows communication foundation (wcf)
 
Windows communication foundation (wcf)
Windows communication foundation (wcf)Windows communication foundation (wcf)
Windows communication foundation (wcf)
 
Servicios web
Servicios webServicios web
Servicios web
 
7 analisis
7 analisis7 analisis
7 analisis
 
7 analisis (caso de uso)
7 analisis  (caso de uso)7 analisis  (caso de uso)
7 analisis (caso de uso)
 
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx
_Concepto de interfaz_interfaz_interfaz_interfaz_interfaz_.pptx
 
Base de datos
Base  de datosBase  de datos
Base de datos
 
Resumen Capitulo 3
Resumen Capitulo 3Resumen Capitulo 3
Resumen Capitulo 3
 
Cap 3
Cap 3Cap 3
Cap 3
 

Más de Pablo Pazos

Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Pablo Pazos
 
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Pablo Pazos
 
openEHR presentacion informativa 2017
openEHR presentacion informativa 2017openEHR presentacion informativa 2017
openEHR presentacion informativa 2017Pablo Pazos
 
CaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresCaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresPablo Pazos
 
CaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludCaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludPablo Pazos
 
CaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludCaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludPablo Pazos
 
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...Pablo Pazos
 
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Pablo Pazos
 
Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Pablo Pazos
 
Design and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRDesign and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRPablo Pazos
 
openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015Pablo Pazos
 
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Pablo Pazos
 
openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015Pablo Pazos
 
openEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadopenEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadPablo Pazos
 
Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Pablo Pazos
 
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Pablo Pazos
 
Developing openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesDeveloping openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesPablo Pazos
 
Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Pablo Pazos
 
Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Pablo Pazos
 
CaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadCaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadPablo Pazos
 

Más de Pablo Pazos (20)

Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018Microservicios y plataformas abiertas en salud - JIAP 2018
Microservicios y plataformas abiertas en salud - JIAP 2018
 
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
Apoyo a la toma de decisiones clínicas con openEHR y SNOMED CT - casos de uso...
 
openEHR presentacion informativa 2017
openEHR presentacion informativa 2017openEHR presentacion informativa 2017
openEHR presentacion informativa 2017
 
CaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándaresCaboLabs - Workshop de interoperabilidad usando estándares
CaboLabs - Workshop de interoperabilidad usando estándares
 
CaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en saludCaboLabs - Estándares e interoperabilidad en informática en salud
CaboLabs - Estándares e interoperabilidad en informática en salud
 
CaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en saludCaboLabs - Proyectos de informatica en salud
CaboLabs - Proyectos de informatica en salud
 
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
EHRServer - Plataforma Abierta para Gestionar y Compartir Datos Clínicos Esta...
 
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
Presentación del Taller de Interoperabilidad con Mirth Connect y HL7
 
Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...Presentacion del programa de formacion profesional de Informática en Salud, E...
Presentacion del programa de formacion profesional de Informática en Salud, E...
 
Design and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHRDesign and implementation of Clinical Databases using openEHR
Design and implementation of Clinical Databases using openEHR
 
openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015openEHR Developers Workshop at #MedInfo2015
openEHR Developers Workshop at #MedInfo2015
 
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
Towards the Implementation of an openEHR-based Open Source EHR Platform (a vi...
 
openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015openEHR training in Latin America - Pablo Pazos #MedInfo2015
openEHR training in Latin America - Pablo Pazos #MedInfo2015
 
openEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidadopenEHR: aspectos de interoperabilidad y mantenibilidad
openEHR: aspectos de interoperabilidad y mantenibilidad
 
Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...Generación automática de interfaces de usuario para sistemas de información c...
Generación automática de interfaces de usuario para sistemas de información c...
 
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
Presentacion InfoLac 2014 - generacion de interfaz de usuario para sistemas d...
 
Developing openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalitiesDeveloping openEHR EHRs - core functionalities
Developing openEHR EHRs - core functionalities
 
Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013Taller de Modelado Clínico con openEHR - HIBA 2013
Taller de Modelado Clínico con openEHR - HIBA 2013
 
Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013Taller de implementación de openEHR - HIBA 2013
Taller de implementación de openEHR - HIBA 2013
 
CaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidadCaboLabs: expertos en informática médica, estándares e interoperabilidad
CaboLabs: expertos en informática médica, estándares e interoperabilidad
 

Análisis de capacidades de transformacion de mensajes en jboss-esb

  • 1. Proyecto: análisis de capacidades de transformación de mensajes en JBossESB Informe final Pablo Pazos Gutierrez Taller de Sistemas de Información 4, Instituto de Computación Facultad de Ingeniería, Universidad de la República
  • 2. Resumen Hoy en día los sistemas informáticos orientados al dominio de la salud han crecido en importancia, tamaño y complejidad, siendo la interoperabilidad entre los sistemas existentes, y también con nuevos sistemas que se generen, el problema a resolver. Para intentar resolver los problemas de interoperabilidad entre estos sistemas informático-clínicos existen distintos estándares propuestos por la industria, dentro de estos HL7 es un grupo de estándares para resolver la interoperabilidad entre sistemas de registro clínico orientado al intercambio de mensajes. El presente proyecto intenta explorar una solución de comunicación entre sistemas que son compatibles con HL7 y sistemas que no lo son y que manejan su propio formato de mensajes para interoperar con otros sistemas. Esta solución se basará en un middleware JBossESB en donde se resolverán las diferencias entre los formatos de mensajes que soportan los sistemas que intentan interoperar, de modo de que no sea necesario modificar un sistema existente para hacerlo compatible con mensajes HL7, si no que dicha “compatibilización” se hará dentro del ESB.
  • 3. Planteo del problema El objetivo principal del presente proyecto es investigar distintas opciones para implementar la comunicación entre sistemas que se comuniquen mediante mensajes y que utilicen distintos formatos para dichos mensajes, en particular se buscará la interoperación entre sistemas cuyos mensajes sigan el estándar HL7 (*) y sistemas que utilicen otro formato de mensajes distinto a HL7. El objetivo es que ninguno de los sistemas deba adaptar su formato de mensajes al formato del otro sistema, es decir que la conversión entre los distintos sistemas de mensajes será realizada dentro de un ESB. Dicho ESB manejará los distintos aspectos referentes a la comunicación entre los sistemas. Este enfoque de manejo de transformaciones entre distintos formatos de mensajes en el propio ESB permite que los sistemas existentes no necesiten ser modificados para poder interactuar con otros sistemas compatibles con HL7. El ESB que se estará probando es JBossESB, un subproyecto dentro de JBoss. Sobre JBossESB se desea relevar y probar las distintas capacidades de transformación entre formatos de mensajes y también relevar las distintas capacidades de ruteo de mensajes con las que cuente JBossESB. La siguiente figura muestra opciones de transformación de mensajes entre sistemas. En la opción “clásica” se agrega un componente dentro del mismo sistema para que realice la estandarización de sus mensajes a HL7. En la opción centrada en “ESB” la estandarización de los mensajes se realiza en el ESB y es transparente a ambos sistemas, este es el enfoque que se intentará seguir. Figura 1: opciones de estandarización de mensajes entre sistemas (*) HL7 es un conjunto de estándares de comunicación orientados a mensajes, para el dominio de la salud. Los mensajes están basados en el modelo de referencia de HL7 llamado RIM por sus siglas en inglés. Estos mensajes se utilizan para comunicar información clínica y demográfica de pacientes entre sistemas, como por ejemplo: resultados de estudios, medidas de presión de sangre, datos personales, etc.
  • 4. Introducción a JBossESB JBossESB es la solución de middleware para comunicación del stack de proyectos JBoss. JBossESB sirve como infraestructura de comunicación para otros proyectos como jBMP, la solución de BPM del stack JBoss. Con JBossESB se pueden definir servicios que consisten en una serie de acciones que se ejecutan en secuencia llamado “pipeline” de acciones. Estos servicios pueden tener diversos puntos de entrada a los cuales se puede acceder mediante distintos protocolos de comunicación, por ejemplo mediante mensajería JMS, FTP, o vía Web Services, entre otros. La siguiente imagen muestra un ejemplo de un servicio con su pipeline de acciones al cual se accede mediante el protocolo FTP y termina ejecutando lógica de negocio. [1] Figura 2: Acciones en un servicio del ESB El pipeline de acciones se parece mucho al estilo de arquitectura “tubos y filtros”, donde un mensaje es pasado por cada acción, las cuales realizan algún tipo de transformación en los datos del mensaje, y el resultado queda disponible para la siguiente acción. Es necesario diferenciar los conceptos de “mensaje del ESB” [2] y “mensaje”. El ESB utiliza un mensaje interno para transportar los mensajes que le son enviados, ese es el “mensaje del ESB”. El “mensaje del ESB” podría transportar múltiples mensajes distintos dentro del ESB, y las acciones podrías acceder a diferentes mensajes para obtener datos o modificarlos. Por ejemplo, el mensaje del ESB podría contener varios mensajes XML distintos en su Body. Para el caso del taller, el mensaje del ESB contendrá solo un mensaje XML en su Body. El mensaje del ESB cuenta con los siguientes campos: • Body: mantiene información arbitraria que puede ser agregada y modificada por el usuario y por las acciones del canal. • Attachment: contiene información extra a la que aparece en el Body. • Context: el contexto es la sección del mensaje que contiene información para manejar la sesión, transacciones, seguridad, etc. • Fault: sirve para especificar distintas fallas que se podrían dar en la comunicación y devolver un mensaje acorde (es similar a una excepción). • Header: es el cabezal del mensaje. • Properties: mantiene propiedades arbitrarias del mensaje en la forma de un mapa <String, Object>. En la figura 3 se muestra la arquitectura de JBossESB, con las diversas opciones de puntos de entrada al ESB y las opciones de comunicación con componentes de más bajo nivel (lógica de negocio).
  • 6. Alternativas de transformación de mensajes JBossESB utiliza como principal componente de transformación al proyecto Smooks. Smooks es un componente de transformación que “vive” dentro de otro proyecto mayor relacionado con el procesamiento y transformación de datos, el proyecto Milyn (Data Transformation and Análisis). [5][6][7] Smooks ofrece transformaciones entre distintos formatos de mensajes, por ejemplo brinda transformación desde y hacia: XML, EDI, Java (*), CSV, JSON, entre otros. Los mecanismos de transformaciones que ofrece Smooks y que pueden ser de utilidad para este taller son: Transformaciones Java Transformaciones XSLT Transformaciones FreeMarker Transformaciones basadas en modelos (model-driven transformations) Transformaciones Java-Java mediante configuración Smooks (Java Bindings) Los tipos de transformación a analizar serían ente los siguientes formatos (**): Transformación Java-Java Transformación XML-XML Transformación XML-Java [7.2] Transformación Java-XML [7.3] Los mecanismos de transformación indican “como” es que se lleva a cabo la transformación, los tipos de transformación indican “entre que” formatos se está transformando, es decir que el “tipo” de transformación es independiente del “mecanismo” que se aplique para implementar la transformación. Por ejemplo, se podría hacer una transformación XML-XML mediante XSLT o FreeMarker, o una transformación Java-Java basada en modelos o mediante configuración Smooks. (*) Cuando se menciona que un mensaje se encuentra en formato Java, se refiere a que el mensaje es una instancia en memoria de un modelo de datos particular. (**) La notación de los tipos de transformación es: formato_origen – formato_destino, por ejemplo: XML-Java, es la notación de una transformación que toma un mensaje en formato XML y devuelve un mensaje en formato Java. Mecanismos de transformación Transformación Java Este mecanismo de transformación es implementada directamente con lógica Java. La configuración es mínima y la lógica hace todo el trabajo de transformación, el tipo de transformación puede ser Java-Java o XML-XML. La transformación Java puede hacerse dentro de Smooks o directamente como una acción del pipeline de acciones de un canal del ESB. Para implementar una acción en el ESB, es necesario crear una clase que extienda a org.jboss.soa.esb.actions.AbstractActionPipelineProcessor, si la clase que implementa dicha acción se llama ActionProcessor, el segmento de configuración del ESB necesario para agregar dicha acción al pipeline de acciones de un servicio del ESB sería similar al siguiente: <actions> ... <action class="paquete.ActionProcessor" name="ContentFilter"/> ... </actions> La propia implementación de la transformación dependerá del formato del mensaje de entrada y del formato del mensaje de salida. Este mecanismo puede ser ventajoso cuando se necesiten hacer transformaciones muy particulares o que necesiten poco código para ser implementadas, comparando con otros mecanismos que para algún caso particular necesiten más código que la implementación directa en Java.
  • 7. Transformación XSL En la transformación XSL el trabajo de transformación se configura mediante reglas XSL en un documento XML. La configuración de Smooks es mínima, solo se necesita decir donde está el archivo XSL con la transformación, y el intérprete XSL es el que ejecuta la transformación. También se puede poner la transformación XSL directamente dentro del mismo archivo de configuración de Smooks, por lo que no es obligatorio tener un archivo XSL aparte. Ejemplo de configuración de Smooks para una transformación XSL: <smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.0.xsd"> <resource-config selector="$document"> <resource>/ConversionXSL/transformacion.xsl</resource> </resource-config> </smooks-resource-list> En las últimas versiones de JBossESB se ha agregado también la posibilidad de realizar transformaciones XSL nativas, es decir, sin necesidad de utilizar Smooks para dicho propósito. Entonces con transformaciones XSL nativas se utilizaría el intérprete XSL de JBossESB en lugar del intérprete XSL de Smooks. Ejemplo de transformación XSL nativa: Fue creada una clase llamada XSLActionProcessor extiende la clase AbstractActionPipelineProcessor, esto es para poder ser llamada como una acción cuando se ejecute el pipeline de acciones del servicio en el ESB. En XSLActionProcessor se implementa la configuración, carga de la transformación XSL y ejecución de la transformación. El constructor de la clase oficia de operación de configuración de la transformación, que previamente a que el ESB ejecute la acción XSLActionProcessor en el pipeline de acciones, configura la acción para su correcta operación obteniendo el nombre del archivo donde se encuentra la transformación y el mensaje del ESB que contiene el mensaje XML a ser transformado. Luego, automáticamente, el ESB invoca al método “process”, que es donde se ejecuta la lógica de la acción, en este caso, es donde se carga la transformación XSL, donde se realiza la transformación y donde se coloca el resultado en el mensaje del ESB para que pueda ser accedido por la próxima acción del pipeline. El método “getStylesheet” se utiliza como auxiliar para cargar el archivo XSL (con la transformación) desde el sistema de archivos. Luego se creó la clase XSLTransformer, que es en la que se realiza efectivamente la transformación XLS. public class XSLActionProcessor extends AbstractActionPipelineProcessor { private static Map<String, String> cache = new HashMap<String, String>(); private String xsl; private MessagePayloadProxy payloadProxy; public XSLActionProcessor(ConfigTree configTree) { xsl = configTree.getAttribute("xsl"); payloadProxy = new MessagePayloadProxy(configTree); } public Message process(Message message) throws ActionProcessingException { try { XSLTransformer transformer = new XSLTransformer(); System.err.println("XSLActionProcessor INPUT: " + message); byte[] bytes = ((String) payloadProxy.getPayload(message)).getBytes(); ByteArrayInputStream input = new ByteArrayInputStream(bytes);
  • 8. String theXSL = getStylesheet(xsl); ByteArrayOutputStream output = (ByteArrayOutputStream) transformer.transform(input, theXSL); message.getBody().add(output); return message; } catch (Exception e) { throw new ActionProcessingException(e); } } /** * Carga hoja de estilo XSL de un archivo o del cache. * * @return * @throws IOException */ private String getStylesheet(String stylesheetFileName) throws IOException { String result = null; synchronized (cache) { result = cache.get(stylesheetFileName); if (result == null) { File file = new File(stylesheetFileName); if(!file.exists()) { throw new IllegalArgumentException("Input message file [" + file.getAbsolutePath() + "] not found."); } result = FileUtil.readTextFile(file); cache.put(stylesheetFileName, result); } else { System.err.println("Stylesheet retrieved from cache"); } return result; } } } public class XSLTransformer { private static TransformerFactory tf = TransformerFactory.newInstance(); /** * Ejecuta la transformacion XSL. * * @param input stream con datos de entrada * @param xsl transformacion XSL (no el nombre del archivo es el contenido) * @return La informacion transformada * @throws TransformerException */ public OutputStream transform(InputStream input, String xsl) throws TransformerException { if (input == null || xsl == null) throw new IllegalArgumentException("input cannot be null"); Transformer t = tf.newTransformer( new StreamSource( new StringReader(xsl) ) ); ByteArrayOutputStream output = new ByteArrayOutputStream(4096); t.transform(new StreamSource(input), new StreamResult(output)); return output; } }
  • 9. Transformaciones Java-Java mediante configuración Smooks Este mecanismo de transformación se utiliza cuando se tiene una instancia de un modelo Java y se quiere generar una instancia de otro modelo con la información que tiene el primer modelo. Existen dos conceptos importantes llamados “Binding” y “Wiring”. “Binding” se utiliza para generar las instancias simples de las clases del modelo destino, a las cuales se les setean los datos del modelo origen. “Wiring” se utiliza para generar relaciones entre las instancias simples del modelo destino para formar una estructura de datos completa. Ambas tareas se realizan mediante reglas de configuración de Smooks basadas en XML. [7.1] Una característica interesante es que para seleccionar los valores de los atributos del modelo origen se utilizan expresiones XPath sobre un XML. Dicho XML es generado internamente por Smooks, a partir del modelo de entrada, mediante XStream. XStream es una librería que permite serializar cualquier instancia de modelo de datos a XML y volver del XML a la instancia. Entonces es necesario saber que forma tiene el XML generado a partir del modelo de entrada para poder escribir las expresiones XPath. Este mecanismo de transformación tiene varias restricciones, sobre todo en el modelo destino. En el modelo origen no existen restricciones particulares, ya que en realidad la transformación se realiza tomando la serialización a XML del modelo origen y no el propio modelo. Para la transformación Java-Java es necesario que el modelo destino se comporte según las siguientes reglas: • Debe tener un constructor simple (sin argumentos). • Debe tener setters públicos para las propiedades de cada clase. No es necesario seguir algún formato de nombres particular para estos métodos, pero se aconseja seguir el estándar de nombres para setters de Java. • Setear una propiedad de forma directa no está soportado, es necesario hacerlo invocando al setter de la propiedad. Si no se siguen estas reglas, el transformador Smooks configurado mediante XML no sabrá como establecer los valores, extraídos del modelo origen, en el modelo destino. El problema que presenta esto, es que en la transformación de un modelo “custom” en el modelo de referencia de HL7 (RIM), se debe utilizar alguna implementación de RIM. JavaSIG es una librería para generar y consumir mensajes HL7, pero su implementación no sigue las reglas impuestas por este mecanismo de transformación, por lo que no es posible utilizar dicha implementación. Se hizo una prueba de esto, constatándose la imposibilidad de generar una instancia del RIM mediante este mecanismo de transformación. Para resolver este problema se plantearon las siguientes alternativas: 1. Probar la transformación generando el RIM a partir de esquemas XSD mediante JAXB y probar utilizar esas clases. 2. No hacer la transformación mediante configuración XML, si no hacer una transformación directamente implementada en Java. 3. Modificar el RIM implementado en JavaSIG para que las clases sigan las reglas antes mencionadas. 1. Utilizando JAXB y transformación Java-Java: Se pudo generar un modelo de clases a partir de los esquemas XSD para los mensajes CDA provistos por la especificación de HL7 mediante la librería JAXB. En el anexo “Prueba transformación Java-Java BindingAndWiring” se comenta cómo se generó el modelo a partir del XSD utilizando JAXB. Uno de los problemas que tiene este modelo de clases es que para las colecciones no tiene un método del tipo “add to collection”, que es lo que necesita Smooks para generar la colección y agregarle elementos, las clases que tienen atributos de tipo colección tienen un método get para la colección y luego se invoca el “add” directamente sobre la colección. Para poder ejecutar una transformación mínima se tuvo que modificar algunas clases que tenían atributos de tipo colección, agregando un método “addXXX” donde “XXX” es el nombre del campo de tipo colección. Un tema a tener en cuenta es que Smooks sirve para colocar el modelo origen en un modelo destino, pero no se puede generar más modelo. Por ejemplo, si el modelo destino tiene más información que el
  • 10. mensaje original, este tipo de transformación no permite generar el modelo extra. Una posible solución es la de agregar la información faltante en una etapa posterior a la transformación Java-Java, por ejemplo utilizando transformaciones XSL o templates FreeMarker. Esto sucede cuando se tiene un modelo “custom” y se quiere llevar a un CDA, se pueden colocar los valores presentes en el modelo “custom” que se correspondan en la estructura CDA, pero CDA necesita mucha más información, porque tiene una estructura más compleja y muchos atributos que no existen en el modelo “custom”, esto es porque CDA agrega información para poder hacer una interpretación semántica de los documentos CDA. Por ejemplo existen muchos atributos con valores fijos que no pueden ser generados directamente con este mecanismo de transformación. En el caso inverso no habría problemas, es decir pasar CDA a el modelo “custom”, porque se toman del CDA solo los valores que se necesiten, los demás valores no serían utilizados para generar la instancia del modelo “custom”. En conclusión, esta prueba necesita gran cantidad de código de configuración para poder hacer la transformación Java-Java mediante Binding y Wiring, y las restricciones sobre el modelo de salida lo hacen poco flexible. Además la configuración es como implementar la transformación directamente en Java, lo que no solo llevaría menos código, si no sería más flexible, ya que puedo utilizar la API que me provea el modelo destino sin ninguna restricciones sobre los métodos que debe proveer. En el anexo “Prueba transformación Java-Java BindingAndWiring” están las referencias de implementación de la transformación probada y los resultados obtenidos. 2. Implementar la transformación directamente en Java: Esta opción no fue probada por ser considerada la opción más simple, ya que lo único que se necesita hacer es generar una instancia del modelo destino, e ir pidiendo los valores a la instancia del modelo origen y setear dichos valores en la instancia destino. Esta opción no tendría inconvenientes con la API del modelo destino, al contrario del mecanismo de Bindings y Wirings que pone estrictas reglas sobre dicha API. De modo que esta es una solución más genérica que la antes mencionada y también necesita escribir menos código para ser implementada, la diferencia es que mientras aquí se escribe código Java, en la opción anterior se escribían reglas en formato XML. Como conclusión, esta sería una buena opción si se tiene un modelo de datos destino con una API que no cumple con las restricciones del método anterior, o también si la estructura es muy compleja, cuanto más compleja es la estructura más reglas deben ser escritas y cada regla lleva en promedio 8 líneas de código, si en una implementación Java se necesitaran menos líneas que estas, al agregar atributos o relaciones, se necesitaría mucho menos código para implementar la misma transformación. 3. Modificar JavaSIG Esta puede ser la opción más costosa, ya que la API de la implementación del RIM de JavaSIG es muy particular, no solo habría que modificar decenas de clases, si no que habría que escribir gran cantidad de reglas para poder realizar la transformación. Esta opción no se llevó a cabo por las razones mencionadas. En este caso, implementar la transformación directamente en Java sería una mejor opción.
  • 11. Transformación FreeMarker En la transformación FreeMarker, la información de la transformación se encuentra en la configuración de Smooks (definido mediante reglas FreeMarker) o también puede estar en un archivo aparte (los archivos FreeMarker tienen extensión .FTL por FreeMarker Template). El formato en el que se especifica es el marcado por FreeMarker y se puede acceder aquí: http://www.milyn.org/xsd/smooks/freemarker-1.1.xsd, es declarativo como el XSL pero parece menos verboso que este último, o sea, con menos código se hace lo mismo. FreeMarker es una herramienta de “templating” o aplicación de plantillas que sirve para recorrer un archivo de texto (estructurado o no), extrayendo su información y generando un nuevo archivo te texto (estructurado o no) con un formato distinto. FreeMarker es soportado por los creadores de Smooks, los cuales lo prefieren sobre XSL. Comparándolo con XSL, FreeMarker está hecho para transformación de texto en general, mientras que XSL solo sirve para procesar texto estructurado en forma de árbol, como ser un archivo XML. Por otra parte, FreeMarker tiene constructores basados en programación imperativa, mientras que XSL los constructores están basados en programación funcional, esto se refiere a la característica de poder definir funciones y variables en cada una de las herramientas, los desarrolladores de FreeMarker afirman que esto es una ventaja porque la mayoría de los desarrolladores conocen la programación procedural- imperativa, mientras que pocos conocen la programación funcional. FreeMarker también apunta a que sea más fácil de aprender y entender que XSL. Obviamente la principal diferencia entre ambas tecnologías es que XSL es un estándar y tiene diversas implementaciones, y FreeMarker una herramienta Java. Si bien se realizó una implementación de transformación utilizando FreeMarker, sería interesante poder comparar más a fondo las opciones de transformación utilizando FreeMarker y XSL, y verificar cual es la opción más simple de utilizar, la que posee más funcionalidades que ayuden a realizar transformaciones según las características particulares de las transformaciones que se necesiten, si es necesario escribir más o menos reglas de transformación, y evaluar la capacidad, características y estabilidad de cada herramienta. Lo que si se constató es que en las pruebas, para lograr el mismo resultado en la transformación XML custom a XML CDA, el trabajo que tomó hacer funcionar la transformación XSL fue aproximadamente una semana, mientras que el trabajo que tomó hacer funcionar la transformación completa con FreeMarker fueron alrededor de cuatro horas. También se pudo ver que el código necesario para especificar la transformación XSL es aproximadamente tres veces más que el código necesario para especificar el template FreeMarker. Obviamente esta es una comparación en solo una transformación particular, por lo que no se puede derivar un resultado general y decir que estas diferencias se dan en otras transformaciones. Se realizó una implementación de una transformación de un mensaje XML “custom” a un mensaje XML CDA, la documentación se encuentra en el documento anexo “Prueba transformación XML-XML FreeMarker”. Transformación basada en modelo Por último, para las transformaciones basadas en modelos, es necesario definir un modelo de datos intermedio entre la entrada y la salida, al cual se pueda mapear la entrada y desde el cual se pueda generar la salida. El único código Java a implementar es dicho modelo de datos y la transformación se especifica en la configuración de Smooks, donde se definen las correspondencias del formato de entrada al modelo y del modelo al formato de salida. La ventaja de este esquema es la posibilidad de definir múltiples formatos de entrada y salida pudiendo hacer combinaciones de éstos sin necesidad de especificar todas las combinaciones entrada-salida, solo se especifican las diferentes combinaciones entrada-modelo y modelo-salida, luego automáticamente se obtienen todas las combinaciones entrada- modelo-salida. Para la transformación Java-Java se utiliza la notación que se utiliza en la transformación basada en modelos para especificar dicha transformación. Esta notación está basada en “bindings” que toman un valor de la fuente y lo ponen en un lugar del destino, en el caso Java-Java, esto es hacer “gets” en el modelo fuente y “sets” en el modelo destino.
  • 12. Propuesta de transformación Java-Java híbrida Si bien se analizaron varias opciones de transformación entre instancias de modelos Java, hasta ahora no se analizó la posibilidad de mezclar otros mecanismos de transformación para lograrlo. Como se comentó en la respectiva sección, para realizar la transformación Java-Java, Smooks internamente serializa la instancia del modelo origen a un XML mediante la librería XStream. Transformación Java-Java mediante FreeMarker + XStream Esta opción utilizaría la transformación FreeMarker y la funcionalidad de convertir XML a una instancia y viceversa de XStream, los pasos serían los siguientes: 1. Recibir una instancia del modelo origen. 2. Registrarla como bean en el mapa de beans del contexto de la transformación Smooks. 3. Tener un template FreeMarker que ejecuta la transformación obteniendo los datos desde el bean registrado con el modelo original y generando el XML del modelo destino, siguiendo el formato de XStream de una instancia válida de dicho modelo. 4. Mediante XStream, levantar el XML generado y convertirlo a la instancia del modelo destino en memoria. Figura 4: Transformación Java-Java con FreeMarker+XStream Aunque esta opción es similar a la prueba de transformación XML-XML mediante FreeMarker, los pasos de transformación no son los mismos (por lo menos no en el mismo orden). La documentación completa sobre la transformación XML-XML mediante FreeMarker se encuentra en el documento anexo llamado “Prueba transformacion XML-XML FreeMarker”. Otra opción sería teniendo una transformación XSL en lugar del template FreeMarker para generar el XML de salida compatible con XStream para que este pueda generar una instancia del modelo de salida. Distintas opciones de transformación se pueden generar mezclando los mecanismos ya vistos, también se pueden utilizar otras herramientas como XStream, esto posibilita la realización de distintos pasos de transformación de uno o más mensajes de forma simultánea, donde se pueden realizar distintas transformaciones mediante distintos mecanismos para diferentes secciones de los mensajes que se procesen.
  • 13. Especificación Técnica de Implementación de HL7 Si bien todos los mecanismos vistos hasta el momento son válidos para definir transformaciones entre distintos formatos de mensajes, siendo uno de los formatos HL7, la mayoría de los mismos no cumplen con la especificación técnica de implementación de HL7 (ITS por sus siglas en inglés). La ITS es la forma estándar en la que dos sistemas deberían interoperar utilizando mensajes HL7. En la misma se definen una serie de transformaciones que son necesarias para que dos sistemas que tengan su propio modelo de datos, lo puedan hacer corresponder en el RIM (modelo de referencia de HL7). Estas correspondencias de su modelo de datos al RIM y viceversa garantiza que el intercambio de datos será semánticamente correcto, y esto habilita a los sistemas para poder enviar y recibir mensajes HL7, que no son más que instancias de RIM serializadas a XML. En la siguiente imagen se muestran los pasos definidos por la ITS: Figura 5: Especificación Técnica de Implementación El escenario que plantea la ITS es el de dos sistemas, con un sistema emisor y otro receptor. Cada uno con un modelo particular de datos, más algún mecanismo que ejecute transformaciones entre esos datos e instancias de RIM. Los pasos que sigue la ITS son: 1. El sistema “emisor” tiene los datos que desea enviar al receptor en su propio modelo. 2. Mediante una transformación, genera una instancia de RIM a la cual le incluye los datos de su modelo. 3. Ahora se tiene una instancia de RIM con todos los datos que se quieren enviar. Esta instancia no es más que el mensaje que se va a enviar, en memoria. 4. Mediante algún mecanismo que serialice modelos RIM, se genera un mensaje XML válido según los esquemas XSD distribuidos por HL7 (dependiendo del tipo de mensaje, el XSD puede variar). 5. Ahora el mensaje en formato XML es enviado a través de un canal hacia el sistema “receptor”. 6. El “receptor” recibe el XML y reconstruye la instancia de RIM a partir del mensaje XML. 7. Se obtiene una instancia de RIM análoga a la que se obtuvo en el paso 3 dentro del sistema “emisor”. 8. A través de una transformación definida en el sistema “receptor”, se genera una instancia del modelo de datos de dicho sistema a partir de los datos contenidos en la instancia de RIM. 9. Se tiene la instancia del modelo de información del sistema “receptor”, que es semánticamente equivalente a la instancia del sistema de información del sistema “emisor” (la información que este sistema quería transmitir).
  • 14. Propuesta de transformación siguiendo la HL7 ITS Por lo mencionado anteriormente resulta interesante plantear una solución de transformación que cumpla con la ITS y utilice el ESB para realizar las transformaciones necesarias. Figura 6: Arquitectura del problema de envío y transformación de mensajes En el caso de que el Sistema A (emisor) envíe mensajes “custom” al Sistema B (receptor) el cual los recibe en formato HL7, donde las comunicaciones se realizan mediante Web Services, en el ESB se haría el pasaje del modelo SOAP a una instancia del modelo de datos del Sistema A. Luego, dentro del ESB se hace la conversión entre ese modelo de datos y el modelo RIM, por último se genera el XML a partir de la instancia RIM obtenida (esta transformación es automática utilizando una librería como JavaSIG). Ese XML es el que es enviado al Sistema B. Para el caso inverso, donde el Sistema B envía un XML HL7 al ESB, el ESB lo transforma a una instancia del RIM (esta transformación es automática utilizando una librería como JavaSIG). Luego, con los datos del modelo RIM se genera el modelo de datos que espera recibir el Sistema A, ese modelo es enviado directamente al Sistema A mediante Web Services SOAP (SOAP se encarga de hacer la serialización a XML).
  • 15. Relevamiento de opciones para ruteo de mensajes El esquema general de procesamiento de un mensaje recibido es similar al estilo de arquitectura de “tubos y filtro”, donde un mensaje es recibido por un filtro, procesado y luego puesto en un tubo hacia otro filtro. En este esquema debe haber algún mecanismo que decida en que tubo se coloca la salida de cada filtro, porque puede haber varios tubos distintos de donde elegir. La selección del tubo en el que se colocará la salida del filtro es llamado “ruteo” del mensaje, y se realiza mediante la verificación de un conjunto de condiciones, lo que permite tomar la decisión de cual será el tubo destino, entonces la ruta del mensaje será el conjunto de tubos y filtros por los que ha pasado el mismo. JBossESB ofrece cuatro tipos de ruteo: 1. Aggregator: es una implementación del patrón “Aggregator” de los “Enterprise Integration Patterns”, el mismo se utiliza para combinar información de varios mensajes distintos. [9] 2. Content Based Router (CBR): acción de ruteo basado en el contenido de los mensajes y la definición de reglas. 3. Static Router: versión simplificada del Content Based Router que no soporta reglas de ruteo basadas en contenido. 4. Notifier: envía notificaciones a una lista de destinos configurable. Está implementada como ejemplo, no debería ser usada directamente, si no que debería ser extendida por el usuario. Considerando los casos de prueba planteados para realizar en el presente trabajo (*), el “Content Based Router” podría ser de gran utilidad porque podría detectar que tipo de mensaje está recibiendo el ESB, y en base a reglas que se definan, rutear el mensaje al servicio correcto que pueda procesarlo. El CBR puede ser utilizado para enrutar el mensaje al próximo destino basándose en el contenido del mensaje. Por defecto el ESB utiliza “JBossRules” como motor de evaluación de reglas, aunque puede ser configurado para utilizar otro motor. Para utilizar el CBR se debe levantar el servicio de CBR. Luego se deben definir un conjunto de reglas (**). Para la definición de reglas sobre mensajes XML es conveniente utilizar evaluaciones basadas en XPath, especialmente diseñado para poder extraer valores presentes en el XML de forma sencilla. Una vez que se tiene el CBR andando, se le pueden enviar mensajes. Para esto se debe agregar dicho envío como una acción en algún lugar del pipeline de acciones. Luego existen tres modos de ejecución: 1. routeAndDeliver: rutea y entrega el mensaje al(los) destino(s) 2. route: rutea el mensaje y retorna un mensaje con una lista de destinos adjuntos a él. 3. deliver: simplemente entrega el mensaje, un mensaje ruteado previamente será entregado a su(s) destino(s). (*) Los casos de prueba se mencionan en el documento “TSI4 Anexo 1 – Bitácora.doc”, en la sección “Etapa 2: Definición de la arquitectura y casos de prueba”. (**) Estas pueden ser creadas mediante JBossIDE [Eclipse+JBossTools] con el plugin de JBossRules.
  • 16. Descripción del prototipo logrado Para la implementación del prototipo se eligió la transformación XML-XML mediante XSL. El prototipo define dos canales, uno que recibe un mensaje XML “custom”, mediante un punto de entrada expuesto mediante Web Services, y genera un mensaje CDA que es enviado a un sistema externo mediante Web Services, el otro recibe un mensaje CDA, mediante un punto de entrada expuesto mediante Web Services, y genera un mensaje XML “custom” que es enviado a otro sistema mediante Web Services. El prototipo fue implementado en el proyecto “ESBWS” incluido en el directorio de código de la entrega del taller. Los pipelines de acciones de ambos canales son similares: Figura 7: Canales en el ESB prototipo. Lista de acciones y su funcionalidad: • print-before: se encarga de mostrar en pantalla el mensaje entrante. • ContentFilter: transforma el mensaje en el formato de entrada al formato de salida. • print-after: muestra en pantalla el mensaje de salida. • testStore: almacena el mensaje de salida en el filesystem. • request-ws-processor: se encarga de preparar la llamada al Web Service, especificando que método del servicio será invocado y con que parámetros. • soap-ws-client: esta acción invoca al Web Service. • response-ws-processor: muestra en pantalla el resultado de la invocación al Web Service. Algunas acciones tienen asociadas una clase Java que es la que implementa la acción, otras poseen una implementación por defecto provista por el ESB, este último caso es el de las acciones: print-before, print- after y soap-ws-client.
  • 17. Descripción de la implementación de las acciones Acción ContentFilter Esta acción está asociada a la clase XSLActionProcessor, que es la clase en la que se implementó dicha acción. La funcionalidad básica de esta clase es cargar la transformación XSL del filesystem, obtener el mensaje XML a transformar (el cual se encuentra en el body del mensaje del ESB), y aplicar efectivamente la transformación al mensaje. El mensaje XML resultante se coloca en el mensaje del ESB, así la próxima acción en el pipeline de acciones puede acceder al mensaje transformado. A continuación se presenta la implementación de la clase XSLActionProcessor, la cual ejecuta una transformación XSL nativa sobre un mensaje XML. Esta acción es utilizada en ambos canales, al que se envía un mensaje custom y al que se envía un mensaje HL7, como implementación de sus respectivas acciones ContentFilter. Obviamente, en cada canal debe implementar una transformación distinta, esto se lleva a cabo mediante la configuración de una transformación XSL distinta para cada caso. Todas las acciones en el pipeline deben extender la clase AbstractActionPipelineProcessor [4], o su superclase AbstractActionLifecycle [3], la cual define el método “process” que será descrito más adelante. public class XSLActionProcessor extends AbstractActionPipelineProcessor { El campo “cache” es utilizado para almacenar la transformación XSL que es levantada desde el filesystem, de manera que se tenga que hacer una sola lectura del filesystem y en posteriores ejecuciones se obtiene el XSLT desde el cache. private static Map<String, String> cache = new HashMap<String, String>(); El campo “xsl” es el que almacena el nombre del archivo XSL que deberá ser leído. private String xsl; El campo “payloadProxy” se utiliza para acceder a los contenidos del mensaje del ESB. private MessagePayloadProxy payloadProxy; El constructor recibe la configuración del ESB con toda la información necesaria para que la acción pueda ejecutarse correctamente. Por ejemplo se extrae el nombre de la transformación XSL que hay que leer, y trae el mensaje del ESB de donde se leerá el mensaje XML a ser transformado. public XSLActionProcessor(ConfigTree configTree) { xsl = configTree.getAttribute("xsl"); payloadProxy = new MessagePayloadProxy(configTree); } El método “process” es donde se realiza la transformación. public Message process(Message message) throws ActionProcessingException { Aquí se crea la instancia del transformador, donde se realiza la transformación. try { SAXONTransformer transformer = new SAXONTransformer(); System.err.println("XSLActionProcessor INPUT: " + message); Se leen los bytes del mensaje XML de entrada y ponen dentro de la variable “input”. byte[] bytes = ((String) payloadProxy.getPayload(message)).getBytes(); ByteArrayInputStream input = new ByteArrayInputStream(bytes);
  • 18. Se lee el archivo de la transformación del filesystem, o desde cache si ya fue cargado, y se pone su contenido en la variable “theXSL”. String theXSL = getStylesheet(xsl); Mediante el transformador, se ejecuta la transformación XSL sobre el input, obteniéndose el resultado en la variable “output”. ByteArrayOutputStream output = (ByteArrayOutputStream) transformer.transform(input, theXSL); System.err.println("XSLActionProcessor OUTPUT: " + output); El mensaje obtenido se agrega al mensaje del ESB para que quede disponible para la siguiente acción del pipeline. message.getBody().add(output); return message; } catch (Exception e) { throw new ActionProcessingException(e); } } El método “getStylesheet” se utiliza para leer el archivo que contiene la transformación desde el filesystem, o desde el cache si es que ya ha sido leído. private String getStylesheet(String stylesheetFileName) throws IOException { String result = null; synchronized (cache) { Se intenta obtener el contenido de la transformación desde el cache. result = cache.get(stylesheetFileName); if (result == null) { System.err.println("Loading stylesheet from file "+stylesheetFileName); Se lee el archivo de disco. File file = new File(stylesheetFileName); if(!file.exists()) { throw new IllegalArgumentException("Input message file [" + file.getAbsolutePath() + "] not found."); } result = FileUtil.readTextFile(file); Se agrega el contenido leído al cache para acelerar futuras cargas. cache.put(stylesheetFileName, result); } else { System.err.println(" Stylesheet retrieved from cache"); } return result; } }
  • 19. Acción testStore Esta acción almacena el mensaje transformado en el filesystem del sistema donde esté corriendo el ESB. La misma está implementada en la clase StoreMessage. Como toda acción del pipeline, la clase StoreMessage extiende la clase AbstractActionPipelineProcessor. public class StoreMessage extends AbstractActionPipelineProcessor { private MessagePayloadProxy payloadProxy; public StoreMessage(ConfigTree config) { payloadProxy = new MessagePayloadProxy(config); } El método “appendToFile” toma cualquier contenido en forma de String y lo agrega al final de un archivo, conservando su contenido actual. El archivo es creado si es que no existe. public static void appendToFile(String dir, String fileName, String content) { BufferedWriter bw = null; try { bw = new BufferedWriter(new FileWriter(dir + "/" + fileName, true)); bw.write(content); bw.newLine(); bw.flush(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { // always close the file if (bw != null) try { bw.close(); } catch (IOException ioe2) { /* just ignore it */ } } // end try/catch/finally } El método “process” genera un nombre de archivo basado en la fecha actual y una serie de números random, de forma de generar un archivo diferente a los demás. Luego obtiene el contenido del mensaje a almacenar, esto lo saca del mensaje del ESB a través del payloadProxy que se utiliza para acceder a los datos del mensaje del ESB. Por último se llama al método “appendToFile” para generar el archivo con el contenido obtenido. public Message process(Message message) throws ActionProcessingException { Date d = new Date(); String name = ""+(d.getYear()+1900)+(d.getMonth()+1)+d.getDate(); try { System.err.println("PayloadMessageClass: "+ payloadProxy.getPayload(message).getClass()); byte[] btextToStore = ((ByteArrayOutputStream) payloadProxy.getPayload(message)).toByteArray(); System.err.println( "textToStore: " + new String(btextToStore) ); String textToStore = new String(btextToStore); appendToFile ("./", "message_"+name+"["+(Math.random()*5)+"].xml", textToStore.toString()); } catch (MessageDeliverException e) { throw new ActionProcessingException(e); } return message; } }
  • 20. Acción request-ws-processor Esta acción se utiliza para preparar la llamada al Web Service al que se enviará el mensaje transformado, esto está implementado en la clase MyRequestAction. Esta clase MyRequestAction extiende a la clase AbstractActionLifecycle [3]. Antes se vio que las acciones extendían a la clase AbstractActionPipelineProcessor, esto es porque AbstractActionPipelineProcessor a su vez extiende a AbstractActionLifecycle. public class MyRequestAction extends AbstractActionLifecycle { protected ConfigTree _config; private MessagePayloadProxy payloadProxy; En el constructor se recibe la configuración del ESB y el estado actual del mensaje. public MyRequestAction(ConfigTree config) { _config = config; payloadProxy = new MessagePayloadProxy(config); } El método “process” es quien obtiene el mensaje a enviar y configura los parámetros para la invocación al Web Service. En este caso se obtiene el mensaje XML transformado, que está dentro del mensaje del ESB. Luego se agrega a un mapa de parámetros mediante la clave “sendMessage.message”, esto quiere decir que se va a invocar al método “sendMessage” del Web Service, en donde existe un parámetro llamado “message” que tendrá como valor el mensaje XML transformado. public Message process(Message message) throws Exception { byte[] btext = ((ByteArrayOutputStream) payloadProxy.getPayload(message)).toByteArray(); String msgBody = new String(btext); HashMap requestMap = new HashMap(); // add paramaters to the web service request map // Esto es: metodo.paramName requestMap.put("sendMessage.message", msgBody); message.getBody().add(requestMap); System.out.println("Request map is: " + requestMap.toString()); return message; } } Acción response-ws-processor Esta acción simplemente muestra en pantalla el resultado de la invocación al Web Service. Está implementada en la clase MyResponseAction, la cual es análoga a la anterior, solo que en el método “process” se obtiene el resultado de la invocación al Web Service desde el mensaje del ESB y se hace un print del mismo a la consola. public class MyResponseAction extends AbstractActionLifecycle { protected ConfigTree _config; public MyResponseAction(ConfigTree config) { _config = config; } public Message process(Message message) throws Exception { Map responseMsg = (Map)message.getBody().get(Body.DEFAULT_LOCATION); System.out.println("Response Map is: " + responseMsg); return message; } }
  • 21. Trabajo futuro y mejoras 1. Transformación XSL genérica: sería el generar una transformación XSL que sea equivalente al modelo CDA, de esa forma se podría consumir o producir cualquier CDA válido. Posteriormente a esta prueba se buscarían las conclusiones de si es posible crear tal transformación, de que tan costosa sería crearla (comparándola con otros tipos de transformaciones), verificar si tiene problemas de performance y probar varios casos con distintos CDA. 2. Ruteo del mensaje: si bien en el presente trabajo se relevaron las opciones de ruteo que ofrece JBossESB, no se agregó la funcionalidad de ruteo al prototipo. Sería interesante probar, por lo menos, el ruteo basado en contenido, de forma que si se recibe un mensaje CDA dependiendo de sus características sea enviado a un determinado canal del ESB (o a un servicio externo al ESB) para ser procesado total o parcialmente en dicho canal. 3. Solicitar información a servicios externos: un posible caso es que el mensaje entrante tenga menos información de la necesaria para generar el mensaje saliente, sería interesante que, basándose en la información que si se tiene, se consulten determinados servicios que provean la información faltante, de forma de contar con toda la información necesaria para generar el mensaje saliente. 4. Comparar en profundidad las alternativas de utilizar XSL y FreeMarker como opciones de transformación de mensajes, probando y comparando las funcionalidades que sean útiles según los casos particulares de prueba, con cual alternativa se necesita escribir menos código, cual es más sencilla de usar y aprender, etc. Referencias [1] Proyecto JBossESB http://www.jboss.org/jbossesb/ [2] Mensaje de JBossESB http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/message/package- summary.html [3] Clase AbstractActionLifecycle http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/actions/AbstractActionLifecycle. html [4] Clase AbstractActionPipelineProcessor http://www.jboss.org/jbossesb/docs/4.4.GA/javadoc/esb/org/jboss/soa/esb/actions/AbstractActionPipelineP rocessor.html [5] Message Transformation on JBossESB http://www.jboss.org/community/docs/DOC-11397 [6] Smooks User Guide http://docs.codehaus.org/display/MILYN/Smooks+User+Guide [7] Smooks Examples http://www.smooks.org/documentation/documentation-smooks-1-1-x/examples [7.1] Smooks Example JavaToJava: http://docs.codehaus.org/display/MILYN/Smooks+Example+-+java-to-java [7.2] Smooks Example XMLToJava: http://docs.codehaus.org/display/MILYN/Smooks+Example+-+xml-to-java [7.3] Smooks Example JavaToXML: http://svn.codehaus.org/milyn/trunk/smooks-examples/java-to-xml/ [8] Componente Smooks de JavaBeans http://milyn.codehaus.org/javadoc/v1.0/smooks-cartridges/javabean/ [9] Enterprise Integration Patterns http://www.enterpriseintegrationpatterns.com/eaipatterns.html