JAX-WS 2.0: Vista rápida (II)



(Imagen: Rembrandt - Retrato de Titus como monje)

Supongo que al final la vista no era tan rápida que digamos xD. Seguimos con más características de JAX-WS 2.0

Contexto de Mensajes:
JAX-WS nos permite la manipulación del contexto del mensaje (javax.xml.ws.handler.MessageContext) mediante los handlers, endpoints y clientes. Este contexto viaja junto a los mensajes XML de request y response, y nos permite, entre otras cosas, la comunicación entre request handlers, implementaciones de endpoint y response handlers.

SOAP binding:
JAX-WS 2.0 especifica SOAP binding para el proceso de mensajes SOAP. Incluye el procesamiento de mustUnderstand, y soporta los roles nest y ultimateReceiver de SOAP 1.2. El SOAP binding soporta también el uso de SOAP handlers, para el procesamiento de headers SOAP, y mapea las excepiones handler y servicea mensajes de error SOAP.

Las implementaciones de JAX-WS deben soportar SOAP HTTP binding, SOAP con adjuntos y SOAP MTOM.

HTTP Binding
También disponemos de XML/HTTP binding para el despliegue y consumo de Web Services mediante el framework REST. Estos servicios (llamados RESTful) envían y reciben XML sobre un transporte HTTP sin utilizar SOAP.

Conversión de Excepciones a errores SOAP
JAX-WS realiza un mapeo de java.lang.Exception a mensajes de error SOAP (WSDL faults) que son enviados al cliente, incluso al utilizar servicios RESTful. Este proceso en controlado con la anotación WebFault.

Invocación Asíncrona
JAX-WS añade soporte asíncrono al modelo de invocación definido en JAX-RPC 1.1. La "asincronía" es un requisito fundamental de SOAP.

Operaciones one-way
JAX-WS soporta el mapping entre métodos Java y operaciones one-way de WSDL.

Manejo de Threads del lado del cliente
Para proveer control de threads, se puede utilizar instancias de java.util.concurrent.Executor en un cliente JAX-WS (como una instancia de javax.xml.ws.Service).

Estilos WSDL
JAX-WS le encarga la serialización a JAXB, pero para empacar los parámetros serializados en un mensaje SOAP, JAXB necesita de la asistencia de JAX-WS. Esta guía depende del estilo WSDL usado por el Web Service desplegado. JAX-WS soporta los estilos WSDL rpc/literal y document/literal.

Catálogos XML
JAX-WS soporta el uso de catálogos XML. Es útil para los documentos WSDL el importar esquemas externos para evitar duplicidad.

Pseudoreferencias
Las invocaciones de métodos Java pasan las referencias a objetos por valor. Los Web Services no trabajan así: al pasar un objeto a un Web Service, se envuelve una copia serializada de la instancia en un mensaje SOAP y ésta es enviada.

El pasar referencias es útil para, por ejemplo, invocar un método que cambie el estado de una instancia. JAX-WS nos prevee del mecanismo de pase de "pseudoreferencias", mediante la clase Holder.

Esto se hace posible al usar la clase Holder como referencia a nuestra instancia. Al invocar el Web Service, JAX-WS envía una copia de la instancia al destino, y obtiene una versión modificada de la misma. Detrás de bambalinas, JAX-WS actualiza la instancia de Holder para que referencie a la instancia devuelta por el Web Service.

Run-Time Endpoint Publishing (sólo Java SE)
JAX-WS nos permite publicar endpoints de Web Services en tiempo de ejecución. Existe un API (javax.xml.ws.Endpoint) que nos permite asignar una instancia de una implementación Web Service a una URL.

He aquí un ejemplo:

MyServiceImpl myWebService = ... //contruir Web Service
Endpoint myEndpoint = Endpoint.publish("http://localhost/myService", myWebService);

Eso es todo! El runtime de JAX-WS se encarga de crear la infraestructura necesaria. Eso incluye crear un contexto HTTP y el listening de request SOAP en el URL especificado. Al usar este enfoque, el contrato WSDL para el endpoint se crea dinámicamente en base a anotaciones o en documentos de metadata.

Con eso terminaríamos con JAX-WS... por ahora xD

Basado en el capítulo 2 de SOA Using Java Web Services de Mark D. Hansen


JAX-WS 2.0: Vista rápida

(Imagen: Rembrandt - Retrato de Saskia van Uylenburg)


JAX-WS 2.0 es la especificación siguiente a JAX-RPC 1.1. Veamos algunas cosas de lo que hace:

Mapping Java/WSDL

