Tema 3, Apartado 3.4: Servicios Web SOAP con JAX-WS

Anuncio
3.4 JAX-WS
Índice
Introducción a SOAP
JAX-WS
SOAP (1)
SOAP es un protocolo basado en XML para el
intercambio de mensajes en un entorno
distribuido
Los mensajes SOAP se envían encapsulados en otros
protocolos de nivel de aplicación (e.g. HTTP o SMTP)
Originalmente acrónimo de “Simple Object Access Protocol”
Hoy ya no se considera acrónimo
Estandarizado por W3C
HTTP es el usado habitualmente (buena elección para
atravesar firewalls)
Con SOAP, un servicio se compone de puertos, y
cada puerto ofrece un conjunto de operaciones
Cada operación tiene: nombre, parámetros (entrada, salida,
entrada/salida), valor de retorno y posibles “faults”
(excepciones)
SOAP (2)
Las operaciones pueden ser
Síncronas (RPC): el cliente envía la petición y se queda bloqueado
hasta que llegue la respuesta
La alternativa síncrona es la más usada hoy en día
Asíncronas: el cliente envía la petición, continúa con su ejecución,
y más adelante puede comprobar si llegó la respuesta
SOAP estandariza la manera de enviar un mensaje para invocar
una operación del servicio y cómo enviar la respuesta
Misma estructura de mensaje para petición y respuesta
Envelope
Header (opcional)
Elemento raíz de un mensaje SOAP
Puede contener un elemento Header y otro Body
Permite pasar información “extra” a protocolos de nivel superior (e.g.
tokens de seguridad, identificadores de transacción, etc.)
Body (obligatorio)
Contiene los datos del mensaje
SOAP (y 3)
[Ejemplo (fuente Wikipedia): servicio con operación getProductDetails]
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getProductDetails xmlns="http://warehouse.example.com/ws">
<productID>827635</productID>
</getProductDetails>
</soap:Body>
</soap:Envelope>
Cliente
Servicio
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getProductDetailsResponse xmlns="http://warehouse.example.com/ws">
<getProductDetailsResult>
<productName>Toptimate 3-Piece Set</productName>
<productID>827635</productID>
<description>3-Piece luggage set. Black Polyester.</description>
<price currency="NIS">96.50</price>
<inStock>true</inStock>
</getProductDetailsResult>
</getProductDetailsResponse>
</soap:Body>
</soap:Envelope>
WSDL y UDDI
WSDL (Web Services Description Language)
Permite especificar en XML la interfaz de un servicio (puertos,
operaciones, tipos de datos, etc.)
Estandarizado por el W3C
UDDI (Universal Description, Discovery and Integration of Web
Services)
Interfaz SOAP de un servicio (registro UDDI) que proporciona
operaciones registrar y buscar servicios Web
Cada servicio Web se registra dando: su nombre, una descripción (e.g.
la URL de su WSDL, una descripción textual, etc.), etc.
Permite localizar servicios a partir de su nombre, descripción, etc.
Estandarizado por OASIS (http://www.oasis-open.org)
Registro UDDI
SOAP
Client
e
SOAP
SOAP
Servicio
APIs de programación (1)
De bajo nivel
Permiten explícitamente construir, enviar y recibir
mensajes SOAP
De alto nivel
Disponen de un compilador de WSDL
Para el cliente, por cada puerto, el compilador genera un
interfaz, una clase (stub/proxy) que lo implementa y tipos
de datos asociados
El interfaz contiene una operación por cada operación del
puerto
El stub/proxy implementa cada operación
Construye la petición SOAP (convierte los parámetros a XML)
La envía
Espera por la respuesta SOAP (si es una operación síncrona)
Convierte el valor de retorno o “fault” (XML) a un objeto
APIs de programación (2)
De alto nivel (cont)
Para el servicio, por cada puerto, el compilador genera una
clase skeleton y tipos de datos asociados
El skeleton
Recibe las peticiones SOAP
Convierte los parámetros de XML a objetos
Delega en una clase implementada por el desarrollador que
proporciona una operación por cada operación del puerto
Convierte el valor de retorno o excepción a XML
Envía la respuesta SOAP
También proporcionan un compilador desde interfaces o
clases de implementación del servicio a WSDL
Permite que el desarrollador del servicio especifique el interfaz
del servicio en un lenguaje convencional (e.g. Java, C#, etc.)
Genera el WSDL automáticamente
APIs de programación (y 3)
De alto nivel (cont)
Resto aplicación
cliente
getProductDetails
<<interface>>
ProductManager
ProductManagerImpl
getProductDetails
Clase Proxy
Cliente
Skeleton
Servicio
Índice
Introducción a SOAP
JAX-WS
¿Qué es JAX-WS? (1)
JAX-WS es un API estándar en Java para
implementar e invocar Servicios Web.
Forma parte del API de Java SE.
Usa anotaciones para facilitar el desarrollo.
Permite invocar e implementar operaciones de servicios Web
SOAP mediante el paradigma de RPC.
Permite también operaciones asíncronas.
En lugar de quedarse bloqueado esperando por respuesta,s e
proporciona una operación de callback.
Permite también cierto soporte para REST (aunque no es el
objetivo principal).
Como cualquier otro API de Java, está formada por un
conjunto de interfaces
Existen múltiples implementaciones (Metro, CXF, Axis
2,…)
El código escrito por el desarrollador no depende de la
implementación concreta de JAX-WS que se utilice
Nosotros utilizaremos Metro.
¿Qué es JAX-WS? (2)
Especifica un mapping de WSDL a Java
Especifica un mapping de Java a WSDL
Permite que las implementaciones de JAX-WS proporcionen
un compilador de WSDL a Java, que genere stubs
(proxies) para invocar servicios Web.
Permite que las implementaciones de JAX-WS proporcionen
un compilador de Java a WSDL, que genere el
documento WSDL correspondiente a un interfaz o clase de
implementación Java
La definición del interfaz o clase de implementación Java
está sujeta a ciertas restricciones
El documento WSDL permite que un cliente (escrito sobre
cualquier plataforma) pueda invocar el servicio Web
Los mappings están basados en JAXB.
¿Qué es JAX-WS? (y 3)
Proceso de desarrollo
Interfaz Java
Documento WSDL
Compilador Java
Compilador WSDL a Java
Compilador WSDL
Documento WSDL
Stubs, skeletons y tipos Java
¿Qué es Metro?
Una toolkit para construir Servicios Web que incluye
la implementación de referencia de JAX-WS.
A diferencia de otras implementaciones de referencia,
es apta para producción)
Permite implementar servicios SOAP en un servidor
de aplicaciones Java EE
Incluye
http://metro.dev.java.net/
Un conjunto de librerías
Un compilador de Java a WSDL
Un compilador de WSDL a Java
Otras implementaciones de JAX-WS:
Axis 2 (http://ws.apache.org/axis2/)
CXF (http://cxf.apache.org/)
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)
SOAP/HTTP
Cliente
StockQuoteProvider
El ejemplo permitirá aprender cómo en JAX-WS
Se define y se implementa el interfaz de un servicio Web
Se invoca un servicio Web desde un cliente
Definición de la interfaz del servicio Web (1)
Puede definirse explícitamente o puede dejarse que
JAX-WS la obtenga automáticamente desde una clase
anotada de implementación del servicio.
En el ejemplo hemos seguido la segunda
aproximación. Definida en
es.udc.ws.jaxwstutorial.service
El paquete incluye
StockQuoteProviderImpl: la implementación del
servicio. Define la operación getLastTradePrices
TradePrice: la clase que modela una cotización
La operación getLastTradePrices devuelve los
TradePrice correspondientes a un conjunto de
identificadores de valores bursátiles.
IncorrectTickerSymbolException
La operación getLastTradePrices lanza 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.ws.jaxwstutorial.service
Utilizar el compilador de Java a WSDL sobre
StockQuoteProviderImpl
Genera StockQuoteProviderService.wsdl
Usar el compilador de WSDL a Java sobre
StockQuoteProviderService.wsdl
El código generado incluirá
Stub, y clases auxiliares, y
Otra vez StockQuoteProvider, TradePrice e
IncorrectTickerSymbolException (incluyen
atributos y operaciones adicionales que necesitan el stub y
el skeleton)
El cliente del servicio Web usará estos tipos (paquete
es.udc.ws.jaxwstutorial.wsdl)
Modelo de implementación de servicios
Modelo basado en un servidor de aplicaciones Java EE con soporte
para el API de Servlets
Una aplicación Web puede incluir uno o varios servicios Web SOAP
Es el modelo que estudiaremos
SOAP/HTTP
war
Cliente
Aplicaciones
Web (.war)
Servidor de aplicaciones
Modelo basado en un servidor de aplicaciones Java EE con soporte
para el API de EJB
El servicio Web SOAP se implementa como un Stateless Sesion Bean, cuya
interfaz remota es la del servicio Web
SOAP/HTTP
EJB
Cliente
Componentes
EJB (.jar)
Servidor de aplicaciones
Modelo basado en servidor de aplicaciones con soporte para Servlets (1)
Requisitos de la clase de implementación
Debe tener un constructor público.
Debe estar anotada con javax.jws.WebService
name: nombre del tipo de puerto en wsdl.
serviceName: nombre del servicio en wsdl.
targetNamespace. Espacio de nombres en wsdl.
endpointInterface. Si la interfaz se define
separadamente, se indica en esta propiedad.
Las operaciones del servicio deben ser públicas, usar tipos
compatibles JAXB y declarar javax.jws.WebMethod.
name: nombre de la operación en wsdl
exclude: valor booleano. Si true, la operación no se
incluye en el wsdl.
Las excepciones lanzadas deben usar la anotación
javax.xml.ws.WebFault
name: nombre en wsdl.
targetNamespace. Espacio de nombres en wsdl.
Modelo basado en servidor de aplicaciones con soporte para Servlets (2)
Modelo de ejecución
La implementación de JAX-WS tiene que incluir un servlet que
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
SOAP/HTTP
Cliente
Servlet
Skeleton
Implementación
del servicio
Servidor de aplicaciones
Modelo basado en servidor de aplicaciones con soporte para Servlets (3)
Modelo de ejecución (cont)
El servlet crea un pool (conjunto) de instancias de la clase
de implementación
Por defecto, las instancias no pueden mantener estado
específico para el cliente
Pero pueden tener estado global, es decir, atributos
típicamente inicializados al crear el servicio y que optimizan la
ejecución de las operaciones del servicio (e.g. cachés de sólo
lectura, una conexión a una BD, etc.)
Cuidado con el estado global en entornos cluster (e.g. no usar
atributos modificables que afecten a la funcionalidad del
servicio)
Cada vez que llega una petición, el servlet delega en una
instancia que no se esté utilizando en ese momento
Dada que el modelo de ejecución de servlets es multi-thread,
se pueden atender múltiples peticiones SOAP
concurrentemente (cada petición utiliza su propia instancia)
Modelo basado en servidor de aplicaciones con soporte para Servlets (y 4)
Ciclo de vida
Las anotaciones javax.annotation.PostConstruct y import
javax.annotation.PreDestroy permiten marcar métodos que
se ejecutarán respectivamente tras la inicialización y antes de la
destrucción de una instancia.
es.udc.ws.jaxwstutorial.service.StockQuoteProviderImpl (1)
package es.udc.ws.jaxwstutorial.service;
import
import
import
import
import
import
import
javax.jws.WebMethod;
javax.jws.WebService;
javax.annotation.PostConstruct;
java.util.ArrayList;
java.util.HashMap;
java.util.List;
java.util.Map;
@WebService(
name="StockQuoteProvider",
serviceName="StockQuoteProviderService",
targetNamespace="http://ws.adoo.udc.es/"
)
public class StockQuoteProviderImpl {
private Map<String, TradePrice> tradePrices;
es.udc.ws.jaxwstutorial.service.StockQuoteProviderImpl (2)
@PostConstruct
private void init() {
TradePrice ibmTradePrice = new TradePrice();
ibmTradePrice.setTickerSymbol("IBM");
ibmTradePrice.setPrice(10.5);
ibmTradePrice.setElapsedSeconds(60*20);
TradePrice sunTradePrice = new TradePrice();
sunTradePrice.setTickerSymbol("SUN");
sunTradePrice.setPrice(9.1);
sunTradePrice.setElapsedSeconds(60*10);
TradePrice micTradePrice = new TradePrice();
micTradePrice.setTickerSymbol("MIC");
micTradePrice.setPrice(20.3);
micTradePrice.setElapsedSeconds(60*5);
tradePrices = new HashMap<String, TradePrice>();
tradePrices.put(ibmTradePrice.getTickerSymbol(),ibmTradePrice);
tradePrices.put(sunTradePrice.getTickerSymbol(),sunTradePrice);
tradePrices.put(micTradePrice.getTickerSymbol(),micTradePrice);
}
es.udc.ws.jaxwstutorial.service.StockQuoteProviderImpl (3)
public StockQuoteProviderImpl() {
}
@WebMethod(
operationName="getLastTradePrices"
)
public List<TradePrice> getLastTradePrices(List<String> tickerSymbols)
throws IncorrectTickerSymbolException {
List requestedTradePrices = new ArrayList();
System.out.println("Requested " + tickerSymbols.size() + " ticker
simbol(s)");
for (int i=0; i<tickerSymbols.size(); i++) {
TradePrice tradePrice= tradePrices.get(tickerSymbols.get(i));
es.udc.ws.jaxwstutorial.service.StockQuoteProviderImpl (y 4)
if (tradePrice == null) {
IncorrectTickerSymbolExceptionInfo info = new
IncorrectTickerSymbolExceptionInfo();
info.setIncorrectTickerSymbol(tickerSymbols.get(i));
throw new IncorrectTickerSymbolException(info);
}
requestedTradePrices.add(tradePrice);
}
System.out.println("Successfully resolved " +
requestedTradePrices.size() + " ticker simbol(s)");
return requestedTradePrices;
}
}
es.udc.ws.jaxwstutorial.servicedef.TradePrice (1)
package es.udc.ws.jaxwstutorial.service;
public class TradePrice {
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.ws.jaxwstutorial.service.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.ws.jaxwstutorial.service.IncorrectTickerSymbolException
package es.udc.ws.jaxwstutorial.service;
import javax.xml.ws.WebFault;
@WebFault(name = "IncorrectTickerSymbolException", targetNamespace =
"http://ws.adoo.udc.es/")
public class IncorrectTickerSymbolException extends Exception {
private IncorrectTickerSymbolExceptionInfo exceptionInfo;
public IncorrectTickerSymbolException(IncorrectTickerSymbolExceptionInfo
exceptionInfo) {
this.exceptionInfo = exceptionInfo;
}
public IncorrectTickerSymbolExceptionInfo getFaultInfo() {
return exceptionInfo;
}
}
es.udc.ws.jaxwstutorial.service.IncorrectTickerSymbolExceptionInfo
package es.udc.ws.jaxwstutorial.service;
public class IncorrectTickerSymbolExceptionInfo {
protected String incorrectTickerSymbol;
public String getIncorrectTickerSymbol() {
return incorrectTickerSymbol;
}
public void setIncorrectTickerSymbol(String value) {
this.incorrectTickerSymbol = value;
}
}
Comentarios
Por la forma en la que JAX-WS define el mapping de
Exceptions java a WSDL y viceversa, es conveniente
que las Excepciones utilizadas cumplan las siguientes
reglas:
La información encapsulada en la Excepción debe ir en un
objeto separado
IncorrectTickerSymbolExceptionInfo
Este objeto debe ser obtenido a través del método
getFaultInfo.
De esta forma, las excepciones lanzadas por los stubs
del cliente serán iguales que las usadas en el
servicio.
En algunas toolkits esto no es necesario.
Visión global de WSDL
Dejaremos momentáneamente la explicación de los
detalles de la definición del interfaz remoto
StockQuoteProviderService 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
StockQuoteProviderService.wsdl (1)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://ws.adoo.udc.es/"
name="StockQuoteProviderService" xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://ws.adoo.udc.es/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<types>
<xsd:schema>
<xsd:import namespace="http://ws.adoo.udc.es/"
schemaLocation="StockQuoteProviderService_schema1.xsd"/>
</xsd:schema>
</types>
StockQuote…schema1.xsd (1)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="http://ws.adoo.udc.es/"
xmlns:tns="http://ws.adoo.udc.es/"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="IncorrectTickerSymbolException" nillable="true"
type="tns:incorrectTickerSymbolExceptionInfo"/>
<xs:element name="getLastTradePrices" type="tns:getLastTradePrices"/>
<xs:element name="getLastTradePricesResponse"
type="tns:getLastTradePricesResponse"/>
<xs:complexType name="getLastTradePrices">
<xs:sequence>
<xs:element name="arg0" type="xs:string" minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="getLastTradePricesResponse">
<xs:sequence>
<xs:element name="return" type="tns:tradePrice" minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
StockQuote…schema1.xsd (y 2)
<xs:complexType name="tradePrice">
<xs:sequence>
<xs:element name="elapsedSeconds" type="xs:int"/>
<xs:element name="price" type="xs:double"/>
<xs:element name="tickerSymbol" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="incorrectTickerSymbolExceptionInfo">
<xs:sequence>
<xs:element name="incorrectTickerSymbol" type="xs:string"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
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
También se pueden usar tipos SOAP.
Metro genera las definiciones de tipos en un fichero
aparte (no es necesario hacerlo así).
En el ejemplo se definen
El tipo complejo getLastTradePrices, que corresponde
al tipo Java de entrada a la operación List<String>
Se define como una secuencia de elementos xsd:string
Los tipos complejos TradePrice e
IncorrectTickerSymbolException que corresponden
a los tipos Java con el mismo nombre.
getLastTradePricesResponse representa el tipo de la
respuesta de la operación List<TradePrice>.
nillable=true especifica que el correspondiente
elemento puede tomar el valor nil (null en Java)
StockQuoteProviderService.wsdl (2)
<message name="getLastTradePrices">
<part name="parameters" element="tns:getLastTradePrices"/>
</message>
<message name="getLastTradePricesResponse">
<part name="parameters" element="tns:getLastTradePricesResponse"/>
</message>
<message name="IncorrectTickerSymbolException">
<part name="fault" element="tns:IncorrectTickerSymbolException"/>
</message>
<portType name="StockQuoteProvider">
<operation name="getLastTradePrices">
<input message="tns:getLastTradePrices"/>
<output message="tns:getLastTradePricesResponse"/>
<fault message="tns:IncorrectTickerSymbolException"
name="IncorrectTickerSymbolException"/>
</operation>
</portType>
Definición de mensajes y puertos – Comentarios
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
StockQuoteProviderService.wsdl (y 3)
<binding name="StockQuoteProviderPortBinding"
type="tns:StockQuoteProvider">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document"/>
<operation name="getLastTradePrices">
<soap:operation soapAction=""/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
<fault name="IncorrectTickerSymbolException">
<soap:fault name="IncorrectTickerSymbolException" use="literal"/>
</fault>
</operation>
</binding>
<service name="StockQuoteProviderService">
<port name="StockQuoteProviderPort"
binding="tns:StockQuoteProviderPortBinding">
<soap:address location="REPLACE_WITH_ACTUAL_URL"/>
</port>
</service>
</definitions>
Definición de bindings y servicios – Comentarios
Definición de bindings
Un binding especifica un protocolo y formato de datos para
un tipo de puerto (e.g. SOAP sobre HTTP)
Definición de servicios
Un servicio especifica un conjunto de “puertos” (endpoints)
Cada puerto está asociado a un binding particular y
especifica su dirección de contacto
REPLACE_WITH_ACTUAL_URL. Ahí debe indicarse la URL
por defecto de acceso al servicio.
También puede indicarse al generar los stubs.
En JAX-WS
Se usa el término “service endpoint” para referirse al puerto
de un servicio Web
Usaremos indistintamente los términos “service endpoint” y
“puerto”
Mapping de Java a WSDL (1)
No todos los tipos se pueden emplear en la definición
de las operaciones de los Servicios Web.
Tipos primitivos y sus contrapartidas objetuales
Clases estándar
Clases que sigan las convenciones de “bean”.
Colecciones de tipos válidos
Se utilizan los mappings de JAXB (Java Architecture
for XML Binding).
Define unos mappings por defecto.
Pueden adaptarse mediante anotaciones.
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
Colecciones (e.g. Listas) de tipos válidos
Se mapean a tipos complejos que son secuencias del tipo
base.
Mapping de Java a WSDL (4)
Objetos tipo “bean”:
En general, estas clases deben tener atributos públicos de
tipos válidos o usar las convenciones de nombrado de
JavaBeans para sus atributos (métodos getXXX y setXXX)
Pueden heredar de otras clases valor
Se mapean a tipos WSDL complejos con compositor all o
sequence
En caso de herencia, el tipo complejo se define por derivación
Ejemplo: TradePrice
Mapping de Java a WSDL (5)
Definición de operaciones remotas
Utilizan las anotaciones @WebService y @WebMethod tal
y como ya hemos comentado.
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
Ejemplo: StockQuoteProviderImpl
Mapping de Java a WSDL (y 6)
Excepciones
Las excepciones se mapean a un wsdl:fault
El objeto que contiene la información de la excepción se mapea
a un tipo complejo.
Dicho objeto ser accede mediante la operación
getFaultInfo.
Ejemplo: IncorrectTickerSymbolException
Mapping de WSDL a Java (1)
Las reglas del mapping de Java a WSDL a la inversa
xsd:dateTime se mapea a
javax.xml.datatype.XMLGregorianCalendar (y no a
java.util.Calendar)
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 como se mapean algunas
construcciones no existentes en JAVA (nuevamente, se usan
las normas de JAXB):
¿Cómo se traducen los parámetros out e inout?
Parámetros de salida y de entrada/salida disponibles en otros
lenguajes de programación.
Mapping de WSDL a Java (y 2)
Parámetros out e inout
Uso de clases Holder
Son necesarias porque Java no tiene soporte directo (palabras
reservadas en el lenguaje) para parámetros in/inout
Son clases que contienen un valor, accesible mediante el atributo
público value
Ejemplo
Supongamos un endpoint con la operación
Nombre: add
Parámetros: increment (in, double), amount (inout, double)
Sin tipo de retorno
La operación se mapearía a Java como
void add(double increment, Holder<Double> amount)
Uso
Holder<Double> amount = new Holder(20);
puerto.add(10, amount);
System.out.println(amount.value); // 30
Modelos de implementación de clientes
Modelo basado en Java SE
Es el que usaremos.
Modelo basado en Java EE
El cliente corre dentro de un servidor de aplicaciones Java
EE con soporte para JAX-WS.
es.udc.ws.jaxwstutorial.client.StockQuoteProviderClient (1)
package es.udc.ws.jaxwstutorial.client;
import
import
import
import
es.udc.ws.jaxwstutorial.wsdl.IncorrectTickerSymbolException;
es.udc.ws.jaxwstutorial.wsdl.StockQuoteProvider;
es.udc.ws.jaxwstutorial.wsdl.StockQuoteProviderService;
es.udc.ws.jaxwstutorial.wsdl.TradePrice;
import
import
import
import
import
javax.xml.ws.BindingProvider;
javax.xml.ws.WebServiceRef;
java.util.ArrayList;
java.util.List;
java.text.MessageFormat;
public class StockQuoteProviderClient {
public static StockQuoteProviderService stockQuoteProviderService =
new StockQuoteProviderService();
public static void main (String args[]) {
es.udc.ws.jaxwstutorial.client.StockQuoteProviderClient (2)
try {
if (args.length < 2) {
System.err.println(MessageFormat.format("Usage: {0}
stockQuoteProviderURL [tickerSymbol1 tickerSymbol2 ...]",
StockQuoteProviderClient.class.getName()));
System.exit(-1);
}
String stockQuoteProviderURL = args[0];
List<String> tickerSymbols = new ArrayList<String>();
for (int i=1; i < args.length; i++) {
tickerSymbols.add(args[i]);
}
StockQuoteProvider stockQuoteProvider =
stockQuoteProviderService.getStockQuoteProviderPort();
((BindingProvider)stockQuoteProvider).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
stockQuoteProviderURL);
es.udc.ws.jaxwstutorial.client.StockQuoteProviderClient (y 3)
List<TradePrice> tradePrices =
stockQuoteProvider.getLastTradePrices(tickerSymbols);
// Show results
…
for (int i=0; i<tradePrices.size(); i++) {
System.out.println(
MessageFormat.format ( …
…,
tradePrices.get(i).getTickerSymbol(),
…));
} catch (IncorrectTickerSymbolException e) {
System.out.println("Unable to get ticker symbol“ +
e.getFaultInfo().getIncorrectTickerSymbol()));
}
}
}
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
El proxy implementa el interfaz del puerto
(StockQuoteProvider en el ejemplo, generado por el
compilador de WSDL a Java).
El ejemplo recibe la URL de invocación del servicio por línea de
comandos y la fija modificando la propiedad
ENDPOINT_ADDRESS_PROPERTY del contexto de la petición.
Hay otras propiedades (e.g. autenticación).
Comentarios (2)
Clientes Java EE
Un cliente (e.g. una aplicación Web) que corra dentro de un
servidor de aplicaciones Java EE puede obtener una
referencia al servicio de una manera estándar.
Anotación javax.xml.ws.WebServiceRef
@WebServiceRef(wsdlLocation="http://localhost:9090/wsjaxwstutorial-service/services/StockQuotesService?wsdl"")
private static StockQuoteProvider service;
Usando JNDI (Java Naming and Directory Interface)
API incluida en Java SE (javax.naming)
Entre otras cosas, es un API que permite acceder a información
de configuración y recursos externos
Ejemplo:
@WebServiceRef(name=”service/StockQuoteProviderService”)
Private static StockQuoteProvider service;
Comentarios (y 3)
Clientes Java EE (cont)
Tiene que declarar en sus ficheros de configuración
(web.xml o ejb-jar.xml) las referencias a los servicios
Web que usa
<service-ref>
<service-ref-name>service/StockQuoteProviderService
</service-ref-name>
<service-interface>es.udc.ws.jaxwstutorial.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 servidor de
aplicaciones (e.g. especificar las URLs de contacto de los
puertos)
ws-jaxwstutorialservice.war
Incluye
WEB-INF/lib
Incluye las librerías (ficheros .jar) de Metro
WEB-INF/classes
Contiene las clases requeridas por el servicio (paquete
es.udc.ws.jaxwstutorial.wsdl)
WEB-INF/web.xml
Fichero de configuración de la aplicación web.
WEB-INF/sun-jaxws.xml
Configuración de los Servicios Web de Metro.
web.xml (1)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>
<display-name>JAXWSTutorial Web Service</display-name>
<servlet>
<servlet-name>WSServlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
web.xml (y 2)
<servlet-mapping>
<servlet-name>WSServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
Comentarios (1)
Se declara una clase Listener específica de Metro (las clases
Listener son llamadas cuando una sesión se crea y se destruye).
Se declara el servlet WSServlet
Forma parte de las librerías de Metro
WSServlet
El servidor de aplicaciones Web le pasará todas las peticiones (tag
servlet-mapping) dirigidas a las URLs
http://.../NombreAplicacionWeb/services/*
<servlet-mapping>
<servlet-name>WSServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
En este caso, asumiendo que instalemos la aplicación Web con el
nombre ws-jaxwstutorial-service, el cliente usará la URL
http://.../ws-jaxwstutorialservice/services/StockQuoteProvider para acceder al
puerto StockQuoteProvider
Comentarios (y 2)
WSServlet (cont)
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
sun-jaxws.xml
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime'
version='2.0'>
<endpoint name='StockQuoteProvider'
implementation=
'es.udc.ws.jaxwstutorial.service.StockQuoteProviderImpl'
url-pattern='/services/StockQuotesService'/>
</endpoints>
Comentarios
name. Nombre del puerto.
implementation. Clase de implementación del puerto.
urlpattern. Tiene que concordar con el indicado en el
web.xml.
Descargar