Introduzione
SOAP
(Simple Object Access Protocol) [1] è un protocollo di interazione
fra componenti remoti basato su XML e HTTP. Il protocollo si compone di
tre parti
-
un envelop
che rappresenta un framework per descrivere il contenuto di un messaggio
e come elaborarlo (SOAP envelope);
-
una serie
di regole di codifica per rappresentare i tipi di dato definiti per l'applicazione
(SOAP encoding rules);
-
delle
convenzioni per rappresentare le invocazioni remote e le corrispondenti
reply (SOAP RPC).
In
pratica si tratta di un meccanismo di RPC in cui le richieste e le reply
vengono definite mediante XML mentre il protocollo di trasporto è
HTTP. L'utilizzo di XML per la descrizione di servizi distribuiti permette
la massima interoperabilità.
Il
protocollo vuole essere semplice ed estendibile quindi le specifiche non
includono caratteristiche come garbage collection distribuita e gestione
dei riferimenti remoti, tipiche dei sistemi a oggetti distribuiti.
SOAP
si appoggia pesantemente sull'architettura Web in quanto sfrutta HTTP come
protocollo di trasporto. Altri meccanismi di computazione distribuita,
come COM+, Java RMI e CORBA, si integrano con difficoltà su Web
in quanto ad esempio possono essere bloccati dai firewall.
SOAP
è una proposta di varie aziende, fra le quali Microsoft, IBM e DevelopMentor,
sottoposta al W3C e all'IETF per la standardizzazione. Il protocollo è
alla base dell'architettura .NET di Microsoft e di Web Services di IBM.
L'XML Apache Group fornisce un'implementazione Java, chiamata Apache-SOAP,
basata sulla versione 1.1 del protocollo (http://xml.apache.org/soap);
l'esempio presentato in questa sezione farà uso di Apache-SOAP.
SOAP: le basi
Un
messaggio SOAP è un documento XML costituito da un envelope, un
header e un body. Il SOAP envelope è obbligatorio e rappresenta
il messaggio. L'header è un elemento opzionale che contiene informazioni
che estendono il messaggio, relative ad esempio a gestione delle transazioni
e autenticazione. Il body è un elemento obbligatorio che permette
di trasmettere informazioni destinate al ricevente del messaggio. Un messaggio
SOAP può infatti transitare attraverso diversi nodi intermedi. Eventuali
errori vengono rappresentati dall'elemento SOAP Fault.
In
SOAP sono previsti due tipi di messaggi, Call e Response. Un messaggio
di tipo Call permette di invocare un servizio remoto. Si supponga ad esempio
di voler richiedere la somma di due numeri a un server remoto; la richiesta
in SOAP verrebbe espressa con il seguente messaggio
POST
/Calculator HTTP/1.1
Host:
www.mycalculator.com
Content-Type:
text/xml
Content-Length:
x
SOAPMethodName:
My_Namespace_URI#GetSum
<SOAP:Envelope
xmlns:SOAP=http://schemas.xmlsoap.org/soap/envelop"">
<SOAP:Body>
<m:GetSum xmlns="http://www.mycalculator.com">
<first>3</first>
<second>8</second>
</m:GetSum>
</SOAP:Body>
</SOAP:Envelope>
Le
prime quattro linee sono specifiche del protocollo HTTP e indicano che
si tratta di una richiesta POST inviata all'host http://www.mycalculator.com
per il servizio Calculator. Il messaggio è contenuto all'interno
della SOAP envelope: l'elemento GetSum contiene i parametri forniti per
il servizio, in questo caso due numeri da sommare individuati dagli elementi
first e second.
I
messaggi Response contengono il risultato dell'elaborazione del servizio.
Il messaggio Response corrispondente alla richiesta precedente sarebbe
HTTP/1.1
200 OK
Content-Type:
text/xml
Content-Length:
x
<SOAP:Envelope
xmlns:SOAP=http://schemas.xmlsoap.org/soap/envelop"">
<SOAP:Body>
<m:GetSumResponse xmlns="http://www.mycalculator.com">
<return>11</return>
</m:GetSumResponse>
</SOAP:Body>
</SOAP:Envelope>
In
questo caso la SOAP-envelope contiene il risultato dell'elaborazione come
valore dell'elemento return.
Il
modello a oggetti di Apache-SOAP viene esposto dal package org.apache.soap.rpc.
Il client che vuole usare un servizio remoto utilizza l'oggetto Call mediante
il quale specifica il nome del metodo, l'ID e i parametri. Una volta
impostato l'oggetto Call è possibile invocarne il metodo
invoke(URL
url, String SOAPActionURI) nei cui parametri si indicano rispettivamente
l'URL in cui si trova il componente che fornisce il servizio e l'header
della richiesta.
Il
metodo invoke() restituisce un oggetto Response che contiene la risposta
al servizio richiesto oppure una segnalazione di errore.
Apache-SOAP
supporta i protocolli HTTP e SMTP. Se usato su HTTP si ha il seguente processo
di funzionamento
-
il client
esegue un POST di un SOAP-envelope al server;
-
questo
a sua volta costruisce un oggetto Call, localizza l'oggetto destinatario
basandosi sull'object ID, verifica il nome del metodo e quindi chiama il
metodo invoke() sull'oggetto;
-
il metodo
invoke() restituisce un oggetto Response da cui il server estrae le informazioni
da inserire nel messaggio response da inviare al client.
Un esempio completo
Si
vedrà ora un esempio di servizio esposto via SOAP. Si realizzerà
in Java un semplice servizio di somma remota come nell'esempio precedente.
Sia il client che il server verranno implementati in Java per ragioni 'didattiche'.
Si noti che potrebbero essere realizzati in qualsiasi linguaggio per il
quale esista una implementazione di SOAP, come ad esempio Perl o linguaggi
COM-enabled in ambiente Microsoft.
Segue
ora il codice, molto semplice, del server che esegue la somma
public
class MyCalculator {
public
static int getSum(int arg1, int arg2) {
return (arg1 + arg2);
}
}
Per
fare in modo che il servizio precedente sia visibile via Apache-SOAP è
necessario scrivere un deployment descriptor in XML per la classe precedente
<?xml
version="1.0"?>
<n:service
xmlns:n="http://xml.apache.org/xml-soap/deployment"
id="urn:xml-soap-demo-mycalculator">
<n:provider
type="java"
scope="Application"
methods="getSum">
<n:java class="MyCalculator" static="true"/>
</n:provider>
</n:service>
Una
volta installato Apache-SOAP è possibile eseguire il deploy del
servizio. Questo può essere fatto attrraverso un apposita pagina
Web oppure da linea di comando.
Il
seguente codice mostra impostare l'invocazione del servizio di somma. Per
semplicità è stata tralasciata qualsiasi gestione degli errori.
Call
call = new Call();
call.setTargetObjectURI("urn:xml-soap-demo-mycalculator");
call.setMethodName("getSum");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector
parms = new Vector();
parms.addElement(new
Parameter("first", int.class, 3, null));
parms.addElement(new
Parameter("second", int.class, 8, null));
call.setParams(parms);
URL
url = new URL("http://localhost:8080/soap/servlet/rpcrouter");
Response
response = call.invoke(url, "");
Parameter
result = response.getReturnValue();
System.out.println("Il
risultato è " +
((Integer)result.getValue()).intValue());
Conclusioni
SOAP
è un passo molto importante verso l'integrazione di sistemi eterogenei
e offre i grandi vantaggi della semplicità: non esiste infatti una
API alla quale debbano conformarsi le implementazioni del protocollo. L'implementazione
in Java fornita dall'Apache Group permette di rendere i programmi Java
interoperabili via SOAP e si è dimostrata molto semplice da usare.
I sorgenti dell'esempio mostrato sono disponibili per il download qui.
Riferimenti
[1]
- Le specifiche su SOAP del W3C: http://www.w3c.org/soap;
|