5.2 jax-rpc. caso de estudio: apache axis -...

64
5.2 JAX-RPC. Caso de estudio: Apache Axis

Upload: lyhanh

Post on 20-Sep-2018

225 views

Category:

Documents


0 download

TRANSCRIPT

5.2 JAX-RPC. Caso de estudio: Apache Axis

¿ Qué es JAX-RPC ? (1)

JAX-RPC es el API estándar en Java para implementar e invocar operaciones de servicios web mediante el paradigma de los RPCs

Similar al paradigma de CORBAEspecifica un mapping de WSDL a Java

Permite que las implementaciones de JAX-RPC proporcionen un compilador de WSDL a Java, que genere stubs (proxies) y skeletons para invocar e implementar servicios web

Especifica un mapping de Java a WSDLPermite que las implementaciones de JAX-RPC proporcionen un compilador de Java a WSDL, que genere el documento WSDL correspondiente a un interfaz JavaLa definición del interfaz Java está sujeta a ciertas restriccionesEl documento WSDL permite que un cliente (escrito sobre cualquier plataforma) pueda invocar el servicio web

¿ Qué es JAX-RPC ? (y 2)

Proceso de desarrollo

Interfaz Java

Compilador Java2WSDL

Documento WSDL

Compilador WSDL2Java

Stubs, skeletons y tipos Java

Compilador Java

Documento WSDL

¿ Qué es Apache Axis ?

Una implementación de JAX-RPC para contenedores web J2EE

Como veremos más adelante, existen dos maneras de implementar un servicio web

Dentro de un contenedor web Dentro de un contenedor de EJBs

IncluyeUn conjunto de libreríasUn compilador de Java a WSDLUn compilador de WSDL a Java

Ejemplo StockQuoteServicio Web que ofrece una interfaz con una operación que a partir de un conjunto de identificadores de valores bursátiles devuelve sus cotizacionesCada cotización incluye

Su identificadorSu valorEl número de segundos de antigüedad que tiene el valor (el valor real actual sería ligeramente distinto)

StockQuoteProvider

Clientestandalone

InternetSOAP/HTTP SOAP/HTTP

El ejemplo permitirá aprender cómo en JAX-RPCSe define el interfaz de un servicio webSe invoca un servicio webSe implementa un servicio web

Definición de la interfaz del servicio web (1)

Se ha definido en el paquete es.udc.fbellas.corbaws.stockquote.servicedef

El paquete incluyeStockQuoteProvider: la interfaz propiamente dicha

Define la operación getLastTradePrices

TradePrice: la clase que modela una cotizaciónLa operación getLastTradePrices devuelve los TradePrice correspondientes a un conjunto de identificadores de valores bursátiles que recibe como parámetro

IncorrectTickerSymbolExceptionLa operación getLastTradePrices levanta esta excepción si alguno de los identificadores no existe

Definición de la interfaz del servicio web (2)

Método de trabajoCompilar las clases del paquete es.udc.fbellas.corbaws.stockquote.servicedefUtilizar el compilador de Java a WSDL sobre StockQuoteProvider

Genera StockQuoteProvider.wsdlUsar el compilador de WSDL a Java sobre StockQuoteProvider.wsdl

Se le indicará que genere el código Java en el paquete es.udc.fbellas.corbaws.stockquote.wsdlEl código generado incluirá

Stub, skeleton y clases auxiliares, y Otra vez StockQuoteProvider, TradePrice e IncorrectTickerSymbolException (incluyen atributos y operaciones adicionales que necesitan el stub y el skeleton)

Tanto el cliente como el servicio web usarán estos tipos (paquete es.udc.fbellas.corbaws.stockquote.wsdl)Los tipos definidos en es.udc.fbellas.corbaws.stockquote.servicedef sólo se definen para poder usar el compilador de Java a WSDL y obtener el fichero WSDL (y a partir de éste, usar el compilador de WSDL a Java)

Definición de la interfaz del servicio web (y 3)

Alternativamente se podría intentar usar sólo un paqueteEjemplo

