MokaByte 74- Maggio 2003
Corso di Java Web Services
IV parte: Descrivere, WSDL e JAX-RPC
di
Massimiliano Bigatti

Un altro elemento fondamentale nell'insieme di tecnologie che supportano i servizi Web è lo standard WSDL (Web Service Definition Language), che consente di descrivere un servizio in tutti i suoi aspetti. In un documento WSDL si trovano tutte le possibili chiamate che è possibile fare ad un servizio Web, le specifiche delle strutture dati di input ed output, gli URL per accedere ai servizi. Inoltre, WSDL non è uno standard legato ad un livello di trasporto particolare (come SOAP), ma è aperto all'utilizzo con protocolli differenti, specificando di volta in volta bindings (collegamenti) a questo o quell'altro protocollo. Nonostante ciò, WSDL privilegia SOAP, indicando, in una sezione delle sue specifiche, le modalità di collegamento a questo standard. Con in mano un documento WSDL, un integratore di sistemi è in grado di sapere come dialoga un determinato servizio, oppure un sistema software evoluto può dinamicamente invocare un servizio Web ed elaborarne il risultato. Questo tipo di informazioni sono quelle che dovranno essere presenti all'interno dei registri di servizi Web: costituiscono le specifiche tecniche per l'accesso ad un servizio.


Perché WSDL
L'utilizzo di WSDL ha due vantaggi: per prima cosa, alcuni strumenti di sviluppo sono in grado di prendere in input un file WSDL e produrre del codice che implementa l'infrastruttura per realizzare il servizio, oppure per crearne un runtime per la semplice implementazione di un client; in secondo luogo, è un modo per disaccoppiare il servizio Web dal protocollo di trasporto e dai percorsi fisici, come gli endpoint.
Come accennato, nel file WSDL è presente l'indicazione del protocollo da utilizzare: un sistema di runtime che supporti diversi protocolli di comunicazione XML, come SOAP ed XML-RPC, potrebbe capire dal WSDL come ricondurre a messaggi SOAP o XML-RPC reali, le rappresentazioni astratte contenute nel documento WSDL. Un servizio potrebbe infatti partire utilizzando SOAP come protocollo, ma poi passare a XML-RPC con l'intento di ottimizzarne le prestazioni, ad esempio per via della sua potenziale minor occupazione di banda. Se il client del servizio viene codificato direttamente su SOAP, il suo passaggio a XML-RPC potrebbe essere problematico. Con un runtime dinamico che supporta entrambi i protocolli e che faccia riferimento al file WSDL per conoscere quale protocollo deve essere fisicamente utilizzato, la migrazione potrebbe essere più indolore.
Sicuramente uno scenario del genere comporta l'utilizzo di infrastrutture per i servizi Web più complesse di quelle fornite da JAXM e SAAJ. Inoltre, un'esigenza di questo tipo potrebbe più facilmente nascere in un futuro, magari quando esisterà un legacy di servizi Web in SOAP e XML-RPC e si dovrà migrare ad un ipotetico nuovo protocollo di comunicazione XML.
Ma anche senza considerare aspetti così futuribili, l'utilizzo dinamico di WSDL potrebbe limitarsi anche alla sola acquisizione dell'endpoint del servizio: invece che configurare direttamente l'URL del servizio, questo andrebbe letto dal documento WSDL. Si introduce così un livello di indirezione, simile a quanto fanno i servizi di DNS sugli indirizzi Internet.
Il vantaggio di avere un livello di indirezione è che se si hanno molti client che puntano ad un file WSDL per ottenere l'endpoint di un servizio, nel momento in cui questo cambia indirizzo, non è necessario riconfigurare tutti i client, ma è sufficiente modificare il solo file WSDL.

 

All'interno di WSDL
Un documento WSDL è un file XML contentente un insieme di definizioni. Nello standard WSDL è possibile trovare quattro diversi tipi di informazioni. Sicuramente l'aspetto principale sono l'insieme di regole che consentono di definire in modo astratto un servizio Web; oltre a ciò, sono presenti le specifiche per collegare il servizio a SOAP, HTTP e MIME.
La definizione astratta dei servizi Web di WSDL è composta da cinque diversi elementi:

  • i tipi (types);
  • i messaggi (messages);
  • le operazioni (portType);
  • i collegamenti (bindings);
  • la definizione del servizio (service);

La struttura di un file WSDL è presente nel listato 1.

Listato 1 - Struttura di un file WSDL

<wsdl:definitions name="nmtoken"? targetNamespace="uri"?>

<import namespace="uri" location="uri"/>*

<wsdl:documentation .... /> ?

<wsdl:types> ?
<wsdl:documentation .... />?
<xsd:schema .... />*
<-- extensibility element --> *
</wsdl:types>

<wsdl:message name="nmtoken"> *
<wsdl:documentation .... />?
<part name="nmtoken" element="qname"? type="qname"?/> *
</wsdl:message>

