Posts Tagged ‘SOAP’

h1

Usando Telnet para llamar Web Services

10/23/2009

Wizdoc [Icon By Buuf]  Tips & Tricks.
Hace tiempo publiqué un post donde hablo un poco acerca de las herramientas que todo desarrollador debe conocer para simplificar el trabajo y mejorar su productividad. Entre ellas incluyo a SOAP UI, que nos facilita integrar web services en una aplicación. Como mencioné anteriormente, SOAP UI permite generar peticiones a un web service, ya sea mediante el WSDL de manera local o a través de la URL donde se encuentra remotamente dicho documento, en caso de ser accesible desde nuestra computadora.

Sin embargo, muchas veces al integrar web services resulta que por cuestiones de seguridad, existen dos servidores de prueba – uno de nuestro lado y otro del lado del servicio que estamos integrando – con restricciones de IP. Esto complica nuestro trabajo porque no podremos probar la funcionalidad de manera directa desde nuestra máquina pues al intentar llamar al web service, nuestro cliente marcará un Connection Refused o Connection Timeout.

Existen versiones de SOAP UI para Solaris y Linux, pero puede llegar a dificultarse instalar la herramienta ya que en más de una ocasión he visto que a los desarrolladores se les proporcionan usuarios sin permisos mas que de ejecución, y sólo en ciertos directorios aprobados por el área de seguridad.

¿Qué hacer al respecto? Valiéndonos de SOAP UI y el pedestre pero poderoso cliente Telnet podremos avanzar sin muchas complicaciones:

Para generar nuestras peticiones debemos contar con el WSDL que describe la funcionalidad del servicio. La manera más fácil de obtenerlo es apuntar al URL donde está publicado y recuperarlo mediante la ejecución de telnet <ip o nombre del servidor> <puerto> de la siguiente manera:

# telnet 192.168.100.105 8080
Trying 192.168.100.105…
Connected to 192.168.100.105.
Escape character is ‘^]’.
_

Una vez que hemos abierto una nueva conexión, ejecutamos una petición HTTP GET para recuperar el WSDL que estamos buscando mediante GET <URI del WSDL> más dos <Enters>, como se muestra a continuación:

# telnet 192.168.100.105 8080
Trying 192.168.100.105…
Connected to 192.168.100.105.
Escape character is ‘^]’.
GET /axis/services/RemoteWebService?wsdl
<Enter>
<Enter>

Y esto generará como respuesta el WSDL completo. Para aquellos que cuenten con los permisos correspondientes, es posible utilizar el comando wget (localizado en /usr/bin/wget o en /usr/sfw/bin/wget) con la dirección completa del WSDL para recuperarlo:

# wget http://192.168.100.105:8080/axis/services/RemoteWebService?wsdl
–19:35:26– http://192.168.100.105:8080/axis/services/RemoteWebService?wsdl
Connecting to 192.168.100.105:8080… connected.
HTTP request sent, awaiting response… 200 OK
Length: unspecified [text/xml]
Saving to: `RemoteWebService?wsdl’

[ <=> ] 16,010 39.5K/s in 0.4s

19:35:27 (39.5 KB/s) – `RemoteWebService?wsdl’ saved [16010]

# _

Ahora, mediante SOAP UI o alguna otra herramienta como XML Spy podemos generar los XML de las peticiones al web service y editar dichos documentos para agregarles los valores necesarios. Un ejemplo con SOAP UI es el siguiente:

SOAP UI XML Request

Ejemplo de una petición XML-SOAP con un WSDL importado mediante SOAP UI. (Dar click en imagen para ver versión original).

Al haber creado un nuevo proyecto en SOAP UI mediante el WSDL, tenemos un template de petición al web service que vamos a llamar. Podemos editarlo y agregar los valores faltantes, incluyendo la etiqueta <?xml version="1.0" encoding="UTF-8"?> que es indispensable incluir al inicio de nuestro mensaje:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema&quot; xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:ser="http://in.dustry.com/web/services"&gt;
  <soapenv:Header/>
  <soapenv:Body>
    <ser:getUserProfile soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"&gt;
      <seq_id xsi:type="xsd:string">11223344</seq_id>
      <client_id xsi:type="xsd:string">1122</client_id>
    </ser:getUserProfile>
  </soapenv:Body>
</soapenv:Envelope>

Debemos remover los espacios e indentaciones para simplificar nuestro copy-paste final en el cliente de Telnet (en un momento veremos por qué):

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema&quot; xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:ser="http://in.dustry.com/web/services"><soapenv:Header/><soapenv:Body><ser:getUserProfile soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><seq_id xsi:type="xsd:string">11223344</seq_id><client_id xsi:type="xsd:string">1122</client_id></ser:getUserProfile></soapenv:Body></soapenv:Envelope>

Y hacemos el paso de la muerte, ejecutando nuevamente nuestro cliente Telnet, pero en ves de realizar un HTTP GET, generaremos una petición HTTP POST con ciertos parámetros que son tomados por el cliente Telnet como el encabezado de nuestra petición:

# telnet 192.168.100.105 8080
Trying 192.168.100.105…
Connected to 192.168.100.105.
Escape character is ‘^]’.
POST /axis/services/RemoteWebService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 123.456.789.101
Content-Length: 527
<Enter>
<Enter>

A continuación explico qué significa cada línea del encabezado:

• La primera línea indica que realizaremos una petición HTTP POST a la dirección del web service remoto en /axis/services/RemoteWebService, usando el protocolo HTTP versión 1.1.
• La línea dos indica que podremos enviar mensajes comprimidos. Esta línea es opcional.
• La línea tres indica la codificación de nuestro mensaje.
• La línea cuatro indica que este es un mensaje SOAP y que realizaremos una acción con esta llamada. Puede dejarse vacía, pero es indispensable incluirla pues de lo contrario el servidor nos responderá con el mensaje de error "no SOAPAction header!".
• Las líneas cinco y seis indican el user-agent o cliente que está realizando la petición, así como la IP desde la que se está llamando. Conviene incluirlas en caso de que el web service remoto realice algún tipo de filtrado por IP o tipo de cliente.
• Finalmente, la longitud del mensaje que debe ser exactamente la misma del mensaje SOAP enviado.

