1. Lezione 10: Web Service
in Java (2)
Corso di Programmazione in Rete
Laurea Magistrale in Ing. Informatica
Università degli Studi di Salerno
1
2. Outline
✦ I tipi di dato utilizzabili
✦ Parametri di uscita e ingresso/uscita
✦ Servizi stateless e stateful
2
3. I tipi di dato utilizzabili
✦ Poiché i WS devono essere indipendenti
dal linguaggio, introducono delle
limitazioni più forti rispetto a RMI sui tipi
di dato utilizzabili per i parametri e i
valori di ritorno
3
4. I tipi di dato utilizzabili
✦ Il mapping tra i tipi definiti in WSDL e i
tipi di Java non è univoco, ma dipende
dalla specifica libreria usata per i WS
• Faremo riferimento al mapping di JAX-WS
✦ Alcune librerie consentono di
personalizzare il mapping quando la
corrispondenza di default non è
appropriata
4
5. I tipi di dato utilizzabili
✦ I tipi utilizzabili sono ristretti a:
• tipi atomici (es. int, boolean, ecc.)
• String
• array e List
• semplici JavaBeans usati come strutture
5
6. Array e liste
✦ È possibile usare array il cui tipo base sia
tra quelli citati
✦ È possibile utilizzare List<T> se il tipo T è
tra quelli citati
✦ Negli stub, i parametri/valori di ritorno di
tipo array vengono comunque convertiti
in List<T>
6
7. Oggetti
✦ È possibile usare dei semplici JavaBeans a
condizione che abbiano un costruttore
pubblico senza argomenti
✦ Vengono trasmessi solo:
• campi pubblici appartenenti a tipi utilizzabili
• proprietà accessibili attraverso coppie di metodi
che seguono la convenzione di naming getXxxx()
e setXxxx(), se il valore appartiene a un tipo
utilizzabile
7
8. Oggetti
✦ NOTA BENE
• gli stub generati non usano la stessa classe
definita nel server, ma una nuova classe con lo
stesso nome che rende accessibili le proprietà con
coppie di metodi getXxxx e setXxxx
• la classe definita dagli stub (e quindi vista dal
client) non contiene gli eventuali altri metodi
presenti nella classe usata dal server, né i campi
che non rientrano nelle condizioni viste
precedentemente
• in altre parole, gli oggetti utilizzabili si
comportano come Data Transfer Objects: semplici
contenitori di dati, a cui non sono associati
8
comportamenti
9. Oggetti
✦ Esempio: sul server
package myservice;
public class Dimension {
public int width;
public int height;
}
package myservice;
import javax.jws.*;
@WebService
public class MyService {
public Dimension getDim() {
Dimension dim=new Dimension();
dim.width=800;
dim.height=600;
return dim;
}
// etc etc etc
9
10. Oggetti
✦ Esempio: sul client
package client;
import client.stub.*;
public class TestClient {
public static void main(String args[]) {
MyServiceService service=new TestService();
MyService test=service.getPort(MyService.class);
Dimension dim=test.getDim();
int width=dim.getWidth();
// NOTA: non posso usare dim.width !
}
}
10
11. I tipi di dato utilizzabili
✦ Non è possibile usare direttamente come
parametro/valore di ritorno il riferimento
a un oggetto remoto
• vedremo successivamente un modo per aggirare
(in parte) questa limitazione
11
12. Parametri di uscita e ingresso/uscita
✦ In linguaggi diversi da Java i parametri
possono essere anche di uscita e di
ingresso/uscita, usando il meccanismo del
passaggio per riferimento
✦ Perciò operazioni definite in un WS
possono anche avere parametri di uscita
o di ingresso/uscita
• occorre un meccanismo per rappresentare questi
parametri in Java
12
13. La classe Holder<T>
✦ La classe Holder<T> definita nel package
javax.xml.ws è usata per rappresentare
un parametro di tipo T
✦ Holder ha un campo pubblico value, che
contiene il valore del parametro
• per i parametri di uscita, il metodo deve
assegnare un valore al campo value
• per i parametri di ingresso/uscita, il metodo può
usare il valore iniziale di value e può modificarlo
• in entrambi i casi, il nuovo valore di value verrà
trasmesso al client
13
14. L’annotazione @WebParam
✦ Nella classe che implementa il servizio
occorre indicare che il parametro è di
uscita o ingresso/uscita con le seguenti
annotazioni:
• @WebParam(mode=WebParam.Mode.OUT)
• @WebParam(mode=WebParam.Mode.INOUT)
14
15. Esempio
✦ Il server:
package myservice;
import javax.jws.*;
import javax.xml.ws.*;
@WebService
public class Location {
public void getCoordinates(
@WebParam(mode=WebParam.Mode.OUT) Holder<Double> longitude,
@WebParam(mode=WebParam.Mode.OUT) Holder<Double> latitude) {
longitude.value = -13.7;
latitude.value = 41.1;
}
}
15
16. Esempio
✦ Il client:
package client;
import client.stub.*;
import javax.xml.ws.Holder;
public class TestLocation {
public static void main(String args[]) {
LocationService service=new LocationService();
Location loc=service.getPort(Location.class);
Holder<Double> longitude=new Holder<Double>();
Holder<Double> latitude=new Holder<Double>();
loc.getCoordinates(longitude, latitude);
System.out.println("Long: "+longitude.value);
System.out.println("Lat: "+latitude.value);
}
}
16
17. Servizi stateless
✦ In JAX-WS gli oggetti che implementano
un servizio sono considerati “stateless”
• una singola istanza dell’oggetto serve le richieste
di tutti i client
• l’oggetto non può mantenere implicitamente
traccia della conversazione con un singolo client
‣ Esempio: l’oggetto che implementa il service non può
sapere se il client che fa una richiesta ha già effettuato una
qualche forma di login, a meno che questa informazione
non sia passata come parametro dal client stesso
17
18. Gestione delle sessioni
✦ Fino alla versione 2.1 di JAX-WS per
mantenere una forma di stato associato a
una sessione di lavoro c’erano due
alternative:
• usare un parametro esplicito per identificare la
sessione in tutte le operazioni
• usare meccanismi legati al sottostante
meccanismo di trasporto (es. HttpSession)
18
19. Gestione delle sessioni
✦ Usare un parametro esplicito per
identificare la sessione
• semplice da implementare
‣ al momento della prima connessione il client riceve
(eventualmente a seguito di una verifica di identità) un
identificatore della sessione di lavoro
‣ ogni altra richiesta prevede che il client passi questo
identificatore al server
‣ il server usa questo identificatore come chiave in una
struttura dati che contiene le informazioni relative alla
particolare sessione di lavoro
• complica l’interfaccia con il client, che deve
aggiungere esplicitamente questo parametro a
tutte le operazioni
19
20. Gestione delle sessioni
✦ usare meccanismi legati al livello di
trasporto (es. cookie HTTP)
• trasparente al client
• il server deve accedere a tali meccanismi,
perdendo l’indipendenza dal tipo di trasporto
utilizzato (es. il server diventa usabile solo con
HTTP)
20
21. Servizi stateful
✦ Con JAX-WS 2.1 è stato introdotto il
concetto di servizi stateful:
• è possibile creare più istanze
dell’implementazione del servizio, in modo che
un’istanza serva un singolo client
• le diverse istanze sono associate alla stessa URL;
viene usata l’estensione WS-Addressing del
protocollo SOAP, che definisce un Endpoint
Reference all’interno del messaggio, per
distinguere tra le diverse istanze
21
22. Servizi stateful
✦ Per definire un servizio come stateful
bisogna:
• annotare il servizio con le annotazioni:
‣ @javax.xml.ws.soap.Addressing
‣ @com.sun.xml.ws.developer.Stateful
• definire un campo public static di tipo
StatefulWebServiceManager<T>, dove T è la
classe che implementa il web service
(StatefulWebServiceManager è nel package
com.sun.xml.ws.developer)
22
23. Esempio
✦ Supponiamo di voler realizzare un WS per
gestire i conti correnti di una banca
package myservice;
import javax.jws.*;
import javax.xml.ws.soap.Addressing;
import com.sun.xml.ws.developer.*;
@WebService @Stateful @Addressing
public class Account {
public static StatefulWebServiceManager<Account> manager;
private int number;
private double balance;
public Account(int number) {
this.number=number;
this.balance=1000;
}
public synchronized double getBalance() {
return balance;
}
public synchronized void transfer(double amount) {
balance+=amount;
}
23 }
24. Istanziazione
✦ Per pubblicare un WS stateful occorre
usare il metodo export dell’oggetto
StatefulWebServiceManager associato al
WS
• l’oggetto StatefulWebServiceManager viene
inserito automaticamente nel campo static della
classe
• il metodo export restituisce un
W3CEndpointReference, che deve essere
comunicato al client per poter accedere al WS
24
25. Esempio
✦ Definiamo un WS Bank (stateless) per
istanziare i conti correnti
package myservice;
import javax.jws.*;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import java.util.*;
@WebService
public class Bank {
private Map<Integer, Account> accounts=new HashMap<Integer, Account>();
public synchronized
W3CEndpointReference getAccount(int number, String password) {
if (!"pippo".equals(password))
throw new RuntimeException("Unvalid password!");
Account acc=accounts.get(number);
if (acc==null) {
acc=new Account(number);
accounts.put(number, acc);
}
return Account.manager.export(acc);
}
}
25
26. Deployment
✦ Il WS stateful deve essere installato
regolarmente, in modo da rendere
disponibile il suo WSDL
• nell’esempio precedente, occorre installare sia il
WS Bank che il WS Account, su due URL diverse
26
27. Accesso a un WS stateful
✦ Il client deve innanzitutto ottenere un
W3CEndpointReference per l’istanza del
servizio stateful che intende usare
✦ Il client accede al WS passando il
W3CEndpointReference come primo
parametro del metodo getPort
dell’oggetto Service
27
28. Esempio
✦ Accediamo ai nostri conti correnti
package client;
import client.stub.*;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
public class TestAccount {
public static void main(String args[]) {
BankService bankService=new BankService();
Bank bank=bankService.getPort(Bank.class);
AccountService accountService=new AccountService();
W3CEndpointReference ref=bank.getAccount(123, "pippo");
Account account=accountService.getPort(ref, Account.class);
account.transfer(100);
System.out.println("Account 123 balance:" + account.getBalance());
W3CEndpointReference ref2=bank.getAccount(456, "pippo");
Account account2=accountService.getPort(ref2, Account.class);
account2.transfer(150);
System.out.println("Account 456 balance:" + account2.getBalance());
}
}
28