JAX-WS 2.0 define un mapping estándar para Java/WSDL. Determina como las operaciones WSDL están relacionadas con métodos Java. En otras palabras, cuando un mensaje SOAP invoca una operación WSDL el mapping Java/WSDL determina que método Java invocar y como el mensaje SOAP contiene los parámetros del método. También, el mapping determina como el resultado del método es encapsulado en el response SOAP.

Este mapping estándar nos permite comenzar con una clase Java, pasársela al procesador JAX-WS (puede ser java2wsdl o wsgen) y generar la descripción WSDL del endpoint del Web Service.

Por otro lado, se puede comenzar por un documento WSDL y generar las clases Java y las interfaces. Las clases Java que obtenemos son clases wrapper y es necesario que implementemos la lógica de negocio. Estas clases generadas ya incluyen anotaciones que describen el mapping Java/WSDL.

Algunos principios del mapping WSDL/Java:

  • Los port types del WSDL se mapean a Interfaces Java: Un elemento wsdl:portType es mapeado a una interfaz Java denominada service endpoint interface (SEI). No se puede mapear operaciones individuales dentro de un port type a interfaces Java diferentes. Para implementar un port type, se debe desplegar una SEI.
  • Los mappings de los parámetros y del valor retornado deben ser compatibles con JAXB: Las clases usadas para los parámetros de la SEI y su valor de retorno deben usar anotaciones JAXB para especificar los componentes del esquema XML al que van a ser mapeados.

WSDL estático

JAX-WS nos permite especificar un documento WSDL estático y omitir la generación automática de WSDL que se basa en los mappings estándar WSDL/Java y XML/Java (JAXB). Esto es útil cuando se necesita publicar un Web Service (WS) que se ajuste a un WSDL específico. También nos permite publicar WSDL basados en esquemas existentes.

Clientes estáticos y dinámicos

Los clientes de Web Services de JAX-WS son instancias de javax.xml.ws.Service. Una instancia de Service se corresponde con el elemento wsdl:service del documento WSDL del WS al que nos queremos conectar. Las instancias de Service pueden ser generadas de manera estática o dinámica. La generación dinámica es realizada en tiempo de ejecución por los métodos Service.create. En lo concerniente a generación estática, es posible generar subclases de Service de un documento WSDL usando herramientas de JAX-WS (como wsimport en GlassFish)

Invocación mediante Interfaces Proxy Java

Las instancias de Service pueden crear un proxy para invocar al WS mediante una SEI. Los métodos Service.getPort se utilizan para crear instancias SEI relacionadas con el wsdl:port a invocar. La SEI generada debe ser consistente con los mappings Java/WSDL (JAX-WS) y XML/Java (JAXB). Es por esto que cuando se utilizan proxys SEI se hacen por lo general con instancias de Service generadas junto al SEI, al compilar el WSDL a invocar mediante herramientas JAX-WS(e.j wsimport).

Invocación con XML

Una instancia de Service puede invocar un WS enviando y recibiendo mensajes XML. Para esto, la clase Service nos provee una instancia de javax.xml.ws.Dispatch al invocar cualquier método createDispatch. Esto nos permite interactuar con el WS directamente via XML sin tener que serializar y deserializar a Java.

XML Service Providers

Es posible desplegar un servicio que simplemente envíe y reciba mensajes XML sin preocuparse en el mapping con clases JAXB, mediante la interfaz javax.xml.ws.Provider. Al crear un servicio mediante Provider, no se hace uso de una SEI; por lo que nos permite crear servicios que trabajen directamente con los request y response en XML.

Framework para Handlers

JAX-WS define handlers de request y de response que pueden ser usados en el lado del cliente o del servidor. Los Handlers nos permite el pre-procesamiento y post-procesamiento de mensajes.

Los handlers tienen acceso de lectura y escriuta al mensaje XML y a su contexto. Los handlers JAX-WS se organizan en listas ordenadas llamadas cadenas de handlers. Las cadenas de handlers se definen a nivel de puerto, por lo que todos los métodos de una SEI usan la misma cadena de handlers.

Basado en el capítulo 2 de SOA Using Java Web Services de Mark D. Hansen

Ahora es más fácil hacer Web Services (se supone)

(Imagen: Edvard Munch - Niña enferma)

Una de las ideas detrás de JWS (Java Web Services) es facilitarle la vida a los desarrolladores en la ya tediosa tarea de crear y desplegar Web Services. Supuestamente, ahora ya es así, por lo que revisaremos a grosso modo las características de JWS que nos harán trabajar menos xD:

Anotaciones en código fuente