Luego copiamos el XML de nuestra llamada al web service y tecleamos dos <enters> nuevamente;

# telnet 192.168.100.105 8080
Trying 192.168.100.105…
Connected to 192.168.100.105.
Escape character is ‘^]’.
POST /axis/services/RemoteWebService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
User-Agent: Jakarta Commons-HttpClient/3.1
Host: 123.456.789.101
Content-Length: 527
 
 
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/2001/XMLSchema&quot; xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/&quot; xmlns:ser="http://in.dustry.com/web/services"><soapenv:Header/><soapenv:Body><ser:getUserProfile soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><seq_id xsi:type="xsd:string">11223344</seq_id><client_id xsi:type="xsd:string">1122</client_id></ser:getUserProfile></soapenv:Body></soapenv:Envelope>
<Enter>
<Enter>

Con esta llamada al web service, se deberá generar una respuesta que nos será devuelta en forma de otro mensaje XML-SOAP:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.4; JBoss-4.2.1.GA (build: SVNTag=JBoss_4_2_1_GA date=200707131605)/Tomcat-5.5
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Wed, 21 Oct 2009 16:34:56 GMT

4b8
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope>
  <soapenv:Body>
    <ns1:getUserProfileResponse>
      <userprofile href="#id0"/>
    </ns1:getUserProfileResponse>
    <multiRef id="id0" soapenc:root="0">
      <SEQ_ID xsi:type="soapenc:string">556677889900</SEQ_ID>
      <regionId href="#id1"/><userType href="#id2"/>
    </multiRef>
    <multiRef id="id1" soapenc:root="0">9</multiRef>
    <multiRef id="id2" soapenc:root="0">1</multiRef>
  </soapenv:Body>
</soapenv:Envelope>
0

¡Voila! Algo talachuda pero exitosa llamada a un web service desde un cliente Telnet.

Troubleshooting

Hay un par de detalles que debemos observar cuando realicemos la llamada:

La primera, algo trivial, es el detalle de la codificación del mensaje. Siempre es importante saber el tipo de codificación que están usando tanto el cliente como el web service, pues en caso de ser diferentes podemos toparnos con errores debido a que cualquiera de los dos puntos, ya sea el de publicación o el de consumo, no reconozcan algunos de los caracteres del XML enviado o la respuesta retornada. Por ello, si el servidor codifica UTF-8, el cliente deberá ajustarse a UTF-8.

Segunda y más importante es el tamaño del mensaje en la última línea del encabezado HTTP así como los dos <enters> que tecleamos entre encabezado y mensaje y al final del mensaje. Por ello es mejor eliminar espacios e indentación del mensaje: disminuyen el riesgo que incluyamos "caracteres demás" ya que pueden aparecernos cualquiera de los siguientes errores:

• java.net.SocketTimeoutException: Read timed out. Debido a que el web service está esperando el resto del mensaje "faltante". Esto es porque la longitud es incorrecta o nos faltaron los dos <enters> al final del propio mensaje.

• org.xml.sax.SAXParseException: Reference is not allowed in prolog. Debido a que encuentra un ampersand (&) en el encabezado de la petición. Esto es porque nos faltó un <enter> entre el encabezado y el mensaje o la longitud que se incluyó es demasiada.

