Práctica 6. Servicios WEB (Java JAX-WS)
En esta práctica se pretende mostrar el uso del API de servicios web de Java
(JAX-WS [Java API for XML Web Services]). Se mostrará como acceder a servicios Web
ya publicados y como crear un servicio Web propio.
Los paquetes, clases, anotaciones e interfaces que implementan JAX-WS habitualmente forman parte de un servidor de
aplicaciones Java EE, aunque la implementación de referencia se distribuye
dentro de JAVA SE 6 (jdk 1.6), por lo que es posible utilizarlo de forma aislada.
- Las clases, interfaces y anotaciones se encuentran en el paquete javax.xml.ws y sus descendientes.
JAX-WS reemplaza y amplía al anterior API de accesos a servicios Web (JAX-RPC), aunque actualmente ambos están en uso.
JAX-WS hace uso de anotaciones Java para describir elementos de las clases implicadas en la implementación
del servicio y simplificar el desarrollo de servicios Web.
- Las anotaciones Java
son un mecanismo
para asociar metadatos al código Java que permiten describirlo.
- Se introdujeron en la versión Java SE 5 (jdk 1.5)
- Permiten indicar de forma declarativa caraterísticas y/o propiedades de fragmentos
de código (clases, atributos, métodos, etc) que hacen posible automatizar determinadas tareas.
Para el manejo de los ficheros XML que conforman los mesnajes de petición y respuesta SOAP, JAX-WS hace uso del API
JAXB (Java Architecture for XML Binding).
Con JAXB es posible mapear un documento XML en una jerarquía de objetos Java y viceversa, haciendo más sencilla la gestión y manejo de documentos XML, sin necesidad de trabajar con APIs de más bajo nivel como SAX o DOM.
Nota: Internamente la implementación de JAXB usa SAX para procesar los docuentos XML.
- Para hacer esta traducción JAXB hace uso de anotaciones (@XmlRoot,@XmlElement,
@XmlAttribute, ... [ver Javadoc de JAXB]) que decoran los objetos y clases Java indicando como debe realizarse su serialización/deserialización a XML (marshalling y unmarshaling en terminología JAXB)
- También se puede hacer uso de documentos XML-Schema (que describen la estructura de los ficheros XML) para generar a partir de ellos las clases que contendrán los datos y la estructura de los ficheros XML procesados.
Para el caso concreto de los servicios WEB basados en SOAP se incluyen 2 herramientas adicionales:
- wsgen: genera el documento WSDL que describe un Servicio WEB SOAP ofrecido por un objeto Java marcado
con las anotaciones @WebService y @WebMethod (ver anotaciones JAX-WS), junto con los tipos de datos
usados como parámetro y valor de retorno.
- wsimport:genera a partir del documentos WSDL que describe un Servicio WEB
una jerarquía de clases (con anotaciones JAXB) para almacenar en ellas los parámetros y valores de retorno.
Se mostrará un ejemplo de creación de clientes para Servicios Web ya publicados
a partir del documento WSDL
que los describe.
- Se hará uso de la herramienta wsimport incluida en Java SE 6
- wsimport analiza el documentos WSDL que describe el servicio Web y crea un
conjunto de clases auxiliares
- Clases stub que representan localmente al servicio Web
- Crea una clase para cada <service> y cada <port>
declarado en el fichero WSDL (mantiene los nombres del WSDL)
- Las clases asociadas a los <port> disponen de un método
por cada una de las operaciones (<operation>) incluidas
en el <portType> correspondiente.
- Clases complementarias para implementar la serializacion/deserializacion
de los mensajes SOAP de cada una de las operaciones (basado en JAXB)
- Clases de apoyo para el acceso a estructuras XML complejas que se usen
como parámetro o valor de retorno en las invocaciones SOAP (basado en JAXB)
- Permiten acceder a fragmentos XML mediante objetos Java
Para el ejemplo se usarán los servicios Web del repositorio http://www.webservicex.net/
- En concreto se trabajará con el
USA Weather Forecast
que
permite consultar la predicción semanal del tiempo para una ciudad de Estados Unidos.
- Se invocará la operación GetWeatherByPlaceName que recibe como argumento un String
con el nombre de una ciudad y devuelve un elemento XML <WeatherForecasts> que almacena
una estructura de datos (datos de la ciudad + array de predicciones) [ver WSDL]
Comentarios:
- Desde la página de http://www.webservicex.net donde se describe cada servicio web
se pude acceder a ellos e invocar sus operaciones desde la sección demo.
- El acceso a http://www.webservicex.net y a los servicios que gestiona suele estar congestionado,
por lo que las peticiones realizadas pueden tardar algo de tiempo en ser respondidas (o abotarse por fallos de time-out).
Interesante: Repositorios de Servicios Web públicos
- Importar las definiciones WSDL y generar las clases de apoyo para el cliente (artefactos del cliente)
$ mkdir cliente1 (crear un directorio de trabajo)
$ cd cliente1
$ wsimport http://www.webservicex.net/WeatherForecast.asmx?wsdl -p usa_weather -verbose
Se genera el paquete usa_weather que contiene las clases de apoyo
- stubs para el servicio WeatherForecast y el port WeatherForecastSoap
[ver sección <service> del WSDL]
- Este Servicio Web tiene 3 ports, uno para cada uno de los tipos
de acceso que se permiten (SOAP, mensajes HTTP GET y mensajes HTTP POST)
- JAX-WS y wsimport sólo gestionan peticiones SOAP, las demás se omiten
- Clases de apoyo para los mensajes SOAP definidos:
GetWeatherByPlaceName, GetWeatherByPlaceNameResponse, etc
[ver secciones <message> del WSDL]
- Clases de acceso a los elementos XML definidos en la respuesta:
WeatherForecasts, ArrayOfWeatherData, WeatherData
[ver secciones <types> y <message> del WSDL]
Notas:
- wsimport recibe un fichero WSDL o una URL apuntando a su ubicación.
- La opción -p usa_weather indica el nombre del paquete (package)
donde dejar las clases generadas
- si no se hubiera indica se habría creado el paquete net.webservicex
- Se puede añadir la opción -keep para ver el código fuente de las clases generadas
- Escribir el cliente que haga uso del servicio
- Descarga: ClienteTiempo.java
- Descripción del cliente
- Importa las clases de apoyo (generadas desde el WSDL) del paquete weather_usa
- Crea un stub del servicio WeatherForecast del que obtiene
un stub del port WeatherForecastSoap
- Llama a la operación getWeatherByPlaceName(".....") con el nombre de una ciudad
y obtiene un objeto WeatherForecasts
- Imprime el contenido del objeto WeatherForecasts (métodos getXXX(..) para acceder a los
distintos elementos)
[ver sección <types> del WSDL]
- Compilar el cliente
$ javac ClienteTiempo.java
- Ejecutar el cliente
$ java ClienteTiempo "Las Vegas"
$ java ClienteTiempo "New York"
Se propone repetir el mismo ejercicio con otro servicio Web similar.
- Partir del servicio GlobalWeather
- Generar los artefactos del cliente en un nuevo paquete
- Crear un cliente nuevo ClienteTiempo2.java
- Llamará a la función getWeather() del port GlobalWeatherSoap
con dos parámetros de tipo String:
la ciudad y el país (p. ej. ``Santiago'' ``Spain'')
- En este caso el valor de retorno es un String [ver su WSDL]
que contiene un documento XML o un mensaje de error.
- No es necesario analizarlo, bastará con imprimir el String recibido tal cual
Nota: Este ejercicio no hay que entregarlo, es sólo una propuesta
Se verá un ejemplo de la definición de un Servicio Web propio. Se trata de crear un servicio Web que ofrezca las funcionalidades de una calculadora remota.
Se parte de un código de muestra con la siguiente estructura de directorios
- servidor/: Implementación del servicio Web
- servidor/CalualdoraWS.java: Código fuente del Servicio Web
- cliente/: Ejemplo de cliente
- cliente/EjemploClienteWS.java: Código fuente del cliente
- LanzadorServicio.java: Programa auxiliar para lanzar un mini-servidor Web donde residirá
el Servicio Web
Descarga: ws2.tar.gz
ws2.zip
- Descomprimir el paquete.
$ tar xzvf ws2.tar.gz
$ cd ws2
- Implementación del servicio Web (fichero servidor/CalculadoraWS.java)
- El API JAX-WS hace uso de anotaciones Java para simplificar el desarrollo de Servicios Web
- La anotación @WebService marca una clase que será accesible en forma de Servicios Web
- Puede especificarse como argumentos de la anotación
la URL donde residirá el servicio y los nombres de servicio y ports a usar en el fichero WSDL
- Por defecto se usa [nombre de clase + Service] como nombre de servicio
y [nombre de clase + Port] como nombre de port
- La anotación @WebMethod marca qué métodos de la clase serán accesibles a través de
operaciones SOAP (etiqueta <operation> en el WSDL)
- Admite argumentos que permiten modificar el nombre que se le dará la operación
en el documento WSDL
- Más información: anotaciones JAX-WS.
- Compilar la clase del servicio
$ javac servidor/CalculadoraWS.java
- Generar artefactos del servidor: clases auxiliares (skeleton) + docuemnto WSDL
$ wsgen -cp . -wsdl servidor.CalculadoraWS -verbose
Se hace uso de la herramienta wsgen incluida en Java SE 6
- wsgen analiza clases marcadas con la anotación @WebService
- Crea un conjunto de clases auxiliares (skeleton)
para ser usadas por el servidor que implemente el Servicio Web
- Crea el documento WSDL describiendo el Servicio Web
- También crea documentos XML complementarios con los tipos de datos
empleados
Importante: Si no se ha especificado una URL en la anotación @WebService es necesario
indicar la URL de ''escucha'' en el atributo location de <soap:address location=".......">
dentro del elemento <service> <port> .... </port> </service>
- En nuestro caso editar el fichero CalculadoraWSService.wsdl y
reemplazar
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
por <soap:address location="http://localhost:8888/calculadora"/> (al final del documento)
Notas:
- la opción -wsdl indica que se cree el documento WSDL del servicio Web
- En este caso se crea CalculadoraWSService.wsdl en el directorio
actual (puede modificarse el destino con la opción -d)
- También se crea el fichero XML Schema CalculadoraWSService_schema1.xsd
con los tipos de datos usados
- Las clases generadas se dejan en el paquete servidor.jaxws (se puede cambiar el paquete
de destino con la opción -p <nombre paquete>)
- Se puede añadir la opción -keep para ver el código fuente de las clases generadas
Tareas: Inspeccionar los ficheros generados (especialmente el WSDL)
- Despliegue del servidor
En este caso se simplificará el despliegue usando el mini-servidor web que se incluye en Java SE
para estas situaciones.
- La clase javax.xml.ws.Endpoint ofrece el método estático pubish(URL, Objeto)
que lanza un servidor web y pone a la ''escucha'' el objeto indicado (instancia de una clase marcada
con la anotación @WebService) en la URL indicada
- En nuestro ejemplo el programa LanzadorServicio.java hace esa tarea,
dejando el servicio Web CalculadoraWS a la escucha en la
URL http://localhost:8888/calculadora
Importante: En un entorno real, el Servicio Web se desplegaría dentro de un Servidor
de Aplicaciones Java EE (ver comentarios finales), normalmente mediante un servlet
que atendría sus peticiones, redirigiéndolas a los métodos de implementación.
< en un terminal distinto >
$ javac LanzadorServicio.java
$ java LanzadorServicio [queda a la espera]
Se puede comprobar que ha funcionado correctamente abriendo la URL http://localhost:8888/calculadora?wsdl
en un navegador WEB. Se debería mostar el documentos WSDL del servicio.
- Implementación del cliente
El esquema es análogo al realizado en el ejemplo 1
- Generar artefactos del cliente a partir del documento WSDL
$ wsimport CalculadoraWSService.wsdl -p cliente.calc_aux -verbose
Notas:
- Las clases auxiliares se dejarán en el paquete cliente.calc_aux
- Podría indicarse la URL http://localhost:8888/calculadora?wsdl en lugar del fichero WSDL
- Escribir código del cliente (ya está hecho)
- Debe importar el paquete calc_aux
- El service a usar es CalculadoraWSService [ver el WSDL generado]
- El port a usar CalculadoraWSPort [ver el WSDL generado]
- Compilar y ejecutar (desde el directorio /home/alumno/.../ws2/)
$ javac cliente/EjemploClienteWS.java
$ java cliente.EjemploClienteWS
Se pide realizar una evaluación del redimiento de las llamadas a Servicios Web usando el ejemplo de la calculadora remota.
- Implementar un programa Java que haga 5.000-10.000 invocaciones a un método int suma(int, int) local y otras 5.000-10.000
llamadas SOAP al método suma de la calculadora remota.
- (opcional) Retomar las implementaciones de la calculadora remota en RMI y CORBA de prácticas anteriores (si las hubiera)
y crear un cliente para cada una de las dos implementaciones (RMI, CORBA) que haga esas 5.000-10.000 invocaciones.
- Medir el tiempo consumido en la batería de invocaciones (usar el método System.nanotime())
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
- Para el ejercicio 1 y el ejercico 2 se pide una descripción breve de los pasos realizados
en cada una de los ejemplos y los resultados obtenidos (lista de fichero generados, warnings devueltos,
salida de los programas ejecutados, etc)
- Para las tareas a realizar del ejercico 2 se pide el código del cliente
implementado para la bateria de invocaciones del servicio Web, los resultados de tiempo obtenidos
en los 3 experimentos (RMI, CORBA y servicios Web) y un comentario de las conclusiones obtenidas.
- Como se mencionó, los servicios Web Java (construidos con JAX-WS o con JAX-RPC) suelen desplegarse
dentro de un servidor de aplicaciones Java EE (Java Enterprise Edition).
- Normalmente se desplegarán como un servlet que será quien gestione y redirecciones las
peticiones HTTP que contengan los mensajes SOAP dirigidos al servicio Web
- En ese caso la clase compilada que implementa el servicio Web, junto con las clases auxiliares
generadas con wsgen y el correspondiente fichero WSDL se empaquetarán en un fichero
.WAR (un .jar que contiene componentes Web).
- Ese fichero WAR se desplegará (deploy) conforme al esquema que define el servidor de
aplicaciones Java EE (ficheros web.xml, etc)
- También es posible que un Enterprise Java Bean (objeto remoto de Java EE) exponga sus
métodos en forma de Servicios Web (en ese caso se empaquetaría en un fichero .EAR)
- En el ejemplo se ha usado un esquema simple (uso de un ''mini-servidor web'' integrado
en la distribución Java SE 6) útil para depuración, pero no apto para un entorno de producción.
- La mayoría de IDEs (entornos integrados de desarrollo) de Java, como Eclipse
o
Netbeans, incluyen
asistentes y/o automatizan las tareas de importación/exportación de WSDL, generación de ''artefactos'',
compilación, empaquetado y despliegue de aplicaciones.
- En los ejemplos anteriores hemos visto paso a paso las tareas que se realizan ''por debajo''
para comprobar como funciona JAX-WS
- En un entorno de desarrollo real se usarían las facilidades que ofrecen estos IDEs (editores
de WSDL, asistentes, etc) y el desarrollo de servicios Web sería ligeramente distinto (y más fácil)
- En general, es una práctica recomentable tender a automatizar el tipo de tareas que aqui hacíamos a mano,
utilizando herramientas como Makefiles (para C, C++) o como ant
o maven
(para Java [ant se usa en los proyectos Netbeans y
Eclipse de forma nativa])
ribadas
2010-11-23