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
¿ 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
„
„
Especifica un mapping de WSDL a Java
„
„
Similar al paradigma de CORBA
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 WSDL
„
„
„
Permite que las implementaciones de JAX-RPC proporcionen
un compilador de Java a WSDL, que genere el documento
WSDL correspondiente a un interfaz Java
La definición del interfaz Java está sujeta a ciertas
restricciones
El 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
Documento WSDL
Compilador Java
Compilador WSDL2Java
Compilador Java2WSDL
Stubs, skeletons y tipos 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
Incluye
„
„
„
Un conjunto de librerías
Un compilador de Java a WSDL
Un compilador de WSDL a Java
Ejemplo StockQuote
„
„
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
„
„
„
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
SOAP/HTTP
Internet
SOAP/HTTP
StockQuoteProvider
„
El ejemplo permitirá aprender cómo en JAX-RPC
„
„
„
Se define el interfaz de un servicio web
Se invoca un servicio web
Se implementa un servicio web
Definición de la interfaz del servicio web (1)
„
„
Se ha definido en el paquete
es.udc.fbellas.corbaws.stockquote.servi
cedef
El paquete incluye
„
StockQuoteProvider: la interfaz propiamente dicha
„
„
TradePrice: la clase que modela una cotización
„
„
Define la operación getLastTradePrices
La operación getLastTradePrices devuelve los
TradePrice correspondientes a un conjunto de
identificadores de valores bursátiles que recibe como
parámetro
IncorrectTickerSymbolException
„
La 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 trabajo
„
„
Compilar las clases del paquete
es.udc.fbellas.corbaws.stockquote.servicedef
Utilizar el compilador de Java a WSDL sobre
StockQuoteProvider
„
„
Genera StockQuoteProvider.wsdl
Usar 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.wsdl
El 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 paquete
„
Ejemplo
„
„
Compilar las clases del paquete
es.udc.fbellas.corbaws.stockquote.servicedef
Utilizar el compilador de Java a WSDL sobre StockQuoteProvider
„
„
Usar el compilador de WSDL a Java sobre
StockQuoteProvider.wsdl
„
„
Genera StockQuoteProvider.wsdl
Indicando que genere el código Java en el paquete
es.udc.fbellas.corbaws.stockquote.servicedef
Problema
„
„
El compilador de WSDL a Java machaca los tipos
StockQuoteProider, TradePrice y
IncorrectTickerSymbolException con los generados por él
En 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) throws
RemoteException, 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 asociados
Una vez compilados los anteriores ficheros Java, se
puede obtener el documento WSDL
Un documento WSDL consta de varias partes
„
„
„
„
„
„
Definición
Definición
Definición
Definición
Definición
de
de
de
de
de
tipos de datos
mensajes
tipos de puertos
bindings
servicios
Vamos a echar un vistazo al fichero generado
„
Objetivo: 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 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
„
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 (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)
„
Definición de mensajes
„
„
„
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 (fault)
Definición de tipos de puertos
„
„
„
Un tipo de puerto especifica un conjunto de operaciones
Cada 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ón
Un 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 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
„
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://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:address
location="http://localhost:8080/StockQuote/services/StockQuoteProvider"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Definición de bindings y servicios – Comentarios
„
Definición de bindings
„
„
Definición de servicios
„
„
„
Un binding especifica un protocolo y formato de datos para
un tipo de puerto (e.g. SOAP sobre HTTP)
Un servicio especifica un conjunto de “puertos” (endpoints)
Cada puerto está asociado a un binding particular y
especifica su dirección de contacto
En JAX-RPC
„
„
„
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”
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 objetuales
Clases estándar
Tipos valor JAX-RPC
Arrays ([]) de tipos válidos
Mapping de Java a WSDL (2)
„
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
xsd:float
double
xsd:double
„
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
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
„
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)
„
Tipos valor JAX-RPC
„
En general estas clases deben tener
„
„
„
„
Pueden heredar de otras clases valor
Se mapean a tipos WSDL complejos con compositor all o
sequence
„
„
„
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
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 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
„
„
Actualmente SOAP no ofrece soporte para ello
Ej.: StockQuoteProvider
Mapping de Java a WSDL (6)
„
Excepciones
„
„
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
„
„
„
„
„
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)
„
Otros tipos
„
„
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
„
„
Deserializador
„
„
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
„
Ej.: Axis proporciona clases serializadoras/deserializadoras para
algunas de las implementaciones de java.util.Collection
Mapping de Java a WSDL (y 8)
„
Interoperabilidad
„
El 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 WSDL
Esta 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 inversa
„
„
„
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
„
„
„
„
¿ 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)
„
Enumeraciones
„
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)
„
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)
„
Parámetros out e inout
„
„
Uso de clases Holder similares a las de CORBA
Existen 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>Holder
implements 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 J2SE
„
„
„
Cliente stand-alone
Es el que usaremos en el ejemplo
Modelo basado en J2EE
„
El 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 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>
„
„
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
„
„
„
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.Stub
El 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)
„
StockQuoteProviderServiceLocator
„
„
„
Clase concreta generada por el compilador de WSDL a Java
Es específica de Axis
Implementa el interfaz StockQuoteProviderService
Invocación
„
StockQuoteClient.sh
http://.../StockQuote/services/StockQuoteProvider IBM SUN MIC
Comentarios (3)
„
Clientes J2EE
„
„
Un 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
sencilla
Se 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 J2EE
„
Es el modelo que estudiaremos
SOAP/HTTP
Internet
Aplicaciones web
(con Servicios Web)
SOAP/HTTP
war
Cliente J2SE
Contenedor web J2EE
„
Contenedor web J2EE
„
„
„
„
Servidor en el que se pueden instalar un conjunto de
aplicaciones web J2EE
Cada aplicación web (servlets, páginas JSP, páginas HTML,
librerías, clases de la aplicación, etc.) se empaqueta en un
fichero war
Una aplicación web puede incluir uno o varios servicios web, o
puede contener sólo servicios web
Usaremos Jakarta Tomcat como contenedor web
Modelo de implementación de servicios (y 2)
„
Modelo basado en contenedor de EJBs
„
El servicio web se implementa como un Stateless Sesion
Bean, cuya interfaz remota es la del servicio web
Modelo basado en contenedor web (1)
„
Requisitos de la clase de implementación
„
„
„
Implementa el interfaz remoto
Ofrece un constructor público sin argumentos
Por 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ón
„
La implementación de JAX-RPC tiene que incluir un servlet (o
varios) que
„
„
Recibe las peticiones SOAP sobre HTTP que envían los clientes
Invoca 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
SOAP/HTTP
Cliente
Servlet
Skeleton
Implementación
del servicio
Contenedor web
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 equivalentes
No pueden mantener estado específico para el cliente
Una instancia puede recibir varias peticiones concurrentemente
(en varios threads)
Diferente a CORBA
„
„
En CORBA, puede haber múltiples instancias que implementan
un determinado interfaz, cada una con su propio estado
Ej.: 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-safe
Normalmente 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 vida
„
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();
}
„
„
Cada vez que el servlet crea una instancia de la clase de
implementación, tiene que invocar a init
„
„
Permite realizar tareas de inicialización y destrucció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.
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 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
„
„
El interfaz remoto no expone ninguna operación de
modificación
En un caso real
„
„
„
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)
„
En J2EE, las aplicaciones web se empaquetan en
ficheros war
„
„
jar cvf aplicacionWeb.war directorio
„
„
„
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
„
Directorio WEB-INF/classes
„
„
„
Ficheros .class que conforman la aplicación web, agrupados
en directorios según su estructura en paquetes
¡ Sin ficheros fuente !
Directorio WEB-INF/lib
„
Ficheros 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 subdirectorios
„
„
Vista 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.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
/StockQuoteProviderSoapBindingImpl.class
WEB-INF/web.xml
Comentarios
„
WEB-INF/lib
„
„
Incluye las librerías (ficheros .jar) necesarias de Apache
Axis
WEB-INF/classes
„
„
Contiene las clases del paquete
es.udc.fbellas.corbaws.stockquote.wsdl
Definición del servicio web e implementació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)
„
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 URLs
http://.../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/StockQuotePro
vider para acceder al puerto StockQuoteProvider (es
la URL que aparece en el documento WSDL)
Comentarios (y 2)
„
AxisServlet (cont)
„
„
AdminServlet
„
„
„
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
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
Especificación JSR-109
„
Define 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 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
„
El stub del cliente envía una petición SOAP para
invocar la operación getLastTradePrices sobre el
service endpoint StockQuoteProvider
„
„
AxisServlet recibe la petición SOAP
„
„
„
„
„
„
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
„
Deserializa el valor de retorno