• org.xml.sax.SAXParseException: The processing instruction target matching &quot;[xX][mM][lL]&quot; is not allowed. Esto se debe a que el parser del lado del servidor está encontrando un caracter menor-que (<), mayor-que (>), comillas (") ó ampersand (&) en el encabezado de la petición. De nueva cuenta, puede ser porque nos faltó un <enter> entre el encabezado y el mensaje XML o nos quedamos cortos con la longitud que se incluyó en el encabezado.

Conclusiones

Y así podemos hacer de manera rápida y puntual una pequeña prueba de concepto para verificar que un web service está arriba, parsee correctamente un mensaje y nos regrese una respuesta válida. Claro que si vamos a desarrollar algo más que un par de peticiones, siempre será mejor instalar SOAP UI o pedir a los administradores que nos echen la mano con el firewall para poder ver el web service publicado desde las máquinas de desarrollo, con el fin de que mejoremos nuestra productividad, acabemos más rápido y todos seamos más felices.

h1

SOA (Parte 2)

09/11/2008

Wizdoc [Icon By Buuf]

 Tips & Tricks.

En el anterior post describimos de manera general qué es un SOA, cuáles son sus orígenes y sus elementos más característicos. En esta ocasión nos enfocaremos en la parte funcional del SOA: qué elementos arquitectónicos lo componen y cómo interactúan entre sí. Adicionalmente veremos los frameworks SOA comerciales más fuertes en el mercado y revisaremos sus principales ventajas y desventajas.

Los elementos arquitectónicos de un SOA

Como comentamos anteriormente, un SOA es un modelo de diseño de arquitecturas empresariales; sin embargo, la implementación del mismo no sólo consiste en publicar web services y ya: aunque en un principio esto puede funcionar para facilitar la adopción de SOA, poco a poco conforme vayamos publicando más y más servicios, volveremos a un esquema desordenado. Así entonces, tarde o temprano el volumen de servicios será tal que:

• Será difícil encontrar los servicios que se necesitan. Esto es progresivamente más frecuente conforme publiquemos un más servicios.

• No será posible realizar una efectiva administración de los servicios y forzar su adhesión a un estándar organizacional, incluyendo características tales como seguridad o políticas de publicación y consumo.

Comúnmente este tipo de problemas son resueltos sobre la marcha, sin embargo es importante considerarlos y atacarlos desde la fase de diseño del SOA para evitar futuros cuellos de botella, facilitando la adopción del nuevo paradigma y lograr ver desde un principio los beneficios asociados a este tipo de arquitecturas:

Un esquema que muestra los componentes del SOA y las relaciones (publicación, descubrimiento, consumo) entre éstos.

[Click en imagen para ver a mayor escala]

A continuación se describen los componentes del SOA en mayor detalle:

• Capa aplicativa. Este elemento contiene las interfaces de usuario final; principalmente las aplicaciones web o cliente-servidor que consumen los procesos construidos a través del Gestor de Procesos y aquellos servicios que han sido publicados por terceros. La capa aplicativa es más dependiente de lenguajes o frameworks de desarrollo (por ejemplo, interfaces web desarrolladas en Java o aplicaciones que interactúan con sistemas legados desarrolladas en C/C++).

• Capa de servicios de terceros. Son los servicios publicados por organizaciones ajenas a la nuestra (por ejemplo, el servicio SOAP publicado por Google para explotar su motor de búsquedas). Dichos servicios son consumidos por la Capa Aplicativa y el Gestor de Servicios, siendo publicados en el Directorio de Servicios[1].

• Orquestador de Datos/Gestor de Servicios. El gestor de servicios u orquestador de datos[2] es el componente cuya función principal es la construcción de los procesos de negocio que utilizará la organización en su capa aplicativa mediante el uso de los servicios que han sido publicados en el Service Registry, incluyendo los servicios publicados por terceros[1]. Adicionalmente, este elemento interactúa con el Directorio de Servicios para extraer los metadatos de los servicios que se integrarán, aunque también hace uso de otro tipo de características como monitoreo o gestión del ciclo de vida de los procesos generados. Por otro lado, es frecuente que este componente incluya una interfaz de usuario que permita construir los procesos mediante la representación diagramática de BPEL (Business Process Execution Language – Lenguaje de Ejecución de Procesos de Negocio)[3].

• Directorio de Servicios. Este elemento es en su forma más simple un repositorio de los servicios publicados así como una "sección amarilla" que utilizará el Gestor de Servicios para construir los procesos de negocio. En versiones más sofisticadas incluye un componente de gestión y gobierno de los servicios incluyendo características tales como gestión del ciclo de vida de los servicios, versionamiento y gobernabilidad (es decir, adhesión a las políticas de negocio y seguridad que permean toda la arquitectura).

• Adaptadores ESB/ETL/EAI y Conexión XDMS[4]. No todas las fuentes de datos o lógica de negocio son fácilmente convertibles a servicios. En algunos casos, es necesario primero utilizar conectores o drivers nativos que son accedidos mediante "servicios empaquetadores" (wrapper services) para su uso por el resto de la arquitectura. Un ejemplo clásico es extraer la información de una AS400 utilizando un adaptador basado en la especificación JCA (Java EE Connector Architecture).

• Repositorio de Datos. Son las fuentes de información como Bases de Datos o archivos planos así como de lógica de negocio, incluyendo sistemas de Planeación de Recursos Empresariales (Enterprise Resource PlanningERP) como SAP R/3. Como se vio en el punto anterior, algunas de estas fuentes de datos no cuentan con interfaces de extracción de datos homogéneas que puedan usarse en un SOA, por lo que la extracción de la información de éstas requiere de adaptadores[4] para su explotación.

El Enterprise Service Bus

Un tema que no hemos visto hasta ahora ha sido, de entre todos estos componentes, ¿quien funciona como el "pegamento" que los une y permite su interacción? ¿Quién realiza la validación de mensajes entre servicios, reforzando las políticas de negocio y seguridad definidas? ¿Quién se dedica a realizar las transformaciones de los mensajes del formato seleccionado para nuestro SOA a los formatos utilizados por la capa aplicativa?

Presentamos el Enterprise Service Bus (o Bus de Servicios Empresariales – ESB) cuya función principal, de manera análoga al bus de las placas base o motherboards, es conectar los diferentes componentes del SOA, permitiendo el intercambio de información entre todos los elementos de la arquitectura:

Vista esquemática del Enterprise Service Bus. Éste es el middleware que gestiona el transporte, ruteo y seguridad de los mensajes entre los consumidores y publicadores de los servicios.

[Click en imagen para ver a mayor escala]

Como puede verse en el diagrama, el ESB es un bus de datos que facilita el transporte de los mensajes entre los consumidores y los publicadores de servicios realizando la tarea de mediación entre éstos:

• Transformaciones: conversiones XML a XML, búsquedas en base de datos y agregaciones (jerarquías de documentos).

• Validación de Mensajes: verificación de campos de datos o combinación de éstos contra reglas específicas de negocio.

• Selecciones de servicio de contenido o calidad: Selección de servicios basada en el contenido o calidad del servicio requeridos. En pocas palabras, balanceo de carga y failover.

• Ruteo basado en contenido: Como ejemplo, si los parámetros del servicio contienen información del país de origen, la petición puede ser redirigida al proveedor designado para ese país.

• Logueo personalizado: Este es un requerimiento legal que puede ser necesario para algunas interacciones entre servicios.

• Monitoreo y métricas de funcionamiento: Un bus debe poseer los puntos de control necesarios para controlar su comportamiento y de los servicios integrados:

Consola de monitoreo del AquaLogic Enterprise Service Bus de BEA/Oracle. (Original obtenido de BEA AquaLogic Service Bus 2.1 Documentation > User Guide > Monitoring )

[Click en imagen para ver a mayor escala]

• Comportamiento automático: Debe existir alguna funcionalidad que permita la auto-configuración, alta disponibilidad y optimización de recursos.

• Administración de políticas: Descripción de las reglas de comportamiento requeridas por todos los puntos anteriores y fácilmente configurables a través de archivos de metadatos basados en XML o algún otro lenguaje descriptivo.

Visto desde el punto de vista de implementación, el ESB es el framework de desarrollo o producto comercial con el cual construiremos nuestro SOA, siendo tan sencillo o tan complejo como deseemos; la mejor opción es utilizar frameworks que contengan todos los elementos de un SOA ya integrados para facilitar la adopción de la nueva arquitectura, como veremos en la siguiente sección.

Implementaciones SOA/ESB

Actualmente existen de manera dominante tres suites, frameworks o implementaciones comerciales del middleware SOA/ESB que permiten la adopción de una arquitectura orientada a servicios:

• AquaLogic de BEA/Oracle.

• Java Composite Application Platform Suite (Java CAPS) de Sun Microsystems.

• Connected Services Framework (CSF) de Microsoft.

Adicionalmente existen otras implementaciones (Como OpenESB) pero su principal limitante es el escaso soporte que ofrecen, un punto muy importante en un proyecto tan complejo como puede ser SOA y que podría requerir una alta curva de aprendizaje; por otro lado a menos que el presupuesto de migración a SOA sea muy reducido[5], es mejor contar con las soluciones que estos proveedores ofrecen.

Ahora bien, haciendo la comparación entre las tres plataformas:

•  AquaLogic es el mejor producto de su clase pero el precio que manejan, aún con el modelo de ventas utilizado por Oracle[6], es astronómico.

• El producto de Sun es muy bueno, pero le falta un poco de pulido a sus interfaces de usuario (esencialmente porque en ocasiones la construcción de procesos puede volverse una pesadilla de micromanagement y "necesitamos" un monitor de 24 pulgadas):

Interfaz de usuario del Process Manager (vista de alto nivel de un proceso, sin detallar los servicios individuales) en el Java CAPS. (Original obtenido de From Java CAPS 5.1.x to Java CAPS 6 and Open ESB – Reuse or Rewrite)

[Click en imagen para ver a mayor escala]

• Finalmente CSF tiene que ver con la penetración de la tecnología Microsoft: si nuestra infraestructura está montada en una arquitectura Wintel, adelante; de lo contrario estamos saltando de la sartén al fuego.

Conclusiones

Hemos visto que la implementación de un SOA no sólo es publicar y consumir web services: se trata de hacer disponibles los servicios de datos y lógica de negocio de una manera estandarizada para que puedan ser utilizados por las diferentes áreas de una organización; todo ello mediante un marco tecnológico – el Enterprise Service Bus – que nos permita realizar de manera efectiva las tareas de gestión, transporte y mediación de los servicios y procesos que componen nuestro SOA. Por otro lado, hemos visto que Sun, BEA/Oracle y Microsoft son los proveedores de soluciones tecnológicas de implementación SOA más importantes del mercado, siendo AquaLogic la mejor pero más cara, JCAPS la de mayor curva de aprendizaje y Microsoft una solución efectiva si disponemos de una infraestructura Wintel.

Notas y pies de página

1. ¿Por qué publicar servicios de terceros en nuestro Directorio de Servicios? Porque adicionalmente a la "sección amarilla" que ofrece, incluye otras funcionalidades como el cache y versionamiento de servicios; características que pueden ser útiles cuando hay que integrar a terceros en nuestros procesos de negocio.

2. Se denomina orquestador de datos porque en su forma más pura, éste componente sólo utiliza servicios de extracción de datos para conformar – orquestar – los procesos de negocio que requiere la capa aplicativa.

3. BPEL es un lenguaje basado en XML que posee una representación diagramática (ver aquí un ejemplo de un algoritmo de transformación) que permite la construcción de procesos de negocio y que fue originalmente desarrollado por la Organización para el Avance de Estándares Estructurados de Información (Organization for the Advancement of Structured Information StandardsOASIS). Actualmente, en la versión 2.0, dicho leguaje ha sido tomado por proveedores para desarrollar sus implementaciones de ESB y frameworks SOA.

4. Los adaptadores ESB (Enterprise Service Bus) son aquellos que de manera nativa pueden ser utilizados para un SOA (por ejemplo, si nuestro protocolo es HTTP y nuestro formato es SOAP, implicaría que nuestra fuente de datos puede regresar queries en forma de documentos XML). Los adaptadores ETL (Extract, Transform and Load – Extraer, Transformar y Cargar) son aplicaciones que obtienen consultas de las fuentes de información y las transforman de manera no nativa al formato que estamos buscando. Los adaptadores EAI (Enterprise Application Integration – Integración de Aplicaciones Empresariales) son, en resumidas cuentas, aquellos que se conforman a un estándar de integración como JCA. Finalmente, XDMS (XML Document Management Server – Servidor de Gestión de Documentos XML) es el equivalente a una base de datos que en vez de almacenar esquemas entidad-relación, almacena jerarquías de documentos XML.

5. Sin embargo, queda la interrogante: si el cliente escatima en un proyecto de tal envergadura – que por poner un ejemplo, puede consistir de unas 20,000 horas/hombre – ¿no es probable que no esté entendiendo el alcance de SOA o los beneficios que ofrece?

6. El modelo de ventas de Oracle es en resumidas cuentas: el costo de licencia por cada producto se multiplica por el número de CPUs en los que está corriendo, considerando los siguientes tabuladores: si el CPU es específicamente un Sun UltraSPARC T1 con 4, 6 u 8 cores, las licencias se multiplican 0.25 por cada core; en el caso de AMD es 0.5 por cada core y en el caso de cualquier otro fabricante multicore – es decir, Intel o alguno de sus partners – se multiplica 0.75 por cada core. Para procesadores de un solo core se contabiliza una licencia por CPU.

h1

SOA (Parte 1)

09/06/2008

Wizdoc [Icon By Buuf]

 Tips & Tricks.

Había una vez un paradigma de diseño de arquitecturas IT – si es que así lo podemos llamar – donde todos los sistemas y recursos de una organización se localizaban y eran ejecutados desde una computadora central o mainframe. Dicho paradigma, denominado monolítico, tenía como misión generar reportes mediante procesos por lotes para facilitar la toma de decisiones de la alta dirección.

Sin embargo, a partir de la década de 1960 y con la creación del microprocesador, este paradigma comenzó a menguar en favor de las arquitecturas cliente-servidor, donde una computadora (el cliente) generaba una petición a otra (el servidor), que tomaba dicha petición, realizaba un procesamiento y devolvía un resultado; todo ello a través de un medio electrónico.

Desde ese momento la información de una organización y los procesos que la "masajeaban" ya no residían en una misma máquina, lo que desembocó en una explosión de requerimientos de las unidades de negocio hacia sus respectivas áreas IT para diseñar, construir y liberar cada vez más soluciones de acuerdo a sus necesidades específicas. Con la venida del Internet se reforzó la tendencia, pues aunadas a los sistemas de apoyo a la toma de decisiones, ahora se demandaban soluciones IT para prácticamente cualquier ámbito dentro de la organización: desde catálogos, órdenes de compra o administración de los recursos humanos hasta soluciones de mensajería y chat.

Sin embargo, esta explosión de sistemas de información trajo consigo un problema de gestión de arquitecturas: conforme aumentaba el número de aplicaciones, mayor necesidad había de integrar la información y los procesos que operaban sobre ésta, degenerando en un esquema como se muestra a continuación:


Una arquitectura empresarial convencional.
[Click en imagen para ver a mayor escala]

Este desorden genera estructuras rígidas y difíciles de adaptar a los requerimientos de una organización o sus necesidades de negocio. Así entonces, se encontró que la mejor forma de atacar el problema era diseñando una arquitectura que hiciera provecho de las tecnologías que facilitaban la interconexión entre plataformas de un ambiente heterogéneo generando un nuevo modelo de implementación arquitectónica. CORBA y SOAP son las tecnologías de mayor relevancia, aunque EDI fue el precursor de dichas plataformas de integración.

¿El resultado? La Arquitectura Orientada a Servicios (Service Oriented Architecture – SOA):

SOA es un paradigma de diseño de arquitecturas empresariales que facilita la conexión de las diferentes aplicaciones y fuentes de información mediante componentes seguros y estandarizados (los servicios) de tal manera que puedan ser reutilizados y combinados de manera flexible para atacar las cambiantes prioridades del negocio:

Una Arquitectura Orientada a Servicios. Nótese que el Gestor de Procesos es el encargado de combinar los servicios para generar procesos coherentes que sirvan a las necesidades de la organización, mientras que el Directorio de Servicios funciona como una "Sección amarilla" que permite listar y encontrar todos los servicios que contiene la organización.


[Click en imagen para ver a mayor escala]

Los servicios que componen un SOA

Una arquitectura orientada a servicios está compuesta por unidades lógicas individuales que existen de manera autónoma sin estar aisladas totalmente unas de otras. Estas unidades deben ajustarse a una serie de reglas y principios que les permiten evolucionar de manera independiente, manteniendo al mismo tiempo cohesión entre ellas y hacia un estándar. Dichas unidades son conocidas como los servicios:

Cuando se realiza la transformación de una arquitectura convencional a un SOA, comúnmente la generación de servicios se implementa sobre soluciones con procesos claramente definidos:

Los servicios pueden encapsular fragmentos de lógica de negocio de diferente "tamaño", "peso" o complejidad.

Como puede apreciarse en el diagrama, podemos fragmentar los procesos en unidades lógicas más sencillas que encapsulen operaciones con mayor o menor complejidad; si generamos nuestro SOA a partir de aplicaciones implementadas bajo el modelo de Programación Orientada a Objetos (Object-Oriented Programming – OOP), esta tarea puede ser llevada a cabo con mayor facilidad pues las operaciones de los objetos pueden ser publicadas como servicios:

Un Objeto de Acceso a Datos (Data Access Object – DAO) y un componente de negocio (en este caso un Enterprise Java Bean – EJB) tienen publicados sus métodos como servicios.


[Click en imagen para ver a mayor escala]

Frecuentemente se asocia un SOA y los servicios que lo componen a los llamados web services o servicios web, sin embargo la implementación de web services no es un SOA por sí mismo ni un SOA tiene que estar compuesto necesariamente por web services: los web services son una plataforma de interoperabilidad que facilita la generación y envío de mensajes entre sistemas heterogéneos. Es decir, mientras existan (1) un protocolo de transporte y (2) un formato de codificación y decodificación de los mensajes, cualquier medio puede ser utilizado para construir un SOA:

• SOAP – Simple Object Access Protocol.
• CORBA – Common Object Request Broker Architecture.
• SNMP – Simple Network Management Protocol.
• FTP – File Transfer Protocol.
• SMTP – Simple Mail Transfer Protocol.

Por ejemplo, es posible construir un SOA basado en SOAP para definir el formato de los mensajes y SMTP como medio de envío. Dicho de otra manera: llamadas a través de mensajes XML sobre correos electrónicos para ejecutar los servicios (aquí se muestra un ejemplo de esta implementación en el lenguaje de programación Python).

Conclusiones

SOA es un paradigma de construcción de arquitecturas empresariales como en un momento lo llegaron a ser los sistemas monolíticos, el cliente-servidor o las arquitecturas de N-Capas. SOA es un compendio de todas las buenas prácticas de desarrollo e implementación de soluciones de hardware, software y gestión de sistemas basándose en la modularidad de componentes y procesos, agilizando el desarrollo de nuevas aplicaciones que sirvan a las necesidades de negocio de una organización. Por otro lado, un SOA no sólo se trata de UDDI, WSDL y HTTP: los web services sólo son una plataforma de interconexión mientras que SOA es un modelo arquitectónico.

Por el momento, sólo hemos visto la punta del iceberg. En el próximo post veremos que una Arquitectura Orientada a Servicios no sólo se trata de publicar servicios sin ton ni son, sino que la implementación – véase las "tripas" – de un SOA está compuesta por una multitud de elementos arquitectónicos como BPEL (Business Process Execution Language), XDMS (XML Document Management Server) o el tan cacareado ESB (Enterprise Service Bus).

h1

Desarrollo de servicios web sin SOAP con XMLBeans

06/03/2008

Wizdoc [Icon By Buuf]

 Tips & Tricks

Generalmente se piensa que los Web Services [o Servicios Web] son sinónimo de servicios ofrecidos a través de SOAP. Esta es una visión limitada de los web services. Cualquier pieza de código con una descripción WSDL de sus aspectos funcionales y protocolos de acceso puede ser considerada un Web Service.

— Nirmal Mukhi, Web service invocation sans SOAP, 01 Sep 2001

Especificación General

Como puede verse en la siguiente figura, se requiere hacer la llamada al sistema Y desde el sistema X mediante el envío de un XML sobre una conexión HTTP/POST síncrona. Del lado del servicio publicado se encontrará un servlet que recibirá las peticiones y fungirá como un Service Facade, atrapando las peticiones y remitiéndolas a los componentes de parseo, validación y ejecución correspondientes para este servicio (denominados Core API del sistema o capa de negocio). Del lado del cliente o consumidor del servicio se espera implementar un componente que realice una conexión HTTP con el servicio y envíe el XML esperado a través del método POST. Más tarde, el servicio responderá con otro XML detallando el éxito o error resultante de la llamada que a su vez será parseado y validado por el cliente para tomar las acciones pertinentes.

Diagrama de componentes UML 2.0 (no estándar) que contempla la distribución a grosso modo de los elementos que conforman el servicio.

[Click en imagen para ver original]

Especificación de los mensajes

En la siguiente tabla se especifican los puntos requeridos en forma y formato de los mensajes a enviar. Nótese que entre los requerimientos no se incluye la necesidad de implementar SOAP como protocolo de envío.

Protocolo

XML codificado en UTF-8 sobre HTTP versión 1.1

Método de petición al servidor

HTTP/POST

Formato XML petición (X a Y)

<?xml version="1.0" encoding="UTF-8"?>
<ProvisioningRQ>
  <IdTransaction>0</IdTransaction>
  <TypeTransaction>BAJA</TypeTransaction>
  <Dn>1234567890</Dn>
</ProvisioningRQ>

Formato XML respuesta (Y a X)

<?xml version="1.0" encoding="UTF-8"?>
<ProvisioningRS>
  <IdTransaction>0</IdTransaction>
  <CodError>0</CodError >
  <DescError>OK</DescError >
</ProvisioningRS>

Aunque no es requerido, debemos generar un WSDL como referencia para saber cómo se realizará la llamada al servicio:

<?xml version="1.0" ?>
<definitions
 targetNamespace="http://everac99.spaces.live.com/wsdlexample&quot;
 xmlns:ytox="http://everac99.spaces.live.com/ytoxxsd&quot;
 xmlns:xsd="http://www.w3.org/1999/XMLSchema&quot;
 xmlns="http://schemas.xmlsoap.org/wsdl/"&gt;

  <message name="ProvisionInput">
   <part name="ProvisionRequest" type="ytox:ProvisioningRQ"/>
  </message>

  <message name="ProvisionOutput">
   <part name="ProvisionResponse" type="ytox:ProvisioningRS"/>
  </message>

  <portType name="ProvisionPT">
   <operation name="Provision">
    <input message="tns:ProvisionInput"/>
    <output message="tns:ProvisionOutput"/>
   </operation>
  </portType>
</definitions>

Los componentes e información seguirán el siguiente flujo:

Diagrama de secuencia UML que contempla el flujo de eventos a seguir por el servicio.
Notas:
1.Si la sintaxis o valores de negocio de la petición al servicio son incorrectos, se construirá la respuesta correspondiente.
2.Si la sintaxis o valores de negocio son correctos, se prosigue con la llamada a las funciones que requiere la operación.
3.Por "operaciones necesarias" contemplamos la llamada a una o más funciones del sistema "Y", tratando todo como una sola unidad transaccional.

[Click en imagen para ver original]

A partir del diagrama, podemos ver que se requiere un framework XML basado en DOM que nos facilite el trabajo de parsear y validar los valores contenidos en el XML; adicionalmente nos debe permitir construir documentos XML de forma eficiente y con un buen desempeño al generar nuestra respuesta. Por ello, se decidió utilizar la implementación 2.3.0 de XMLBeans. Este framework nos permite utilizar las funciones de parseo, validación o generación de XMLs en base a una jerarquía de componentes de java generados mediante las herramientas que posee dicho framework. A continuación describiremos el proceso de generación de nuestros componentes en base a tan sólo los XMLs de prueba que tenemos más arriba y cómo utilizarlos en un servicio web que recibe y envía los XMLs a través de la conexión HTTP.

Paso 1: Generando un XSD

Uno de los buenos hábitos al utilizar XML, es que siempre es recomendable definir un XSD (XML Schema Definition) para gestionar nuestros XMLs de manera centralizada. Adicionalmente, para generar los correspondientes XMLBeans requerimos un XSD.

Puesto que sólo disponemos de los XML de petición y respuesta deberemos generar el XSD a través de éstos. Existen varias herramientas de conversión XML a XSD en el mercado, pero podemos utilizar la herramienta de conversión on-line ofrecida por HiT Software donde podemos transformar nuestros XMLs en los XSDs que necesitamos.

Herramienta de conversion xml a xsd
Un screenshot de la herramienta de conversión de XML a XSD y el archivo XML con el ProvisioningRQ de nuestro servicio. NOTA: La herramienta no parsea correctamente XMLs con varios elementos, es decir, hay que generar un XSD con el merge de los resultados la transformación de ProvisioningRQ y ProvisioningRS.

[Click en imagen para ver original]

El resultado de la conversión de nuestros XMLs será algo así:

<?xml version="1.0" encoding="UTF-8" ?>

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
 <xs:element name="Dn">
  <xs:complexType mixed="true"/>
 </xs:element>

 <xs:element name="IdTransaction">
  <xs:complexType mixed="true"/>
 </xs:element>

 <xs:element name="ProvisioningRQ">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="IdTransaction"/>
    <xs:element ref="TypeTransaction"/>
    <xs:element ref="Dn" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>

 <xs:element name="TypeTransaction">
  <xs:complexType mixed="true"/>
 </xs:element>

</xs:schema>

El código mostrado es el XSD del elemento ProvisioningRQ. Para generar el XSD de la aplicación, es necesario realizar un merge de los XSDs del request y response e incluir las reglas de formato, tipos de datos o restricciones que sean requeridas para parsear correctamente los XMLs que utilizará la aplicación. Las propiedades que pueden tomar estos elementos pueden verse en el tutorial sobre XSDs del W3Schools; para validar los XMLs contra nuestra XSD refinada podemos utilizar una pequeña herramienta llamada XmlValidator. La definición final para esta aplicación sería la siguiente:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;

 <!– Tipos de datos –>
 <xs:element name="IdTransaction" type="xs:string"/>
 <xs:element name="Dn" type="xs:string"/>
 <xs:element name="TypeTransaction" type="xs:string"/>
 <xs:element name="CodError" type="xs:string"/>
 <xs:element name="DescError" type="xs:string"/>

 <xs:element name="ProvisioningRQ">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="IdTransaction" minOccurs="1" maxOccurs="1"/>
    <xs:element ref="TypeTransaction" minOccurs="1" maxOccurs="1"/>
    <xs:element ref="Dn" minOccurs="1" maxOccurs="1"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>

 <xs:element name="ProvisioningRS">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="IdTransaction" minOccurs="0" maxOccurs="1"/>
    <xs:element ref="CodError" minOccurs="0" maxOccurs="1"/>
    <xs:element ref="DescError" minOccurs="0" maxOccurs="1"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>

</xs:schema>

Paso 2: Generando los XMLBeans

En Adictos al Trabajo podemos encontrar un buen tutorial para instalar y ejecutar las herramientas de conversión de los XMLBeans. Sin embargo, existen tres detalles que es necesario observar:

•  Hay que tener cuidado con qué versión de Java estamos trabajando. Es decir, necesitamos verificar que el compilador y el ambiente de ejecución (javac.exe y java.exe, respectivamente) estén correctamente configurados en el path del ambiente de desarrollo y en el archivo ${XMLB_HOME}binscomp(.cmd) porque puede surgir el error "CreateProcess Exception" al tratar de compilar el XSD (En el Java Boutique se encuentra la explicación y solución al problema).

•  Por otro lado, si estamos usando una versión anterior a Java 1.5, adicionalmente a la librería base de XMLBeans llamada xbean.jar, deberemos incluir en la distribución de la aplicación el archivo xmlbeans-qname.jar para poder utilizar correctamente esta funcionalidad.

•  Finalmente, la tarea de ant para generación de XMLBeans deja mucho que desear. La forma más flexible de crear y empaquetar correctamente los componentes es mediante la línea de comando:

>${XMLB_HOME}/bin/scomp -javasource 1.4 -out ${ProjectHome}/lib/xmltypes.jar ${ProjectHome}/config/xsd/ytoxxsd.xsd ${ProjectHome}/config/xsd/ytox.xsdconfig
Time to build schema type system: 0.937 seconds
Time to generate code: 0.328 seconds
Time to compile code: 3.422 seconds
Compiled types to: ${ProjectHome}/lib/xmltypes.jar
>

Donde:
•  ${XMLB_HOME} Es el directorio donde está instalado el framework.
•  ${ProjectHome} Es el directorio donde está nuestro proyecto.
•  ytoxxsd.xsd Es el XSD que generamos en el paso anterior.
•  ytox.xsdconfig Es un archivo de configuración XML que permite mapear los namespaces del XSD con paquetes de java:

<?xml version="1.0" encoding="UTF-8"?>
<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config"&gt;
  <xb:namespace uri="##any">
    <xb:package>
     com.spaces.everac99.xml.types
    </xb:package>
  </xb:namespace>
</xb:config>

Esto dará por resultado un JAR con los componentes de Java que podrán ser utilizados en el proyecto de Eclipse:

El JAR con XMLBeans en nuestro proyecto de Eclipse
El JAR con XMLBeans en nuestro proyecto de Eclipse.

Paso 3: Usando los XMLBeans

Como puede verse en el siguiente fragmento de código:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

/* Parseo del HttpRequest InputStream para construir un XMLBean */
BufferedInputStream in = new BufferedInputStream(request.getInputStream());
ProvisioningDocument req = ProvisioningDocument.Factory.parse(in);
String idTransaction = req.getProvisioning().getIdTransaction();

/* Validacion de reglas de negocio y ejecucion de operacion (llamada a Core API)*/

/* Construccion de un nuevo XMLBean desde cero y envio al HttpResponse OutputStream*/
ProvisioningResponseDocument res = ProvisioningResponseDocument.Factory.newInstance();
res.documentProperties().setVersion("1.0");
res.documentProperties().setEncoding("UTF-8");
res.addNewProvisioningResponse();
res.getProvisioningResponse().setIdTransaction("12345");
res.getProvisioningResponse().setCodError("007");
res.getProvisioningResponse().setDescError("UNKNOWN ERROR");

BufferedWriter out = new BufferedWriter(response.getWriter());
res.save(out);
out.flush();
out.close();

}