<wsdl:portType name="nmtoken">*
<wsdl:documentation .... />?
<wsdl:operation name="nmtoken">*
<wsdl:documentation .... /> ?
<wsdl:input name="nmtoken"? message="qname">?
<wsdl:documentation .... /> ?
</wsdl:input>
<wsdl:output name="nmtoken"? message="qname">?
<wsdl:documentation .... /> ?
</wsdl:output>
<wsdl:fault name="nmtoken" message="qname"> *
<wsdl:documentation .... /> ?
</wsdl:fault>
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="nmtoken" type="qname">*
<wsdl:documentation .... />?
<-- extensibility element --> *
<wsdl:operation name="nmtoken">*
<wsdl:documentation .... /> ?
<-- extensibility element --> *
<wsdl:input> ?
<wsdl:documentation .... /> ?
<-- extensibility element -->
</wsdl:input>
<wsdl:output> ?
<wsdl:documentation .... /> ?
<-- extensibility element --> *
</wsdl:output>
<wsdl:fault name="nmtoken"> *
<wsdl:documentation .... /> ?
<-- extensibility element --> *
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

<wsdl:service name="nmtoken"> *
<wsdl:documentation .... />?
<wsdl:port name="nmtoken" binding="qname"> *
<wsdl:documentation .... /> ?
<-- extensibility element -->
</wsdl:port>
<-- extensibility element -->
</wsdl:service>

<-- extensibility element --> *

</wsdl:definitions>

Tipi
I tipi definiti da WSDL sono l'equivalente delle strutture (struct) del linguaggio C: strutture dati anche complesse che sono utilizzate come elementi base per costruire i messaggi di input ed output definiti nella sezione "messaggi". Ad esempio, la seguente porzione di file XML (listato 2), definisce due elementi: TradePriceRequest, composto da una stringa e TradePrice, composto da un valore in virgola mobile.

Listato 2 - Un esempio di definizione di tipi
<types>
<schema targetNamespace="http://example.com/stockquote.xsd"
xmlns="http://www.w3.org/2000/10/XMLSchema">
<element name="TradePriceRequest">
<complexType>
<all>
<element name="tickerSymbol" type="string"/>
</all>
</complexType>
</element>
<element name="TradePrice">
<complexType>
<all>
<element name="price" type="float"/>
</all>
</complexType>
</element>
</schema>
</types>

In questo caso, dove la struttura dati contiene un solo campo, la definizione di un tipo specifico non è indispensabile: la sua utilità è per lo più relativa alla manutenibilità del documento WSDL. In questo modo infatti viene creato un "alias" e nel resto del documento WSDL si utilizzeranno i tipi definiti al posto che i tipi di dati primitivi, disaccoppiando il resto delle definizioni dai tipi di dati reali.

 

Messaggi
I messaggi sono gli elementi che costituiscono gli input e gli output dei servizi. I singoli messaggi possono contenere i tipi di dati complessi definiti nella sezione types (Figura 1), oppure semplici dati primitivi.


Figura 1 - La struttura di un
messaggio WSDL

Un esempio di messaggio è presente nel listato 3, ed è relativo al file WSDL del servizio di cambio valute utilizzato nel paragrafo precedente. Come si può notare osservando il listato, vengono definiti due diversi messaggi, uno relativo alla richiesta, getRateRequest, ed uno relativo alla risposta, getRateResponse. Il primo definisce due elementi, di tipo stringa, chiamati country1 e country2; il secondo definisce un unico elemento di risposta Result, di tipo float.

Listato 3 - Un esempio di definizione di messaggi
<message name="getRateRequest">
<part name="country1" type="xsd:string"/>
<part name="country2" type="xsd:string"/>
</message>
<message name="getRateResponse">
<part name="Result" type="xsd:float"/>
</message>

 

Operazioni
Questa sezione definisce le operazioni fornite dal servizio Web. Se si ponessero in relazione i servizi Web con la programmazione distribuita, ad esempio RMI, le operazioni WSDL equivarrebbero ai singoli metodi dell'oggetto remoto (Figura 2). Per ciascuna operazione, WSDL definisce i messaggi di input e di output. Un esempio di operazione è presente nel listato 4, sempre estratto dal WSDL del servizio di cambio valuta.


Figura 2
- L'accesso al servizio Web
avviene tramite le "port"

Listato 4 - Un esempio di operazione
<portType name="CurrencyExchangePortType">

<operation name="getRate">
<input message="tns:getRateRequest" />
<output message="tns:getRateResponse" />
</operation>
</portType>

L'elemento <operation> definisce una singola operazione e può contenere opzionalmente almeno uno dei due sottoelementi <input> ed <output>. La presenza e l'ordine di questi elementi determina la tipologia di servizio, che può rientrare all'interno di quattro diverse nature:

  • one-way. Anche detto fire&forget, è una configurazione dove l'endpoint si limita a ricevere il messaggio inviato dal client. In questo caso è presente un solo elemento di input;
  • request-response. In questo caso l'endpoint riceve un messaggio di richiesta, esegue l'elaborazione necessaria e restituisce al client un messaggio di risposta correlato alla richiesta ricevuta. Sono presenti gli elementi input ed output;
  • solicit-response. E' l'opposto del precedente. In questo caso è l'endpoint che inizia la comunicazione inviando un messaggio al client che a sua volta dovrà rispondere di conseguenza. Nel file WSDL è presente prima l'elemento output e poi quello input;
  • notification. E' l'opposto della tipologia one-way. In questo caso è l'endpoint ad inviare un messaggio al client, senza che questo debba inviare una risposta. E' presente il solo elemento output.

