MokaByte 72- Marzo 2003
Corso di Java Web Services
II parte: SOAP
di
Massimiliano Bigatti
Come abbiamo visto nella prima parte, la comunicazione è un elemento fondamentale nella visione dei Web Services ed il protocollo affermato che risolve questo aspetto è SOAP. Acronimo di Simple Object Access Protocol, è uno standard nato in casa Microsoft e supportato in una seconda fase da IBM. Ora è quasi uno standard del W3C, che ne ha raccolto la versione 1.1 proposta dalle due aziende, e che ne sta derivando l'evoluzione (versione 1.2).

Le specifiche di SOAP 1.2 sono definite in due diversi documenti ("Part 1: Messaging Framework" e "Part 2: Adjuncts") a cui è stato aggiunto un terzo documento di introduzione. Sebbene gran parte della logica e dei concetti di SOAP 1.1 sia mantenuta in SOAP 1.2, in quest'ultima versione sono state applicate diverse piccole variazioni, cambi di nomi e chiarimenti di semantica, che rendono incompatibili le due versioni. Per di più, si noti che la presenza di namespace specifici all'interno dei messaggi è il meccanismo utilizzato da SOAP per garantire che un nodo elabori un messaggio in funzione della specifica versione in cui è stato codificato. Ad esempio, un servizio è in grado, analizzando il messaggio, di verificare se questo è stato codificato secondo le specifiche SOAP 1.1 oppure SOAP 1.2 ed attivare le due differenti gestioni, in funzione della versione.
In questo capitolo si considererà solo SOAP 1.1, in quanto è la versione stabile attualmente disponibile e quella supportata dalla piattaforma Java e dalla maggior parte degli strumenti disponibili.

Nelle specifiche SOAP convivono quattro diversi aspetti che affrontano differenti parti del problema:

  1. il modello di scambio dei messaggi;
  2. l'encoding SOAP;
  3. il collegamento tra SOAP ed http;
  4. l'utilizzo di SOAP come meccanismo di RPC.

Il modello di scambio dei messaggi definisce un modo standard per definire come strutturare messaggi XML che saranno scambiati tra i diversi nodi, come vengono gestiti gli errori e come si devono chiamare i tag XML che contengono le informazioni.
L'encoding SOAP fornisce una specifica (opzionale), per definire come strutture dati anche complesse, come enumerazioni e vettori sparsi, vengono rappresentate in XML. E' basata su una prima bozza delle specifiche XML Schema.
Il collegamento con HTTP, invece, definisce come i messaggi SOAP debbano essere veicolati tramite questo protocollo di filo e come devono essere utilizzate le intestazioni HTTP ed i codici di ritorno per l'invio di messaggi SOAP.
Infine, il modello RPC definisce come SOAP può essere utilizzato per rappresentare chiamate a procedure remote. Le specifiche SOAP consentono infatti di realizzare applicazioni di semplice messaggistica o più evolute applicazioni distribuite, anche se mancano i dettagli per aspetti legati alla sicurezza ed alla garbage collection distribuita.

 

Anatomia del messaggio
La comunicazione tramite SOAP avviene tramite lo scambio di messaggi strutturati in modo specifico comprendente elementi obbligatori ed elementi opzionali. Il tag principale che racchiude tutti gli altri è Envelope (busta). Dentro questo è presente Header (intestazione) e Body (corpo). Il primo è opzionale, mentre nel corpo sono presenti tutte le informazioni applicative che il nodo vuole inviare.

Listato 1 - Esempio di richiesta SOAP
<?xml version="1.0"?>

<SOAP-ENV:Envelope
xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/>

<SOAP-ENV:Body>
<ns1:getRate xmlns:ns1="urn:xmethods-CurrencyExchange">

<country1>England</country1>
<country2>Japan</country2>

</ns1:getRate>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Nel listato 1 è presente un esempio di semplice messaggio SOAP. I tag Evelope e Body appartengono al namespace http://schemas.xmlsoap.org/soap/envelope. L'utilizzo di SOAP-ENV è semplicemente una convenzione: al suo posto si sarebbe potuto utilizzare un qualsiasi nome simbolico, come ad esempio "ns1", utilizzato nel corpo del messaggio.
Come si può notare, all'interno del tag Body è definito il messaggio applicativo: nel tag getRate sono presenti i tag country1 e country2. Questo blocco SOAP potrebbe essere un messaggio utilizzato in una applicazione che si occupi di fornire il tasso di conversione tra diverse valute.
L'utilizzo dei namespace è importante: consente di essere sicuri che non ci siano conflitti di nomi: come due classi Java con lo stesso nome possono convivere nello stesso programma se appartengono a package differenti, anche in SOAP possono coesistere tag con lo stesso nome, purché questi appartengano a namespace diversi.
La risposta SOAP (listato 2) è strutturata in modo similare, con tag Envelope e Body e con una risposta applicativa all'interno di quest'ultimo.

Listato 2 - Esempio di risposta SOAP
<?xml version="1.0"?>

