Gli Handler sono uno strumento molto utile soprattutto per 2 scenari: compensazione dei fault e integrazione con altri sistemi. In questo articolo vedremo come si implementano usando la piattaforma Open Source per i Web Services offerta da Sun.
Gli Handler
Un Handler per i Web Services è un componente software in grado di eseguire operazioni a ogni richiesta, risposta o fault. Anche se non esiste un vero limite alle operazioni svolte dagli Handler, essi in genere, visto il punto in cui intervengono, eseguono i seguenti tipi di attività:
- tracciamento di richieste e risposte
- modifica della richiesta, della risposta o del fault
- modifica dei dati contenuti nel contesto dei Web Services
- compensazione dei fault
Esiste inoltre un’altra categoria di Handler che viene usata per problematiche legate alla sicurezza ma non verranno trattati in questo articolo.
Contesto di applicazione
Le attività indicate per gli Handler sono riconducibili a due scenari molto importanti: l’integrazione e la compensazione di eventuali errori.
In effetti l’uso massiccio dei Web Services è strettamente legato all’evoluzione delle applicazioni verso modelli architetturali di tipo SOA.In questi modelli l’applicazione o il sistema informativo è composto da un insieme di servizi completamente separati tra loro (e a volte gestiti da organizzazioni diverse) e quindi può essere necessario implementare attività di monitoring per riuscire a seguire i flussi delle singole richieste. In questo caso l’uso di un Handler è una opzione importante poiche‘ consente di tracciare le richieste e le risposte dei singoli servizi e quindi verificare, in caso di errore, quale di questi non ha funzionato correttamente.
Anche la possibilità di modificare la richiesta, la risposta o il fault si sposa molto bene con gli scenari di integrazione. Questa funzionalità può essere usata, per esempio, per arricchire il messaggio di tutte le informazioni opzionali con dei dati di default.
Inoltre è possibile ricavare delle informazioni infrastrutturali che non si vogliono esporre direttamente nella firma del servizio, ma che possono essere dedotte in qualche modo e passate al servizio, per esempio, tramite il MessageContext.
Infine possiamo invocare altri servizi o compensare eventuali condizioni di errore.
Questa possibilità consente di creare dei sistemi basati sul paradigma ad eventi in modo tale da iniziare determinate attività solo in corrispondenza di richieste specifiche.
Questo tipo di responsabilità vengono facilmente collocate all’interno di un Handler perch� esso può lavorare in modo trasversale a tutti i servizi e lo può fare sia durante la richiesta che durante la risposta.
Come si implementa un Handler
Un Handler è una normale classe Java che può estendere una delle seguenti interfacce:
javax.xml.ws.handler.soap.SOAPHandler javax.xml.ws.handler.LogicalHandler
Ecco un esempio di handler che estende l’interfaccia LogicalHandler:
public class MyLogicaHandler implements LogicalHandler { public boolean handleFault(LogicalMessageContext ctx) { // Something to do ... return true; } public boolean handleMessage(LogicalMessageContext ctx) { Boolean direction = (Boolean) ctx.get( LogicalMessageContext.MESSAGE_OUTBOUND_PROPERTY); // Something to do ... return true; } public void close(MessageContext arg0) { // nothing to do. } }
Ed ecco un esempio di handler che estende l’interfaccia SOAPHandler:
public class MySoapHandler implements SOAPHandler { public void close(MessageContext arg0) { } public Set getHeaders() { return null; } public boolean handleFault(SOAPMessageContext ctx) { return true; } public boolean handleMessage(SOAPMessageContext ctx) { // Something to do ... return true; } }
Se si utilizza SOAPHandler si avrà un accesso completo al messaggio soap, compresi gli header, mentre LogicalHandler si astrae dal protocollo utilizzato e può accedere al payload del messaggio.
Come si può vedere l’implementazione del Handler nei due casi differisce solo per il tipo di contesto utilizzato, il quale fornisce appunto le funzionalità citate in precedenza.
Da notare, inoltre, che i due metodi principali (handleMessage e handleFault) ritornano un boolean, il quale condiziona la logica del metodo stesso, infatti se il valore ritornato è true allora il processo continua, mentre se è false allora il processo viene bloccatoPer esempio, se vogliamo bloccare tutti i fault allora nel metodo handleFault ritorneremo false e di conseguenza il client (in caso di eccezione) non vedrà arrivare nessuna risposta.
Il metodo handleMessage è in grado di gestire sia le richieste che le risposte verificando tramite il MessageContext la “direzione” del messaggio (inbound o outbound).
Una volta ottenuto il messaggio è quindi possibile applicare qualsiasi tipo di trasformazione o interagire con qualsiasi altro componente per passare informazioni o iniziare attività collaterali.
Come applicare un Handler a un Web Service
Una volta definito l’Handler è necessario indicare a quali servizi applicarlo.
È possibile fare questa operazione sia dentro le classi Java tramite una normale annotazione che tramite un file di configurazione.
Uso dell’annotazione
Tra le annotazioni previste dallo standard [JSR 181] ne esiste una chiamata @HandlerChain la quale accetta 2 parametri: file e name (opzionale), dove file rappresenta il percorso in cui trovare il file di configurazione degli Handler e name rappresenta il nome dell’HandlerChain da applicare al servizio.
@WebService @HandlerChain(file="handlers.xml") public class MyServiceImpl {} // ... }
Il file indicato deve quindi contenere la “catena” degli handler da applicare secondo un file di definizione standard simile al seguente.
MySoapHandler
Naturalmente è possibile indicare più Handler, i quali verranno applicati nell’ordine di definizione.
Uso degli Handler in SUN Metro
Nel caso si utilizzi come Runtime Web Services Metro (si veda [JAXWS)] allora possiamo indicare gli Handler anche usando il suo specifico file di configurazione chiamato sun-jaxws.xml (vedere [Moka127]).
Questo file indica quali sono gli Endpoint (cioè i servizi) da pubblicare e quali sono gli Handler da applicare ad ognuno di essi.
<endpoint name='moka-ws' implementation='it.mokabyte.MyWSImpl' url-pattern='/'> MySoapHandler
L’uso di questo file ci consente di non inserire delle annotazioni all’interno del codice e quindi di applicare gli Handler semplicemente tramite una configurazione centralizzata senza ricorrere a modifiche dentro al codice sorgente.
Conclusioni
In questo articolo abbiamo visto che gli Handler sono dei componenti che possono essere implementati tramite una normale classe Java che estende una interfaccia nota e un file di configurazione.
Questo è un approccio classico nel mondo Java e Java EE in particolare per cui tutti gli sviluppatori dovrebbero trovarsi a proprio agio con questa procedura.
Abbiamo poi capito a cosa servono: grazie alla loro grande flessibilità infatti sono molto utili in scenari di integrazione, monitoring e compensazione.
Attività importantissime in particolare se correlate a elementi architetturali come i Web Services che sono quasi sempre stateless e fortemente separati tra loro.
Possiamo quindi concludere dicendo che gli Handler sono molto utili e che devono far parte della pila delle conoscenze di uno sviluppatore Java moderno.
Abbiamo infine visto che l’introduzione del Runtime di sun (Metro/Wsit) non complica lo sviluppo in modo inutile, ma anzi fornisce la possibilità di centralizzare la configurazione degli Handler nel file in cui si configurano gli Endpoint stessi evitando così di disperdere l’informazione in più punti.
Note
Nel precedente articolo su MokaByte [Moka127] è stato presentato un progetto in cui si sviluppano dei Web Services usando Metro.
La presentazione degli Handler è la naturale continuazione di quel articolo e quindi per poter creare un progetto in cui inserire un componente di questo tipo è sufficiente utilizzare quello precedentemente descritto senza particolare accorgimenti.
La struttura delle directory e i target Ant rimangono invariati e le librerie incluse sono sufficienti a sviluppare dei semplici servizi con un Handler, per esempio, che traccia richiesta, risposta ed eventuali eccezioni.
Riferimenti
[Moka127] Web Services con Java5: La nuova piattaforma JAXWS – WSIT – I parte
https://www.mokabyte.it/cms/iconservlet?articleId=8LB-HV5-AXM-UTT_7f000001_33280598_8a400966
[WSI] WSI Organisation home page
http://www.ws-i.org/
[JAXWS] JAXWS Metro Home page
https://jax-ws.dev.java.net/
[NB] Building JAX-WS 2.0 Services with NetBeans 5.0
http://www.netbeans.org/kb/50/jaxws20.html
[JSR 181]
http://jcp.org/en/jsr/detail?id=181