Relazione sulla tecnologia
Giacomo Sacchetti <[email protected]>
Imad Zaza <[email protected]>
22 ottobre 2006
2
Indice
1
2
Gli Web Services
1.1 Introduzione . . . . . . . . . . . . . .
1.2 World Wide Web . . . . . . . . . . .
1.3 Service Oriented Architecture . . . .
1.4 XML Web Services . . . . . . . . . .
1.4.1 Transport . . . . . . . . . . .
1.4.2 XML Base technology . . . .
1.4.3 Messaging . . . . . . . . . . .
1.4.4 Description . . . . . . . . . .
1.4.5 Composizione . . . . . . . . .
1.4.6 Ciclo di vita . . . . . . . . . .
1.4.7 Pubblicazione di un servizio
1.4.8 Scoperta di un servizio . . . .
1.4.9 UDDI . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
AXIS
2.1 Introduzione . . . . . . . . . . . . . . . . .
2.2 Installazione di Axis . . . . . . . . . . . .
2.3 Architettura di Axis . . . . . . . . . . . . .
2.3.1 Struttura principale . . . . . . . . .
2.3.2 Handler e Chain . . . . . . . . . .
2.3.3 Percorso del messaggio lato server
2.3.4 Percorso del messaggio lato client
2.4 Primi passi con Axis . . . . . . . . . . . .
2.5 Web Service Deployment Descriptor . . .
2.6 Applicazioni di esempio . . . . . . . . . .
2.7 Codifica dei dati . . . . . . . . . . . . . . .
2.8 Gestione delle eccezioni . . . . . . . . . .
2.9 Il tool WSDL2Java . . . . . . . . . . . . . .
2.10 Generazione di un servizio web . . . . . .
2.10.1 Creazione dell’interfaccia . . . . .
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
7
8
8
10
12
12
13
14
15
17
18
18
19
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
21
21
23
23
24
25
26
26
29
32
35
37
37
38
38
4
INDICE
2.10.2 Creazione del WSDL . . . . . . . . . . . . . . . . . . . . . .
2.10.3 Creazione dei bindings con WDSL2Java . . . . . . . . . . .
2.11 Il servizio PasswordCollector . . . . . . . . . . . . . . . . . . . . .
40
40
42
A Web Semantico
A.1 Il Web attuale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
A.2 Il progetto Semantic Web . . . . . . . . . . . . . . . . . . . . . . . .
53
53
54
Introduzione
Lo scopo di questa relazione è mostrare un esempio di utilizzo della tecnologia Apache Axis. Per descrivere le funzionalità offerte da questa tecnologia,
sarà prima mostrata una breve panoramica sull’architettura dei Web Services,
considerandola come una fase intermedia per il passaggio da Web tradizionale a Semantic Web, per poi concentrarci sulla descrizione di questa particolare
soluzione, mostrando anche dei semplici esempi applicativi.
La trattazione ed i relativi esempi sono stati sviluppati e testati sul sistema
operativo Mac OS X 10.4 (Tiger), con server web Apache 2.2 e Tomcat 5.5.17
come application server. La versione della servlet Axis è la 1.4 (tralasciamo la
definizione delle librerie collegate, i cui dettagli sono specificati nel capitolo 2).
5
6
INDICE
1
Gli Web Services
1.1
Introduzione
Il concetto di integrazione è diventato negli ultimi anni un concetto fondamentale per il software. La nascita e l’enorme successo che ha riscontrato il World
Wide Web, ha causato una crescita esponenziale delle esigenze di integrazione
(anche in contesti diversi), per la natura dello Web stesso, cioè un sistema per lo
scambio di informazioni tra agenti per mezzo di una rete. L’integrazione di software
diversi ha determinato, nell’ultimo decennio, dei compromessi tra flessibilità
di utilizzo e scalabilità: le soluzioni create hanno portato da un lato alla creazione di linguaggi di programmazione flessibili ma utilizzabili solo in sistemi
fortemente accoppiati (ad esempio DCOM di Microsoft), dall’altro lato a sistemi
debolmente accoppiati ma ad una difficile integrazione tra software, in termini
di facilità di utilizzo, costi, manutenibilità (ad esempio lo standard CORBA).
Gli Web Services rappresentano una soluzione importante, che trae vantaggio
dallo strumento di comunicazione (finora utilizzato principalmente da utenti
umani) per eccellenza: il web. Gli Web Services costituiscono inoltre una parte
importante del percorso di evoluzione da Web tradizionale a Web Semantico1 . I
services rappresentano una qualsiasi funzione che ha una certa utilità e possono
considerarsi come componenti software riutilizzabili: possiamo combinare tali
services per creare una funzione più complessa. Inoltre questi services operano
in un sistema molto aperto, cioè un sistema dove l’utilizzatore di un servizio
1
Una breve descrizione del Web Semantico è riportata nell’appendice A
7
CAPITOLO 1. GLI WEB SERVICES
8
ed il fornitore del servizio possono operare su piattaforme diverse (sia software
che hardware), ma sono in grado di fornire un soddisfacente livello di interoperabilità. Inoltre questo meccanismo di comunicazione è molto flessibile, in
quanto il cambiamento nodo non compromette la possibilità di conoscere il suo
contenuto informativo. Per questo lo sviluppo di un software Web Services non
segue le metodologie di sviluppo tradizionali: la progettazione e realizzazione si basano principalmente sull’aggregazione di componenti già sviluppati da
terzi.
1.2
World Wide Web
Per comprendere gli argomenti che tratteremo in seguito è opportuno precisare un insieme di concetti che stanno alla base dell’architettura del World Wide Web, che indicheremo d’ora in avanti con la sigla WWW. Seguendo quanto
descritto in [Web Arch], abbiamo:
Agenti Persone o software che operano sul WWW (server, spider, browser, . . .).
Identificatori Un URI (Uniform Resource Identifier) è un etichetta associabile a
qualunque risorsa disponibile nel sistema
Risorse Sono tutto ciò che è identificato da un URI
Rappresentazioni Sono un insieme di formati di dato che definiscono le informazioni che descrivono lo stato di una risorsa
Protocolli Sono regole che definiscono le modalità di comunicazione tra agenti
Il processo di comunicazione avviene in questo modo: per conoscere lo stato
di una risorsa è necessario conoscerne la locazione (l’URI), sottoponendo questa ad una particolare operazione è possibile cosı̀ ottenere una rappresentazione
dello stato di una risorsa. I dati ottenuti saranno presentati all’utente finale, in
funzione dei metadati associati, per mezzo di un agente. La semantica dell’informazione è attribuita dall’utente umano, gli agenti hanno solo il compito di
trasferire i dati da interpretare (accade cosı̀ per il Web tradizionale e per i Web
Services, per il Web Semantico ogni agenti disporrà di informazioni semantiche
e regole di inferenza che gli consentiranno di capire i dati che stà trasferendo).
1.3
Service Oriented Architecture
La Service Oriented Architecture (SOA) è l’evoluzione del modello classico di
distributed computing: è un modello dove ogni nodo (della rete) è un entità
1.3. SERVICE ORIENTED ARCHITECTURE
9
capace di fornire servizi ad altri nodi, attraverso la pubblicazione di un’interfaccia, che gli utilizzatori possono trovare e dalla quale possono ricavare le informazioni per usufruire del servizio. Questa interfaccia consente di mostrare
un insieme di funzioni utili, fornendo il nome delle operazioni, il formato dei
parametri di ingresso e uscita, i protocolli per invocare tali funzioni. Esistono,
in questa architettura, tre tipi di nodi:
Service Provider (SP) è il fornitore del servizio, che si occupa di sviluppare
funzioni ed offrirle attraverso un interfaccia omogenea
Service Broker (SB) è un archivio in cui vengono collezionate le descrizioni sui
servizi forniti da un certo SP
Service Requestor (SR) è l’entità che richiede l’utilizzo delle funzioni di un SP
Tali tipi di nodi non sono esclusivi, cioè un nodo può ricoprire più ruoli contemporaneamente. Generalmente un SP segnala ad un SB, attraverso un’operazione
di publish, che è disponibile un servizio. Il SB rende disponibile questa informazione ai SR, che lo interrogano tramite una operazione di find. Un SR che ottiene
la descrizione dell’interfaccia di un SP può utilizzare le funzioni tramite un’operazione di bind. Uno schema di questo modello è rappresentato nella figura 1.1.
Lo scopo fondamentale della SOA è la realizzazione dell’accoppiamento debole
Service
Broker
d
Pu
b
Bin
lish
Service
Provider
Find
Service
Requestor
Figura 1.1: Modello SOA
(loose coupling). Come è suggerito in [Hao He], esistono due principali problemi nella realizzazione di un’applicazione che si prefigge il riuso di componenti:
CAPITOLO 1. GLI WEB SERVICES
10
le dipendenze reali e le dipendenze artificiali. Ad esempio, chi viaggia spesso
oltreoceano e vuol usare il proprio notebook, ha la dipendenza reale della corrente elettrica ed la dipendenza artificiale dell’adattatore di corrente. Lo scopo
della SOA non è eliminare completamente le dipendenze artificiali, ma ridurle
al minimo, ottenendo cosı̀ l’accoppiamento debole e lasciando inalterate le dipendenze reali. Volendo fare un esempio dell’architettura SOA nella vita reale,
possiamo pensare ad un lettore CD, che fornisce il servizio di riproduzione dei
CDROM; questo lettore CD è dotato di un interfaccia dotata di alcune funzionalità: play, stop, pause, ... e questa stessa interfaccia è presente anche in altri
lettori CD, in modo che sia possibile cambiare il lettore (o anche il supporto)
ed ottenere lo stesso servizio. Per raggiungere lo scopo di loose coupling sono
introdotti due vincoli sull’architettura:
Generalità delle interfacce le interfacce sono semplici, contengono informazioni strutturare sulle operazioni offerte, senza dettagli semantici
Messaggi descritti non prescrittivi I messaggi sono vincolati nella struttura da
uno schema estendibile che è contenuto nell’interfaccia, non indicano il
comportamento del sistema.
1.4
XML Web Services
La scelta del Web come infrastruttura per la realizzazione degli Web Services
non è solamente giustificata dalla sua semplicità e diffusione: l’introduzione di
un nuovo paradigma può incontrare larghi consensi solamente se la sua introduzione è rapida ed ha costi sostenuti. In realtà il termine Web è abusato perchè
il vero cardine dei Web Services è il sistema di indirizzamento globale fornito
dagli URI. Riferendoci a [WSA], che è il documento di base dei WS, abbiamo
che:
• poichè ad ogni servizio è associato un URI, in base alle considerazione
precedenti, questo è una risorsa del Web
• la descrizione è scritta il XML, un linguaggio universalmente noto, humanreadable e soprattutto indipendente dal livello di presentazione
• i messaggi per interagire con il servizio, i cui dettagli sono contenuti nella descrizione, sono documenti XML trasportati per mezzo di protocolli
Internet (HTTP, FTP, SMTP, ...)
Proprio per lo stretto legame con il linguaggio XML, parleremo in seguito di
XML Web Service. Per quanto riguarda le caratteristiche del servizio, quelle di
1.4. XML WEB SERVICES
11
base per realizzare un WS queste sono, come descritto in precedenza, lo scambio di messaggi, la descrizione del servizio, la pubblicazione e scoperta della
descrizione di un servizio. Tuttavia, al fine di agevolare la comunicazione in
particolari contesti, tali caratteristiche sono solitamente estese ed, in particolare,
possono essere presenti le seguenti:
Gestione delle transazioni Una transazione è composta da una serie di messaggi e, nel caso in cui uno di questi non superi qualche vincolo, è da
considerarsi nulla tutta la sequenza e conseguentemente la transazione è
fallita
Rielable messaging Un messaggio deve essere ricevuto una sola volta dal destinatario. Nel caso in cui il messaggio vada perduto, deve esistere un
meccanismo per richiedere automaticamente al mittente il re-invio, senza
coinvolgere l’applicazione
Autenticazione dei messaggi Deve essere possibile stabilire in modo certo il
mittente del messaggio
Confidenzialità ed integrità dei messaggi Se è necessario i messaggi devono
essere cifrati, in modo che siano disponibili solo per il legittimo destinatario.
Caching È preferibile poter conservare una copia dei messaggi in modo da
migliorare le performance
Correlazione Un messaggio deve poter essere collegabile con altri relativi allo
stesso flusso informativo.
Message routing Un messaggio può seguire percorsi diversi in base allo stato
della rete
Gestione delle sessioni Un messaggio deve essere considerato valido in un
determinato lasso di tempo
Gli XML Web Services costituiscono una particolare istanza della SOA: le interfacce ed i servizi sono espressi tramite un opportuno linguaggio XML che
soddisfa la genericità e l’estendibilità. Allo stesso modo i messaggi sono espressi tramite un opportuno XML, in modo da soddisfare il vincolo description not
prescription. La struttura degli XML Web Services può essere schematizzata come mostrato in figura 1.2. In riferimento a questo schema, ogni protocollo o
linguaggio è da considerarsi aperto, nel senso che a parte i primi due livelli
(transport e XML Base) gli altri sono standard de facto, adottati in seguito alle proposte fatte dai maggiori produttori di software. Analizziamo adesso le
proposte fatte per ciascun livello.
CAPITOLO 1. GLI WEB SERVICES
Management
Description
Messaging
SOAP
XML Base Technology
Transport (HTTP, FTP, ...)
Security
{
Aggregation
{
12
Figura 1.2: XML Web Services
1.4.1
Transport
In questo layer sono considerati gli aspetti propri della trasmissione dei messaggi, tramite l’uso di alcuni protocolli. Non esiste alcuna limitazione per i
protocolli di rete utilizzati, è sufficiente che il flusso di esecuzione continui a
seguire il modello publish - find - bind. Quello che si vuol adottare è l’indipendenza dal canale di comunicazione, per cui protocolli come SSL o JMS non sono
indicati: si preferisce agire direttamente sul linguaggio XML. Lo standard de
facto è HTTP.
1.4.2
XML Base technology
Con questo termine si vuol indicare che XML ha un ruolo essenziale per ogni livello sovrastante, quindi ogni informazione o proprietà da esprimere và codificata in XML. Viene pertanto sfruttata la funzionalità di marshalling dell’XML: le
informazioni strutturate sono convertite in un testo in formato Unicode, in modo da poter scambiare informazioni tra sistemi eterogenei indipendentemente
della codifica utilizzata; una volta ricevuto il dato, ogni nodo compie un operazione di unmarshall, riportando i dati alla propria codifica. L’elaborazione
dell’XML non è vincolata a particolari schemi, cioè ogni sistema può decidere
autonomamente come trattare i dati XML.
1.4. XML WEB SERVICES
1.4.3
13
Messaging
Come già accennato in precedenza, la comunicazione dei Web Services si basa fondamentalmente sullo scambio di messaggi, utilizzando la codifica XML.
Nonostante qualsiasi testo in XML possa essere considerato un messaggio, è
opportuno dare una struttura ai messaggi, in modo che l’interazione tra servizi ed utilizzatori sia possibile senza dover progettare ogni volta i messaggi.
Lo standard di fatto in questo livello è dunque SOAP (Simple Object Access
Protocol).
SOAP
Il Simple Object Access Protocol è lo strumento largamente più utilizzato per
rappresentare messaggi XML. Esistono varie versioni di questo protocollo, che
hanno notevoli differenze l’una dall’altra, ma nella presente trattazione ci riferiremo all’ultima versione (la 1.2). Possiamo pensare al meccanismo SOAP come
ad una busta (envelope), composta da un’intestazione opzionale ed un contenitore in cui inserire dati e metadati da comunicare, ed il tutto codificato in XML.
Ogni busta è atomica, cioè contiene al proprio interno tutto quello di cui necessita per interpretare i dati trasportati. Una comunicazione tra nodi SOAP è
SOAP Envelope
SOAP Header
SOAP Body
Figura 1.3: Struttura messaggio SOAP
costituita dalla trasmissione di una busta da un nodo mittente ad un nodo destinatario, detto anche ultimate receiver, per distinguerlo dagli intermediari SOAP,
che sono i nodi in grado di processare parti del messaggio alla scopo di fornire
funzionalità aggiuntive. In particolare un intermediario riceve un messaggio
SOAP e lo inoltra, eventualmente riscrivendo alcune parti dell’header, ma non
CAPITOLO 1. GLI WEB SERVICES
14
modificando il body. Il ruolo e le funzionalità degli intermediari non sono definite nel protocollo SOAP, viene cosà lasciato spazio libero ad estensioni. Una
caratteristica che è importante sottolineare per SOAP è il binding framework,
che stabilisce una serie di vincoli che il protocollo di trasporto deve rispettare
per trasmettere i messaggi SOAP.
1.4.4
Description
La descrizione è l’attività il cui obiettivo è informare un possibile utilizzatore
sul funzionamento e sulle caratteristiche del servizio. Tale descrizione, per la
sua complessità, può essere definita in livelli. cosı̀ come mostrato nelle figura
1.4. Il primo livello ha l’obiettivo di descrivere l’interfaccia da cui ricavare le
Description
Business Level Agreements
Service Level Agreements
Composition
Orchestration
Presentation
Policy
Implementation Description
Interface Description
XML Schema
Figura 1.4: Description
informazioni necessarie per utilizzare un servizio. Il linguaggio de facto per
questa attività e’ WSDL (Web Service Description Language).
WSDL
Il WSDL divide l’interfaccia del servizio in due componenti logiche distinte:
la Service Interface Definition e la Service Implementation Definition. La prima
descrive il tipo di servizio come una definizione di una classe in OOP, la seconda
è un’implementazione completa di tale classe.
1.4. XML WEB SERVICES
15
Interface Description
Service Implentation Definition
Port
Service
Service Interface Definition
Binding
Port Type
Message
Type
Figura 1.5: wsdl
Service Interface Definition
La definizione dell’interfaccia astratta è fornita per mezzo di:
wsdl:portType che definisce le operazioni del servizio
wsdl:message che definisce gli XML dei messaggi semplici
wsdl:types che definisce i tipi XML complessi dei messaggi
wsdl:binding che definisce il rapporto tra messaggi e trasporto
Service Implementation Definition
La definizione dell’implementazione è fornita da
wsdl:service che è una collezione di elementi wsdl:port
wsdl:port che è un elemento che rappresenta il legame tra un URI ed un wsdl:binding
1.4.5
Composizione
È stato accennato nei paragrafi precedenti che, nel modello SOA, un nodo potrebbe fornire il servizio di raggruppamento di servizi di altri nodi. Questo
CAPITOLO 1. GLI WEB SERVICES
16
servizio è però difficilmente ottenibile mediante i meccanismi SOAP-wsdl, poichè le informazioni che essi forniscono sono state-less. Il concetto di stato di
una comunicazione è importante però per le applicazione B2B: in questi ambiti abbiamo una conversazione tra agenti, cioè una scambio di messaggi in un
determinato arco temporale, dotato delle proprietà ACID. In questo caso per
integrazione si intende quella tra processi, cioè entità in grado di scambiare
un’insieme prestabilito di messaggi con altri, secondo un’insieme di vincoli, dipendenze, regole, in modo da ottenere una sequenza significativa. È giustificata
quindi l’introduzione di un livello ulteriore che fornisca la funzionalità per poter conoscere lo stato della conversazione e di descrivere il comportamento di
un processo. Tale linguaggio avrà ovviamente sintassi XML e deve permettere
di:
• definire una sequenza
• stabilire l’ordine di invio e ricezione dei messaggi
• determinare l’inizio e la fine di una sequenza
• esprimere regole, vincoli, dipendenze, relazioni tra messaggi
• fornire visione globale del servizio solo in base al flusso di messaggi
La soluzione più utilizzata in questo momento è BPEL4WS. L’utilizzo di questo
tipo di linguaggi non ha chiari impatti nel mondo dei WS, poichè non rientra
nella categoria delle funzionalità basic. Un codice scritto in BPEL4WS è destinato ad essere eseguito su un nodo dell’architettura SOA, tramite un opportuno
engine, che coordina l’attivitaà dei vari processi, attraverso lo scambio di messaggi. Ogni processo BPEL è ovviamente un servizio, dotato di interfaccia wsdl.
I processi sono suddivisibili in:
Astratti specificano la sequenza dei messaggi
Eseguibili specificano come un partecipante si comporti durante un fase del
protocollo
Le attività sono classificate in:
Basic come un componente interagisce con un processo esterno
Structured come i componenti agiscono nel complesso
1.4. XML WEB SERVICES
1.4.6
17
Ciclo di vita
Abbiamo precedentemente accennato al fatto che qualunque software è riconducibile ad un WS: è necessario solo sovrapporgli un’interfaccia in XML. Possiamo allora schematizzare il ciclo di vita di un software che implementi in WS
in quattro fasi e precisamente build, deploy, run e manage.Tali operazioni possono
consistere in:
• creare un nuovo servizio e la relativa interfaccia mediante gli strumenti presenti nell’ambiente del SP (librerie, linguaggi di programmazione,
scripts, ...)
• trasformazione di un software esistente in un servizio tramite la creazione
di un interfaccia
• composizione di altri servizi tramite l’orchestrazione dei flussi di messaggi
originati dal loro utilizzo
Nello specifico di un SP, le quattro fasi consistono in:
Build In questa fase si sviluppa il software e l’interfaccia
Deploy In questa fare si procede alla pubblicazione dell’interfaccia ed all’integrazione con il sistema che ospita il servizio
Run si raggruppano le interazioni con gli utilizzatori
Manage si raggruppano le attività per la pubblicazione, l’auditing e la manutenzione del servizio
Nel caso di un SR abbiamo invece:
Build insieme delle operazioni per la localizzazione di un servizio, creazione
del software per il binding
Deploy insieme delle attività per l’esecuzione il software
Run invocazione vera e propria, eventuale tempo di attesa o di servizio
Manage gestione, manutenzione e controllo dei risultati ottenuti
Per quanto riguarda la fase di build, possiamo individuarne quattro categorie:
Green field è il ciclo di sviluppo di un WS quando non esistono né il software
né l’interfaccia. Solitamente quindi si crea l’applicazione software vera e
propria (che ovviamente implementa la logica del servizio nel SP), poi si
crea l’interfaccia XML, cioè il file wsdl relativo al servizio appena creato
(la creazione di tale file è generalmente affidata a tool automatici)
CAPITOLO 1. GLI WEB SERVICES
18
Top down In questo caso abbiamo da sviluppare un’applicazione in base ad
un interfaccia già definita (tipicamente è il caso di un accordo tra business
partner)
Bottom up In questo caso abbiamo un’applicazione potenzialmente in grado
di fornire un servizio ed è sufficiente creare l’interfaccia che descrive il
servizio.
Meet in the middle Abbiamo sia l’interfaccia che l’implementazione, dobbiamo eseguire un processo di adattamento dei due elementi
Per quello che riguarda il SR, ci sono fondamentalmente due modi per integrarsi
con un servizio:
Static Binding Quando il servizio è stato già selezionato prima dell’esecuzione
dell’applicazione per conto della quale il SP agisce
Dynamic Binding Quando il servizio è scelto a tempo di esecuzione in base
alle caratteristiche espresse dalla sua interfaccia
1.4.7
Pubblicazione di un servizio
Il passo successivo alla creazione della descrizione di un servizio è notificare
l’esistenza dello stesso, tramite l’operazione di pubblicazione. Esistono due
principali strategie per la pubblicazione:
• la pubblicazione diretta, cio‘e il SR richiede direttamente al SP la descrizione del servizio offerto. In questo caso i nodi si conoscono già perché il
SR è a conoscenza dell’URI per ottenere l’informazione richiesta.
• utilizzare un service broker, cioè un particolare nodo, detto anche discovery
agent, che offre un servizio di archiviazione delle descrizione di servizi di
altri nodi della rete.
1.4.8
Scoperta di un servizio
L’operazione find consiste nell’ottenere le descrizione di un servizio. È possibile
distinguere due classi di scoperta di un servizio:
• la scoperta a tempo di progettazione, cioè prima che avvenga l’integrazione tra nodi
• la scoperta a runtime, in cui i risultati della ricerca sono le caratteristiche
definite nell’interfaccia stessa
1.4. XML WEB SERVICES
19
Sicuramente l’approccio a tempo di esecuzione è più elegante, ma la limitazione
espressiva del wsdl rendono il suo utilizzo improbabile, oltre al fatto che per
quanto riguarda la sicurezza va gestita la fiducia tra i nodi.
1.4.9
UDDI
Lo standard UDDI, Universal Description Discovery and Integration, attualmente alla terza versione, è utilizzato per la pubblicazione e scoperta di descrizioni di servizi. La sua struttura è molto simile a quella di un servizio di
directory con associata una struttura dati per memorizzare descrizioni di servizi. La nascita dell’UDDI ha qualche analogia con lo sviluppo del sistema DNS:
finchè il numero di servizi è limitato, gestire la pubblicazione e la scoperta possono essere svolte manualmente; quando il numero dei servizi supera un certo
limite, o non è stimabile a priori, è necessario uno strumento che ci consenta di
accedere alle informazioni necessarie e rilevanti. Abbiamo dunque un registro,
che può essere anche replicato tra vari nodi, per fornire servizi di:
Pagine bianche informazioni di base sul fornitore del servizio (e-mail, indirizzi, ...), in modo da avere identificatori del mondo reale
Pagine gialle informazioni sul servizio in base alla categoria di appartenenza
Pagine verdi informazioni su come accedere e come utilizzare un servizio
In riferimento alla figura 1.6 un insieme di nodi, gli operator nodes, contiene una
copia del contenuto del registro e vi è un meccanismo per la sincronizzazione
periodica. Un elemento di questo registro ha la struttura logica che è rappresentata nella figura 1.7. Un elemento businessEntity contiene informazioni di base
per individuare un servizio nel mondo reale. Ognuno di questi elementi può
offrire più businessService, le infrmazioni per accedere ad essi contenute in un
bindingTemplate. Ci sono fondamentalmente tre categorie di registri UDDI:
Internal registry sono utilizzati all’interno di un organizzazione per integrare
applicazioni interne, SP e SR appartengono allo stesso dominio amministrativo
Portal registry sono utilizzati per segnalare la disponibilità di un servizio nei
confronti di partners esterni, di cui si conosce il dominio di trust
Marketplace registry sono utilizzati per fornire servizi verso utenti esterni, non
appartenenti ad un dominio fidato
CAPITOLO 1. GLI WEB SERVICES
20
UDDI Specifications
Operator
Node
Replication
+
Operator
Node
Replication
Operator
Node
UDDI Schema
Figura 1.6: UDDI
<businessEntity>
- Name, contact, description
- Identifiers and categories
<publisherAssertion>
- Relationship between two
companies
<businessService>
- Grouping of logical services
<tModel>
<bindingTemplate>
- Technical information of a single
web service
- URL access points for service
- Specification implemented by
web service
- URL pointer to specifications
Figura 1.7: UDDI Entry
2
AXIS
Forniremo in questo capitolo una descrizione di Axis, illustrando i passi necessari per la configurazione e dei semplici esempi applicativi.
2.1
Introduzione
Axis (Apache eXtensible Iteraction System) è un framework per la costruzione
di agenti SOAP. È scritto in Java ed offre, oltre al supporto a WSDL, una serie di
piccole, ma utili, funzionalità quali: un tool per la generazione delle classi Java
da WSDL, un tool di monitoraggio di pacchetti TCP/IP, un server stand-alone.
Axis funziona come Web Application, cioè per funzionare necessita di essere
installata su un server J2EE compilant. Nel nostro caso utilizzeremo Apache
Tomcat, un servlet engine del progetto Jakarta, largamente utilizzato anche in
produzioni aziendali.
2.2
Installazione di Axis
Il processo di installazione che illustreremo è stato realizzato sul sistema operativo Mac OS X 10.4.7 (Tiger). La versione di Tomcat installata su tale sistema
operativo è la 5.5.17 ed useremo l’ultima versione stabile di Axis (al momento la 1.4). Al momento dell’avvio di Tomcat, le informazioni mostrate sono le
seguenti
neperobook:˜ giacomo$ sudo /Library/Tomcat/bin/startup.sh
21
CAPITOLO 2. AXIS
22
Using
Using
Using
Using
CATALINA_BASE:
/Library/Tomcat
CATALINA_HOME:
/Library/Tomcat
CATALINA_TMPDIR: /Library/Tomcat/temp
JRE_HOME:
/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home
Per installare Axis sarà sufficiente installare la web application nella cartella
CATALINA BASE/webapps. Nel nostro caso Tomcat è configurato per stare in
ascolto sulla porta 8080, per cui Axis sarà raggiungibile all’indirizzo:
http://localhost:8080/axis/
La pagina di Axis visualizzata al precedente indirizzo è mostrata nella figura
2.1. Per validare l’installazione di Axis è sufficiente visitare il link Validation
Figura 2.1: Homepage dell’applicazione web Axis
presente in tale pagina. Solitamente quello di cui si ha bisogno, perché non
sono incluse in Axis, sono le seguenti librerie:
• SAAJ API ( javax.xml.soap.SOAPMessage )
• JAX-RPC API ( javax.xml.rpc.Service )
• Apache-Axis ( org.apache.axis.transport.http.AxisServlet )
2.3. ARCHITETTURA DI AXIS
23
• Jakarta-Commons Discovery ( org.apache.commons.discovery.Resource )
• Jakarta-Commons Logging ( org.apache.commons.logging.Log )
• Log4j ( org.apache.log4j.Layout )
• IBM’s WSDL4Java ( com.ibm.wsdl.factory.WSDLFactoryImpl )
• JAXP implementation ( javax.xml.parsers.SAXParserFactory )
• Activation API ( javax.activation.DataHandler )
Le librerie opzionali sono
• Mail API ( javax.mail.internet.MimeMessage )
• XML Security API ( org.apache.xml.security.Init )
• Java Secure Socket Extension ( javax.net.ssl.SSLSocketFactory )
Il modo più semplice per non avere complicazioni con il CLASSPATH è collocare tali librerie nella directory CATALINA BASE/common/lib. La pagina di
validazione, se le librerie sono correttamente installare, dovrebbe essere come
quella nella figura 2.2. Va precisato che la visualizzazione corretta di tale pagina
di validazione è una condizione necessaria ma non sufficiente.
2.3
Architettura di Axis
Forniremo in questa sezione la descrizione dell’architettura di Axis, entrando
anche nello specifico lavoro che compiono le classi che lo implementano.
2.3.1
Struttura principale
Essendo un processore SOAP, il lavoro fondamentale di Axis è processare messaggi. Tali messaggi vengono elaborati passando per una serie di handler. Il
numero e l’ordine in cui questi handler vengono invocati dipende dalla configurazione del servizio. L’oggetto che passa tra un handler e l’altro è il MessageContext. Tale oggetto contiene tutte le informazioni necessarie per l’elaborazione del messaggio stesso. Gli handler sono solitamente raggruppati in insiemi
ordinati per formare una chain.
CAPITOLO 2. AXIS
24
Figura 2.2: Pagina di validazione di Axis
2.3.2
Handler e Chain
Una chain è una collezione di handler ed è a sua volta un handler, poichè l’interfaccia org.apache.axis.Chain estende l’interfaccia Handler (sempre del
package org.apache.axis), integrandola con alcuni metodi per l’aggiunta e
la rimozione degli handler, come mostrato nella figura (2.3). Ogni handler che
appartiene alla chain ha la possibilità di leggere il messaggio e modificarlo prima di passarlo all’handler successivo. Alcuni handler hanno la caratteristica di
avere un pivot point. Tale pivot point è un handler in cui una richiesta cessa di
essere processata e inizia ad essere processata una risposta. I chain che hanno
un pivot point sono anche detti targeted chain. Esistono tre di tipi di handler:
Handler di trasporto sono gli handler che possono svolgere operazioni di compressione dati, autenticazione e si differenziano in base al tipo di protocollo di trasporto usato (HTTP, SMTP, . . . ).
Handler globali sono handler che processano qualsiasi messaggio diretto ad
Axis, qualsiasi sia il Web Service e qualsiasi sia il protocollo di trasporto
usato.
Handler server-specific serve per far sı̀ che l’handler venga usato solo con un
2.3. ARCHITETTURA DI AXIS
25
<< interface >>
Handler
<< abstract >>
<< interface >>
BasicHandler
Chain
<< concrete >>
SimpleChain
Figura 2.3: Handlers e Chains
determinato servizio, in modo da implementare funzionalità come crittografia, autenticazione, etc.
2.3.3
Percorso del messaggio lato server
Nel momento in cui arriva un messaggio SOAP sul server, questo viene letto
dal TransportListener che lo inserisce in un oggetto Message. Quest’ultimo viene poi inserito in un MessageContext, un oggetto contiene anche informazioni
tra cui SOAPAction e transportName, che rispettivamente indicano un parametro presente nell’header del messaggio ed il tipo di protocollo di trasporto
usato. A questo punto il MessageContext viene passato alla catena handler di
trasporto, che contiene una request chain, una response chain o entrambi. Se
la chain di trasporto è configurata, allora il MessageContext è passato al metodo invoke() dell’handler. Dopo essere passato per la chain di trasporto, il
MessageContext passa per la chain globale, se definita. Infine il MessageContext arriva alla chain server-specific che lo invierà ad un provider. Il provider,
che è anch’esso un handler, si occupa della logica di codifica e background del
servizio.
CAPITOLO 2. AXIS
26
Figura 2.4: Percorso messaggio lato server
2.3.4
Percorso del messaggio lato client
Il percorso del messaggio dal lato del client è speculare rispetto a quello del
server, con la differenza che non esiste un provider (perchè non è fornito alcun
servizio). Il Sender si occupa di gestire le operazioni relative al protocollo di
trasporto e di inviare/ricevere messaggi. Le chain che si possono definire lato
client sono le stesse definibili per il server.
Figura 2.5: Percorso messaggio lato client
2.4
Primi passi con Axis
Il modo più semplice per realizzare un servizio web con Axis è copiare il file
sorgente Java nella cartella di Axis e rinominare il file con estensione jws. Ad
esempio, se abbiamo la seguente classe:
Listing 2.1: Classe di esempio
1
public class PasswordCollector {
2.4. PRIMI PASSI CON AXIS
27
private DbText db;
2
3
public String toString () {
[...]
}
4
5
6
7
[...]
8
9
}
per avere il servizio web sarà sufficiente copiare il file PasswordCollector.java
in CATALINA HOME/webapps/axis/PasswordCollector.jws e tale servizio sarà cosı̀ raggiungibile all’indirizzo:
http://localhost:8080/axis/PasswordCollector.jws
Richiedendo la risorsa con questo indirizzo, Axis si occuperà di compilare la
classe, pubblicare il servizio e convertire le chiamate SOAP in chiamate di funzioni Java. Aggiungendo il suffisso “?WSDL” all’URI precedente Axis genererà automaticamente la specifica WSDL del servizio, per cui per l’esempio
precedente avremo:
Listing 2.2: WSDL Generato da Axis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://localhost:8080/axis/PasswordCollector.jws"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://localhost:8080/axis/PasswordCollector.jws"
xmlns:intf="http://localhost:8080/axis/PasswordCollector.jws"
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 created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
<wsdl:message name="toStringRequest">
</wsdl:message>
<wsdl:message name="toStringResponse">
<wsdl:part name="toStringReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="PasswordCollector">
<wsdl:operation name="toString">
<wsdl:input message="impl:toStringRequest"
name="toStringRequest"/>
<wsdl:output message="impl:toStringResponse"
name="toStringResponse"/>
</wsdl:operation>
</wsdl:portType>
CAPITOLO 2. AXIS
28
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<wsdl:binding name="PasswordCollectorSoapBinding"
type="impl:PasswordCollector">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="toString">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="toStringRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://DefaultNamespace" use="encoded"/>
</wsdl:input>
<wsdl:output name="toStringResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://localhost:8080/axis/PasswordCollector.jws"
use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PasswordCollectorService">
<wsdl:port
binding="impl:PasswordCollectorSoapBinding"
name="PasswordCollector">
<wsdlsoap:address
location="http://localhost:8080/axis/PasswordCollector.jws"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Axis fornisce anche un package Java per poter utilizzare i servizi web dal lato
client. Ad esempio per poter utilizzare la funzionalità toString del servizio
PasswordCollector il codice è il seguente:
Listing 2.3: Test.java
1
2
3
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String [] args) {
try {
String endpoint =
"http://localhost:8080/axis/PasswordCollector.jws";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("toString");
String ret = (String) call.invoke(new Object [] {} );
2.5. WEB SERVICE DEPLOYMENT DESCRIPTOR
System.out.println("La risposta del servizio e’: "+ret);
} catch (Exception e) {
System.err.println(e.toString());
}
15
16
17
18
}
19
20
29
}
Come è facile vedere dal codice precedente, alle righe 10 e 11 vengono creati gli
oggetti Service e Call, che sono gli oggetti standard di JAX-RPC per memorizzare i metadati sul servizio da richiamare. L’impostazione dell’endpoint
URL definisce il destinatario del messaggio SOAP. Sul tipo dei parametri del
metodo chiamato e sul tipo di ritorno parleremo nei paragrafi seguenti.
2.5
Web Service Deployment Descriptor
I file jws sono sicuramente un modo semplice per trasformare classi Java in servizi web, ma non sempre sono la miglior scelta. Ad esempio, non sempre disponiamo del codice sorgente di un’applicazione che vogliamo rendere disponibile
sul Web. Inoltre, la configurazione che possiamo specificare sul servizio è molto limitata: si pensi alla gestione dei tipi oppure ai meccanismi di sicurezza. La
soluzione a questo problema è l’utilizzo dei WSDD (Web Service Deployment
Descriptor). Un file WSDD è scritto in XML e contiene un insieme di direttive
per indicare quali funzionalità pubblicare con Axis. Un esempio di file WSDD
per pubblicare il servizio PasswordCollector potrebbe essere:
Listing 2.4: Semplice file WSDD
1
2
3
4
5
6
7
8
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="PasswordCollector" provider="java:RPC">
<parameter name="className"
value="net.nepero.portal159.passwordcollector.PasswordCollector" />
<parameter name="allowedMethods" value="*" />
</service>
</deployment>
In generale l’elemento service può essere costituito da: in flusso di richieste, un pivot Handler (o provider), un flusso di risposta. Per quanto riguarda
il provider, in questo caso abbiamo che è java:RPC ed indica il servizio Java
RPC (org.apache.axis.providers.java.RPCProvider). La classe che
il provider deve instanziare è definita dal parametro chiamato className ed
i parametri a cui possiamo accedere sono definiti da allowedMethods, separati da virgola oppure specificando * se si vuol dar l’accesso a tutti i metodi
CAPITOLO 2. AXIS
30
pubblici. Un ulteriore parametro che possiamo specificare è scope, che serve
a definire il tipo di azione che il provider deve compiere sull’oggetto Java che
definisce il servizio. I possibili valori di scope e le relative azioni sono:
• request: in questo caso ad ogni richiesta del servizio viene instanziato
un nuovo oggetto
• application: viene creato un oggetto singleton alla prima richesta ed il
suo stato è condiviso alle richieste successive
• session: viene creato un nuovo oggetto per ogni sessione attivata
Per specificare lo scope è sufficiente inserire il parametro con nome scope tra
quelli del servizio, ad esempio:
Listing 2.5: File WSDD con scope
1
2
3
4
5
6
7
8
9
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="PasswordCollector" provider="java:RPC">
<parameter name="className"
value="net.nepero.portal159.passwordcollector.PasswordCollector" />
<parameter name="allowedMethods" value="*" />
<parameter name="scope" value="request" />
</service>
</deployment>
Per configurare gli handler di servizio, è necessario aggiungere, nel file WSDD,
un elemento handler per ognuno di essi ed un elemento requestFlow all’interno delle specifiche del servizio, per impostare l’ordine di esecuzione. Ad
esempio
Listing 2.6: File WSDD con service-handler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<handler name="log" type="java:net.nepero.portal159.log.LogHandler">
<parameter name="filename" value="login.log" />
</handler>
<service name="PasswordCollector" provider="java:RPC">
<requestFlow>
<handler type="log" />
</requestFlow>
<parameter name="className"
value="net.nepero.portal159.passwordcollector.PasswordCollector" />
<parameter name="allowedMethods" value="*" />
<parameter name="scope" value="request" />
</service>
</deployment>
2.5. WEB SERVICE DEPLOYMENT DESCRIPTOR
31
In questo caso il servizio LogHandler si occuperà di monitorare le informazioni riguardanti le richieste al servizio PasswordCollector, come mostrato dal
listato 2.7 (la definizione di un logger è di notevole importantanza durante lo
sviluppo dello web service per fare debugging).
Listing 2.7: Codice dell’handler del servizio
1
package net.nepero.portal159.log;
2
3
4
5
6
import
import
import
import
org.apache.axis.AxisFault;
org.apache.axis.Handler;
org.apache.axis.MessageContext;
org.apache.axis.handlers.BasicHandler;
7
8
9
10
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.Date;
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class LogHandler extends BasicHandler {
public void invoke(MessageContext msgContext) throws AxisFault
{
try {
Handler serviceHandler = msgContext.getService();
String filename = (String)getOption("filename");
if ((filename == null) || (filename.equals("")))
throw new AxisFault("Server.NoLogFile",
"Errore nella configurazione del logger.",
null, null);
FileOutputStream fos = new FileOutputStream(filename,
true);
PrintWriter writer = new PrintWriter(fos);
Integer numAccesses =
(Integer)serviceHandler.getOption("accesses");
if (numAccesses == null)
numAccesses = new Integer(0);
numAccesses = new Integer(numAccesses.intValue() + 1);
Date date = new Date();
String result = date + ": servizio " +
msgContext.getTargetService() +
" richiesto " + numAccesses + " volte.";
serviceHandler.setOption("accesses", numAccesses);
writer.println(result);
writer.close();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
}
}
CAPITOLO 2. AXIS
32
Per poter pubblicare il servizio appena configurato con il file WSDD sono necessarie alcune operazioni ben più complesse di una semplice copia del file, come
nel caso precedentemente descritto. Innanzitutto le informazioni su tutti i servizi installati sono registrate nel file di configurazione server-config.wsdd,
contenuto nella cartella WEB-INF di Axis. Quindi per installare il servizio si può
procedere attraverso la modifica di questo file oppure utilizzando il tool AdminClient di Axis. Per utilizzare questo tool, che è sicuramente il modo più semplice per pubblicare un servizio, è sufficiente richiamarlo da linea di comando
tramite:
java org.apache.axis.client.AdminClient
Per poter effettuare un deploy di un servizio sarà necessario specificare come
paramentro il nome del file WSDD che ne descrive la configurazione:
java org.apache.axis.client.AdminClient passwordcollector.wsdd
È disponibile avere la lista dei servizi attualmente installati tramite il comando
java org.apache.axis.client.AdminClient list
2.6
Applicazioni di esempio
Analizziamo in questo paragrafo come realizzare le applicazioni lato client, cioè
i SR. Un semplice codice per interagire con il servizio echo è il seguente:
Listing 2.8: Client.java
1
2
3
4
5
import
import
import
import
import
org.apache.axis.Constants;
java.xml.rpc.ParamaterMode;
java.net.URL;
org.apache.axis.client.Call;
org.apache.axis.client.Service;
6
7
8
9
10
11
12
13
14
public class Client {
public static void main(String [] args) {
String endp = "http://localhost:8080/axis/echo.jws";
String message = "hello!";
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new URL(endp) );
call.setOperationName("echo");
15
16
17
call.addParameter("message", Constants.XSD_STRING,
ParameterMode.IN);
18
19
20
call.setReturnType(Constants.XSD_STRING);
String ret = (String) call.invoke(
2.6. APPLICAZIONI DI ESEMPIO
new Object[] { message } );
System.out.println("Ho inviato: " + message + "\n");
System.out.println("Ho ricevuto: " + ret);
21
22
23
}
24
25
33
}
Rispetto all’esempio del paragrafo precedente, và notata alle righe 16, 17 e 18 la
definizione dei tipi di dato dei parametri di input ed output che verranno poi
introdotti nel messaggio SOAP che deriva dalla serializzazione dell’oggetto che
rappresenta il messaggio. Avremo in questo caso:
Listing 2.9: SOAP Request
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echo xmlns:ns1="http://www.nepero.net">
<message xsi:type="xsd:string">hello!</message>
</ns1:echo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
E la risposta del server sarà:
Listing 2.10: SOAP Response
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:echoResponse xmlns:ns1="http://www.nepero.net">
<response xsi:type="xsd:string">hello!</response>
</ns1:echoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Analizziamo adesso un esempio più complesso di interazione tra client e web
service che fà uso anche degli header SOAP. La gestione è più complessa perché
è necessario far uso delle API per gestire dati in XML. Ad esempio, per creare il
messaggio:
Listing 2.11: SOAP con header
1
2
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
CAPITOLO 2. AXIS
34
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<x:Authentication>
<x:login>zaza</x:login>
<x:password>zaza</x:password>
</x:Authentication>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:echo xmlns:ns1="http://www.nepero.net">
<message xsi:type="xsd:string">hello!</message>
</ns1:echo>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Una possibile implementazione Java potrebbe essere:
Listing 2.12: Esempio utilizzao SOAP Header
1
import java.net.URL;
2
3
4
5
6
7
8
9
10
11
12
import
import
import
import
import
import
import
import
import
import
javax.xml.parsers.DocumentBuilder;
javax.xml.parsers.DocumentBuilderFactory;
org.w3c.dom.Document;
org.w3c.dom.Element;
org.apache.axis.client.Service;
org.apache.axis.client.Call;
org.apache.axis.message.SOAPEnvelope;
org.apache.axis.message.SOAPHeaderElement;
org.apache.axis.message.RPCElement;
org.apache.axis.message.RPCParam;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Client {
public static void main (String [] args) {
String endp = "http://localhost:8080/axis/echo.jws";
String message = "hello!";
// Creazione XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.newDocument();
// Costruisco gli elementi <authentication>, <login> e <password>
Element auth = doc.createElementNS("http://www.nepero.net",
"Authentication");
Element login = doc.createElementNS("http://www.nepero.net",
"login");
Element password = doc.createElementNS("http://www.nepero.net",
"password");
// Assemblo gli elementi
login.appendChild( doc.createTextNode("zaza") );
2.7. CODIFICA DEI DATI
35
password.appendChild( doc.createTextNode("zaza") );
auth.appendChild(login);
auth.appendChild(password);
// Creo l’header
SOAPHeaderElement she = new SOAPHeaderElement(auth);
// Costruisco un messaggio SOAP
SOAPEnvelope envelope = new SOAPEnvelope();
// Aggiungo l’header al messaggio
envelope.addHeader(she);
// Creo la codifica RPC del messaggio e della chiamata del metodo
// e lo aggiungo al body del messaggio SOAP
Object [] params = new Object [] { message };
RPCElement rpcCall = new RPCElement("http://www.nepero.net",
"echo", params);
envelope.addBodyElement(rpcCall);
// Uguale all’esempio di client senza header
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress( new java.net.URL(endp));
// Effettuo la chiamata passando l envelope
SOAPEnvelope respEnv = call.invoke (envelope);
// Recupero il risultato dal messaggio SOAP di risposta
RPCElement respRPC = (RPCElement) respEnv.getFirstBody();
RPCParam result = (RPCParam) respRPC.getParams().get(0);
System.out.println("Ricevuto: " +
(String) result.getValue());
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
}
}
2.7
Codifica dei dati
Una aspetto molto importante nell’utilizzo dei Web Services ed in particolare di
Axis è la codifica dei dati, cioè la rappresentazione dei parametri in ingresso ed
uscita di un servizio. In Axis, i dati vengono mappati usando le regole definite
nella specifica JAX-RPC e la tabella 2.1 ne mostra un riassunto. Per quanto riguarda le collezioni di Java (Vector, ArraList, . . . ) non esistono serializzatori o
deserializzatori specifici e quindi l’unico modo per inviare tali collezioni è usare
gli array di SOAP. Anche per quanto riguarda i tipi definiti dall’utente, non è
possibile trasferirli direttamente tramite Axis, senza prima effettuare il mapping
con un serializzatore o deserializzatore. Axis fornisce una serie di serializzatori
e deserializzatori il cui compito è convertire tipi Java e codificarli nello standard JAX-RPC. Uno dei serializzatori più flessibili è BeanSerializer: con
questo è possibile convertire qualunque classe Java scritta seguendo lo stile dei
CAPITOLO 2. AXIS
36
xsd:base64Binary
xsd:boolean
xsd:byte
xsd:dateTime
xsd:decimal
xsd:double
xsd:float
xsd:hexBinary
xsd:int
xsd:integer
xsd:long
xsd:QName
xsd:short
xsd:string
byte[]
boolean
byte
java.util.Calendar
java.math.BigDecimal
double
float
byte[]
int
java.math.BigInteger
long
javax.xml.namespace.QName
short
java.lang.String
Tabella 2.1: Mapping tra tipi XSD e Java
JavaBeans. Per poter utilizzare questi serializzatori/deserializzatori è necessario specificare il mapping tra tipo e classe serializzatrice, sia lato server che lato
client. Dal lato server il mapping và definito nel file WSDD, aggiungendo una
voce del tipo:
Listing 2.13: Bean Mapping
1
2
<beanMapping qname="ns:local" xmlns:ns="http://www.nepero.net"
languageSpecificType="java:net.nepero.TestClass" />
Con questo codice è associato “ns:local” a “net.nepero.TestClass” e viceversa. Quando all’interno del messaggio SOAP viene letto un tipo con il nome
“ns:local” questo sarà associato dal server a “net.nepero.TestClass” e
verrùsata la classe BeanSerializer per la codifica. Per quanto riguarda il
mapping dei tipi lato client, torniamo ad analizzare l’istruzione
...
call.addParameter("message",
Constants.XSD\_STRING,
ParameterMode.IN);
...
Il parametro Costants.XSD STRING è in realtà un oggetto della classe Java
javax.xml.namespace.QName che rappresenta xsd:string. Axis riesce a
risalire, tramite l’oggetto Constants.XSD STRING, alla classe che si occupa
della serializzazione del parametro. Per serializzare un tipo è dunque necessario creare un’istanza di QName che rappresenti il nome del tipo e specificare
successivamente gli oggetti che si occupano della serializzazione. Dal lato client
questo si esprime attraverso il costrutto:
2.8. GESTIONE DELLE ECCEZIONI
37
...
QName qn = new QName("http://www.nepero.net", "local");
call.registerTypeMapping(net.nepero.TestClass,
qn,
BeanSerializerFactory.class,
BeanDeserializerFactory.class);
...
Un caso particolare è quello della trasformazione di una applicazione legacy1
all’architettura SOA. In questo caso si preferisce specificare i serializzatori e
deserializzatori direttamente nel file WSDD.
Listing 2.14: Type mapping
1
2
3
4
5
<typeMapping qname="ns:local" xmlns:ns="http://www.nepero.net"
languageSpecificType="java:net.nepero.TestClass"
serializer="javaClassSerializerFactory"
deserializer="javaClassDeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
2.8
Gestione delle eccezioni
Se il metodo lancia un eccezione che è istanza o sottotipo della classe Java
java.rmi.RemoteException, questa è convertita autometicamente da Axis
in un SOAP fault. In tale specifica, il valore del faultcode è il nome della classe ed il client proverà a deserializzare tale eccezione attraverso un’eccezione
Java. Nel caso in cui il client non disponga di tale classe verrà usata un’istanza
di java.rmi.RemoteException. Tale funzionalità è ovviamente possibile se
e solo se sia lato server che lato client è disponibile Axis. Infatti, non tutte le
piattaforme software dispongono del concetto di eccezione, quindi ogni client è
libero di mappare i SOAP fault come ritiene più opportuno.
2.9
Il tool WSDL2Java
Axis fornisce un tool, WSDL2Java, che a partire da un documento WSDL genera automaticamente stub, skeleton, tipi di dati e client ad hoc. Tale tool è
richiamabile da linea di comando tramite:
java org.apache.axis.WSDL.WSDL2Java descr.WSDL
1
Il sistema legacy è un sistema informatico esistente o una applicazione che continua ad
essere usata poiché l’utente (tipicamente un’organizzazione) non vuole o non può rimpiazzarla.
Le ragioni che inducono a mantenere sistemi legacy sono soprattutto dovute ai costi sostenuti
per la loro implementazione e ai costi da sostenere per la migrazione a nuovi sistemi. (fonte
wikipedia.it)
CAPITOLO 2. AXIS
38
Descriviamo brevemente il comportamento si questo tool:
• per ogni entry della sezione type vengono generati una classe Java dello stile JavaBean ed una classe holder se i tipi definiti sono usati come
parametri di I/O
• per ogni elemento portType viene generata un interfaccia Java come
interfaccia del servizio
• per ogni binding viene generata una classe stub
• per ogni service viene generata una interfaccia serviz ed un service locator
Inoltre, specificando alcuni parametri si possono generare anche i file lato server, in particolare con
java org.apache.axis.WSDL.WSDL2Java -s -S true descr.WSDL
Vengono generati
• per ogni binding un template della classe che implementa il servizio
• per tutti i servizi i file per il deploy e l’undeploy
2.10
Generazione di un servizio web
La creazione di un servizio web può essere facilmente realizzata utilizzando i
tool Java2WSDL e WSDL2Java. Descriveremo in questa sezione gli step necessari per costruire un servizio web partendo da una interfaccia Java (tali step
forniscono solo un indicazione, non sono l’unico modo per avere un implementazione di un web service con Axis).
2.10.1
Creazione dell’interfaccia
Il primo step è la creazione dell’interfaccia Java che descrive l’interfaccia del
servizio, ad esempio:
Listing 2.15: Interfaccia Java
1
package net.nepero.portal159.passwordcollector;
2
3
4
5
6
7
/**
* La classe PasswordCollector realizza il sistema per la memorizzazione
* della password in un db del tipo DbText (e’ un file di testo)
*
* @author Giacomo Sacchetti <[email protected]>
2.10. GENERAZIONE DI UN SERVIZIO WEB
8
9
39
* @version 2-Ott-2006
*/
10
11
12
13
import java.io.IOException;
import net.nepero.db.text.DbText;
import net.nepero.util.AssociativeArray;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class PasswordCollector
{
/**
* cancellazione informazioni su un servizio
*
username
* @param sUsername
nome del servizio
* @param sService
*/
public void deleteAuthForService(String sUsername, String sService)
throws NoSuchFieldException, IOException
{
[...]
}
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* inserimento informazioni su un servizio
*
informazione di autenticazione
* @param info
/
*
public void insertAuthForService(AuthInfo info)
throws IOException,
DuplicateIdentifierException,
NoSuchFieldException
{
[...]
}
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* recupero informazioni su un servizio
*
username
* @param sUsername
@param
sService
nome del servizio
*
@return
informazioni
di autenticazione sul servizio
*
/
*
public AuthInfo getAuthForService(String sUsername,
String sService)
throws NoSuchFieldException, IOException
{
[...]
}
55
56
/**
CAPITOLO 2. AXIS
40
* recupero informazioni su un servizio
*
username
* @param sUsername
* @return vettore di info di autenticazione di un utente
*/
public AuthInfo[] getAuthForUser (String sUsername)
throws BackingStoreException, IOException,
NoSuchFieldException
{
[...]
}
57
58
59
60
61
62
63
64
65
66
67
68
69
}
2.10.2
Creazione del WSDL
Il secondo step è l’utilizzo del tool Java2WSDL per creare il file WSDL partendo
dall’interfaccia del servizio. Ad esempio, tramite l’invocazione di
java org.apache.axis.wsdl.Java2WSDL -o passwordcollector.wsdl
-l"http://localhost:8080/axis/services/PasswordCollector"
-n"urn:PasswordCollector"
-p"net.nepero.portal159.passwordcollector" "urn:PasswordCollector"
net.nepero.portal159.passwordcollector.PasswordCollector
dove abbiamo che
• l’opzione “-o” serve per specificare il nome del file WSDL di output
• l’opzione “-l” serve per specificare la locazione del servizio
• l’opzione “-n” è il target namespace del file WSDL
• l’opzione “-p” serve per specificare il mapping dal package al namespace
• infine la classe specificata è l’interfaccia del servizio
Se l’interfaccia che abbiamo definito ci sono riferimenti a classi definite dall’utente, come nell’esempio precedente, il tool Java2WSDL si occuperà di convertire tali tipi alla rappresentazione in XML oppurtuna, cosı̀ come descritto nei
paragrafi precedenti.
2.10.3
Creazione dei bindings con WDSL2Java
Il terzo step consiste nell’usare il file WDSL appena generato per costruire il
binding client/server appropriato per il web service. Per far ciò si usa il tool
WDSL2Java:
2.10. GENERAZIONE DI UN SERVIZIO WEB
41
java org.apache.axis.wsdl.WSDL2Java
-o .
-d Session
-s -S true
-Nurn:PasswordCollector net.nepero.portal159.passwordcollector
passwordcollector.wsdl
In questo caso verranno generati i seguenti file:
• PasswordCollectorSoapBindingImpl.java è il file che contiene l’implementazione lato server del web service
• PasswordCollector.java la nuova interfaccia del servizio, che contiene le appropriate chiamate a java.rmi.Remote
• PasswordCollectorService.java è il file che contiene l’interfaccia
lato client del servizio
• PasswordCollectorServiceLocator.java è il file contiene l’implementazione dell’interfaccia lato client
• PasswordCollectorSoapBindingSkeleton.java lo skeleton lato server
• PasswordCollectorSoapBindingStub.java lo stub lato client
• deploy.wsdd descrittore per il deploy del servizio
• undeploy.wsdd descrittore per l’undeploy del servizio
Nella versione di Axis che abbiamo utilizzato, la creazione del file deploy.wsdd
non sempre è corretta. Nell’utilizzo di questo tool, non viene infatti creato il
mapping corretto per rappresentare i vettori di classi JavaBean definite dall’utente. In particolare il tipo AuthInfo[] viene mappato nel descrittore del
servizio come:
Listing 2.16: Rappresentazione errata di un array
1
2
3
4
5
6
7
8
<arrayMapping
xmlns:ns="urn:PasswordCollector"
qname="ns:ArrayOf_soapenc_string"
type="java:java.lang.String[]"
innerType="cmp-ns:string"
xmlns:cmp-ns="http://schemas.xmlsoap.org/soap/encoding/"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
/>
Con tale rappresentazione non è possibile deserializzare il tipo da parte del
client. La rappresentazione corretta è invece:
CAPITOLO 2. AXIS
42
Listing 2.17: Rappresentazione corretta di un array
1
2
3
4
5
6
7
8
<typeMapping
xmlns:ns="urn:PasswordCollector"
qname="ns:ArrayOfAuthInfo"
type="java:net.nepero.portal159.passwordcollector.AuthInfo[]"
serializer="org.apache.axis.encoding.ser.ArraySerializerFactory"
deserializer="org.apache.axis.encoding.ser.ArrayDeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
/>
2.11
Il servizio PasswordCollector
Il servizio PasswordCollector nasce con l’intento di realizzare una base di dati centralizzata per memorizzare le informazioni di accesso a vari servizi web.
In particolare PasswordCollector memorizza le informazioni relative all’autenticazione BASIC dei web services, è anch’esso un web service che usa l’autenticazione di tipo BASIC per l’accesso. Lo schema UML che mostra l’interazione tra agenti per l’utilizzo del servizio è mostrata nella figura 2.6. In pratica,
avendo accesso al servizio PasswordCollector è possibile reperire da una base
di dati le informazioni di accesso per altri servizi, inserire nuove informazioni
ed eventualmente cancellarle. L’interfaccia del servizio è già stata presentato
nel paragrafo precedente ed il suo codice è mostrato nel listato 2.15. Notiamo in
questo codice che esiste un metodo, getAuthForService, il cui tipo di ritorno
è AuthInfo: è un tipo che abbiamo noi stesso definito allo scopo di mostrare il
mapping che i tool di Axis riescono ad effettuare. La definizione di questo tipo
è mostrata nel listato 2.18.
Listing 2.18: Il tipo AuthInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package net.nepero.portal159.passwordcollector;
/**
* Write a description of class AuthInfo here.
*
* @author Giacomo Sacchetti <[email protected]>
* @version 2-Ott-2006
*/
public class AuthInfo
{
private String sServiceCall;
private String sServiceName;
private String sServicePassword;
private String sServiceUsername;
private String sUsername;
2.11. IL SERVIZIO PASSWORDCOLLECTOR
Figura 2.6: Interazione con il servizio PasswordCollector
43
44
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
CAPITOLO 2. AXIS
/**
* Constructor for objects of class AuthInfo
*/
public AuthInfo()
{
sServiceCall = new String("");
sServiceName = new String("");
sServicePassword = new String("");
sServiceUsername = new String("");
sUsername = new String("");
}
// metodi get/set
public void setUsername(String username)
{
sUsername = username;
}
public String getUsername()
{
return sUsername;
}
public void setServiceCall(String servicecall)
{
sServiceCall = servicecall;
}
public String getServiceCall()
{
return sServiceCall;
}
public void setServiceName(String servicename)
{
sServiceName = servicename;
}
public String getServiceName()
{
return sServiceName;
}
public void setServicePassword(String servicepassword)
{
sServicePassword = servicepassword;
}
public String getServicePassword()
{
return sServicePassword;
}
public void setServiceUsername(String serviceuser)
{
sServiceUsername = serviceuser;
}
public String getServiceUsername()
2.11. IL SERVIZIO PASSWORDCOLLECTOR
{
64
return sServiceUsername;
65
}
66
67
45
}
Seguendo la metodologia che abbiamo descritto nel paragrafo precendente, l’interfaccia PasswordCollector è stata processata dal tool Java2WSDL, ed il
risultato è il seguente file WSDL:
Listing 2.19: passwordcollector.wsdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="urn:PasswordCollector"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="urn:PasswordCollector"
xmlns:intf="urn:PasswordCollector"
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 created by Apache Axis version: 1.4
Built on Apr 22, 2006 (06:55:48 PDT)-->
<wsdl:types>
<schema
targetNamespace="urn:PasswordCollector"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="AuthInfo">
<sequence>
<element name="serviceCall" nillable="true" type="soapenc:string"/>
<element name="serviceName" nillable="true" type="soapenc:string"/>
<element name="servicePassword" nillable="true" type="soapenc:string"/>
<element name="serviceUsername" nillable="true" type="soapenc:string"/>
<element name="username" nillable="true" type="soapenc:string"/>
</sequence>
</complexType>
<complexType name="DuplicateIdentifierException">
<sequence/>
</complexType>
<complexType name="ArrayOfAuthInfo">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="impl:AuthInfo[]"/>
</restriction>
</complexContent>
</complexType>
</schema>
</wsdl:types>
46
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
CAPITOLO 2. AXIS
<wsdl:message name="DuplicateIdentifierException">
<wsdl:part name="fault" type="impl:DuplicateIdentifierException"/>
</wsdl:message>
<wsdl:message name="deleteAuthForServiceRequest">
<wsdl:part name="sUsername" type="soapenc:string"/>
<wsdl:part name="sService" type="soapenc:string"/>
</wsdl:message>
<wsdl:message name="insertAuthForServiceRequest">
<wsdl:part name="info" type="impl:AuthInfo"/>
</wsdl:message>
<wsdl:message name="getAuthForUserResponse">
<wsdl:part name="getAuthForUserReturn" type="impl:ArrayOfAuthInfo"/>
</wsdl:message>
<wsdl:message name="insertAuthForServiceResponse">
</wsdl:message>
<wsdl:message name="deleteAuthForServiceResponse">
</wsdl:message>
<wsdl:message name="getAuthForUserRequest">
<wsdl:part name="sUsername" type="soapenc:string"/>
</wsdl:message>
<wsdl:message name="getAuthForServiceResponse">
<wsdl:part name="getAuthForServiceReturn" type="impl:AuthInfo"/>
</wsdl:message>
<wsdl:message name="getAuthForServiceRequest">
<wsdl:part name="sUsername" type="soapenc:string"/>
<wsdl:part name="sService" type="soapenc:string"/>
</wsdl:message>
<wsdl:portType name="PasswordCollector">
<wsdl:operation name="deleteAuthForService"
parameterOrder="sUsername sService">
<wsdl:input message="impl:deleteAuthForServiceRequest"
name="deleteAuthForServiceRequest"/>
<wsdl:output message="impl:deleteAuthForServiceResponse"
name="deleteAuthForServiceResponse"/>
</wsdl:operation>
<wsdl:operation name="insertAuthForService"
parameterOrder="info">
<wsdl:input message="impl:insertAuthForServiceRequest"
name="insertAuthForServiceRequest"/>
<wsdl:output message="impl:insertAuthForServiceResponse"
name="insertAuthForServiceResponse"/>
<wsdl:fault message="impl:DuplicateIdentifierException"
name="DuplicateIdentifierException"/>
</wsdl:operation>
<wsdl:operation name="getAuthForService"
parameterOrder="sUsername sService">
<wsdl:input message="impl:getAuthForServiceRequest"
name="getAuthForServiceRequest"/>
<wsdl:output message="impl:getAuthForServiceResponse"
2.11. IL SERVIZIO PASSWORDCOLLECTOR
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
47
name="getAuthForServiceResponse"/>
</wsdl:operation>
<wsdl:operation name="getAuthForUser"
parameterOrder="sUsername">
<wsdl:input message="impl:getAuthForUserRequest"
name="getAuthForUserRequest"/>
<wsdl:output message="impl:getAuthForUserResponse"
name="getAuthForUserResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="PasswordCollectorSoapBinding"
type="impl:PasswordCollector">
<wsdlsoap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="deleteAuthForService">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="deleteAuthForServiceRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:input>
<wsdl:output name="deleteAuthForServiceResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="insertAuthForService">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="insertAuthForServiceRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:input>
<wsdl:output name="insertAuthForServiceResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:output>
<wsdl:fault name="DuplicateIdentifierException">
<wsdlsoap:fault
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
name="DuplicateIdentifierException"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="getAuthForService">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getAuthForServiceRequest">
CAPITOLO 2. AXIS
48
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:input>
<wsdl:output name="getAuthForServiceResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getAuthForUser">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="getAuthForUserRequest">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:input>
<wsdl:output name="getAuthForUserResponse">
<wsdlsoap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:PasswordCollector" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PasswordCollectorService">
<wsdl:port binding="impl:PasswordCollectorSoapBinding"
name="PasswordCollector">
<wsdlsoap:address
location="http://localhost:8080/axis/services/PasswordCollector"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Adesso tale file và processato attraverso il tool WSDL2Java, che genererà i file
sorgente Java necessari per realizzare client e server, ed i descrittori del servizio,
in particolare:
• per il web service i file sono:
– PasswordCollector.java
– PasswordCollectorSoapBindingImpl.java
– PasswordCollectorSoapBindingSkeleton.java
• per il client:
– PasswordCollectorService.java
2.11. IL SERVIZIO PASSWORDCOLLECTOR
49
– PasswordCollectorSoapBindingStub.java
– PasswordCollectorServiceLocator.java
• per la pubblicazione: deploy.wsdd, undeploy.wsdd (vanno modificati
secondo quanto detto nel paragrafo precedente)
Solitamente l’unico file che và modificato, per inserire l’implementazione del
servizio, è PasswordCollectorSoapBindingImpl.java, ma nella nostra
applicazione è necessario compiere alcune modifiche lato client per gestire l’autenticazione. Apportate le opportune modifiche è necessario copiare i file
PasswordCollector.class
PasswordCollectorSoapBindingImpl.class
PasswordCollectorSoapBinsingSkeleton.class
in CATALINA BASE/webapps/axis/WEB-INF/classes (con le opportune
directory date dal package a cui tali classi appartengono). Infine è necessario
eseguire il deploy del servizio, tramite l’applicazione AdminClient:
neperobook: giacomo$ java org.apache.axis.client.AdminClient \
net/nepero/portal159/passwordcollector/deploy.wsdd
Processing file net/nepero/portal159/passwordcollector/deploy.wsdd
<Admin>Done processing</Admin>
Se il deploy del servizio ha avuto successo, esso sarà visibile all’indirizzo
http://localhost:8080/axis/servlet/AxisServlet
come è mostrato nella figura 2.7. A questo punto il servizio è pronto per essere utilizzato, ed abbiamo per questo realizzato una piccola applicazione web
per la gestione delle informazioni di autenticazione. Tale applicazione web è
scritta in JSP ed all’interno del codice vengono effettuate le chiamate al servizio PasswordCollector proprio attraverso le classi stub generate dal tool
WSDL2Java. Alcune pagine dell’applicazione web sono mostrate nelle figure
seguenti.
CAPITOLO 2. AXIS
50
Figura 2.7: Servizio PasswordCollector pubblicato
Figura 2.8: Login
2.11. IL SERVIZIO PASSWORDCOLLECTOR
Figura 2.9: Gestione servizi
Figura 2.10: Aggiunta di un servizio
51
52
CAPITOLO 2. AXIS
Il Semantic Web è un’estensione
dell’attuale Web, nella quale
all’informazione viene dato un
significato ben definito, permettendo
cosı̀ ai computer e alle persone di
lavorare meglio in cooperazione.
Tim Berners-Lee, James Hendler,
Ora Lassila, The Semantic Web,
Scientific American
A
Web Semantico
A.1
Il Web attuale
Come è ben precisato nella citazione iniziale di questo capitolo, il Semantic Web
o Web Semantico, non è una realtà alternativa rispetto al Web attuale, ma piuttosto un’estensione che dovrebbe potenziarne le funzionalità. Tale estensione
costituisce una soluzione ai principali limiti dell’attuale Web:
Ricerca di documenti Per trovare documenti nell’attuale Web, esistono fondamentalmente due strade: seguire i link da una pagina all’altra, fino a raggiungere l’informazione che ci interessa, oppure servirci di un motore di
ricerca per ottenere una lista di link tra i quali selezionare quello che ci
interessa. La prima soluzione è una processo cognitivamente ricco per un
essere umano, perchè in genere riusciamo a capire il contenuto della pagina a cui punta il link in base alla descrizione che ne troviamo, o da altre
informazioni relative al contesto a cui appartiene. Tuttavia questo metodo
può essere dispendioso in termini di tempo e difficile da avviare se non
sappiamo da dove partire. Utilizzare invece i motori di ricerca ha il vantaggio di richiedere poche informazioni di partenza, ma essi non coprono
tutto il contenuto Web (è stimato che circa l’80% del Web è nascosto) e può
essere frustrante perchè nella lista compaiono spesso dei falsi-positivi () o
falsi-negativi ().
53
54
APPENDICE A. WEB SEMANTICO
Ricerca di informazione Un altro limite del Web è che la ricerca restituisce sempre documenti, quindi non precisamente l’informazione che cercavamo.
Integrazione di informazione Spesso diverse parti delle informazioni cercate
sono contenute in documenti diversi, magari su siti diversi: non sono però
esprimibili i concetti per correlare queste parti.
Cooperazione Il Web attuale non consente la cooperazione tra programmi e tra
programmi e essere umani per risolvere problemi più complessi. I siti Web
sono progettati come contenitori di informazioni e non come fornitori di
servizi.
A.2
Il progetto Semantic Web
Il Sematic Web è un progetto di ricerca che ha lo scopo di ridefinire e ristrutturare i dati su Web in modo che il loro significato sia accessibile non solo ad
utenti umani, ma anche a programmi che li utilizzano per manipolarli, integrarli, renderli disponibili ad altri programmi (attualmente le informazioni vengono
solamente mostrate). Tale risultato si basa sui seguenti concetti:
Rappresentazione della conoscenza Per poter fornire un risultato soddisfacente per l’utente, i programmi scritti per il Semantic Web devono avere un
accesso al significato dei dati con cui lavorano. Per far ciò è necessario raccogliere tali dati, strutturarli e corredarli di metadati (dati che descrivono
dati).
Utilizzo delle ontologie I soli linguaggi non dispongono di uno strato concettuale che leghi i termini tra loro, mostrandone le relazioni, in modo da
farne emergere il significato. Questo compito è svolto dalle ontologie, documenti che hanno lo scopo di esprimere il significato, inteso come un
certo insieme di termini, definendone le relazioni reciproche. Le ontologie pensate per il Web hanno spesso la forma di tassonomie corredate di
un insieme di regole di inferenza e forniscono definizioni formali delle
relazioni.
Agenti software Gli agenti software sono programmi che dovrebbero sfruttare la conoscenza contenuta nei metadati per fornire servizi complessi agli
utenti del Semantic Web. Gli agenti sono entità abbastanza autonome e sono capaci di ragionare in modo complesso sull’informazione a cui hanno
accesso: devono essere in grado di rappresentare gli obiettivi di un certo
utente, di mettere in atto una sequenza di azioni che possa soddisfare tali
A.2. IL PROGETTO SEMANTIC WEB
55
obiettivi ed eventualmente di cooperare con altri agenti per ottenere tale
risultato.
Uso degli standard Ovviamente per poter realizzare metadati e conoscenza è
necessario utilizzare dei formati standard, basati su XML, per poter definire tali caratteristiche.
56
APPENDICE A. WEB SEMANTICO
Bibliografia
[Web Arch] Ian Jacobs, Norman Walsh, Architecture of the World Wide Web, W3C
Reccomendation, 15th December 2004
[IBM SOA] Steve Burbeck, The Tao of e-business services, IBM DeveloperWorks,
1st October 2000
[Hao He] Hao He, What is Service-Oriented Architecture?, O’Reilly webservices.xml.com, 30th September 2003
[WSA] David Booth, Hugo Haas, Francis McCabe, Eric Newcomer, Michael
Champion, Chris Ferris, David Orchard Web Services Architecture,W3C
Working Group Note, 11th February 2004
[Axis User’ s Guide] Apache Software Foundation, Axis User’s Guide, 1.2
Version, 2005
[Tecno] Ludwig Bargagli, Gabriele Fatigati, Implementazione e protezione di Web
Services con Oc4j ed Axis, http://www.tecnoteca.it/howto/oc4j
57