Construir y manipular los XMLBeans generados a partir del XSD es muy intuitivo: En el primer segmento de código se está construyendo un XMLBean a través de la secuencia de llamadas BeanClassDocument.Factory.parse(InputStream). Por otro lado se está construyendo un nuevo documento mediante la secuencia BeanClassDocument.Factory.newInstance() y se está almacenando en la respuesta de la petición mediante el método BeanObjectDocument.save(OutputStream).

XMLs con elementos mixtos

Un detalle que puede presentarse durante la construcción de un servicio de este tipo es la generación o parseo de documentos XML que poseen elementos mixtos: es decir, nodos que pueden contener más subnodos, texto o combinaciones de ambos:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <RESULT msisdn="telefono1">ABCD999999A1B</RESULT>
  <RESULT msisdn="telefono2">
    <ERROR id="045">UNKNOWN NUMBER</ERROR>
  </RESULT>
</Response>

En el ejemplo se muestra la respuesta a un servicio de búsqueda donde puede traer de 1 a 10 elementos de tipo RESULT. Cada elemento contiene una propiedad denominada msisdn y dentro de la etiqueta en sí puede existir un texto o un elemento de tipo ERROR.

Sin embargo, esta situación no tiene por qué generar preocupación, pues con un XSD de este tipo de documento podremos generar los XMLBeans que necesitamos:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;

 <xs:element name="ERROR">
  <xs:complexType mixed="true">
   <xs:attribute name="id" type="xs:string"/>
  </xs:complexType>
 </xs:element>

 <xs:element name="RESULT">
  <xs:complexType mixed="true">
   <xs:sequence>
    <xs:element ref="ERROR" minOccurs="0" maxOccurs="1"/>
   </xs:sequence>
   <xs:attribute name="msisdn" type="xs:string" use="required"/>
  </xs:complexType>
 </xs:element>

 <xs:element name="RESPONSE">
  <xs:complexType>
   <xs:sequence>
    <xs:element ref="RESULT" minOccurs="1" maxOccurs="10" />
   </xs:sequence>
  </xs:complexType>
 </xs:element>

