Metro: Pila de webservices de Sun  

Posted by Danny in ,

Metro es la actualización del antiguo JWSDP (Java Web Services Developer Pack), y digo actualización porque la mayor parte del código se hereda de JWSDP (dicho por uno de sus desarrolladores, si el código es bueno y funciona bien, para que cambiarlo? ).

Esta incluido en Glassfish (Servidor de aplicaciones de Sun) a partir de su versión 2.

Metro realmente es un paquete de diferentes tecnologías, entre las que se encuentran JAX-WS, JAXB, y WSIT (implementación de webservices, implementación de XML-Bindings y Webservices intercomunication tecnology, que permite comunicar sin problemas webservices java y .net 3).

Según los desarrolladores de Metro,

Veamos que necesitamos para usarlo y un pequeño ejemplo.

AVISO: Este tutorial presupone el conocimiento por parte del lector de muchos de los términos e ideas que aquí se exponen, por tanto exige niveles de conocimiento altos en las tecnologías subyacentes. Los ejemplos se muestran como fragmentos que el lector debe completar.

Instalación

La instalación es muy sencilla. Hay que descargarse el jar (https://metro.dev.java.net/1.1/) y ejecutarlo (java -jar metro-installer.jar o doble clic sobre el archivo si estas en windows).

Lo que nos va a instalar es una serie de herramientas y los ficheros necesarios para su funcionamiento. Estas herramientas, al igual que en axis, son las que nos van a permitir la generación automática de código para poder crear nuestros webservices.

Tendremos por tanto 2 posibilidades de crear un webservice.

  • A partir de un fichero WSDL (WebServices Description Language).


      • útil cuando ya tenemos este tipo de fichero, o queremos reimplementar la funcionalidad de un webservice ya publicado en internet (y que nos da igual que este en .net, java o cualquier otra tecnología).
      • No es recomendable este método para generar un webservice desde 0, puesto que es trabajo de crear el fichero .wsdl puede llegar a ser muy tedioso.

      • En la versión usada, Metro 1.1, WSDL 2.0 no está soportado.



  • A partir de una clase java.
      • Perfecto para crear un webservice desde 0, o publicar ciertos métodos de una aplicación java que tenemos ya desarrollada.

      • No recomendable cuando tengamos el fichero wsdl (El webservice generado puede no ser totalmente compatible con el del wsdl que teníamos).

Veamos detalladamente cada uno de los pasos.


Crear un WebService


Para todos los ejemplos vamos a usar el webservice público definido en 'http://wscc.info/index.php?show=32031_SWE&&page_anchor=http://wscc.info/p32031/p32031_swe.php', y que devuelve información de geolocalización de una ip dada. Además el webservice está realizado en .net, y así comprobaremos si WSIT funciona.


Desde un fichero WSDL


Para generar el webservice desde este tipo de ficheros vamos a usar la herramienta que trae Metro, wsimport, y que nos va a crear todas las clases necesarias para poder poner en funcionamiento el webservice. Un ejemplo de uso del comandos sería:


wsimport.sh -s src/main/java -p com.autentia.service -Xnocompile http://ws.ip2location.com/ip2locationwebservice.asmx?wsdl

Donde:



  • -s: ruta donde se van a generar los fuentes.

  • -p : paquete en el que se generará el código.

  • -Xnocompile : indica a la herramienta que no compile el código generado.

y nos generará las siguientes clases:

IP2Location.java: Java bean de tipo de dato complejo.

Ip2LocationWebService.java: Proxy del webservice.

IP2LOCATION.java: Java bean de tipo de dato complejo.

Ip2LocationWebServiceSoap.java: Interfaz del servicio.

IP2LocationResponse.java: Java bean de la respuesta del servicio.

ObjectFactory.java: Factoría de objetos usados internamente por el servicio.

package-info.java: Archivo para javadoc.

Como lo que vamos a hacer es reescribir el servicio web (hacer un webservice compatible con el wsdl usado pero realizado en java), no nos quedaría nada más que crear la clase skeleton del webservice (la que implementa la lógica de negocio del webservice).

Creamos una nueva clase java que tendrá la siguiente estructura (en este ejemplo la llamaremos IP2LocationSkel.java):


@WebService(endpointInterface="com.autentia.service.Ip2LocationWebServiceSoap")  public class IP2LocationSkel implements Ip2LocationWebServiceSoap {          ...  }

Donde veis lo simple que es: creamos la clase y hacemos que implemente la interfaz generada anteriormente (no es obligatorio, pero si muy recomendable para saber cómo es el método a implementar en tiempo de compilación).


Lo que si es obligatorio es la anotación de la clase (y lo que le da potencia y sencillez a Metro): @WebService. La propiedad endpointInterface indica la clase (nombre cualificado) de la interfaz del webservice (y es por esto por lo que no es obligatorio implemetar la interfaz anterior).


Y ya está! Ya tendríamos nuestro webservice creado, en pocos pasos y de manera muy sencilla!


Desde java


Vamos a hacer ahora la operación inversa. Queremos realizar un webservice desde 0, no tenemos el fichero WSDL o ya tenemos una clase java de la que queremos hacer públicos alguno de sus métodos a través de webservice.


No tedríamos más que generar una clase java, que debe cumplir los siguientes requisitos:



  • La clase se debe anotar con @javax.jws.WebService.

  • Todos los métodos que se desean exponer como operación del webservice se pueden anotar con @javax.jws.WebMethod (si todos los métodos de la clase son operaciones del servicio web se puede omitir dicha anotación).

  • Todos los métodos que se desean exponer como operación del webservice pueden lanzar java.rmi.RemoteException, aparte de todas las excepciones específicas del servicio.

  • Todos los parámetros de los métodos del servicio y tipos de retorno deben ser compatibles con “JAXB 2.0 Java to XML Schema mapping definition".

  • Los parámetros de los métodos del servicio y tipos de retorno no pueden implementar directa o indirectamente la interfaz java.rmi.Remote.

Veamos una sección de la clase (una clase que implementa una pequeña calculadora):
@WebService  public class AddNumbersImpl {       @WebMethod   public int addNumbers(int number1, int number2) throws AddNumbersException {    ...   }  }


Fijaos en las anotaciones: hemos anotado la clase con @WebService, y el método addNumbers con @WebMethod (el único que expondremos como método del servicio web).

El siguiente paso: generar las clases de apoyo necesarias para poner en marcha el webservice, y para ello usaremos otra herramienta que nos provee Metro, y que se llama wsgen
wsgen.sh  -cp  -keep com.autentia.service.AddNumbersImpl
Donde:

  • -cp : indica el classpath a utilizar, es decir, la ruta o rutas de .jar o carpetas que contienen los .class necesarios para la compilación.

  • -keep : indica que no se borren los ficheros .java generados.

  • com.autentia.service.AddNumbersImpl: para el ejemplo, es la clase que implementa el webservice (denominado SEI: service endpoint implementation).

Que nos generará las siguientes clases:

AddNumbersExceptionBean.java : java bean para la excepción que puede lanzar el webservice.

AddNumbers.java : Skeleton del webservice.

AddNumbersResponse.java : clase de tratamiento de la respuesta SOAP.


Ya tenemos nuestro webservice! (sencillito, eh?)


Creando una aplicación web con nuestro webservice (war)

Una vez creado nuestro webservice veamos qué recursos y configuraciones debemos incluir para que el webservice funcione como una aplicación web y la podamos publicar (yo he usado tomcat y funciona sin problemas).

Ante todo debemos meter en la carpeta WEB-INF/lib de nuestro war los .jar (webservice*.jar) que vienen en la instalación de Metro.

Dentro de WEB-INF deben ir localizados web.xml y sun-jaxws.xml

El fichero de descripción de la aplicación web, web.xml, debe contener el siguiente fragmento (se define el servlet y filtros necesarios para que funcione Metro):

web.xml:
...  <listener>          <listener-class>                  com.sun.xml.ws.transport.http.servlet.WSServletContextListener          </listener-class>  </listener>  <servlet>          <description>JAX-WS endpoint - fromjava</description>          <display-name>metro ws engine servlet</display-name>          <servlet-name>metroServlet</servlet-name>          <servlet-class>                  com.sun.xml.ws.transport.http.servlet.WSServlet          </servlet-class>          <load-on-startup>1</load-on-startup>  </servlet>  <servlet-mapping>          <servlet-name>metroServlet</servlet-name>          <url-pattern>/ws/*</url-pattern>  </servlet-mapping>  ...

El fichero de descripción del webservice para Metro:


sun-jaxws.xml:


<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">


    <endpoint          name="addnumbers-example"          implementation="com.autentia.service.AddNumbersImpl"          url-pattern="/ws/addnumbers"/>  </endpoints>

Ojo! El url-mapping del servlet de webservice de metro y de la definición del webservice deben ser compatibles:








Una vez empaquetado el código convenientemente podemos instalar la aplicación en Tomcat, y acceder a http://localhost:8080/<war-name>/ws/addnumbers:








podemos ver el wsdl generado al pulsar sobre el link que nos propone la página.


Generar el cliente


Bien, ya he creado mi web service, ya lo he publicado... y ahora cómo lo uso? O cómo me conecto a un webservice externo?. Veamos cómo crear entonces un cliente apra webservice, y lamaera es muy sencilla, y es 99% igual que la forma en que generábamos un servicio web a partir de un wsdl.


Ejecutando el comando (la URI del wsdl tomaremos la del webservice del ejemplo comentado al inicio):


wsimport.sh -s src/main/java -p com.autentia.service -Xnocompile http://ws.ip2location.com/ip2locationwebservice.asmx?wsdl

con el que ya vimos anteriormente qué clases se generaban automáticamente.


La diferencia entre crear un webservice a aprtir de un WSDL y un cliente es la clase que tenemos que crear. Ahora codificaremos una clase como sigue, que será la que se conecte y haga la llamda al webservice:


public class IP2LocationStub implements Ip2LocationWebServiceSoap {     public IP2LOCATION ip2Location(String ip, String license) {      // Create Service    Ip2LocationWebService service = new Ip2LocationWebService();      // create proxy    Ip2LocationWebServiceSoap proxy = service.getIp2LocationWebServiceSoap();      // invoke    return proxy.ip2Location(ip, license);   }  }






Donde, como al crear el webservice, no es obligatorio que la clase implemente la interfaz Ip2LocationWebServiceSoap, pero si es muy recomendable.


Si llamáis al webservice del ejemplo necesitáis una clave de uso, con lo que la llamada volverá con los datos vacíos y con un mensaje de error, pero eso implica que el ejemplo funciona!!!


Conclusión


Ya habéis visto lo sencillo que es crear un servicio web y un cliente de webservice con Metro (y hemos probado además que WSIT funciona!).


En mi humilde opinión el desarrollo a base de anotaciones agiliza y simplifica mucho la tarea de generar web services, además nos permite reutilizar clases que ya teníamos.


En cuanto al rendimiento, existe en http://weblogs.java.net/blog/kohsuke/archive/2007/02/jaxws_ri_21_ben.html una comparativa de Metro vs Axis2, donde se muestra que para el envío de ciertos tipos de datos, Metro puede llegar a ser el doble de rápido que axis2 (por tanto más eficiente), aunque claro, la comparativa está realizada por uno de los propios desarrolladores de Metro... A final vuestra experiencia será la que diga la última palabra.


No os perdáis los próximos tutoriales sobre metro donde veremos cómo automatizar las tareas que realizábamos 'a mano' mediante maven2, y otro que nos enseñará a usar RESTFull con Metro.




Entradas relacionadas:

0 comentarios

Publicar un comentario

BlogESfera Directorio de Blogs Hispanos - Agrega tu Blog

Archives