<SOAP-ENV:Envelope
xmlns:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/>

<SOAP-ENV:Body>
<ns1:getRateResponse xmlns:ns1="urn:xmethods-CurrencyExchange">

<return>154.9423</return>

</ns1:getRateResponse>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Per convenzione, il nome del tag utilizzato nella risposta è lo stesso della richiesta, a cui è aggiunto la parola "Response". Nell'esempio, il tag applicativo contiene il valore di ritorno della chiamata al servizio, e cioè il tasso di conversione tra le due divise specificate.
I due blocchi SOAP visti in precedenza presuppongono un modello di interazione tra due nodi di tipo request/response: a ciascuna richiesta, il ricevente fornisce una risposta al chiamante. SOAP è utilizzabile anche in modalità oneway (a senso unico, detta anche fire&forget), dove il client si limita ad inviare un messaggio al server, senza che questo formuli una risposta. Queste due modalità verranno viste più in dettaglio nella parte dedicata a WSDL, che tra l'altro, ne definisce di ulteriori.

 

SOAP su HTTP
Le regole per utilizzare SOAP su HTTP ben si sposano con quest'ultimo protocollo, in quanto non vengono aggiunti elementi estranei, ma vengono sfruttate le semantiche già esistenti. In particolare, le regole di mappatura possono essere così riassunte:

  • il Content-Type deve essere "text/xml";
  • l'intestazione HTTP deve riportare il campo SOAPAction. Questo indica al server Web od al firewall l'intento del messaggio, per eventuali operazioni di filtro.

Entrambe queste indicazioni sono obbligatorie.
L'invio di una richiesta dal client al server, avviene tramite una operazione di POST, come si evince dall'esempio presente nel listato 3. Qui è possibile vedere l'intestazione HTTP di una classica richiesta SOAP, con l'indicazione corretta del Content-Type e di SOAPAction.

Listato 3 - Richiesta SOAP veicolata sul protocollo HTTP
POST /StockQuote HTTP/1.1
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://electrocommerce.org/abc#MyMessage"

<SOAP-ENV:Envelope...


Per quanto concerne la risposta (un esempio è presente nel listato 4), il client deve fare affidamento sul codice HTTP di risposta per capire se tutto è andato bene o se si è verificato qualche problema.

Listato 4 - Risposta SOAP veicolata sul protocollo HTTP
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn

<SOAP-ENV:Envelope...

Nel caso del listato 4 il server ha ritornato il codice 200, che indica la corretta elaborazione della risposta. In entrambi i casi, ovviamente, il campo Content-Length conterrà la corretta dimensione del corpo del messaggio SOAP.

 

Se qualcosa va male
Se avviene qualche errore in fase di elaborazione del messaggio SOAP, il server può inviare come risposta, al posto della normale risposta SOAP, una specifico messaggio di errore, detto Fault. Questo definisce, in modo standardizzato, le specifiche dell'errore occorso. I contenuti del tag Fault possono essere:

  • faultcode;
  • faultstring;
  • faultactor;
  • detail.

Questi elementi identificano, nell'ordine, il codice dell'errore, la descrizione dell'errore, l'entità che lo ha generato ed opzionalmente i dettagli dell'errore, strutturati come un blocco XML applicativo. Nel listato 5 è presente un esempio di Fault SOAP.

Listato 5 - Esempio di Fault SOAP
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Errore server</faultstring>
<detail>
<e:myfaultdetails xmlns:e="Some-URI">
<message>
Si è verificato un errore applicativo
</message>
<errorcode>
1001
</errorcode>
</e:myfaultdetails>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Il codice dell'errore è una stringa, composta da parole concatenate, come ad esempio "Client.Authentication". Lo scopo delle specifiche è quello di fornire un meccanismo che sia più flessibile ed espandibile rispetto ai più classici codici di errore numerici, come quelli utilizzati in HTTP.
I prefissi che possono essere utilizzati nei codici di errore sono predefiniti, e sono:

  • VersionMismatch. Indica che il namespace sul tag Envelope che identifica la versione, ha un valore diverso da quello atteso;
  • MustUnderstand. L'elaborazione obbligatoria di una parte dell'intestazione ha avuto esito negativo;
  • Client. Può indicare errori in merito alla strutturazione del messaggio di richiesta;
  • Server. Indica l'impossibilità di elaborare una risposta, anche a fronte di richieste correttamente strutturate (ad esempio nel caso di inconsistenze interne del componente server);

Un utilizzo interessante del tag detail è quello che prevede la sua valorizzazione con lo stack trace della chiamata che ha generato l'errore, in modo da semplificare il debug dell'applicazione. Questa informazione, infatti, non è obbligatoriamente da mostrare all'utente, ma l'applicazione la potrebbe mostrare solo a sviluppatori e sistemisti fornendo una informazione preziosa per indivudare l'errore.

Il collegamento con il protocollo HTTP definisce che il blocco SOAP Fault debba essere veicolato con un messaggio con codice di errore 500 (utilizzato in HTTP per identificare gli errori del server), come si evince dal listato 6.