Compilar las clases del paquete es.udc.fbellas.corbaws.stockquote.servicedefUtilizar el compilador de Java a WSDL sobre StockQuoteProvider

Genera StockQuoteProvider.wsdl

Usar el compilador de WSDL a Java sobre StockQuoteProvider.wsdl

Indicando que genere el código Java en el paquete es.udc.fbellas.corbaws.stockquote.servicedef

ProblemaEl compilador de WSDL a Java machaca los tipos StockQuoteProider, TradePrice y IncorrectTickerSymbolException con los generados por élEn principio esto no debería suponer un problema, pero no funciona bien en Axis 1.3 cuando se repite el proceso una segunda vez (compilador de Java a WSDL + compilador de WSDL a Java)

es.udc.fbellas.corbaws.stockquote.servicedef.StockQuoteProvider

package es.udc.fbellas.corbaws.stockquote.servicedef;

import java.rmi.Remote;import java.rmi.RemoteException;

public interface StockQuoteProvider extends Remote {

TradePrice[] getLastTradePrices(String[] tickerSymbols) throwsRemoteException, IncorrectTickerSymbolException;

}

es.udc.fbellas.corbaws.stockquote.servicedef.TradePrice (1)

package es.udc.fbellas.corbaws.stockquote.servicedef;

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.servicedef.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.servicedef.IncorrectTickerSymbolException

package es.udc.fbellas.corbaws.stockquote.servicedef;

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

Dejaremos momentáneamente la explicación de los detalles de la definición del interfaz remoto StockQuoteProvider y sus tipos asociadosUna vez compilados los anteriores ficheros Java, se puede obtener el documento WSDLUn documento WSDL consta de varias partes

Definición de tipos de datosDefinición de mensajesDefinición de tipos de puertosDefinición de bindingsDefinición de servicios

Vamos a echar un vistazo al fichero generadoObjetivo: comprender el formato general de un documento WSDL

StockQuoteProvider.wsdl (1)<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions

targetNamespace="http://www.tic.udc.es/~fbellas/ws/stockquote" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://www.tic.udc.es/~fbellas/ws/stockquote" xmlns:intf="http://www.tic.udc.es/~fbellas/ws/stockquote" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<wsdl:types><schema targetNamespace="http://www.tic.udc.es/~fbellas/ws/stockquote"

xmlns="http://www.w3.org/2001/XMLSchema"><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

Es posible usar varios sistemas de tiposEl uso de un esquema XML es el más habitualCuando el protocolo que se usa es SOAP, también se pueden usar tipos SOAPEn el ejemplo se definen

El tipo complejo ArrayOf_xsd_string, que corresponde al tipo Java String[]

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 (nullen 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)

Definición de mensajesEspecifica los mensajes que se pueden intercambiar clientes y servidoresCada mensaje consta de “partes”, donde cada parte especifica un parámetro del mensaje, un valor de retorno o una excepción (fault)

Definición de tipos de puertosUn tipo de puerto especifica un conjunto de operacionesCada operación especifica el orden de los parámetros, el mensaje de entrada (input), el de salida (output) y los posibles mensajes fault que puede devolver la operaciónUn mensaje fault sólo puede contener una parte

Definición de mensajes y puertos – Comentarios (y 2)

Definición de tipos de puertos (cont)Tipos de parámetros

In: parámetro que sólo aparece en un mensaje de entradaOut: parámetro que sólo aparece en un mensaje de salidaInout: parámetro que aparece en un mensaje de entrada y salida

Valor de retornoParte 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://www.tic.udc.es/~fbellas/ws/stockquote"/>

</wsdl:input><wsdl:output name="getLastTradePricesResponse"><wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://www.tic.udc.es/~fbellas/ws/stockquote"/>

</wsdl:output><wsdl:fault name="IncorrectTickerSymbolException"><wsdlsoap:fault use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://www.tic.udc.es/~fbellas/ws/stockquote"/>

</wsdl:fault></wsdl:operation>

</wsdl:binding>

StockQuoteProvider.wsdl (y 5)<wsdl:service name="StockQuoteProviderService">

