Hace poco publiqué una entrada donde comentaba la generación de clientes de servicios web JAX-WS desde .NET. Ha llegado el momento de hacer una entrada paralela para explicar el mismo procedimiento pero desde el punto de vista Java.
Existen varios métodos para generar clientes para un servicio web basado en tecnología JAX-WS 2.x, yo me voy a centrar en la herramienta wsimport que viene incluida en la implementación de referencia que Glassfish/Metro proporciona de la especificación.
La implementación de referencia.
La especificación JSR 224 – Java API for XML-Based Web Services establece las bases para trabajar con servicios web que utilizan XML para comunicarse. Como pasa con todas las especificaciones puede haber varias implementaciones, pero siempre hay una que se elige como la implementación de referencia (RI – Reference Implementation).
En el caso de ésta especificación la implementación de referencia la aporta Metro. La RI que yo voy a utilizar es la versión JAX-WS 2.1.9, por que se acerca mucho a la versión 2.1.5 que es la que incluye de saque el servidor de aplicaciones Weblogic 11g (parche 10.3.6), que es el que estoy utilizando para realizar estas pruebas.
En teoría, se podría utilizar cualquier versión de la implementación de referencia teniendo en cuenta que si difiere de la que incorpora weblogic habrá que incluir las librerías correctas en la aplicación y tal vez marcar la opción prefer-web-inf-classes en el descriptor weblogic.xml de nuestra aplicación.
La implementación de referencia se descarga de la página jax-ws.java.net (ver sección Links) y va empaquetada en un fichero JAR que si ejecutamos nos muestra un acuerdo de licencia y descomprime en la carpeta donde se ejecuta el contenido de la implementación.
La sintaxis de la herramienta wsimport
Los ejecutables de esta herramienta son insustancialmente diferentes en windows y en linux. En windows la herramienta está en \bin\wsimport.bat y en linux se puede encontrar en /bin/wsimport.sh.
La sintaxis en ambos sistemas es la misma:
wsimport [options] <wsdl>
<wsdl> indica una url que permita acceder al WSDL del servicio web para el que vamos a generar el cliente. Esta url puede ser tanto un recurso local, como un recurso obtenido mediante protocolo http.
[options] es el apartado donde se pueden incluir diferentes opciones que variarán el comportamiento de la herramienta. A continuación se presenta una lista completa de estas opciones:
- -d <directory> : Indica el directorio de salida donde se dejan las clases compiladas. Si no se utiliza esta opción las clases compiladas se dejarán en el mismo directorio desde el que se llama a wsimport.
- -b <path> : Añade ficheros XSD adicionales que se puedan necesitar en los binding jaxws/jaxb del servicio web.
- -B <jaxbOption>
- -catalog <file> : Especifica un fichero de catálogo que resuelve las referencias a entidades externas. Los formatos de catálogo soportados son: TR9401, XCatalog y OASIS XML Catalog.
- -extension : Permite extensiones de terceros. Esta funcionalidad no está soportada por la especificación, por lo que el cliente generado puede no ser portable o permitir la interoperabilidad entre plataformas.
- -help : Muestra una ayuda con el listado de las opciones.
- -httpproxy:<host>:<port> : Si para acceder a la URL del WSDL que queremos generar hay que viajar a través de un proxy, con esta opción podremos indicar su configuración. Si no se rellena el puerto, por defecto será el 8080.
- -keep : Si se incluye esta opción los fuentes que generan los compilados del cliente no se borran.
- -p : Especifica el paquete java de las clases del cliente generado. Si se indica esta opción no se tendrán en cuenta; ni el nombre de paquete que puede incluirse en el wsdl, ni el nombre de paquete por defecto que se genera cuando no se indica esta opción.
- -s <directory> : Especifica un directorio donde se guardan los ficheros de código fuente generados.
- -verbose : Muestra los mensajes del compilador indicando las tareas que está realizando.
- -version : Muestra un mensaje informativo con la versión de la implementación de referencia que se está utilizando.
- -wsdllocation <location>
- -target : Genera el código para la versión JAX-WS indicada. La versión 2.0 genera código compatible con la especificación JAX-WS 2.0.
- -quiet: Elimina cualquier salida que se pueda generar. Útil para generaciones automatizadas de clientes.
Clases generadas
La herramienta wsimport genera las clases necesarias para poder invocar a las operaciones del servicio web de forma correcta. Las clases que se generan siguen siempre el siguiente criterio:
- Clase PortType. Una clase que lleva el mismo nombre que el atributo name del elemento porttype del wsdl y contiene un método por cada operación definida con los elementos operation.
- Clase Service. Una clase que lleva el mismo nombre que el atributo name del elemento service del wsdl. Esta clase accede al servicio web y permite instanciar la clase PortType.
- Por cada operación definida en el portType
- Tantas clases como sean necesarias para rellenar los Input
- Tantas clases como sean necesarias para devolver el resultado de la operación
- Clase ObjectFactory. Esta clase facilita la instanciación interna de las clases input y response.
- Clase package-info. Anota el paquete java para que los objetos generados a partir del xsd del wsdl estén correctamente ubicados.
Una generación de ejemplo.

