670 likes | 1.06k Views
Tema 5 - Servicios Web con Axis. Dr. Diego Lz. de Ipiña Gz. de Artaza http://paginaspersonales.deusto.es/dipina http://paginaspersonales.deusto.es/dipina/cursos/J2EECesine.zip dipina@eside.deusto.es. Introducción I.
E N D
Tema 5 - Servicios Web con Axis Dr. Diego Lz. de Ipiña Gz. de Artaza http://paginaspersonales.deusto.es/dipina http://paginaspersonales.deusto.es/dipina/cursos/J2EECesine.zip dipina@eside.deusto.es
Introducción I • Los Servicios Web son la piedra angular de cualquier desarrollo de sistemas distribuidos actual • Los ordenadores hablan unos a otros a través de la web usando HTTP y otros protocolos. • Un servicio web no tiene interfaz gráfica • Provee una API de métodos que pueden ser invocados en la web • Diseñados para proveer “servicios”
Introducción II • Futuro en el que los negocios exponen aplicaciones a clientes como Servicios Web en los cuales se paga por su uso • Los sistemas de diferentes empresas cooperan unos con otros a través de la Web • Mientras que DCOM está basado en estándares propietarios, los Servicios Web lo están en XML y HTTP • Son independientes de la plataforma y del lenguaje como CORBA, pero más aceptados • En .NET, IIS y la infraestructura ASP.NET compilan las fuentes, construyen contratos WSDL y manejan las peticiones y respuestas de los servicios web. • En Java AXIS realiza una tarea muy similar
SOA • Los servicios web han dado lugar a un nuevo modo de diseñar sistemas distribuídos: • Arquitecturas SOA (Service Oriented Arquitecture) • SOA = colección de servicios • Más información en http://www.service-architecture.com/ • http://msdn.microsoft.com/Longhorn/understanding/pillars/Indigo/default.aspx?pull=/library/en-us/dnbda/html/srorientwp.asp
Servicios Web • Son un estándar basado en protocolos abiertos como HTTP y SOAP • SOAP es un vocabulario XML que representa RPCs • http://www.w3.org/TR/SOAP • No necesitas ni Windows ni .NET, ni UNIX ni Java para escribir servicios web • Servicio web = aplicación que: • se ejecuta en un servidor web • expone métodos a clientes • escucha peticiones HTTP representando comandos que invocan a métodos Web • ejecuta métodos web y devuelve resultados
SOAP • SOAP es un protocolo de comunicación basado en XML útil para la comunicación entre aplicaciones • Actualmente en versión 1.2, aunque la más utilizada es la 1.1 • http://www.w3.org/2000/xp/Group/ • SOAP es reconocido como el backbone de una nueva generación de aplicaciones multi-platforma y multi-lenguaje, denominado Servicios Web. • SOAP es un mecanismo para el intercambio de mensajes a través de Internet independiente de los lenguajes de programación • Es un protocolo de transporte • Los clientes envían una petición SOAP mediante un HTTP POST normalmente y reciben un código de respuesta (éxito o error) y una respuesta SOAP • Un mensaje SOAP es un mensaje XML que consta de un conjunto de cabeceras opcionales y de un cuerpo.
Petición SOAP <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <getProductDetails xmlns="http://warehouse.example.com/ws"> <productId>827635</productId> </getProductDetails> </soap:Body> </soap:Envelope>
Respuesta SOAP <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <getProductDetailsResponse xmlns="http://warehouse.example.com/ws"> <getProductDetailsResult> <productName>Toptimate 3-Piece Set</productName> <productId>827635</productId> <description>3-Piece luggage set. Black Polyester.</description> <price>96.50</price> <inStock>true</inStock> </getProductDetailsResult> </getProductDetailsResponse> </soap:Body> </soap:Envelope>
Apache AXIS • AXIS es un motor SOAP, una framework para construir tanto la parte servidora como cliente de Servicios Web. • Además: • Incluye un servidor • Un servlet que se integra con motores de servlets como Tomcat • Soporte extensivo del estándar Web Service Description Language (WSDL) • Una herramienta para generar clases Java a partir de WSDL • Un conjunto de aplicaciones de ejemplo • Una herramienta para la monitorización de los paquetes TCP/IP • Open source, disponible en: http://ws.apache.org/axis/ • WS-*
Apache Axis • Axis es disponible en el fichero axis.jar; que implementa la API JAX-RPC API declarada en los ficheros JAR jaxrpc.jar y saaj.jar. Requiere varias bibliotecas de ayuda, para logeo, procesamiento WSDL e introspección.
Características AXIS • La arquitectura de AXIS está basada en cadenas configurables de manejadores de mensajes que implementan pequeños fragmentos de funcionalidad de una manera flexible • Sus propiedades principales: • Rápido implementado con un procesador XML SAX • Flexible • Estable • Orientado a Compontes • Soporta WSDL 1.1 • Apache EXtensible Interaction System (AXIS) motor SOAP muy configurable
Instalación Axis • Bajarse la distribución de Apache Axis de http://ws.apache.org/axis/ • La versión actual es 1.2RC2 • Bajarse tanto versión binaria (ya compilado) como fuente (contiene ejemplos) • Instalar un contenedor de servlets como Tomcat 5 • Copiar el directorio axis-1_2RC2\webapps\axis contenido en la distribución de Axis en %TOMCAT_HOME\webapps • Instalar .jar terceros necesitados por Axis, copiándolos en %TOMCAT_HOME%\common\lib: • Junit.jar (Junit Testing System - http://www.junit.org/index.htm) • mail.jar (Java Mail - http://java.sun.com/products/javamail/) • activation.jar (Java Beans Activation Framework - http://java.sun.com/products/javabeans/glasgow/jaf.html)
Instalación Axis • Arrancar el servidor web • Validar la instalación: http://127.0.0.1:8080/axis/ (hacer clic en Validate) • Validar un SOAP endpoint: http://localhost:8080/axis/services/Version?method=getVersion • Axis soporta HTTP GET
Creando Servicios Web .jws • Axis tiene un método muy sencillo de crear servicios web básicos, mediante el mecanismo de ficheros .jws • Cuando alguien solicita a través de una url un fichero .jws, éste es compilado y ejecutado • Revisar ejemplo: http://localhost:8080/axis/EchoHeaders.jws?method=list
Cómo Instalar un Nuevo Servicio Web • Dos pasos: • Copiar el código del servicio web bajo el directorio %TOMCAT_HOME%\webapps\axis WAR • En el directorio WEB-INF\classes de AXIS copiar las clases de tu nuevo servicio web • Si tus clases están en un .jar simplemente copiarlas a WEB-INF\lib • Informar al motor de AXIS acerca del nuevo fichero • Se realiza haciendo un POST de un fichero de explotación (wsdd) mediante el programa AdminClient • El Web Service Deployment Descriptor describe en XML cuál es el servicio web y qué métodos exporta
Compilando Servicios Web • Para compilar servicios web necesitamos colocar en nuestro CLASSPATH las dependencias de AXIS set AXIS_HOME=c:\axis set AXIS_LIB=%AXIS_HOME%\lib set AXISCLASSPATH=%AXIS_LIB%\axis.jar;%AXIS_LIB%\commons-discovery.jar;%AXIS_LIB%\commons-logging.jar;%AXIS_LIB%\jaxrpc.jar;%AXIS_LIB%\saaj.jar;%AXIS_LIB%\log4j-1.2.8.jar;%AXIS_LIB%\xml-apis.jar;%AXIS_LIB%\xercesImpl.jar • Luego podemos hacer: • javac –classpath %AXISCLASSPATH% • java -cp %AXISCLASSPATH% ...
Ejecución del AdminClient • Buscar en axis\samples\stock un ejemplo de un fichero de explotación web de AXIS: deploy.wsdd. • Registrar el servicio web mediante el comando: java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService deploy.wsdd • Para probar el servicio web acceder a: java -cp .;%AXISCLASSPATH% samples.stock.GetQuote -lhttp://localhost:8080/axis/servlet/AxisServlet -uuser1 -wpass1 XXX
Cómo Añadir AXIS a tu Aplicación Web • Los pasos a seguir son: • Añadir axis.jar, wsdl.jar, saaj.jar, jaxrpc.jar y otras bibliotecas dependientes a tu fichero WAR • Copiar todas las declaraciones del servlet de Axis y sus mapeos de axis/WEB-INF/web.xml y añadirlos a tu propio web.xml • Construir y desplegar la aplicación web • Ejecutar el AdminClient de AXIS contra tu propia aplicación web, en vez de contra AXIS, cambiando la url con la que invocas a AXIS
Consumiendo un Servicio Web • Vamos a desarrollar una pequeña aplicación cliente que consume el servicio web más sencillo que podemos imaginar, implementado en Echo.jws, que copiaremos a %TOMCAT_HOME%\webapps\AXIS\: public class Echo { public String echoString(String msg) { return msg; } }
Consumiendo un Servicio Web • A continuación, vamos a definir un cliente que me permita consumir este servicio web desde línea de comando • Desde un navegador podríamos invocar a este servicio mediante la URL: http://localhost:8080/axis/Echo.jws?method=echoString&msg=hola
Consumiendo un Servicio Web import org.apache.axis.client.Call; import org.apache.axis.client.Service; import javax.xml.namespace.QName; public class EchoClient { public static void main(String [] args) { try { String endpoint = "http://localhost:8080/axis/Echo.jws"; Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName(new QName("http://soapinterop.org/", "echoString") ); String ret = (String) call.invoke( new Object[] { "Hello!" } ); System.out.println("Sent 'Hello!', got '" + ret + "'"); } catch (Exception e) { System.err.println(e.toString()); } } }
Consumiendo un Servicio Web • Los objetos Service y Call son los objetos estándar JAX-RPC que permiten guardar metadatos sobre el servicio a invocar.
Consumiendo un Servicio Web • Al invocar el método la siguiente información aparecería en el navegador: <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <ns1:echoString xmlns:ns1="http://soapinterop.org/"> <arg0 xsi:type="xsd:string">Hello!</arg0> </ns1:echoString> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Consumiendo un Servicio Web • Si deseamos dar nombre a los parámetros solamente deberemos insertar el siguiente código: // Call to addParameter/setReturnType as described in user-guide.html call.addParameter("testParam", org.apache.axis.Constants.XSD_STRING, javax.xml.rpc.ParameterMode.IN); • Si queremos indicar a AXIS cuál es el tipo de dato devuelto haríamos: call.setReturnType(org.apache.axis.Constants.XSD_STRING);
Publicando un Servicio Web con AXIS • Vamos a suponer que tenemos una clase Calculator que queremos sea accesible como Servicio Web. • Tenemos dos mecanismos: • A través de un fichero .JWS • Registrando el nuevo servicio vía AxisAdmin usando desplegamiento propietario
Publicando con JWS • Sólo para Servicios Web muy sencillos • Con esta instrucción se desplegaría: • copy Calculator.java <your-webapp-root>/axis/Calculator.jws • Para invocarlo haríamos: http://localhost:8080/axis/Calculator.jws • O nos crearíamos nuestros clientes propietarios. • Revisar samples/userguide/example2/Calculator.java
Calculator.java public class Calculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } }
CalcClient.java import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; import org.apache.axis.utils.Options; import javax.xml.rpc.ParameterMode; public class CalcClient { public static void main(String [] args) throws Exception { Options options = new Options(args); String endpoint = "http://localhost:" + options.getPort() + "/axis/Calculator.jws"; args = options.getRemainingArgs(); if (args == null || args.length != 3) { System.err.println("Usage: CalcClient <add|subtract> arg1 arg2"); return; } String method = args[0]; if (!(method.equals("add") || method.equals("subtract"))) { System.err.println("Usage: CalcClient <add|subtract> arg1 arg2"); return; }
CalcClient.java Integer i1 = new Integer(args[1]); Integer i2 = new Integer(args[2]); Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpoint) ); call.setOperationName( method ); call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN ); call.addParameter( "op2", XMLType.XSD_INT, ParameterMode.IN ); call.setReturnType( XMLType.XSD_INT ); Integer ret = (Integer) call.invoke( new Object [] { i1, i2 }); System.out.println("Got result : " + ret); } }
Custom Deployment • Habrá ocasiones en que queramos exportar código anteriormente realizado como un servicio web • Además a menudo se requerirán configuraciones más sofisticadas: inclusión de Handlers • Para acceder a toda la flexibilidad configurativa de AXIS necesitamos utilizar Web Service Deployment Descriptor (WSDD)
Web Service Deployment Descriptor • Describe un conjunto de configuraciones que quieres hacer disponible a AXIS • Por ejemplo: <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="MyService" provider="java:RPC"> <parameter name="className" value="samples.userguide.example3.MyService"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> • Indicamos que el servico web MyService de tipo java:RPC es definido en la clase samples.userguide.example3.MyService y hacemos disponibles todos los métodos públicos en esa clase
Web Service Deployment Descriptor • Algunas opciones adicionales que se pueden especificar en un .wsdd son: • Alcance de los servicios, se pueden definir servicios web con tres alcances: • request crea un nuevo objeto cada vez que se recibe una petición al servicio • application un solo objeto servirá todas las peticiones • session un objeto por cada sesión de cliente • Por ejemplo: <service name="MyService"...> <parameter name="scope" value=“request"/> ... </service>
Utilizando el AdminClient • La clase org.apache.axis.client.AdminClient permite el envío del fichero de explotación al servidor Tomcat, si está escuchando en un puerto diferente al 8080 hay que enviar el parámetro –p <port>. • java org.apache.axis.client.AdminClient deploy.wsdd • java org.apache.axis.client.AdminClient list • java org.apache.axis.client.AdminClient undeploy.wsdd • Revisar samples/userguide/example3.
Manejadores y Cadenas • Los Handlers (o manejadores) permiten pre/post procesar peticiones a servicios web. • Por ejemplo, para contar el número de invocaciones recibidas • Revisar ejemplo samples/log • En el .wsdd podemos colocar un elemento handler que puede recibir una serie de parámetros (subelemento parameter) • Después, podemos definir services que usan los handler, mediante subelementos requestFlow del service • Estos handlers son invocados antes de que el provider sea invocado
Manejadores y Cadenas <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <!-- define the logging handler configuration --> <handler name="track" type="java:samples.userguide.example4.LogHandler"> <parameter name="filename" value="MyService.log"/> </handler> <!-- define the service, using the log handler we just defined --> <service name="LogTestService" provider="java:RPC"> <requestFlow> <handler type="track"/> </requestFlow> <parameter name="className" value="samples.userguide.example4.Service"/> <parameter name="allowedMethods" value="*"/> </service> </deployment>
Pasos para Crear un Servicio Web con Custom Deployment • Crear un directorio de trabajo: examples/webservices/ej3customdeployment • Crear la clase Java que define el servicio web (MyService.java) • Crear el cliente web (Client.java) • Crear el descriptor de despliegue para este servicio (deploy.wsdd) • Crear el descriptor para eliminar este servicio (undeploy.wsdd) • cd ej3customdeployment • Compilar el código: javac *.java • Ejecutar el AdminClient: java org.apache.axis.client.AdminClient deploy.wsdd • copy ej3customdeployment/*.class %TOMCAT_HOME%\axis\WEB-INF\classes\ ej3customdeployment • Ejecutar: cd ..; java ej3customdeployment.Client -lhttp://localhost:8080/axis/services/MyService "test me!"
MyService.java package ej3customdeployment; public class MyService { public String serviceMethod(String arg) { return arg; } }
Client.java package ej3customdeployment; import org.apache.axis.client.Call; import org.apache.axis.client.Service; import org.apache.axis.encoding.XMLType; import org.apache.axis.utils.Options; import javax.xml.namespace.QName; import javax.xml.rpc.ParameterMode; public class Client { public static void main(String [] args) { try { Options options = new Options(args); String endpointURL = options.getURL(); String textToSend; args = options.getRemainingArgs(); if ((args == null) || (args.length < 1)) { textToSend = "<nothing>"; } else { textToSend = args[0]; } Service service = new Service(); Call call = (Call) service.createCall(); call.setTargetEndpointAddress( new java.net.URL(endpointURL) ); call.setOperationName( new QName("http://ej3_customdeployment", "serviceMethod") ); call.addParameter( "arg1", XMLType.XSD_STRING, ParameterMode.IN); call.setReturnType( org.apache.axis.encoding.XMLType.XSD_STRING ); String ret = (String) call.invoke( new Object[] { textToSend } ); System.out.println("You typed : " + ret); } catch (Exception e) { System.err.println(e.toString()); } } }
deploy.wsdd/undeploy.wsdd • deploy.wsdd <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="MyService" provider="java:RPC"> <parameter name="className" value="ej3customdeployment.MyService"/> <parameter name="allowedMethods" value="*"/> </service> </deployment> • undeploy.wsdd <undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="MyService"/> </undeployment>
Pasando Objetos en Servicios Web • Las excepciones se representan como elementos wsdl:fault • Podemos pasar objetos como argumentos con la ayuda del elemento del elemento beanmapping en un .wsdd <beanMapping qname="ns:local" xmlns:ns="someNamespace" languageSpecificType="java:my.java.thingy"/> • Revisar ejemplo: samples/userguide/example5/BeanService.java <deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="OrderProcessor" provider="java:RPC"> <parameter name="className" value="samples.userguide.example5.BeanService"/> <parameter name="allowedMethods" value="processOrder"/> <beanMapping qname="myNS:Order" xmlns:myNS="urn:BeanService" languageSpecificType="java:samples.userguide.example5.Order"/> </service> </deployment>
Pasando Objetos en Servicios Web • Dado que el BeanSerializer no permite transformar clases ya existentes que no conformen con el estándar JavaBean, es posible utilizar custom serialization • Para ello en el wsdd colocaremos: <typeMapping qname="ns:local" xmlns:ns="someNamespace" languageSpecificType="java:my.java.thingy" serializer="my.java.Serializer" deserializer="my.java.DeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
Web Services Description Language (WSDL) • Si miramos al fichero WSDL encontraremos: • Elemento service que describe el servicio web • Elementos operation que documentan las operaciones • Elementos binding que documentan los protocolos soportados por el servicio web • Etc. • Para publicar un servicio web deberemos publicar su contrato, WSDL. • Otros desarrolladores pueden utilizar el contrato para desarrollar clientes web • Nomalmente procesan el fichero WSDL a través de una herramienta que genera clases wrapper
Usando WSDL con Axis • Web Service Description Language (WSDL) permite describir los servicios web de una manera estructurada • Un WSDL nos da la siguiente información: • La interfaz al servicio • Los parámetros que acepta • La localización del servicio • AXIS soporta WSDL de tres formas: • Podemos obtener el wsdl de un servicio accediendo a su URL en un navegador y colocando el sufijo ?wsdl http://localhost:8080/axis/Echo.jws?wsdl • Herramienta WSDL2Java que genera Java proxies y skeletons a partir de descriptores WSDL • Herramienta Java2WSDL que construye WSDL a partir de clases Java
WSDL2Java: proxies, stubs y tipos de datos • Esta herramienta es disponible en la clase: org.apache.axis.wsdl.WSDL2Java • Su uso sería: java org.apache.axis.wsdl.WSDL2Java (WSDL-file-URL) • Existe la tarea wsdl2java en Ant
Mapeo Tipos <xsd:complexType name="phone"> <xsd:all> <xsd:element name="areaCode" type="xsd:int"/> <xsd:element name="exchange" type="xsd:string"/> <xsd:element name="number" type="xsd:string"/> </xsd:all> </xsd:complexType> • Mapearía a: public class Phone implements java.io.Serializable { public Phone() {...} public int getAreaCode() {...} public void setAreaCode(int areaCode) {...} public java.lang.String getExchange() {...} public void setExchange(java.lang.String exchange) {...} public java.lang.String getNumber() {...} public void setNumber(java.lang.String number) {...} public boolean equals(Object obj) {...} public int hashCode() {...} }
Mapeo Parámetros de Entrada/Salida package samples.addr.holders; public final class PhoneHolder implements javax.xml.rpc.holders.Holder { public samples.addr.Phone value; public PhoneHolder() { } public PhoneHolder(samples.addr.Phone value) { this.value = value; } }
Mapeo PortTypes <message name="empty"> <message name="AddEntryRequest"> <part name="name" type="xsd:string"/> <part name="address" type="typens:address"/> </message> <portType name="AddressBook"> <operation name="addEntry"> <input message="tns:AddEntryRequest"/> <output message="tns:empty"/> </operation> </portType> • Mapearía a: public interface AddressBook extends java.rmi.Remote { public void addEntry(String name, Address address) throws java.rmi.RemoteException; }