<wsdl:port name="StockQuoteProvider" binding="impl:StockQuoteProviderSoapBinding">

<wsdlsoap:addresslocation="http://localhost:8080/StockQuote/services/StockQuoteProvider"/></wsdl:port>

</wsdl:service>

</wsdl:definitions>

Definición de bindings y servicios – Comentarios

Definición de bindingsUn binding especifica un protocolo y formato de datos para un tipo de puerto (e.g. SOAP sobre HTTP)

Definición de serviciosUn servicio especifica un conjunto de “puertos” (endpoints)Cada puerto está asociado a un binding particular y especifica su dirección de contacto

En JAX-RPCSe usa el término “service endpoint” para referirse al puerto de un servicio webSe usa el término “interfaz del service endpoint” para referirse al interfaz del puertoUsaremos indistintamente los términos “service endpoint” y “puerto”

Mapping de Java a WSDL (1)

Tipos válidos JAX-RPC: tipos que se pueden emplear en la definición de interfaces remotos

Tipos primitivos y sus contrapartidas objetualesClases estándarTipos valor JAX-RPCArrays ([]) de tipos válidos

Mapping de Java a WSDL (2)

Tipos primitivos y sus contrapartidas objetuales

xsd:doubledouble

xsd:floatfloat

xsd:longlong

xsd:intint

xsd:shortshort

xsd:bytebyte

xsd:booleanbooleanTipo WSDLTipo Java

En el caso de las contrapartidas objetuales, el correspondiente elemento lleva el atributo nillable a true

Mapping de Java a WSDL (3)

Clases estándar

xsd:dateTimejava.util.Date

xsd:dateTimejava.util.Calendar

xsd:decimaljava.math.BigDecimal

xsd:integerjava.math.BigInteger

xsd:stringjava.lang.String

Tipo WSDLTipo Java

Arrays ([]) de tipos válidosSe 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)

Tipos valor JAX-RPCEn general estas clases deben tener

Un constructor público sin argumentosAtributos públicos de tipos válidos o usar las convenciones de nombrado de JavaBeans para sus atributos (métodos getXXXy setXXX)

Pueden heredar de otras clases valorSe mapean a tipos WSDL complejos con compositor all o sequence

En caso de herencia, el tipo complejo se define por derivación

Es buena práctica que implementen java.io.Serializable (interfaz marker)Ej.: TradePrice

Mapping de Java a WSDL (5)

Definición de interfaces remotos (“interfaces de service endpoints”)

Extienden java.rmi.Remote (interfaz marker)Todas las operaciones deben declarar java.rmi.RemoteException

Cada interfaz se mapea a un puertoDado que en WSDL no existe herencia entre puertos, si un interfaz deriva de otro, el puerto hijo incluye todas las operaciones del padreUna operación no puede recibir como parámetro o devolver como valor de retorno una referencia a un interfaz remoto

Actualmente SOAP no ofrece soporte para elloEj.: StockQuoteProvider

Mapping de Java a WSDL (6)

Excepcionesjava.rmi.RemoteException se mapea a un fault de SOAPLas 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

Definen un método getXXX para recuperar el valor de cada propiedadDisponen de un constructor que recibe las propiedades como parámetrosEj.: IncorrectTickerSymbolExceptionSi la excepción sólo tiene una propiedad, la parte del faultserá de tipo simple; en otro caso, será de tipo complejoLa herencia de excepciones se mapea a herencia de tipos complejos

Mapping de Java a WSDL (7)

Otros tiposSi 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 deserializadorasSerializador

Convierte el valor de un tipo Java a XML

DeserializadorConvierte el valor de un tipo XML a Java

Algunas implementaciones de JAX-RPC proporcionan serializadores/deserializadores para clases estándar usuales

Ej.: Axis proporciona clases serializadoras/deserializadoras para algunas de las implementaciones de java.util.Collection

Mapping de Java a WSDL (y 8)

InteroperabilidadEl uso de clases serializadoras/deserializadoras puede causar problemas de interoperabilidad