Ahora es posible anotar nuestro código fuente para hacer más simple el despliegue de Web Services. Estas anotaciones están definidas en JAX-WS, WS-Metadata y JAXB

Mapping Java/WSDL estándar

JAX-WS define un mapping estándar (sorry, pero no sé como traducir mapping xD) de WSDL a Java y viceversa. Cuando un service implementation bean (SIB : clase que puede ser desplegada como endpoint de WS) es desplegado, el WSDL resultante está basado en este mapping por defecto. Este mapping por defecto le facilita la vida al programador Java que quiere desplegar un Web Service y no conoce mucho de WSDL o XML.

Aunque no todo es perfecto, y este mapping tiene sus limitaciones. Por ejemplo, no se puede mapear mapear dos operaciones en el mismo puerto WSDL que pertenezcan a diferentes SIB's. En cristiano, si tenemos el puerto wsdl:port con las operaciones foo y bar, tanto foo como bar deben pertenecer a las misma clase/interface Java. Además, sólamente es posible mapear un WSDL a un SIB, por lo que es imposible desplegar una clase no anotada como Web Service.

Contexto de Serialización estándar

Ahora ya no es necesario especificar mappings y serializadores al momento del despliegue de un Web Service. Parafraseando, con el contexto de serializacióne estándar no hay que definir el XML al que las clases Java van a ser mapeadas. Y esto es posible debido a que JAXB se encarga de la serialización. JAXB tiene reglas estándar para serializar/deserializar componentes de un esquema XML a/desde objetos Java.

Modelos de desarrollo

El primero es "comienzo por Java". En este modelo, se empieza el desarrollo del Web Service(WS) construyendo una clase Java. Luego, para desplegar esta clase como WS la anotamos con @WebService y listo xD!. Los runtimes de JAX-WS y JAXB se encargan de mapear esta clase a un documento WSDL usando los mappings estándar de WSDL/Java y XML/Java. Si queremos modificar nuestro WSDL lo podemos hacer mediante anotaciones.

El otro modelo es "comienzo por el WSDL". En este caso tomamos un WSDL ya existente y usamos un compilador WSDL (que nos brinda la implementación JAX-WS) para generar las clases Java que implementan ese WSDL. Con este modelo obtenemos una grupo de SEI's (Service Endpoint Interface) que se corresponden con el WSDL. Entonces, nuestro trabajo es implementar las SEI's con lógica de negocio.

Y el último modelo es "comienzo por WSDL y por Java". La idea aquí es referenciar un WSDL pre-existente en la anotación @webService, que usaremos en la clase Java que pretende implementarla. Entonces, utilizamos anotaciones para hacer mapping entre la clase y el WSDL referenciado.

Basado en el capítulo 2 de SOA Using Java Web Services de Mark D. Hansen

Java Web Services: Una introducción (Parte II)