Listato 6 - Fault SOAP veicolato tramite HTTP
HTTP/1.1 500 Internal Server Error
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">


Encoding
Il concetto di encoding riguarda le informazioni applicative contenute nel tag Body: definisce come i dati vengono rappresentati in XML. Le specifiche SOAP lasciano una certa libertà, ma suggeriscono l'uso dell'encoding SOAP. Altri, come Apache, hanno storicamente proposto un econding più semplice, denominato encoding letterale.

Ecoding letterale
Questo tipo di encoding è semplicemente un blocco XML applicativo appartenente opzionalmente ad un determinato namespace. Un esempio è presente nel listato 7.

Listato 7 - Un esempio di encoding letterale
<Contatti>
<Persone>
<Persona id="1">
<Nome>Mario</Nome>
<Cognome>Rossi</Cognome>
</Persona>
<Persona id="2">
<Nome>Giuseppe</Nome>
<Cognome>Verdi</Cognome>
</Persona>
</Persone>
</Contatti>

Anche i primi esempi SOAP visti in precedenza (listati 1 e 2), utilizzano un encoding letterale, utilizzando però uno specifico namespace. Come si nota, la codifica è molto semplice, ma non sono presenti informazioni sui tipi di dati.

Encoding SOAP
L'encoding SOAP definisce regole (derivate da una prima versione di XML Schema), per rappresentare il tipo di dato utilizzato nel blocco dati applicativo, mutuando le tipologie dai più diffusi linguaggi di programmazione e dai tipi di dati utilizzati nei database.
Le strutture complesse, come i dati compositi (ad esempio le struct del linguaggio C), trovano quindi uno standard per la loro serializzazione in XML.
Sono previsti diversi tipi di dati, come:

  • tipi semplici (numeri interi, reali, stringhe, etc);
  • enumerazioni;
  • array di bytes (base64);
  • strutture;
  • array;


La gestione degli array in particolare è molto potente, in quanto consente anche di specificare array sparsi, dove cioè, gli indici possono anche non essere contigui (ad esempio possono essere presenti solo gli elementi 1, 3, 4, 11).
L'encoding SOAP è più stringente rispetto all'encoding letterale. Questo consente di rendere più facile l'interoperabilità delle informazioni trasferendo, insieme ai dati, anche metainformazioni che ne descrivono il tipo. Ad esempio, è possibile capire direttamente dal flusso XML se un determinato tag è di tipo stringa o numerico.
Per esempio, nel blocco XML:

<X1>12</X1>

il valore 12 potrebbe essere numerico, ma il tag potrebbe anche potenzialmente essere di tipo alfanumerico). Con l'encoding SOAP avremmo:

<X1 xsd:type="String">12</X1>

il contenuto dell'attributo type chiarisce che il tipo di dato è alfanumerico. Sempre in merito ai listati 1 e 2, è possibile codificarli con l'encoding SOAP, come esemplificato nei listati 8 e 9.

Listato 8 - Un esempio di chiamata codificata con l'encoding SOAP
<?xml version="1.0"?>

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body>
<ns1:getRate xmlns:ns1="urn:xmethods-CurrencyExchange"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<country1 xsi:type="xsd:string">England</country1>
<country2 xsi:type="xsd:string">Japan</country2>

</ns1:getRate>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Listato 9 - Un esempio di risposta codificata con l'encoding SOAP
<?xml version="1.0"?>

<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">

<SOAP-ENV:Body>
<ns1:getRateResponse xmlns:ns1="urn:xmethods-CurrencyExchange"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<return xsi:type="xsd:float">154.9423</return>

</ns1:getRateResponse>
</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

Si può notare in questi esempi (listati 8 e 9), come ciascun tag applicativo specifichi anche un attributo che identifica il tipo di dato.

 

SOAP RPC
Le specifiche SOAP definiscono anche gli standard per utilizzare messaggi SOAP per realizzare semplici applicazioni distribuite di tipo Remote Procedure Call (RPC). In particolare, le chiamate sono descritte all'interno del tag body ed i parametri ed il valore di ritorno sono modellati come strutture, anche se la scelta dell'encoding è libera. In caso di errore, questo è codificato come Fault SOAP.
La differenza tra semplici messaggi SOAP e SOAP-RPC è che nel primo caso si parla di generici messaggi di notifica che possono veicolare meri contenuti informativi (come ad esempio, un intero documento XML da inserire in un database). In caso di SOAP-RPC, nel corpo del messaggio SOAP è presente una formalizzazione in XML di una chiamata a metodo, quindi tipicamente le informazioni sul nome del metodo ed i valori dei parametri.
SOAP-RPC verrà visto più nel dettaglio nella prossima puntata, tramite un esempio pratico.

 

Conclusioni
In questo articolo abbiamo affrontato gli aspetti salienti del protocollo SOAP. Nella prossima puntata vedremo come applicare in pratica questa tecnologia utilizzando le API Java per la messaggistica XML: JAXM.

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