Actualmente no hay un formato estándar para transmitir listas, mapas, etc.

Para máxima interoperabilidad es mejor restringirse a los tipos directamente soportados

Con el uso de arrays ([]) y tipos valor JAX-RPC se pueden representar estructuras complejas, que se mapean de forma estándar a tipos WSDLEsta es la técnica usada en todos los ejemplos

Mapping de WSDL a Java (1)

Las reglas del mapping de Java a WSDL a la inversaxsd: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/setXXXpara cada campo del structAdemás, necesitamos saber

¿ 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

Las estudiamos como parte del modelo de implementación de clientes y servidores

Mapping de WSDL a Java (2)

EnumeracionesMuy 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)

Enumeraciones (cont)

// Javapublic class EyeColor {

public static final String _green = “green”;public static final String _blue = “blue”;public static final EyeColor green = new EyeColor(_green);public static final 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)

Parámetros out e inoutUso de clases Holder similares a las de CORBAExisten clases Holder para los tipos WSDL predefinidos en el paquete javax.xml.rpc.holders

Ej.: FloatHolder

Para los tipos definidos por el programador, el compilador de WSDL genera clases Holder con el formato

final public class <XXX>Holderimplements javax.xml.rpc.holders.Holder {

public <XXX> value;

public <XXX>Holder() { ... }public <XXX>Holder(<XXX> value) { ... }

}

Modelos de implementación de clientes

Modelo basado en J2SECliente stand-aloneEs el que usaremos en el ejemplo

Modelo basado en J2EEEl cliente corre dentro de un contenedor web (una aplicación web) o un contenedor de EJBs (un EJB)

es.udc.fbellas.corbaws.stockquote.client.Client (1)

package es.udc.fbellas.corbaws.stockquote.client;

import javax.xml.rpc.Stub;

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. */String stockQuoteProviderURL = 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();

((Stub)stockQuoteProvider)._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY, 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();}

}

}

Comentarios (1)StockQuoteProviderService

Interfaz del servicioGenerada por el compilador de WSDL a JavaSu nombre coincide con el nombre del servicio declarado en el fichero WSDLProporciona métodos get<PortType>

Devuelven una instancia del stub/proxy del puertoDe momento, en JAX-RPC sólo está estandarizado un método get sin parámetros por cada puerto

En el caso de Axis, el proxy del puerto utiliza por defecto la URL declarada en el fichero WSDL

El proxy implementa el interfaz del puerto (StockQuoteProvider en el ejemplo, generado por el compilador de WSDL a Java) y el interfaz javax.xml.rpc.StubEl ejemplo utiliza el método _setProperty del interfaz javax.xml.rpc.Stub para que se utilice la URL del puerto que se pasa como primer argumento de la aplicación

Comentarios (2)

StockQuoteProviderServiceLocatorClase concreta generada por el compilador de WSDL a JavaEs específica de AxisImplementa el interfaz StockQuoteProviderService

InvocaciónStockQuoteClient.shhttp://.../StockQuote/services/StockQuoteProvider IBM SUN MIC

Comentarios (3)

Clientes J2EEUn cliente J2EE (aplicación web o EJB) puede obtener una referencia al servicio de una manera estándar y obtener una instancia de un proxy de un puerto de una manera más sencillaSe usa JNDI (Java Naming and Directory Interface)

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 =

(StockQuoteProviderService) initialContext.lookup("java:comp/env/service/StockQuoteProviderService");

StockQuoteProvider stockQuoteProvider =stockQuoteProviderService.getStockQuoteProvider();

Comentarios (y 4)

Clientes J2EE (cont)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>

Las referencias se pueden localizar por JNDI en el contexto java:comp/env

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)

Modelo de implementación de servicios (1)

Modelo basado en contenedor web J2EEEs el modelo que estudiaremos

Contenedor web J2EE

Internet

Cliente J2SE

SOAP/HTTP SOAP/HTTPwar

Aplicaciones web(con Servicios Web)