</xs:schema>

Al utilizar este tipo de documentos tendremos que utilizar una característica algo enredosa de los XMLBeans denominada XMLCursor:

/* Leyendo un elemento de tipo mixed de un XMLBean */
BufferedInputStream in = new BufferedInputStream(request.getInputStream());

ResponseDocument res = ResponseDocument.Factory.parse(in);

if(res.getResponse().getRESULTArray(0).getERROR() == null) {
  /* Significa que este elemento contiene texto */
  XmlCursor cursor = res.getResponse().getRESULTArray(0).newCursor();
  cursor.toFirstContentToken();
  String valor = cursor.getChars();
} else {
  /* Significa que este elemento contiene un subnodo */
  String errorId = res.getResponse().getRESULTArray(0).getError().getId();
}

/* Escribiendo texto en un elemento de tipo mixed en un XMLBean*/
ResponseDocument doc = ResponseDocument.Factory.newInstance();
doc.addNewResponse();
doc.getResponse().addNewRESULT();
doc.getResponse().getRESULTArray(0).setMsisdn("telefono1");
XmlCursor cursor = doc.getResponse().getRESULTArray(0).newCursor();
cursor.setTextValue("ABCD999999A1B");
cursor.dispose();

Esta interfaz nos permite saltar a lo largo de la estructura del documento XML facilitando la modificación de los valores e incluso agregar nuevas etiquetas de elementos.

