Download 5.2 JAX-RPC. Caso de estudio: Apache Axis
Document related concepts
no text concepts found
Transcript
5.2 JAX-RPC. Caso de estudio: Apache Axis Introducción (1) n JAX-RPC es el API estándar en Java para implementar e invocar operaciones de Servicios Web mediante el paradigma de los RPCs n Proporciona compilador de WSDL a Java n n n Stubs y Sketons al estilo CORBA También proporciona DII Proporciona compilador de Java a WSDL n n Es posible definir interfaces remotos en Java (más sencillo) El documento WSDL generado es útil para que un cliente (quizás escrito en un lenguaje distinto al del servidor) pueda usar su compilador de WSDL para obtener el stub del interfaz remoto Introducción (2) n Con JAX-RPC ... Interfaz Java Compilador Java Compilador Java2WSDL Documento WSDL Compilador WSDL2Java Stubs, skeletons y tipos Java Introducción (3) n Modelos de implementación de servicios web n n n n Modelos de implementación de clientes n n n Modelo basado en servlets (aplicación web J2EE) Modelo basado en EJB Modelo basado en J2SE Modelo basado en J2EE (aplicación web o EJB) Modelo basado en J2SE Estudiaremos la siguiente combinación HTTP Internet Aplicaciones web (con Servicios Web) HTTP war Cliente J2SE Servidor web J2EE Introducción (4) n Servidor (contenedor) de aplicaciones web J2EE n J2EE incluye un API para implementar aplicaciones web en Java n n n n n n API de servlets y JSP Una aplicación web puede incluir uno o varios servicios web, o puede contener sólo servicios web Cada aplicación web se empaqueta en un fichero war Un servidor de aplicaciones web puede tener varias aplicaciones web instaladas Implementar un servicio web sólo consiste en hacer una clase que implementa el interfaz remoto, y empaquetar ésta y las clases que requiere en el fichero war Axis sólo implementa este modelo de implementación de servicios web Introducción (y 5) n ¿ Qué es Axis ? n Una implementación de JAX-RPC para contenedores web J2EE n n En particular, usaremos con Jakarta Tomcat Contiene un conjunto de librerías (ficheros jar) que se han de instalar en el servidor de aplicaciones web n n n APIs Herramientas (ej.: compiladores Java2WSDL y WSDL2Java) Un servlet que n n n n Recibe las peticiones SOAP sobre HTTP que envían los clientes Invoca la operación correspondiente sobre el servicio web Devuelve una respuesta SOAP sobre HTTP con el resultado de la operación Otra implementación de JAX-RPC puede usar más de un servlet (ej.: un servlet para cada servicio web) Ejemplo StockQuote n n n n Usaremos el ejemplo StockQuote para ilustrar JAX-RPC Paquetes es.udc.fbellas.corbaws.stockquote.{wsdl, client} Servicio Web que ofrece una interfaz con una operación que a partir de un conjunto de identificadores de valores bursátiles devuelve sus cotizaciones Cada cotización incluye n n n Su identificador Su valor El número de segundos de antigüedad que tiene el valor (el valor real actual sería ligeramente distinto) Cliente standalone HTTP Internet HTTP Servidor de aplicaciones web StockQuoteProvider es.udc.fbellas.corbaws.stockquote.wsdl.StockQuoteProvider package es.udc.fbellas.corbaws.stockquote.wsdl; import java.rmi.Remote; import java.rmi.RemoteException; public interface StockQuoteProvider extends Remote { TradePrice[] getLastTradePrices(String[] tickerSymbols) throws RemoteException, IncorrectTickerSymbolException; } es.udc.fbellas.corbaws.stockquote.wsdl.TradePrice (1) package es.udc.fbellas.corbaws.stockquote.wsdl; import java.io.Serializable; public class TradePrice implements Serializable { private String tickerSymbol; private double price; private int elapsedSeconds; public String getTickerSymbol() { return tickerSymbol; } public void setTickerSymbol(String tickerSymbol) { this.tickerSymbol = tickerSymbol; } public double getPrice() { return price; } es.udc.fbellas.corbaws.stockquote.wsdl.TradePrice (y 2) public void setPrice(double price) { this.price = price; } public int getElapsedSeconds() { return elapsedSeconds; } public void setElapsedSeconds(int elapsedSeconds) { this.elapsedSeconds = elapsedSeconds; } } es.udc.fbellas.corbaws.stockquote.wsdl.IncorrectTickerSymbolException public class IncorrectTickerSymbolException extends Exception { private String incorrectTickerSymbol; public IncorrectTickerSymbolException( String incorrectTickerSymbol) { this.incorrectTickerSymbol = incorrectTickerSymbol; } public String getIncorrectTickerSymbol() { return incorrectTickerSymbol; } } Visión global de WSDL n n n Dejaremos momentáneamente la explicación de los detalles de la definición del interfaz remoto StockQuoteProvider y sus tipos asociados Una vez compilados los anteriores ficheros Java, se puede obtener el documento WSDL Un documento WSDL consta de varias partes n n n n n n Definición de tipos de datos Definición de mensajes Definición de puertos Definición de bindings Definición de servicios Vamos a echar un vistazo al fichero generado n Objetivo: comprender el formato general de un documento WSDL StockQuoteProvider.wsdl (1) <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://wsdl.stockquote.corbaws.fbellas.udc.es" xmlns:impl="http://wsdl.stockquote.corbaws.fbellas.udc.es" xmlns:intf="http://wsdl.stockquote.corbaws.fbellas.udc.es" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <wsdl:types> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://wsdl.stockquote.corbaws.fbellas.udc.es"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent> </complexType> StockQuoteProvider.wsdl (2) <complexType name="TradePrice"> <sequence> <element name="elapsedSeconds" type="xsd:int"/> <element name="price" type="xsd:double"/> <element name="tickerSymbol" nillable="true" type="xsd:string"/> </sequence> </complexType> <complexType name="ArrayOfTradePrice"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="impl:TradePrice[]"/> </restriction> </complexContent> </complexType> <complexType name="IncorrectTickerSymbolException"> <sequence> <element name="incorrectTickerSymbol" nillable="true" type="xsd:string"/> </sequence> </complexType> </schema> </wsdl:types> Definición de tipos de datos - Comentarios n n n n Es posible usar varios sistemas de tipos El uso de un esquema XML es el más habitual Cuando el protocolo que se usa es SOAP, también se pueden usar tipos SOAP En el ejemplo se definen n El tipo complejo ArrayOf_xsd_string, que corresponde al tipo Java String[] n n n Los tipos complejos que representan vectores, se definen como una especialización por restricción de soapenc:Array Los tipos complejos TradePrice y ArrayOfTradePrice, que corresponden a los tipos Java TradePrice y TradePrice[] El atributo nillable con valor true especifica que el correspondiente elemento puede tomar el valor nil (null en Java) StockQuoteProvider.wsdl (3) <wsdl:message name="IncorrectTickerSymbolException"> <wsdl:part name="fault" type="impl:IncorrectTickerSymbolException"/> </wsdl:message> <wsdl:message name="getLastTradePricesResponse"> <wsdl:part name="getLastTradePricesReturn" type="impl:ArrayOfTradePrice"/> </wsdl:message> <wsdl:message name="getLastTradePricesRequest"> <wsdl:part name="in0" type="impl:ArrayOf_xsd_string"/> </wsdl:message> <wsdl:portType name="StockQuoteProvider"> <wsdl:operation name="getLastTradePrices" parameterOrder="in0"> <wsdl:input name="getLastTradePricesRequest" message="impl:getLastTradePricesRequest"/> <wsdl:output name="getLastTradePricesResponse" message="impl:getLastTradePricesResponse"/> <wsdl:fault name="IncorrectTickerSymbolException" message="impl:IncorrectTickerSymbolException"/> </wsdl:operation> </wsdl:portType> Definición de mensajes y puertos – Comentarios (1) n Definición de mensajes n n n Especifica los mensajes que se pueden intercambiar clientes y servidores Cada mensaje consta de “partes”, donde cada parte especifica un parámetro del mensaje, un valor de retorno o una excepción Definición de puertos n n n Un puerto especifica un conjunto de operaciones Cada operación especifica el orden de los parámetros, el mensaje de entrada (petición del cliente al servicio), el de salida (respuesta del servicio si no ocurre ninguna excepción) y los posibles mensajes fault (excepciones) que puede devolver la operación Un mensaje fault sólo puede contener una parte (que puede ser de tipo simple o complejo) Definición de mensajes y puertos – Comentarios (y 2) n Definición de puertos (cont) n Tipos de parámetros (idem CORBA) n n n n In: parámetro que sólo aparece en un mensaje de entrada Out: parámetro que sólo aparece en un mensaje de salida Inout: parámetro que aparece en un mensaje de entrada y salida Valor de retorno n Parte que no es parámetro ni excepción StockQuoteProvider.wsdl (4) <wsdl:binding name="StockQuoteProviderSoapBinding“ type="impl:StockQuoteProvider"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getLastTradePrices"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getLastTradePricesRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://wsdl.stockquote.corbaws.fbellas.udc.es"/> </wsdl:input> <wsdl:output name="getLastTradePricesResponse"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://wsdl.stockquote.corbaws.fbellas.udc.es"/> </wsdl:output> <wsdl:fault name="IncorrectTickerSymbolException"> <wsdlsoap:fault use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://wsdl.stockquote.corbaws.fbellas.udc.es"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> StockQuoteProvider.wsdl (y 5) <wsdl:service name="StockQuoteProviderService"> <wsdl:port name="StockQuoteProvider" binding="impl:StockQuoteProviderSoapBinding"> <wsdlsoap:address location="http://localhost:8080/StockQuote/services/StockQuoteProvider"/> </wsdl:port> </wsdl:service> </wsdl:definitions> Definición de bindings y servicios – Comentarios n Definición de bindings n n Definición de servicios n n Un binding especifica detalles particulares al protocolo usado (en este caso, SOAP) para enviar los mensajes Un servicio especifica un conjunto de puertos, especificando para cada uno de ellos la dirección de contacto que tiene que usar un cliente En JAX-RPC n n n Se usa el término “service endpoint” para referirse al puerto de un servicio web Se usa el término “interfaz del service endpoint” para referirse al interfaz del puerto Usaremos indistintamente los términos “service endpoint” y “puerto” Mappings n JAX-RPC especifica n n n El mapping de Java a WSDL El mapping de WSDL a Java Dado que normalmente no se escriben documentos WSDL, no es preciso conocer ambos mappings en detalle, pero sí lo esencial n Mapping de Java a WSDL n n Estudiaremos cuáles son los tipos Java que podemos emplear en la definición de interfaces remotos y cómo se deben definir los interfaces Mapping de WSDL a Java n Estudiaremos cuáles son los tipos Java que se generan cuando partimos de un documento WSDL Mapping de Java a WSDL (1) n Tipos válidos JAX-RPC: tipos que se pueden emplear en la definición de interfaces remotos n n n n Tipos primitivos y sus contrapartidas objetuales Clases estándar Tipos valor JAX-RPC Arrays ([]) de tipos válidos Mapping de Java a WSDL (2) n Tipos primitivos y sus contrapartidas objetuales Tipo Java boolean Tipo WSDL xsd:boolean byte xsd:byte short xsd:short int xsd:int long xsd:long float double xsd:float n xsd:double En el caso de las contrapartidas objetuales, el correspondiente elemento lleva el atributo nillable a true Mapping de Java a WSDL (3) n n Clases estándar Tipo Java Tipo WSDL java.lang.String xsd:string java.math.BigInteger xsd:integer java.math.BigDecimal xsd:decimal java.util.Calendar xsd:dateTime java.util.Date xsd:dateTime Arrays ([]) de tipos válidos n Se mapean a tipos complejos derivados por restricción de un array SOAP, a excepción de byte[] (xsd:base64Binary) Mapping de Java a WSDL (4) n Tipos valor JAX-RPC n En general estas clases deben tener n n n n Pueden heredar de otras clases valor Se mapean a tipos WSDL complejos con compositor all (structs XML) n n n n Un constructor público sin argumentos Atributos públicos de tipos válidos o usar las convenciones de nombrado de JavaBeans para sus atributos (métodos getXXX y setXXX) En caso de herencia, el tipo complejo se define por derivación NOTA: Axis genera el compositor sequence Es buena práctica que implementen java.io.Serializable (interfaz marker) Ej.: TradePrice Mapping de Java a WSDL (5) n Definición de interfaces remotos (“interfaces de service endpoints”) n n n n n Extienden java.rmi.Remote (interfaz marker) Todas las operaciones deben declarar java.rmi.RemoteException Cada interfaz se mapea a un puerto Dado que en WSDL no existe herencia entre puertos, si un interfaz deriva de otro, el puerto hijo incluye todas las operaciones del padre Una operación no puede recibir como parámetro o devolver como valor de retorno una referencia a un interfaz remoto n n Actualmente SOAP no ofrece soporte para ello Ej.: StockQuoteProvider Mapping de Java a WSDL (6) n Excepciones n n java.rmi.RemoteException se mapea a un fault de SOAP Las excepciones específicas al puerto, es decir, las que extienden directa o indirectamente java.lang.Exception (pero no java.lang.RuntimeException) se mapean a un wsdl:fault n n n n n Definen un método getXXX para recuperar el valor de cada propiedad Disponen de un constructor que recibe las propiedades como parámetros Ej.: IncorrectTickerSymbolException Si la excepción sólo tiene una propiedad, la parte del fault será de tipo simple; en otro caso, será de tipo complejo La herencia de excepciones se mapea a herencia de tipos complejos Mapping de Java a WSDL (7) n Otros tipos n n Si se desean usar otros tipos para los que JAX-RPC no tiene soporte directo (ej.: implementaciones de java.util.Collection), JAX-RPC permite implementar clases serializadoras y deserializadoras Serializador n n Deserializador n n Convierte el valor de un tipo Java a XML Convierte el valor de un tipo XML a Java Algunas implementaciones de JAX-RPC proporcionan serializadores/deserializadores para clases estándar usuales n Ej.: Axis proporciona clases serializadoras/deserializadoras para algunas de las implementaciones de java.util.Collection Mapping de Java a WSDL (y 8) n Interoperabilidad n El uso de clases serializadoras/deserializadoras puede causar problemas de interoperabilidad n n Actualmente no hay un formato estándar para transmitir listas, mapas, etc. Para máxima interoperabilidad es mejor restringirse a los tipos directamente soportados n n Con el uso de arrays ([]) y tipos valor JAX-RPC se pueden representar estructuras complejas, que se mapean de forma estándar a tipos WSDL Esta es la técnica usada en todos los ejemplos Mapping de WSDL a Java (1) n Las reglas del mapping de Java a WSDL a la inversa n n n xsd:dateTime se mapea a java.util.Calendar (y no a java.util.Date) Los structs XML (con compositor all o sequence) se mapean a una clase Java con métodos getXXX/setXXX para cada campo del struct Además, necesitamos saber n n n n ¿ Cómo se traducen las enumeraciones ? ¿ Cómo se traducen los parámetros out e inout ? Si partimos de los interfaces remotos Java, estas dos preguntas no son relevantes (porque Java no soporta directamente estos dos conceptos), pero sí lo son si partimos de la definición WSDL También necesitamos conocer algunas clases generadas que son específicas al cliente o al servidor n Las estudiamos como parte del modelo de implementación de clientes y servidores Mapping de WSDL a Java (2) n Enumeraciones n Muy parecido a CORBA // WSDL <simpleType name=”EyeColor”> <restriction base=”xsd:string”> <enumeration value=”green”/> <enumeration value=”blue”/> </restriction> </simpleType> Mapping de WSDL a Java (3) n Enumeraciones (cont) // Java public class EyeColor { public public public public static static static static final final final final String _green = “green”; String _blue = “blue”; EyeColor green = new EyeColor(_green); EyeColor blue = new EyeColor(_blue); protected EyeColor(String value) { ... } public String getValue() { ... } public static EyeColor fromValue(String value) { ... } public boolean equals(Object obj) { ... } public int hashCode() { ... } // Otros métodos ... } Mapping de WSDL a Java (y 4) n Parámetros out e inout n n Uso de clases Holder similares a las de CORBA Existen clases Holder para los tipos WSDL predefinidos en el paquete javax.xml.rpc.holders n n Ej.: FloatHolder Para los tipos definidos por el programador, el compilador de WSDL genera clases Holder con el formato final public class <XXX>Holder implements javax.xml.rpc.holders.Holder { public <XXX> value; public <XXX>Holder() { ... } public <XXX>Holder(<XXX> value) { ... } } Implementación de servicios web en un servidor de aplicaciones web J2EE (1) Aplicaciones web HTTP Internet HTTP war Cliente Servidor aplicaciones web J2EE n n Implementar un service endpoint sólo consiste en hacer una clase que implementa el interfaz remoto, y empaquetar ésta y las clases que requiere en el fichero war Axis sólo implementa este modelo de programación de servicios web Implementación de servicios web en un servidor de aplicaciones web J2EE (2) n Usaremos Tomcat como servidor de aplicaciones web n n n Es un servidor de aplicaciones web conforme con el estándar J2EE No tiene soporte para servicios web Axis consiste en un conjunto de librerías (ficheros jar) que han de estar disponibles a la aplicación web n n Se pueden incluir en el fichero war de la aplicación web Se pueden instalar en Tomcat para que estén disponibles para cualquier aplicación web Implementación de servicios web en un servidor de aplicaciones web J2EE (3) n Requisitos de la clase de implementación n n n Implementa el interfaz remoto Ofrece un constructor público sin argumentos En Axis, por defecto, el nombre de la clase de implementación es XXXSoapBindingImpl, siendo XXX el nombre del interfaz remoto n n Ej.: StockQuoteProviderSoapBindingImpl Ciclo de vida n n El servlet que recibe las peticiones SOAP puede crear una instancia de la clase de implementación cuando arranca o cuando llega la primera petición, así como usar un pool de instancias Cada instancia puede recibir una o más peticiones concurrentemente Implementación de servicios web en un servidor de aplicaciones web J2EE (4) n Ciclo de vida (cont) n La clase de implementación puede implementar opcionalmente el interfaz (del paquete javax.xml.rpc.server) public interface ServiceLifecycle { void init(Object context) throws javax.xml.rpc.ServiceException; void destroy(); } n En caso de implementarlo, el servlet que recibe las peticiones HTTP llama a init después de crear una instancia, y a destroy cuando decide eliminarla Implementación de servicios web en un servidor de aplicaciones web J2EE (5) n Ciclo de vida (cont) n Una instancia puede usar init para tareas de inicialización y acceso a recursos externos n n En el caso de un contenedor de aplicaciones web, el contexto pasado es de tipo javax.xml.rpc.server.ServletEndpointContext, y proporciona métodos para acceder a aspectos tales como la sesión, el ServletContext, etc. Una instancia puede usar destroy para liberar recursos Implementación de servicios web en un servidor de aplicaciones web J2EE (6) n Un service endpoint es stateless n n n n Forma parte de la semántica asociada a los puertos de los servicios web (no es una restricción de JAX-RPC) Todas las instancias de la clase de implementación se consideran equivalentes, no pudiendo mantener estado específico Para un cliente sólo existe una instancia de un service endpoint En CORBA, puede haber múltiples instancias que implementan un determinado interfaz, cada una con su propio estado n n Ej.: En los ejemplos TCS*, existen múltiples objetos Thermostat Con Servicios Web, sólo existiría el service endpoint Controller, que proporcionaría operaciones para leer y manipular el estado de los termostatos n Las operaciones recibirían el identificador del termostato sobre el que se desea realizar la operación Implementación de servicios web en un servidor de aplicaciones web J2EE (y 7) n La clase de implementación de un service endpoint tiene que ser thread-safe n n Normalmente no será necesario hacer nada especial, dado que la implementación de estas operaciones generalmente sólo hace uso de variables locales (pila) o de variables globales (static) de sólo lectura (típicamente caches) Si modifican alguna estructura global (un atributo propio o alguna variable global), necesitan sincronizar su acceso n Sin embargo, en general, eso es mala idea, dado que una aplicación con estas características no será fácil que funcione en un entorno en cluster n n Para lograr escalabilidad y tolerancia a fallos, el servidor de aplicaciones web se puede replicar en varias máquinas En estos casos, es mejor usar una base de datos para las estructuras globales que sean de lectura/escritura es.udc.fbellas.corbaws.stockquote.wsdl.StockQuoteProviderSoapBindingImpl (1) package es.udc.fbellas.corbaws.stockquote.wsdl; import javax.xml.rpc.server.ServiceLifecycle; import javax.xml.rpc.ServiceException; // ... public class StockQuoteProviderSoapBindingImpl implements StockQuoteProvider, ServiceLifecycle { private Map tradePrices; public void init(Object context) throws ServiceException { TradePrice ibmTradePrice = new TradePrice(); ibmTradePrice.setTickerSymbol("IBM"); ibmTradePrice.setPrice(10.5); ibmTradePrice.setElapsedSeconds(60*20); // ... tradePrices = new HashMap(); tradePrices.put(ibmTradePrice.getTickerSymbol(), ibmTradePrice); // ... } public void destroy() {} es.udc.fbellas.corbaws.stockquote.wsdl.StockQuoteProviderSoapBindingImpl (y 2) public TradePrice[] getLastTradePrices(String[] tickerSymbols) throws IncorrectTickerSymbolException { List requestedTradePrices = new ArrayList(); for (int i=0; i<tickerSymbols.length; i++) { TradePrice tradePrice = (TradePrice) tradePrices.get(tickerSymbols[i]); if (tradePrice == null) { throw new IncorrectTickerSymbolException( tickerSymbols[i]); } requestedTradePrices.add(tradePrice); } return (TradePrice[]) requestedTradePrices.toArray( new TradePrice[0]); } } Comentarios n Por simplicidad, la clase de implementación mantiene los valores bursátiles en el atributo tradePrices n n Aunque haya invocaciones concurrentes a getLastTracePrices sobre la misma instancia de la clase de implementación, sólo usan este atributo para lectura Aunque haya varias instancias de la clase de implementación en el mismo contenedor o el contenedor esté replicado, el valor de tradePrices es el mismo en todas las instancias n n El interfaz remoto no expone ninguna operación de modificación En un caso real n n n No existiría el atributo tradePrices, sino que se usaría una BD para almacenar los valores bursátiles getLastTradePrices y las posibles operaciones de escritura leerían y/o escribirían en la BD A la BD se puede acceder concurrentemente de manera segura (para lectura y/o escritura) Empaquetamiento de aplicaciones web (1) n En J2EE, las aplicaciones web se empaquetan en ficheros war n n jar cvf aplicacionWeb.war directorio n n n En particular, una aplicación web puede incluir servicios web Opciones similares al comando Unix tar Ant incluye la tarea interna war Estructura de un fichero war n Directorio WEB-INF/classes n n n Ficheros .class que conforman la aplicación web, agrupados en directorios según su estructura en paquetes ¡ Sin ficheros fuente ! Directorio WEB-INF/lib n n Ficheros jar de librerías que usa la aplicación ¡ Sin ficheros fuente ! Empaquetamiento de aplicaciones web (y 2) n Estructura de un fichero war (cont) n WEB-INF/web.xml n n Configuración estándar de la aplicación web Directorio raíz y subdirectorios n n Vista de la aplicación (ej.: ficheros HTML, páginas JSP, imágenes, etc.) Visible a los navegadores n n Lo que hay debajo de WEB-INF sólo es visible a los servlets y páginas JSP de la aplicación Un fichero war se puede instalar (deployment) en cualquier servidor de aplicaciones web conforme a J2EE jar tvf StockQuote.war WEB-INF/lib/<< librerías Apache Axis >> WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ StockQuoteProvider.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ IncorrectTickerSymbolException.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ TradePrice.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ StockQuoteProviderService.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ StockQuoteProviderServiceLocator.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ StockQuoteProviderSoapBindingStub.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/ StockQuoteProviderSoapBindingSkeleton.class WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl /StockQuoteProviderSoapBindingImpl.class WEB-INF/web.xml Comentarios n WEB-INF/lib n n Incluye las librerías (ficheros .jar) necesarias de Apache Axis WEB-INF/classes n n Contiene las clases del paquete es.udc.fbellas.corbaws.stockquote.wsdl Definición del servicio web e implementación n En el ejemplo, por sencillez, se han incluido algunas que no son necesarias para la implementación del servicio (ej.: el stub) web.xml (1) <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd"> <web-app> <display-name>Apache-Axis</display-name> <servlet> <servlet-name>AxisServlet</servlet-name> <display-name>Apache-Axis Servlet</display-name> <servlet-class> org.apache.axis.transport.http.AxisServlet </servlet-class> </servlet> web.xml (y 2) <servlet> <servlet-name>AdminServlet</servlet-name> <display-name>Axis Admin Servlet</display-name> <servlet-class> org.apache.axis.transport.http.AdminServlet </servlet-class> <load-on-startup>100</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/servlet/AxisServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/servlet/AdminServlet</url-pattern> </servlet-mapping> </web-app> Comentarios (1) n Se declaran los servlets AxisServlet y AdminServlet n n Forman parte de las librerías de Axis (WEB-INF/lib) AxisServlet n El servidor de aplicaciones web le pasará todas las peticiones dirigidas a las URLs http://.../NombreAplicacionWeb/services/* <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> n En este caso, asumiendo que instalemos la aplicación web con el nombre StockQuote, el cliente usará la URL http://.../StockQuote/services/StockQuotePro vider para acceder al puerto StockQuoteProvider (es la URL que aparece en el documento WSDL) Comentarios (y 2) n AxisServlet (cont) n n El servlet invocará la operación correspondiente sobre el service endpoint al que va dirigida la petición, y finalmente enviará una respuesta SOAP con el resultado de la operación AdminServlet n n Permite realizar tareas de administración sobre los servicios web instalados (ej.: activarlos, desactivarlos, etc.) Axis proporciona una aplicación standalone para comunicarse con este servlet es.udc.fbellas.corbaws.stockquote.client.Client (1) package es.udc.fbellas.corbaws.stockquote.client; import import import import java.util.Calendar; java.util.Date; java.rmi.RemoteException; java.net.URL; import es.udc.fbellas.corbaws.stockquote.wsdl.TradePrice; import es.udc.fbellas.corbaws.stockquote.wsdl.StockQuoteProvider; import es.udc.fbellas.corbaws.stockquote.wsdl. StockQuoteProviderService; import es.udc.fbellas.corbaws.stockquote.wsdl. StockQuoteProviderServiceLocator; import es.udc.fbellas.corbaws.stockquote.wsdl. IncorrectTickerSymbolException; class Client { public static void main (String args[]) { es.udc.fbellas.corbaws.stockquote.client.Client (2) try { /* Check arguments. */ if (args.length < 1) { System.err.println("Usage: " + Client.class.getName() + " stockQuoteProviderURL" + " [tickerSymbol1 tickerSymbol2 ...]"); System.exit(-1); } /* Get argument values. */ URL stockQuoteProviderURL = new URL(args[0]); String[] tickerSymbols = new String[args.length-1]; for (int i=0; i<tickerSymbols.length; i++) { tickerSymbols[i] = args[i+1]; } /* Construct an instance of the port proxy. */ StockQuoteProviderService stockQuoteProviderService = new StockQuoteProviderServiceLocator(); StockQuoteProvider stockQuoteProvider = stockQuoteProviderService.getStockQuoteProvider( stockQuoteProviderURL); es.udc.fbellas.corbaws.stockquote.client.Client (y 3) /* Gest last trade prices. */ TradePrice[] tradePrices = stockQuoteProvider.getLastTradePrices(tickerSymbols); /* Print last trade prices. */ for (int i=0; i<tradePrices.length; i++) { System.out.println("Ticker symbol = " + tradePrices[i].getTickerSymbol() + " | " + "Price = " + tradePrices[i].getPrice() + " | " + "Elapsed seconds = " + tradePrices[i].getElapsedSeconds()); } } catch (IncorrectTickerSymbolException e) { System.err.println("Incorrect ticker symbol: " + e.getIncorrectTickerSymbol()); } catch (Exception e) { e.printStackTrace(); } } } Clientes de servicios web (1) n StockQuoteProviderService n n n n Interfaz del servicio Generada por el compilador de WSDL a Java Su nombre coincide con el nombre del servicio declarado en el fichero WSDL Proporciona métodos get<PortType> n n n Devuelven una instancia del stub/proxy del puerto De momento, en JAX-RPC sólo está estandarizado un método get sin parámetros por cada puerto El ejemplo usa un método get<PortType> (específico de Axis) que recibe la URL del puerto como parámetro n En Axis, la clase generada que implementa este interfaz proporciona una implementación del método get<PortType> sin parámetros asumiendo que la URL del puerto es la declarada en el documento WSDL Clientes de servicios web (2) n StockQuoteProviderServiceLocator n n n n Clase concreta generada por el compilador de WSDL a Java Es específica de Axis Implementa el interfaz StockQuoteProviderService StockQuoteProvider n n Interfaz del service endpoint Generado por el compilador de WSDL a Java Invocación n StockQuoteClient.sh http://.../StockQuote/services/StockQuoteProvider IBM SUN MIC Clientes de servicios web (3) n Clientes J2EE n Un cliente J2EE (aplicación web o EJB) puede obtener una referencia al servicio y obtener una instancia de un proxy de un puerto de una manera completamente estándar n n Se usa JNDI (Java Naming and Directory Interface) n n n Será posible a partir de J2EE 1.4 (que incluye las especificaciones 2.4 de servlets y 2.1 de EJB) API incluida en J2SE (javax.naming) Entre otras cosas, es un API que permite acceder a información de configuración y recursos externos Ejemplo: Context initialContext = new InitialContext(); StockQuoteProviderService stockQuoteProviderService = initialContext.lookup( "java:comp/env/service/StockQuoteProviderService"); StockQuoteProvider stockQuoteProvider = stockQuoteProviderService.getStockQuoteProviderPort(); Clientes de servicios web (y 4) n Clientes J2EE n Tienen que declarar en sus ficheros de configuración (web.xml o ejb-jar.xml) las referencias a los servicios web que usan <service-ref> <service-ref-name>service/StockQuoteProviderService </service-ref-name> <service-interface>es.udc.fbellas.corbaws.stockquote.wsdl. StockQuoteProviderService</service-interface> </service-ref> n Las referencias se pueden localizar por JNDI en el contexto java:comp/env n n Se recomienda declarar las referencias a servicios web debajo del subcontexto service Requiere configuración específica en el contenedor web o EJB (ej.: especificar las URLs de contacto de los puertos) TCPMonitor (1) n Axis incluye una herramienta que permite monitorizar las peticiones y respuestas SOAP que envían clientes y servidores n n n Actúa como un “túnel” Recibe las peticiones del cliente, las muestra en pantalla y las redirige al service endpoint Recibe las respuestas del service endpoint, las muestra en pantalla y se las envía al cliente TCPMonitor (2) StockQuoteClient.sh http://localhost:8000/StockQuote/services/StockQuoteProvider IBM SUN MIC 4: Respuesta SOAP 1: Petición SOAP 2: Petición SOAP 3: Respuesta SOAP TCPMonitor.sh 8000 localhost 8080 (escucha por el puerto 8000 y redirige a localhost:8080) $TOMCAT_HOME/bin/startup.sh (por defecto escucha por el puerto 8080) TCPMonitor (y 3) Comentarios n El stub del cliente envía una petición SOAP para invocar la operación getLastTradePrices sobre el service endpoint StockQuoteProvider n n AxisServlet recibe la petición SOAP n n n n n n El parámetro de la operación (String[]) se ha serializado a XML Determina que el cliente desea invocar la operación getLastTradePrices sobre StockQuoteProvider Deserializa el parámetro de la operación Invoca la operación Serializa el valor de retorno (TradePrice[]) de la operación Envía una respuesta SOAP El stub recibe la respuesta SOAP n Deserializa el valor de retorno