Contenedor web J2EEServidor en el que se pueden instalar un conjunto de aplicaciones web J2EECada aplicación web (servlets, páginas JSP, páginas HTML, librerías, clases de la aplicación, etc.) se empaqueta en un fichero warUna aplicación web puede incluir uno o varios servicios web, o puede contener sólo servicios webUsaremos Jakarta Tomcat como contenedor web

Modelo de implementación de servicios (y 2)

Modelo basado en contenedor de EJBsEl servicio web se implementa como un Stateless SesionBean, cuya interfaz remota es la del servicio web

Modelo basado en contenedor web (1)

Requisitos de la clase de implementaciónImplementa el interfaz remotoOfrece un constructor público sin argumentosPor defecto en Axis

El nombre de la clase de implementación es XXXSoapBindingImpl, siendo XXX el nombre del interfaz remoto

Ej.: StockQuoteProviderSoapBindingImpl

El compilador de WSDL a Java genera la clase automáticamente (si no existía) en el paquete en el que se le especificó que generase el código

es.udc.fbellas.corbaws.stockquote.wsdl en el ejemplo

Modelo basado en contenedor web (2)

Modelo de ejecuciónLa implementación de JAX-RPC tiene que incluir un servlet (o varios) que

Recibe las peticiones SOAP sobre HTTP que envían los clientesInvoca la operación correspondiente sobre el servicio web

NOTA A LA FIGURA: en Axis 1.3 el compilador de WSDL a Java no genera una clase Skeleton (el servlet utiliza clases genéricas que realizan esa misma función)

Devuelve una respuesta SOAP sobre HTTP con el resultado de la operación

Servlet Skeleton

Implementación del servicio

Contenedor web

SOAP/HTTPCliente

Modelo basado en contenedor web (3)

Modelo de ejecución (cont)El servlet que recibe las peticiones puede crear una o varias instancias de la clase de implementación

Todas las instancias se consideran equivalentesNo pueden mantener estado específico para el clienteUna instancia puede recibir varias peticiones concurrentemente (en varios threads)

Diferente a CORBAEn CORBA, puede haber múltiples instancias que implementan un determinado interfaz, cada una con su propio estadoEj.: En los ejemplos TCS*, existen múltiples objetos Thermostat

Cada objeto Thermostat representa un termostato real ubicado en una habitación

Modelo basado en contenedor web (4)

Modelo de ejecución (cont)La clase de implementación tiene que ser thread-safeNormalmente no será necesario hacer nada especial, dado que la implementación de las operaciones generalmente sólo hace uso de variables locales (pila) o de variables globales (static) de sólo lectura (típicamente caches)Si modifica alguna estructura global (un atributo propio o alguna variable global), necesita sincronizar su acceso

Sin embargo, en general, eso es mala idea, dado que una aplicación con estas características no funcionará en un entorno en cluster

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

Modelo basado en contenedor web (y 5)

Ciclo de vidaLa 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();

}

Permite realizar tareas de inicialización y destrucción

Cada vez que el servlet crea una instancia de la clase de implementación, tiene que invocar a init

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.

Cada vez que el servlet decide destruir una instancia de la clase de implementación, tiene que invocar a destroy

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

Por simplicidad, la clase de implementación mantiene los valores bursátiles en el atributo tradePrices

Aunque haya invocaciones concurrentes a getLastTracePrices sobre la misma instancia de la clase de implementación, sólo usan este atributo para lecturaAunque 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

El interfaz remoto no expone ninguna operación de modificación

En un caso realNo existiría el atributo tradePrices, sino que se usaría una BD para almacenar los valores bursátilesgetLastTradePrices y las posibles operaciones de escritura leerían y/o escribirían en la BDA la BD se puede acceder concurrentemente de manera segura (para lectura y/o escritura)

Empaquetamiento de aplicaciones web (1)

En J2EE, las aplicaciones web se empaquetan en ficheros war

En particular, una aplicación web puede incluir servicios web

jar cvf aplicacionWeb.war directorioOpciones similares al comando Unix tar

Ant incluye la tarea interna warEstructura de un fichero war