Conclusiones

Como hemos visto, no es difícil construir un servicio web utilizando los XMLBeans como framework de conversión XML a Java, pues como tienen métodos que nos permiten cargar o enviar nuestros XMLs desde o hacia streams de datos, podemos utilizar sus características para ahorrar tiempo, dinero y esfuerzo a la hora de construir la solución. Un beneficio adicional: si necesitamos implementar web services con SOAP también podemos utilizar XMLBeans y trabajar sobre clases de Java, no sobre cadenas de XML que son bastante difíciles de codificar y peor aún de mantener.

h1

Designing Web Services with the J2EE 1.4 Platform: JAX-RPC, SOAP, and XML Technologies (revisited)

11/21/2006

Wizdoc [Icon By Buuf]

 Tips & Tricks

[ES-MX] Nota: originalmente este texto lo escribí para poder mostrárselo a uno de los compañeritos del team del CDS por aquello de mensajes asíncronos con confirmación.

[EN-US]

On Chapter 8.4.3 (Refactoring Synchronous to Asynchronous Interactions) of the book the author states that for synchronous to asynchronous service refactoring it is required to use a request-response communication. What is really defined is a request-null-response-null model combined with a caller/endpoint inversion of roles:


(Figure 8.9a – The Asynchronous Communication detailed on the blueprints).

