1.
Quali sono le tecnologie Java per i Web Services?
La
panoramica delle tecnologie che sono state aggiunti
negli ultimi anni alla piattaforma Java è rappresentata
in figura 1.
Figura 1 - Panoramica delle tecnologie Java
Queste tecnologie hanno il seguente scopo:
- JAXM
(Java API for XML Messaging). Implementazione della
messaggistica SOAP a basso livello. Approfondimento;
- SAAJ
(SOAP with Attachments API for Java). Implementazione
del modello informativo degli elementi di SOAP. Approfondimento;
- JAX-RPC
(Java API for XML Remote Procedure Call). Supporto
client e server allo sviluppo rapido di servizi Web
basati su SOAP (e non solo) e WSDL con un modello
di sviluppo simile ad RMI. Approfondimento;
- JAXR
(Java API for XML Registries). Supporto a registri
di servizi Web come UDDI e ebXML R. Approfondimento;
3. In un messaggio SOAP: cosa metto
nell'header e cosa nel body?
Come noto, un messaggio SOAP può essere composto
da diversi elementi, ed i due principali sono l'intestazione
ed il corpo. La differenza tra queste due sezioni è
semantica: servono a rendere più chiaro lo scopo
di una determinata informazione; se questa è
contenuta nell'intestazione è un meta-dato di
contorno; se è contenuta nel corpo, è
una informazione applicativa. Ad esempio:
Header |
Body |
id dell'utente
token di sicurezza
id della transazione in corso
indirizzo ip del chiamante |
dati applicativi
parametri del servizio da chiamare |
4. Che differenza c'è tra Axis
e JAXM?
JAXM è lo standard Java per la messaggistica
SOAP, mentre Axis è una implementazione di SOAP
per Java con un parziale supporto a JAXM di Apache Group.
Axis sta già migrando a JAXM ed attualmente la
supporta in parte. E' consigliabile sicuramente di codificare
per JAXM, che è una interfaccia indipendente
dall'implementazione, un servizio che verrà messo
a disposizione delle applicazioni da parte dei container,
come ad esempio gli application server come WebSphere,
o lo stesso Axis.
Le due tecnologie sono complementari: JAXM è
l'interfaccia, mentre Axis è (parzialmente) una
implementazione.
5.
Quando usare JAXM e quando usare JAX-RPC?
Entrambe le API di SUN implementano SOAP, quindi si
potrebbe pensare che l'utilizzo, o l'approfondimento,
delle due sia indifferente. In realtà non è
così: JAXM e JAX-RPC non sono una ripetizione
della stessa tecnologia con nomi diversi.
Per prima cosa, entrambe utilizzano SAAJ come implementazione
del modello informativo di SOAP, ma il loro scopo è
differente.
- JAXM
fornisce un controllo fine sul messaggio (tramite
SAAJ), consentendo di manipolare ciascun elemento
della richiesta ed accedere a qualsiasi elemento della
risposta SOAP. Viene utilizzato in soluzioni di messaggistica,
come ad esempio: l'invio asincrono di informazioni
real-time, l'interfacciamento con servizi strutturati
in modo particolare (non standard), collegamento a
servizi che hanno una risposta dinamica (cambia la
struttura al variare della richiesta o dei dati ritornati);
- JAX-RPC
implementa invece un generico sistema di RPC su XML;
la tecnologia non è vincolata a SOAP, ma aperta
ad eventuali evoluzioni future. E' invece basata fortemente
su WSDL, che utilizza per implementare la mappatura
XML->Java e viceversa. Con JAX-RPC non è
necessario codificare a basso livello, se si dispone
di un WSDL, si possono generare le classi Java che
implementano il client ed il server. La stessa cosa
può avvenire a partire da una interfaccia che
estende java.rmi.Remote, in modo similare al
funzionamento di RMI e di rmic.
JAX-RPC è dunque più indicato per sviluppare
applicazioni complesse, con molti servizi, e per integrare
Web Service esistenti e completamente standard, quando
non sia necessario entrare nel dettaglio tecnico della
struttura dei messaggi SOAP di richiesta e risposta.
Con JAX-RPC un servizio Web viene acceduto come se fosse
un oggetto Java locale.
6.
Come faccio a manipolare l'intestazione HTTP durante
l'invio di un messaggio SOAP?
Con JAXM è possibile intervenire in modo fine
su tutto il messaggio, manipolando intestazione, corpo
ed allegati. E' possibile inserire anche nuovi elementi
nell'intestazione HTTP, anche se, poco intuitivamente,
è necessario farlo attraverso le intestazioni
MIME. Inserire una intestazione HTTP aggiuntiva può
servire a diversi scopi, oltre che per fornire indicazioni
aggiuntive al server, ma anche solo per aggiungere la
famigerata chiave SOAPAction che, sebbene spesso
ignorata da molti servizi Web, in alcuni casi è
obbligatoria. La sua mancanza può quindi impedire
la risposta da parte del server, anche quando il messaggio
SOAP nella sua integrità sia corretto. Per un
esempio si veda sotto: è prima necessario ottenere
l'oggetto MimeHeaders dal messaggio SOAP creato
per poi impostare l'header voluta con setHeader()
e poi ricordarsi di salvare le modifiche con saveChanges().
//SOAPMessage msg;
//...
MimeHeaders mh = msg.getMimeHeaders();
mh.setHeader("SOAPAction", "http://tempuri.org/DailyDilbertImage");
msg.saveChanges()
7.
Come faccio ad avere il controllo sull'invio di un messaggio
SOAP?
Alcune volte può rendersi necessario inviare
un messaggio SOAP con un protocollo diverso da HTTP,
l'unico ad oggi supportato da JAXM, oppure intervenire
nell'invio del messaggio per pilotare caratteristiche
di dettaglio del meccanismo di invio, che in SOAP avviene
sempre, se su HTTP, con una operazione di POST.
E' possibile utilizzare le Apache
Commons, una libreria di funzioni basilari comuni
per tutti i progetti di Apache Group, che include una
classe per l'invio tramite HTTP POST: PostMethod.
Questa implementa l'invio tramite HTTP 1.0 o 1.1, ad
esempio, il metodo seguente implementa una chiamata
simile a quella presente nella classe JAXM SOAPConnection
utilizzata per inviare un messaggio SOAP:
public String call( SOAPMessage request, Object to )
throws SOAPException {
String result = null;
try
{
URL url = new URL( to.toString() );
String
host = url.getHost();
int
port = url.getPort();
PostMethod
method = new PostMethod( url.getFile() );
method.setRequestHeader("Content-type",
"text/xml");
ByteArrayOutputStream
out = new ByteArrayOutputStream();
request.writeTo(
out );
String
requestBody = new String( out.toByteArray(), "UTF-8"
);
method.setRequestBody(
requestBody );
method.execute(
new HttpState(), new HttpConnection( host, port ) );
int
returnCode = method.getStatusCode();
byte[]
body = method.getResponseBody();
result
= new String( body, "UTF-8" );
} catch( Exception ex ) {
ex.printStackTrace();
}
return result;
}
La classe PostMethod implementa il meccanismo
di POST HTTP, e con questa realizzare una chiamata SOAP.
I metodi salienti, ed utilizzati nell'esempio sopra
riportato sono:
- setRequestHeader().
Aggiunge una chiave alle intestazioni HTTP, ad esempio
Content-Type, che nel caso di una richiesta
SOAP 1.1 deve essere impostata text/xml;
- setRequestBody().
Imposta la stringa da utilizzare come corpo della
richiesta;
- execute().
Esegue la richiesta, utilizzando un oggetto HttpState,
che consente anche di eseguire una serie di richieste
collegate tra loro;
- getResponseBody().
Ritorna una stringa con la risposta ottenuta dal Web
Server.
8. Come posso inviare e ricevere allegati
binari?
La specifica SOAP w/attachments, supportata sia da JAXM
che da JAX-RPC, consente di inviare allegati binari
a messaggi SOAP, utilizzando il protocollo MIME. Questa
funzionalità può essere impiegata ad esempio
per implementare un servizio di memorizzazione di immagini,
dove il messaggio SOAP indica i metadati sull'immagine
da inserire e l'allegato binario definisce l'immagine
da memorizzare; un'altra possibilità è
quella di passare certificati digitali binari al fine
di eseguire una comunicazione dove il client sia certificato.
Ad ogni modo, in un messaggio con allegati inviato tramite
http, la prima parte MIME contiene il messaggio SOAP
vero e proprio, formattato in XML secondo le consuete
regole; le parti aggiuntive contengono i documenti binari
da inviare. Per allegare un documento è necessario
utilizzare il framework di Java per la gestione espandibile
di contenuti binari, il Java
Activation Framework. Di questo viene utilizzata
la classe DataHandler:
URL
url = new URL("file:///export/files/pic1.jpg");
DataHandler dataHandler = new DataHandler( url );
AttachmentPart att = message.createAttachmentPart( dataHandler
);
att.setContentId( "pic1" );
message.addAttachmentPart( att );
La classe AttachmentPart, parte di SAAJ, definisce
un singolo allegato. Un oggetto di questo tipo viene
creato dal metodo createAttachmentPart() della
classe Message, che si aspetta come parametro
l'oggetto DataHandler che punta al contenuto
binario da allegare. L'oggetto AttachmentPart
viene poi aggiunto al messaggio tramite il metodo addAttachmentPart().
9.
E se l'allegato binario non è un allegato MIME
ma è contenuto nel messaggio come blocco di dati
codificato (p.e. base64)?
Nella domanda precedente si è visto come allegare
contenuti binari ad un messaggio SOAP, secondo le specifiche
SOAP w/attachment. Alcune volte però, sorge la
necessità di interfacciare servizi Web che inviano
allegati binari all'interno del messaggio, magari
codificati in base64. Questa strada ha alcuni vantaggi,
come la semplicità di sviluppo e di debug e l'occupazione
di banda è sostanzialmente simile all'uso del
protocollo SOAP w/attachment, visto che l'uso di MIME
impone la codifica base64 degli allegati. Se un elemento
XML contiene un blocco di dati base64, è possibile
decodificarlo facilmente utilizzando Javamail.
Ad esempio, si consideri questo estratto del programma
Dilbert
Client:
e = (SOAPElement)childs.next();
InputStream is = MimeUtility.decode(new ByteArrayInputStream(
e.getValue().getBytes()
),"base64" );
L'oggetto ByteArrayInputStream crea un InputStream
a partire dal contenuto del SOAPElement e, che
contiene i dati in base64; il formato dei dati, insieme
allo stream, vengono passati al metodo MimeUtility.decode(),
presente nel package javax.mail.internet (deve
essere presente nel CLASSPATH il jar di Javamail).
Una volta ottenuto lo stream dei dati, è possibile
leggerlo e visualizzarlo, ad esempio con Swing, tramite
la classe JLabel. Nella porzione di codice successiva,
viene creato un semplice ciclo che legge le informazione
dal flusso decodificato e le inserisce in un altro flusso,
di tipo ByteArrayOutputStream. Questa classe
consente poi di ritornare le informazioni come un array
di byte, che può essere poi passato al costruttore
di ImageIcon, la classe Swing che implementa
una Icon attraverso una immagine in un formato
riconosciuto dal sistema (come gif o jpeg):
ByteArrayOutputStream
imageFile = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
while( true ) {
int size = is.read( buf );
if( size == -1 )
break;
imageFile.write( buf, 0, size );
}
label.setText("");
label.setIcon( new ImageIcon( imageFile.toByteArray()
) );
10.
Devo implementare una soluzione per il problema X, ma
quale standard scelgo?
Al posto della X si può inserire: sicurezza,
transazioni, prestazioni, gestione... ed altro! Sono
diversi gli aspetti per cui non si è ancora giunti
ad un accordo sulle specifiche, o meglio, sono presenti
più specifiche per risolvere lo stesso problema.
Si consideri la sicurezza: esistono, tra le altre, le
specifiche WS-Security e SAML. La prima è supportata
da OASIS, ed è basata su standard di mercato,
come HTTPS, SSL e X.509, ma richiederebbe specifiche
di routing, per ora solo affrontate da standard creati
da Microsoft e non condivisi con altri; SAML è
invece una creazione di SUN, donata sempre ad OASIS
e si basa su un concetto di asserzioni e di autorità
che ne consentono o negano la validità.
Sulla scelta dello standard si possono prendere sostanzialmente
tre strade: utilizzare uno degli standard presenti,
inventarne uno nuovo, oppure non utilizzarne nessuno.
Probabilmente la scelta strategicamente migliore è
la prima: applicare uno standard esistente consente
di risparmiare i tempi di sviluppo di specifiche alternative,
e poi esiste una possibilità che lo standard
adottato diventi in futuro quello di riferimento; utilizzando
una specifica esistente, è anche possibile che
produttori di software mettano a disposizione degli
strumenti di supporto, oppure che il mondo dell'open
source realizzi qualcosa al riguardo. Creare un proprio
standard in certi casi può portare ad un risparmio
immediato in termini di tempi di sviluppo, ma questo
è in funzione della complessità del problema!
In molti casi, studiare il materiale esistente ed applicarlo,
risulta in un tempo inferiore a quello necessario ad
ideare una nuova soluzione.
Conclusioni
In questo articolo sono state riportate alcune domande
frequenti sulle tecnologie Java che ruotano attorno
ai servizi Web, con le relative risposte. Avete ancora
dei dubbi? Provate a postarli sul forum
di Mokabyte! Forse qualcuno ha già trovato la
risposta che cercate, e magari l'argomento di discussione
potrebbe evolvere in un nuovo articolo.
Webliografia
e riferiementi
[1] Bigatti -"Corso di Web Services, parte
III: JAXM e SAAJ", http://www.mokabyte.it/2003/04/jws-3.htm
[2] Bigatti -"Corso di Web Services, parte V:
JAX-RPC", http://www.mokabyte.it/2003/06/jws-5.htm
[3] Bigatti - "Using XPath with SOAP", http://webservices.xml.com/pub/a/ws/2003/09/16/jaxen.html
|