Directorio WEB-INF/classesFicheros .class que conforman la aplicación web, agrupados en directorios según su estructura en paquetes¡ Sin ficheros fuente !

Directorio WEB-INF/libFicheros jar de librerías que usa la aplicación¡ Sin ficheros fuente !

Empaquetamiento de aplicaciones web (y 2)

Estructura de un fichero war (cont)WEB-INF/web.xml

Configuración estándar de la aplicación web

Directorio raíz y subdirectoriosVista de la aplicación (ej.: ficheros HTML, páginas JSP, imágenes, etc.)Visible a los navegadores

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.warWEB-INF/lib/<< librerías Apache Axis >>WEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

StockQuoteProvider.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

IncorrectTickerSymbolException.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

TradePrice.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

StockQuoteProviderService.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

StockQuoteProviderServiceLocator.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl/

StockQuoteProviderSoapBindingStub.classWEB-INF/classes/es/udc/fbellas/corbaws/stockquote/wsdl

/StockQuoteProviderSoapBindingImpl.classWEB-INF/web.xml

Comentarios

WEB-INF/libIncluye las librerías (ficheros .jar) necesarias de Apache Axis

WEB-INF/classesContiene las clases del paquete es.udc.fbellas.corbaws.stockquote.wsdl

Definición del servicio web e implementaciónEn el ejemplo, por sencillez, se han incluido algunas que no sonnecesarias para la implementación del servicio (ej.: el stub)

web.xml (1)<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-appPUBLIC "-//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)

Se declaran los servlets AxisServlet y AdminServlet

Forman parte de las librerías de Axis (WEB-INF/lib)AxisServlet

El servidor de aplicaciones web le pasará todas las peticiones dirigidas a las URLshttp://.../NombreAplicacionWeb/services/*

<servlet-mapping><servlet-name>AxisServlet</servlet-name><url-pattern>/services/*</url-pattern>

</servlet-mapping>

En este caso, asumiendo que instalemos la aplicación web con el nombre StockQuote, el cliente usará la URL http://.../StockQuote/services/StockQuoteProvider para acceder al puerto StockQuoteProvider (es la URL que aparece en el documento WSDL)

Comentarios (y 2)AxisServlet (cont)

El servlet invocará la operación correspondiente sobre el serviceendpoint al que va dirigida la petición, y finalmente enviará una respuesta SOAP con el resultado de la operación

AdminServletPermite 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

Especificación JSR-109Define un conjunto de descriptores (ficheros XML) adicionales para realizar poder instalar y configurar de manera estándar una aplicación web que contenga servicios web en un contenedor de aplicaciones web o EJB que tenga soporte nativo para servicios web

El ejemplo estudiado asume Axis y no requiere que el servidor de aplicaciones web tenga soporte nativo para servicios web (ej.: Tomcat)

Actualmente son “complejos” (seguramente se simplificarán y serán transparentes al desarrollador en un futuro)

TCPMonitor (1)

Axis incluye una herramienta que permite monitorizar las peticiones y respuestas SOAP que envían clientes y servidores

Actúa como un “túnel”Recibe las peticiones del cliente, las muestra en pantalla y las redirige al service endpointRecibe las respuestas del service endpoint, las muestra en pantalla y se las envía al cliente

TCPMonitor (2)

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)

StockQuoteClient.sh http://localhost:8000/StockQuote/services/StockQuoteProvider IBM SUN MIC

1: Petición SOAP

2: Petición SOAP

3: Respuesta SOAP

4: Respuesta SOAP

TCPMonitor (y 3)

Comentarios

El stub del cliente envía una petición SOAP para invocar la operación getLastTradePrices sobre el service endpoint StockQuoteProvider

El parámetro de la operación (String[]) se ha serializadoa XML

AxisServlet recibe la petición SOAPDetermina que el cliente desea invocar la operación getLastTradePrices sobre StockQuoteProviderDeserializa el parámetro de la operaciónInvoca la operaciónSerializa el valor de retorno (TradePrice[]) de la operaciónEnvía una respuesta SOAP

El stub recibe la respuesta SOAPDeserializa el valor de retorno