However, there is a better approach for the web service asynchronous communication model:

  • Instead of changing the synchronous request/reply interaction into a void, it is possible to introduce an "acknowledge message" response model: the architecture follows the original asynchronous communication concept but defines a request-acknowledge-response-acknowledge process flow, which has increased scalability an robustness, fulfilling most communication-failover needs (Figure 8.9b – The Enhanced Asynchronous Communication):

(Figure 8.9b – The Enhanced Asynchronous Communication).
  • If any of the receivers is down (Endpoint on original request; caller on final response) it is defined a retry mechanism: If the caller does not receive an acknowledge for a finite amount of time (acknowledge timeout), it can try to dispatch the same message for a predefined number of times over a finite period interval between each one (retry number, retry interval).
  • For the retry mechanism, the sender (Caller on original request; endpoint on final response) should send the message to a JMS queue for later delivery; this queue must have a Timer component that resends each message according to individual "failed-to-deliver" timestamps. It is mentioned in the book that this is an optional task; however all dispatching should go through a JMS queue as it limits the consumed resources and provides message delivery reliability.
  • The retry mechanism can also dispatch all queued messages in one pass, if there is a ping[1] service enabled on this architecture.
  • For even more scalability, it is possible to add another indirection layer between the dispatching and business logic modules. This means the receiver component on the endpoint will not call directly a business component for message processing (i.e.: a Session EJB) but will send the message (even on raw, SOAP format) to another JMS queue. On the business layer resides a Message-Driven Bean whose function is to recover this messages and call the appropriate EJB (this assuming that for each message the application should follow different workflows). Although it is displayed on the original diagram, it is not explained in much detail.

Miscellaneous points

  • As a good programming practice, if the document-style[2] web service strategy is selected, all elements sent through the communications channel must be convertible between java objects and their xml representation by means of JAXB implementation frameworks (XMLBeans is a good option); using
    String Object.toXML()

    or

    Object Object.parse(String xmlString)

    is time-consuming, error-prone and difficult to debug.

  • Another area of concern is the web service security that must be integrated as part of all layers in the architecture; however this topic will be explained in a future article.

Footnotes and annotations

1. The ping service should be a synchronous web service that requests simple information between the caller and endpoint tiers; this component allows for tuning and resource optimization:

  • In the event of communications disruption detection, all generated messages can be queued for later delivery without going through the retry mechanism (remember: any delivery failure generates an IOException with its accompanying stack trace).
  • If the communication channel goes live again and is detected by the ping service, all queued messages could be redelivered on demand (according to creation timestamp) or en-masse.

2. The document-style web service strategy implies that the return values and parameters passed through both dispatcher/receiver methods implement the XML DOM specification; on the contrary, an rpc-style web service relies on passing/returning serializable java objects.