- CalculadoraPortType. La clase que contiene los métodos con las operaciones del servicio web.
- CalculadoraService. La clase que comunica con el servicio web y que permite instanciar la clase CalculadoraPortType.
- Division y DivisionResponse. Las clases de entrada y salida para la operación division().
- Multiplicacion y MultiplicacionResponse. Las clases de entrada y salida para la operación multiplicacion().
- Suma y SumaResponse. Las clases de entrada y salida para la operación suma().
- Resta y RestaResponse. Las clases de entrada y salida para la operación resta().
- ObjectFactory. Clase que permite utilizar internamente las clases de entrada y salida.
- package-info. Clase que indica el paquete sobre el que se han generado las clases del cliente.

Finalmente, he generado una clase de ejemplo CalculadoraCompra.java que calcula mediante operaciones aritméticas el resultado de la lista de la compra. Como el servicio web solo permite manejar enteros, las operaciones no manejan decimales y el resultado no es muy exacto, pero es ilustrativo del uso del servicio web.
public static void main(String[] args) {
Integer pan = new Integer (1);
Integer leche = new Integer (2);
Integer carne = new Integer (6);
Integer lentejas = new Integer (3);
Integer totalCompra = new Integer(0);
CalculadoraService cs = new CalculadoraService();
CalculadoraPortType cpt = cs.getCalculadoraPortTypePort();
totalCompra = cpt.suma(pan, leche);
totalCompra = cpt.suma(totalCompra, carne);
totalCompra = cpt.suma(totalCompra, lentejas);
Integer ivaDeLaCompra = new Integer(0);
Integer totalCompraConIva = new Integer(0);
Integer iva = new Integer(21);
ivaDeLaCompra = cpt.multiplicacion(totalCompra, iva);
ivaDeLaCompra = cpt.division(ivaDeLaCompra, new Integer(100));
totalCompraConIva = cpt.suma(totalCompra, ivaDeLaCompra);
System.out.println("Pan: " + pan.toString() + "€");
System.out.println(" + ");
System.out.println("Leche: " + leche.toString() + "€");
System.out.println(" + ");
System.out.println("Carne: " + carne.toString() + "€");
System.out.println(" + ");
System.out.println("Lentejas: " + lentejas.toString() + "€");
System.out.println(" = ");
System.out.println("Total SIN IVA: " + totalCompra.toString() + "€");
System.out.println("Total PVP (" + iva.toString() + "%): " + totalCompraConIva.toString() + "€");
}
El único punto en el que voy a hacer incapié es para subrayar los pasos necesarios para invocar a las operaciones del servicio web que se encuentran en la clase CalculadoraPortType. Esta clase es un interfaz por lo que no se puede crear una instancia, la forma correcta de obtenerla es instanciar la clase del servicio web CalculadoraService y posteriormente obtener el porttype con el método correspondiente getCalculadoraPortTypePort().
CalculadoraService cs = new CalculadoraService(); CalculadoraPortType cpt = cs.getCalculadoraPortTypePort();
El resultado de la ejecución del ejemplo se puede ver en la siguiente imagen.

Links
- Generando clientes de servicio web JAX-WS desde .NET (https://eduvitoriatecnicomio.wordpress.com/2013/02/08/generando-clientes-de-servicios-web-jax-ws-desde-net/)
- Creando un servicio web mediante anotaciones JAX-WS utilizando un enfoque ascendente (bottom-up) (https://eduvitoriatecnicomio.wordpress.com/2013/02/07/creando-un-servicio-web-mediante-anotaciones-jax-ws-utilizando-un-enfoque-ascendente-bottom-up/)
- Implementación de referencia de JAX-WS (http://jax-ws.java.net/)















