Il Direct Web Remoting (DWR) è un framework Ajax per Java/JSP che permette di sfruttare la potenza di Java per le applicazioni Web. DWR fa parte del livello degli strumenti nati per aiutare lo sviluppatore nella realizzazione di un‘invocazione remota. In questo livello risiedono i framework che permettono di accoppiare metodi JavaScript con servizi offerti dal server fornendo l‘impressione che il codice JavaScript lato client acceda direttamente agli oggetti presenti sul server.
Introduzione
Come già abbiamo avuto modo di notare nel precedente articolo, l’individuazione di elementi comuni nelle soluzioni Ajax ha dato origine a diversi framework che hanno lo scopo di consentire lo sviluppo rapido di applicazioni Ajax, liberando lo sviluppatore dalla programmazione della comunicazione client-server a basso livello. In questo articolo trattiamo DWR che fa appunto parte di una serie di framework noti come framework di invocazione remota. Questo significa che il framework è responsabile per la generazione di codice JavaScript lato client che astrae la comunicazione XMLHttp, il passaggio dei parametri e la gestione della risposta [1]. Ci sono framework per la maggior parte delle tecnologie server: noi ci occuperemo di DWR, il framework per il mondo Java.
I livelli degli strumenti Ajax
Gli strumenti (librerie, framework, tool, IDE) che sono nati e si stanno evolvendo in quest’ultimo periodo si posso dividere in livelli come mostrato nella figura 1.
Figura 1 – I livelli di Ajax
Nell’articolo precedente abbiamo trattato una libreria del livello di interfaccia utente cioè Prototype e Script.aculo.us. In questo articolo ci occuperemo invece di una libreria del livello di invocazione remota.
Analizziamo innanzitutto quelle che sono le diverse caratteristiche delle librerie che appartengono a questi due differenti livelli.
Per quanto riguarda le librerie a livello di interfaccia utente esse sono indipendenti dalla tecnologia lato server, per cui non si preoccupano se sul backend ci sono applicazioni Java EE, .Net, PHP, Ruby on Rayls, etc… Inoltre possono essere utilizzate combinandole tra di loro in un’unica applicazione nel caso si vogliano utilizzare widget e utility appartenenti a diverse librerie.
Tali librerie possono essere usate per nascondere le operazioni di basso livello dell’oggetto XMLHttpRequest e quindi realizzare quelle che sono le tipiche funzionalità Ajax già descritte nel primo articolo della serie. Un altro aspetto di cui queste librerie si occupano è la gestione delle incompatibilità tra browser e in più abilitano il pulsante di avanti/indietro che invece viene disabilitato dall’utilizzo puro e semplice dell’oggetto XMLHttpRequest. Ci sono poi altri vantaggi e funzionalità offerti da queste librerie ma ora non ci interessa elencarli uno ad uno.
Passiamo invece a trattare quelle che sono le caratteristiche delle librerie che appartengono all’altro livello introdotto in precedenza, il livello degli strumenti di invocazione remota o livello degli strumenti Ajax basati su proxy. Queste librerie hanno caratteristiche simili agli schemi generali della comunicazione RPC e nello stesso tempo permettono una sintassi di tipo RMI nella parte client attraverso codice JavaScript. Esempi di queste librerie sono :
- DWR (Direct Web Remoting): pensata specificatamente per applicazioni Java al back-end;
- JSON-RPC dove JSON sta per JavaScript Object Notation che è un formato aperto che descrive come rappresentare testualmente gli oggetti JavaScript che possono essere così facilmente creati e analizzati. In altre parole, è possibile inviare dati al browser codificandoli come JSON anziche‘ come XML e poi convertirli facilmente in oggetti JavaScript.
In questo articolo prenderemo in analisi DWR e mostreremo un esempio di come utilizzarlo per realizzare una semplice applicazione Ajax.
Uno dei problemi che si incontrano inserendo della logica applicativa sul lato client dell’applicazione web è che probabilmente questa è legata al server ed è scritta in un particolare linguaggio di programmazione (difficilmente sarà JavaScript lato server…). Come si può accedere a questa logica dall’ambiente cliente scritto in JavaScript?
È senza dubbio possibile creare alcuni punti di ingresso ad hoc nell’applicazione, ma sarebbe comodo poter semplicemente richiamare il codice lato server dal client tramite JavaScript. Per fare questo ci si serve appunto di quelli che sono gli strumenti appartenenti al livello di invocazione remota che vengono anche chiamati strumenti basati su proxy perche‘ in sostanza si tratta di framework che consentono di invocare direttamente della logica che si trova sul server dal codice JavaScript, rendendo naturali e indipendenti le invocazioni di codice server dal client[3].
DWR è una libreria Java e JavaScript open source che permette di scrivere applicazioni Web Ajax nascondendo la gestione basso livello dell’oggetto XMLHttpRequest e che si differenzia dalle altre librerie proprio per la sua naturale predisposizione e integrazione con Java (è stata pensata strutturalmente per la tecnologia Java: il suo motto è “easy Ajax for Java”) e per la sua semplicità di configurazione.
Come già introdotto, appartenendo al livello di invocazione remota, permette di utilizzare codice JavaScript in un browser per chiamare metodi Java che vengono eseguiti su un web server proprio come se fossero nel browser: ed è per questo che è chiamata Direct Remoting.
Senza una libreria del livello di invocazione remota è necessario creare molti endpoint nell’applicazione Web, le servlet, che devono essere indirizzate attraverso un URI e in molti casi non è pratico. Ad esempio se in una classe ci sono diversi metodi che si vogliono invocare dal browser ciascun metodo deve essere indirizzato attraverso un URI se si utilizzano o l’oggetto XMLHttpRequest direttamente, oppure una qualsiasi libreria client side. Inoltre, una volta risolto questo primo punto, rimane la necessità di mappare i parametri e i valori di ritorno per l’output HTML. DWR gestisce tutto questo per noi fornendo in più anche qualche utility interessante in JavaScript.
Figura 2 – DWR in dettaglio
Come funziona DWR
Pensiamo di avere una classe Java nel back-end che si chiama AjaxService e che ha un metodo getOptions().
Sul client, possiamo scrivere il codice JavaScript in cui viene invocato il metodo getOptions() della classe AjaxService servendosi di una sintassi molto simile alla sintassi RMI:
AjaxService.getOption(populateList)
Ora l’unica differenza consiste nel fatto che il metodo getOption() sul server non ha alcun parametro mentre quello sul client ne richiede uno, in questo caso “populateList”.
Questo parametro in più è una funzione di callback che sarà invocata in modo asincrono; e questo, ad eccezione della funzione di callback, rende molto simile questa sintassi alla sintassi tipica di una chiamata RMI.
DWR è composta da due parti:
- una servlet Java che viene fornita a run time da DWR eseguita lato server che processa le richieste DWR e invia le risposte al browser;
- JavaScript che viene inserito nel browser e che invia le richieste e può aggiornare dinamicamente la pagina.
DWR dinamicamente genera una classe JavaScript client side da una classe Java sul back end. Questo perche‘ DWR permette di scrivere codice JavaScript che assomiglia al convenzionale codice RMI, che è molto più intuitivo che scrivere righe di codice JavaScript.
La classe generata da DWR gestisce i dettagli remoti tra il browser e il back end sul server. Per dettagli remoti si intende la gestione della comunicazione asincrona attraverso l’uso dell’oggetto XMLHttpRequest e l’invocazione della funzione di callback lato client. La funzione di callback deve essere fornita da noi. I dettagli remoti includono anche la conversione di tutti i parametri e di tutti i valori di ritorno tra il client e il codice Java sul back end.
Come aggiungere una servlet DWR ad un progetto
DWR è distribuito in due differenti formati: come file JAR e come file WAR. Il file JAR contiene tutti i file necessari per utilizzare DWR nelle applicazioni web. Il file WAR aggiunge, rispetto al JAR, alcuni esempi su come utilizzare DWR incluso un esempio di web.xml, che è possibile copiare e utilizzare nelle proprie applicazioni web. Innanzitutto bisogna inserire il file JAR all’interno della propria applicazione web all’interno della directory WEB-INF/lib, e aggiungere le seguenti righe al proprio file web.xml
dwr-invoker
uk.ltd.getahead.dwr.DWRServlet
debug
true
dwr-invoker
/dwr/*
Una volta aggiunta la servlet di DWR a web.xml, si può distribuire l’applicazione e accedere alla servlet di DWR. È possibile verificare che DWR sia installato correttamente visitando la pagina http://localhost[:port]/[webapp]/DWR/. Apparirà una semplice pagina web simile a quella in figura 3.
Figura 3 – DWR pronto e funzionante
Come creare un file di configurazione DWR
Come abbiamo già detto DWR consente di invocare metodi di oggetti che sono nell’ambiente server. Esistono diverse opzioni per regolare la modalità con cui DWR consente questa invocazione. Potete utilizzare DWR per consentire al codice JavaScript di creare istanze di oggetti(e renderli persistenti tra le richieste memorizzandole nella sessione o nel contesto dell’applicazione) oppure per accedere a oggetti già esistenti o a oggetti di framework di gestione come Spring [4].
Fortunatamente, DWR impone alcune restrizioni per consentire che il tutto avvenga tenendo bene in considerazione la sicurezza. Prima di tutto occorre esporre esplicitamente le classi con cui DWR è autorizzato a interagire. Secondo, sebbene attraverso DWR sia possibile convertire un qualsiasi JavaBean in un oggetto JavaScript, il comportamento predefinito prevede solo la conversione dei tipi base di Java in tipi JavaScript; occorre dichiarare esplicitamente i tipi aggiuntivi che DWR deve convertire quando restituisce i risultati derivanti dall’invocazione di un metodo.
Tutte queste opzioni sono impostate nel file di configurazione di DWR, dwr.xml, che si trova nella directory WEB-INF dell’applicazione web.
"-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN"
"http://www.getahead.ltd.uk/dwr/dwr10.dtd">
L’elemento radice,
Questa è la configurazione di cui abbiamo bisogno per fare in modo che it.imolinfo.dwr.Validator e tutti i suoi metodi siano accessibili dal codice JavaScript. Il valore dell’attributo javascript, JValidator, dichiara che l’oggetto proxy JavaScript che gestirà l’accesso della classe Validator sarà chiamato JValidator. Questa classe fornirà un metodo in grado di validare una stringa che rappresenta una data.
Per completezza viene riportato il codice sorgente della classe Validator.java
package it.imolinfo.dwr;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class Validator {
public String validateDate(String date){
String message="La data inserita è valida"";
if (date != null){
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
try{
formatter.parse(date);
}catch(ParseException pe){
System.out.println(pe.toString());
message= "La data inserita non è valida";
}
}else{
message = "La data inserita è valida";
}
return message;
}
}
La cosa importante di questo codice è che il metodo, validateDate() riceve una stringa contenente una data e restituisce il messaggio adeguato a seconda che la data ricevuta sia o meno corretta a seguito della validazione effettuata. Ora rimane da vedere il codice JavaScript che utilizzerà DWR per comunicare con Validator.
Il codice JavaScript e l’HTML
È molto semplice creare una pagina web che incorpora il JavaScript DWR per utilizzare Ajax seguendo un approccio basato su proxy. Il sorgente che segue mostra una semplice pagina web che utilizzeremo come interfaccia per validare un campo contenente una data di nascita:
Usare Ajax per validare una data
Esempio di validazione Ajax
Data di nascita:
Per aggiungere DWR alla pagina inseriremo lo script JavaScript all’interno della sezione
della stessa poi scriveremo del semplice codice per interagire con la classe Validator che si trova lato server
From DWR Demo
La chiamata Validator.validateDate(value, dateCallback); assomiglia a una normale invocazione Java. DWR rende naturale l’utilizzo del codice Java in JavaScript. Come si può notare, ora passiamo due argomenti mentre il metodo Java ne richiedeva solo uno. Il secondo argomento è un riferimento alla callback. Poiche‘ DWR esegue chiamate Ajax asincrone, dobbiamo fornire una funzione da invocare quando viene ricevuta la risposta alla nostra richiesta. Alla funzione di callback, in questo caso dateCallback(), verrà passata una stringa che contiene la risposta. Tutto ciò che resta da fare è inserire un punto in cui venga invocata la funzione validateDate(). Questa funzione viene invocata ogni volta che il campo birthDate cambia il suo valore. L’HTML è il seguente:
La figura 4 mostra quanto realizzato in azione: quando birthDate cambia valore, DWR lo passa alla classe Validator sul server, la quale restituisce il messaggio appropriato indicando che la data inserita è valida se si è effettivamente inserita una stringa corretta, altrimenti restituisce il messaggio di errore per una stringa contenente una data non valida.
Figura 4 – Esempio di validazione di una data con DWR
Come abbiamo visto, DWR è interessante perche‘ astrae la complessità Ajax sottostante nascondendola dietro una facciata che rende indistinguibili le chiamate agli oggetti Java. Questo rende “familiare” il codice lato client, e più importante ancora, lo rende lineare per lo sviluppatore e il suo gruppo. DWR è il framework Ajax di riferimento per gli sviluppatori Spring [4] e sta diventando rapidamente un’alternativa open source per lo sviluppo di applicazioni Java EE.
Conclusioni
DWR è un ottimo punto di partenza per sviluppatori di applicazioni Web, poiche‘ espone la logica del server in modo intuitivo al codice del client. Tuttavia, al momento, DWR offre un aiuto limitato nell’utilizzo delle informazioni restituite nell’interfaccia utente, essendo strettamente collegato alle problematiche di invocazione remota, Per ottenere effetti interessanti di interfaccia utente dobbiamo scrivere codice JavaScript oppure, meglio, utilizzare quelle librerie di livello interfaccia che abbiamo visto nel precedente articolo (Prototype e Script.aculo.us). D’altro canto DWR rende semplice il recupero delle informazioni, consentendo agli sviluppatori di concentrare le proprie energie sullo sviluppo dell’interfaccia.
Riferimenti
[1] DWR
http://getahead.org/dwr
[2] Nicholas C.Zakas, Jeremy McPeak, Joe Fawcett, “Ajax, guida per lo sviluppatore”, Hoepli 2006
[3] B.Galbraith, D.Almaer, J.Gethland, “Ajax, Guida completa”, rgb, 2006
[4] Spring
http://www.springframework.org/