Ahora toca revisar los estándares (JSR's) vistos desde el lado de un cliente que utilice Java SE 6 o Java EE 5. Igual que en el post anterior, vamos a tomar prestado un dibujito de SOA Using Java Web Services para mostrar las cosas más claramente:

  1. Lo primero que debe hacer un cliente para invocar un Web Service es generar una SEI (Service Endpoint Interface), mediante una herramienta que transforme WSDL en código Java. Una SEI nos brinda una representación Java del Web Service (WS) que invocamos. Para generar la SEI usamos JAXB (convierte los parámetros XML del WSDL en parámetros Java del SEI), anotaciones de WS-Metadata y JAX-WS.
  2. En tiempo de ejecución, utilizamos una instancia de javax.xml.Service (de JAX-WS) he invocamos al método getPort para obtener una instancia del SEI generado en el paso anterior. Esta instancia es llamada en el gráfico Proxy Instance, y como se ve también en el gráfico, implementa nuestra SEI.
  3. Después, se inicia la invocación del WS al invocar uno de los métodos de la SEI en Proxy Instance. El runtime JAX-WS traduce los parámetros JAXB y la invocación del método en un request SOAP que es enviado al Web Service. Antes que el request SOAP (insisto, generado por el runtime JAX-WS) sea enviado al endpoint del Web Service, se procede a invocar a los Handlers (y esto también lo hace el runtime JAX-WS). Los handlers son definidos por el usuario y pueden manipular los mensajes SOAP (de request o de response). Para definir Handlers se hace uso de anotaciones definidas en la especificación WS-Metadata.
  4. Después de que los Handlers hacen su trabajo, se envía el request SOAP al Web Service y se obtiene como resultado un response SOAP. A este response SOAP se le aplican los Handlers y parámetros del response SOAP son deserializados por el runtime JAXB
  5. Finalmente, la Proxy Instance devuelve una instancia JAXB como resultado de la invocación del método.
Basado en el capítulo 2 de SOA Using Java Web Services de Mark D. Hansen

Java Web Services: Una introducción (Parte I)


(Imagen: Edvard Munch - Madonna)


En fin, comenzaremos con una introducción violenta al mundo de los Web Services, dado que ya se acerca el vencimiento de mi voucher y tengo que rendir el SCDJWS antes que eso suceda. Comenzaremos esto con una revisión de los estándares necesarios para desarrollar Web Services con Java, así que van a ver muchas letritas en mayúsculas en este post.

Desarrollar Web Services (WS) implica desarrollar interfaces entre sistemas heterogéneos, las cúales están definidas mediante documentos WSDL, que están expresados en XML (y vamos a ver mucho XML de ahora en adelante). Este documento define los parámetros de entrada y de salida del WS en función a un esquema XML. Los parámetros de entrada llegan al WS usando una estructura de mensajes, que puede ser el estándar SOAP (aunque esto no es obligatorio).

Entonces, se puede utilizar mensajes SOAP (nuestro estándar de mensajes) para la transferencia de los mensajes de entrada y salida especificados en una definición de interfaz WSDL (nuestro lenguaje de definición de interfaces). Estos mensajes SOAP pueden viajar sobre distintos medios (HTTP, SMTP o JMS), pero una opción simple y natural sería utilizar HTTP.

Para poder certificarnos como SCDJWS debemos conocer los estándares Java Web Services , que nos proveen de herramientas para trabajar con WSDL y SOAP/HTTP mediante nuestro lenguaje de programación favorito (espero que su respùesta halla sido Java). Tenemos herramientas del lado del servidor que nos permiten invocar métodos Java mediante SOAP y publicar sus respectivas definiciones de interfaces WSDL. Por otro lado, tenemos herramientas del lado del cliente para leer documentos WSDL y enviar/recibir mensajes SOAP.

Comencemos viendo el despliegue del lado del servidor, y la invocación de un WS. Para esto nos ayudaremos con esta gráfica tomada de SOA Using Java Web Services:


  1. Un puerto es la vista del servidor de un Web Service, que puede estar empaquetado como un WAR o un EJB JAR. El JSR (Java Web Service Standard) utilizado para definir el proceso de despliegue y la estructura de paquetes es WSEE. Asimismo WS-Metadata (otro JSR) describe como las anotaciones del clases empaquetadas se ajustan al despliegue.
  2. El endpoint que se observa en el gráfico soporta peticiones HTTP GET para las que devolverá el WSDL que describe el WS. La estructura de este WSDL es definida por el mapeo WSDL/Java de JAX-WS. Este mapeo puede ser modificado mediante las anotaciones de JAX-WS, JAXB y WS-Metadata.
  3. La invocación del WS desplegado se inicia cuando se recibe una petición SOAP a través de un HTTP POST que llega al endpoint.
  4. El endpoint de un WS se implementa por lo general mediante un servlet que atiende request de un URL especificado al momento del despliegue
  5. En el paso 5 del dibujo la petición SOAP se ha convertido en un grupo de parámetros XML (instancias del esquema XML especificados como parámetros en el WSDL). El runtime JAX-WS es responsable de extraer estos parámetros de mensaje SOAP.
  6. Luego, los parámetros XML son "deserializados" en parámetros Java. Este proceso es manejado por el runtime JAXB, en funciónm de las anotaciones en las clases Java objetivo.
  7. Una vez que los parámetros han sido creados (los parámetros Java),se invoca el método Java correspondiente al WS. Esto es manejado por el runtime JAX-WS. Las clases que nos proveen el método invocado pueden ser EJB's o POJO's. Como se ve en el dibujo, aquí están metidos JAX-WS, JAXB y WS-Metadata.
  8. Después de la invocación, el proceso se ejecuta en orden inverso. El resultado del método, que es una instancia Java, es serializado en una instancia XML mediante JAXB. Para esto, se deben agregar anotaciones en la clase Java resultado.
  9. Luego, el runtime de JAX-WS toma las instancias XML devueltas y las envuelve en una respuesta SOAP.
  10. Finalmente, la respuesta SOAP es enviada al invocador del WS en una respuesta HTTP.


Creo que hasta aquí llegamos hoy. Mañana la continuamos.

Basado en el capítulo 2 de SOA Using Java Web Services de Mark D. Hansen