Il modello di interazione da utilizzare dipende dalla natura del servizio. Se l'interazione request-response potrebbe essere quella usata per la maggior parte dei servizi, in quanto costituisce il tipico modello di comunicazione RPC, altre modalità possono essere utili in altri ambiti. Ad esempio, una interazione one-way può essere utile in sistemi dove il client invia una serie di informazioni al servizio, e questo si limita a raccoglierle. In questo caso il client non è interessato al risultato dell'elaborazione dei suoi dati, come nell'esempio relativo alla raccolta dati ambientali descritto all'inzio del capitolo.

 

Collegamenti
In questa sezione avviene la mappatura del servizio astratto, definito nelle sezioni precedenti, al protocollo concreto di comunicazione (ad esempio SOAP). Il contenuto di questa sezione è fortemente dipendente dal protocollo utilizzato, e quindi delle estensioni WSDL relative.
In WSDL, la struttura di un collegamento (semplificata) è quella riportata nel listato 5. Quella completa è presente nella struttura completa di un file WSL riportata ad inizio paragrafo.

Listato 5 - Sezione WSDL relativa ai collegamenti
<wsdl:binding name="nmtoken" type="qname">*
<wsdl:operation name="nmtoken">*
<wsdl:input> ?
</wsdl:input>

<wsdl:output> ?
</wsdl:output>

<wsdl:fault name="nmtoken"> *
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>

Come si può notare, un collegamento può contenere diverse operazioni, ciascuna delle quali può avere un elemento di input, di output ed una serie di elementi di errore (fault). Nel listato 6 è presente un esempio di collegamento con SOAP, sempre estratto dal file WSDL per il servizio di cambio valuta. La struttura del collegamento è la seguente: per prima cosa, viene definito lo stile del collegamento (può essere rpc oppure document) ed il tipo di trasporto:
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

In questo caso la comunicazione è di tipo RPC ed il trasporto avviene sul protocollo HTTP. In secondo luogo, è necessario definire, per ciascuna operazione, come trattare i messaggi di input ed output. Essendo questo un servizio request-response, le informazioni sono presenti entrambe. Il messaggi di input è così definito:

<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>

In questo elemento viene indicato il namespace del messaggio (urn:xmethods-CurrencyExchange) ed il tipo di encoding. L'attributo use può assumere i valori "econding", oppure "literal". Nel primo caso, l'attributo encodingStyle dovrà indicare il tipi di encoding utilizzato. In questo caso, viene utilizzato l'encoding SOAP.

Listato 6 - Un esempio di collegamento
<binding name="CurrencyExchangeBinding" type="tns:CurrencyExchangePortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getRate">
<soap:operation soapAction=""/>

<input >
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output >
<soap:body use="encoded" namespace="urn:xmethods-CurrencyExchange" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>

 

Definizione del servizio
L'ultimo elemento di un file WSDL è la definizione del servizio: questa sezione consente di raccogliere tutte le operazioni sotto un unico nome (vedi Figura 2). Il servizio è identificato da un nome (l'attributo name dell'elemento service) e può avere una descrizione, contenuta nel sottolemento opzionale documentation. All'interno dell'elemento service vengono elencate tutte le operazioni esposte dal servizio, sottoforma di elementi port. Per ciascuno di questi viene indicato il collegamento utilizzato. Il contenuto dell'elemento port cambia in funzione del tipo di collegamento utilizzato. Nel listato 7 è presente un esempio di definizione di servizio, in particolare del servizio di cambio valute, dove il collegamento utilizzato è quello con SOAP. In questo caso nell'elemento port è presente un elemento address appartenente al namespace soap: (utilizzato in tutto il WSDL per riferirsi agli elementi strettamente relativi al collegamento di WSDL con SOAP). Questo elemento indica l'URL fisico dell'endpoint del servizio.

Listato 7 - Un esempio di definizione di servizio
<service name="CurrencyExchangeService">

<documentation>Returns the exchange rate between the two currencies</documentation>
<port name="CurrencyExchangePort" binding="tns:CurrencyExchangeBinding">
<soap:address location="http://services.xmethods.net:80/soap"/>
</port>
</service>

L'utilizzo di WSDL può diventare anche molto complesso nel momento in cui ci si addentri in collegamenti e protocolli diversi da SOAP ed HTTP. Per ciascun protocollo e livello di trasporto è infatti necessario definire una estensione WSDL specifica e costruire i documenti WSDL secondo questa grammatica. Il vantaggio della grande estensibilità di WSDL si paga quindi in termini di complessità.

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it