Questo articolo continua la trattazione di ZK già fatta nella prima parte, riprende i concetti base su cui poggia l‘architettura di ZK e descrive l‘implementazione di un semplice “Hello World” applicando il pattern MVC per provare come ZK sia un ottimo strumento per scrivere siti web secondo le più moderne architetture per il web.
ZK è un Web Framework open source (LGPL) basato su componenti Ajax, scritto interamente in Java che permette di creare ricche interfacce grafiche per applicazioni web senza alcun bisogno di utilizzare il linguaggio JavaScript ne’ script Ajax. Non richiede numerosi file di configurazione, ne’ lunghi file XML per descrivere le interfacce grafiche, permette di accedere ai dati (e ai data base) con binding automatici [1] [2]. La parte centrale di ZK consiste in un meccanismo “event-driven” basato su oltre duecento componenti Ajax, e un linguaggio di mark-up (XUL/XHTML) usato per disegnare le interfacce grafiche.
Caratteristiche principali di ZK
Riprendiamo brevemente alcune delle caratteristiche principali di ZK già esposte nell’articolo precedente che useremo per implementare il programma “Hello World!”:
- definisce un linguaggio dichiarativo XML (ZUML) per le interfacce grafiche (View) che risulta essere estremamente intuitivo e molto meno prolisso del corrispondente linguaggio XML usato dallo standard JSF;
- è basato su lancio di eventi e sull’utilizzo di componenti: in questa maniera permette di utilizzare lo stesso modello di programmazione usato nelle applicazioni desktop anche per le applicazioni web;
- si integra in maniera trasparente con Spring, Spring Web Flow, Spring Security, JBoss Seam, JSP, JSF, Flash plugin, EJB;
- è server-centrico: questo vuol dire che tutti i componenti grafici vengono creati sul server e quindi permette una più facile comunicazione tra componenti direttamente sul lato server;
- le pagine ZUML si aggiornano automaticamente senza dover ricaricare il contesto del server;
- ZK Script: potete scrivere il codice di script che lega la parte business con la parte vista in qualsiasi linguaggio vogliate: Java, JRuby, Groovy, JavaScript ma anche Python e PHP.
Fatto questo doveroso riassunto, è ora di passare al nostro programma Hello World realizzato con ZK. Realizzeremo le varie parti che compongono il modello MVC: il model, la view, il controller. Partiamo dalla parte Vista, e successivamente vedremo Controller e Model.
Parte Vista: il linguaggio ZUML per la definizione e l’uso di componenti Ajax
Il linguaggio ZUML (XUL e XHTML) permette di definire complicate interfacce grafiche che rappresentano la “vista” dell’applicazione Web. Una pagina ZUML può essere integrata in una pagina XHTML, o JSF, o JSP. Il tag di apertura e chiusura (che la include dentro una pagina web) è
Ogni componente ZUML viene definito con un id univoco all’interno della stessa pagina: l’id è fondamentale per accedere al componente grafico nella parte Controller. Per iniziare vediamo di implementare il classico programma “Hello World!” in ZK. Per ora non servono nè la parte Controller ne’ la parte Model.
Definiamo una pagina web che contiene una finestra con una label “Hello World!”.
Come è possibile personalizzare una finestra? Ecco una serie di personalizzazioni possibili:
- ridimensionabile;
- chiudibile;
- modale o embedded;
- con o senza bordo e con o senza barra del titolo;
- con o senza CSS allegato che ne personalizza i colori e i font.
Creiamo quindi il file index.zul e scriviamo il minimo indispensabile:
width="200px" closable="true" sizable="true">
Hello World!
A questo punto non serve molto altro: basta creare un progetto web che generi un WAR (possiamo usare anche Maven: le librerie sono disponibili su ibiblio), registrare i listener di ZK all’interno del file web.xml (come faremmo con qualsiasi altro web framework) ed è già tutto pronto.
In allegato a questo articolo (menu in alto a sinistra) troverete il progetto helloworld: compilatelo con Maven e otterrete il seguente risultato:
Figura 1 – Ecco la pagina del progetto helloworld
Parte Controller: la definizione dei controlli grafici
ZK è un framework orientato agli eventi, quindi qualsiasi interazione dell’utente con l’interfaccia grafica genera un evento. Come si lanciano e catturano gli eventi? Aggiungiamo dei semplici controlli alla pagina index.zul per illustrare come si lavora con gli eventi.
Modifichiamo la pagina index.zul in una interfaccia che contenga:
- un text field dove l’utente inserisce un messaggio di saluto;
- un bottone che “pubblica” il saluto;
- una label che contiene sempre l’ultimo saluto scritto dell’utente.
Ecco come modifichiamo il vecchio file index.zul:
width="200px" closable="true" sizable="true">
Hello World Message:
Come si rendono effettive le modifiche della nuova vista? Non occorre ricompilare e ridistribuire il war su Tomcat come con altri web framework: con ZK è sufficiente ricaricare la pagina. Basta sostituire il vecchio index.zul con questo nuovo file direttamente nella directory webapps/helloworld di Tomcat e fare “refresh” sul browser; ZK si renderà subito conto che il file zul è stato cambiato e sostituirà quello vecchio con questo nuovo.
La sostituzione del nuovo file è istantanea, se leggete il log di Tomcat vi accorgerete di quanto è successo:
23-ago-2009 12.50.28 org.zkoss.util.resource.ResourceCache$Info isValid:212
INFO: Source is changed: /index.zul
E sul browser comparirà la nuova pagina:
Figura 2 – Il nuovo “Hello World!”
Adesso aggiungiamo la logica che permette di leggere il valore immesso nel text box e visualizzarlo sulla finestra.
Parte Controller: la definizione degli script per gli eventi
Una delle differenze più visibili di ZK con gli altri framework sta nella possibilità di utilizzare praticamente ogni linguaggio di programmazione per scrivere degli script di controllo per legare la vista dato che ZK è server-centrico (gli script vengono elaborati sul server).
Fate riferimento al precedente articolo della serie su ZK per approfondire il concetto di “framework server-centrico” e le differenze con i framework client-centrici come GWT o Echo2.
Torniamo adesso al progetto Hello World e completiamolo aggiungendo la gestione degli eventi per:
- agganciarci all’evento OnClick del bottone “Ok”;
- leggere il valore del text box;
- modificare il valore della label “lMessage”.
Utilizziamo il tipo di linguaggio “Java” e specifichiamolo nel tag
width="200px" closable="true"
sizable="true">
Hello World Message:
//@DECLARATION
public void ok_onclick() {
lMessage.setValue(txMessage.getValue());
}
Analogamente al passo precedente modifichiamo il file index.zul che già si trova nella cartella webapps di Tomcat ed effettuiamo il refresh dal browser; ed ecco la pagina web cambiata:
Figura 3 – Hello world con messaggio.
Dal semplice esempio riportato sopra abbiamo visto come sia possibile implementare comportamenti della vista che rispondono a eventi scatenati dall’utente direttamente sul file ZUL. Potete notare che in questo esempio non abbiamo ancora scritto una sola classe Java! Il codice Java che avete scritto sul file ZUL viene interpretato a run time tramite la libreria BeanShell.
Possiamo anche notare che il programma Hello World! ci porta a “impastare” assieme il codice XML della vista con il codice “procedurale” (diciamo così…) in Java. Sicuramente questa è una soluzione “veloce e sporca” che possiamo seguire in situazioni di emergenza, ma una caratteristica di ZK è che non esiste un solo modo per implementare una applicazione web: possiamo scegliere sia soluzioni “veloci e sporche” che soluzioni “eleganti e pulite”: dipende da come disegniamo l’architettura del nostro software.
Quindi implementiamo il pattern MVC per rimuovere completamente qualsiasi script di elaborazione di eventi dalle pagine ZUL e dimostrare come sia possibile realizzare siti web con ZK in modo semplice ed elegante.
Il pattern MVC con ZK
Con “Model” intendiamo sia le funzionalità di business che gli oggetti business, in pratica logica applicativa e relativi oggetti.
La parte “View” è un insieme di componenti grafici che compongono la pagina web (ZUL file) senza la logica di elaborazione degli eventi.
La parte “Controller” è una classe Java registrata su un EventListener di uno o più componenti che ha il compito di elaborare gli eventi lanciati dalla View.
Per ogni Window è possibile definire una classe java che ascolta gli eventi lanciati dal componente stesso: è sufficiente definire la propria classe Controller tramite l’attributo apply:
width="200px" closable="true" sizable="true">
...
Una classe controller deve implementare l’interfaccia org.zkoss.zk.ui.util.Composer. L’unico metodo che occorre implementare è doAfterCompose(Component) che viene chiamato dopo che ZK ha completamente costruito tutta l’interfaccia grafica. Per implementare il nostro Controller non utilizzeremo direttamente l’interfaccia, ma sarà opportuno utilizzare una classe di utilità che implementa l’interfaccia Composer; nella figura 4 è riportato tutta la gerarchia delle classi:
Figura 4 – Gerarchia dell’interfaccia Composer.
GenericAutowireComposer
Ci permette di accedere in modo trasparente a tutti i componenti grafici figli della window: ogni componente grafico ZUML corrisponde ad una classe Java figlia di Component.
Per utilizzare i componenti ZUML di Hello World! ci basterà dichiarare un campo con lo stesso nome dell’id del componente dichiarato nel file ZUL e ZK inietterà l’oggetto grafico dopo aver chiamato il metodo doAfterComposer().
Ecco come accedere alla Label lMessage e al textbox txMessage:
package org.mokabyte.zk;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericAutowireComposer;
import org.zkoss.zul.Label;
import org.zkoss.zul.Textbox;
public class MyController extends GenericAutowireComposer {
protected Label lMessage;
protected Textbox txMessage;
}
Adesso scriviamo un metodo che cambia il valore testuale della Label lMessage:
public void changeMessage(Event event) {
String message = txMessage.getValue();
lMessage.setValue(message);
}
Come leghiamo il metodo changeMessage all’evento onClick del bottone okButton? Basta dichiarare il forward dell’evento onClick al metodo changeMessage del Controller:
Adesso possiamo levare il codice di script dal file ZUL: in questa maniera abbiamo pulito efficacemente la parte Vista e definito la parte Controller come classe Java che gestisce gli eventi e accede ai componenti della vista.
apply="org.mokabyte.zk.MyController" width="200px" closable="true"
sizable="true">
Hello World Message:
GenericForwardComposer
Ci permette di omettere la dichiarazione di forward degli eventi dal file ZUL utilizzando una nomenclatura prestabilita (ma configurabile) della classe GenericForwardComposer. Ogni evento viene intercettato da un metodo che si chiama nel seguente modo:
nomeEvento$nomeComponente(Event event)
Quindi cambiate il metodo changeMessage(Event event) in:
public void onClick$okButton(Event event) {
String message = txMessage.getValue();
lMessage.setValue(message);
}
E a questo punto possiamo cancellare la dichiarazione di forward nel file ZUL (se non la omettiamo l’evento verrà lanciato due volte).
Adesso il lavoro di “pulitura” della parte Controller e della parte Vista è terminata: la parte vista contiene solo la descrizione dei componenti grafici, mentre la parte Controller contiene solo la definizione degli eventi da intercettare e le procedure da attivare. L’allegato helloworld2 contiene l’esempio appena descritto.
Manca ancora la parte Model: come agganciarci alla parte business, magari gestita da Spring? Qui ci viene in aiuto ZK che ci permette di accedere al contesto di Spring allo stesso modo come si accede a un qualsiasi altro componente grafico. La stessa procedura è applicabile se invece di scegliere Spring preferiamo integrarci con una architettura basata sullo standard degli EJB.
Nei riferimenti bibliografici ho riportato un articolo sull’integrazione di ZK con i prodotti Java EE di RedHat [4] e un breve tutorial [5] su come integrare ZK con una architettura basata su EJB.
La parte Model: come utilizzare servizi business via Spring
La parte Model ci permetterà di utilizzare delle interfacce business gestite da un contesto Java EE che magari possono accedere a un database per effettuare operazioni complicate richieste dall’utente.
Aggiungiamo alla nostra applicazione il listener di Spring nel file web.xml:
contextConfigLocation
/WEB-INF/classes/applicationContext.xml
org.springframework.
web.context.ContextLoaderListener
Definiamo un semplice servizio Spring che effettua una elaborazione sul messaggio di saluto immesso dall’utente:
package org.mokabyte.zk;
public class HelloService implements IHelloService{
public String processMessage(String message) {
return "Ecco il messaggio: " + message;
}
In questo semplice esempio il servizio HelloService non fa nulla di complicato: aggiunge solamente un messaggio di saluto; ma in una applicazione reale possiamo legare il servizio a un catalogo che accede via JPA a un database e questo meccanismo è completamente trasparente all’intero modulo che implementa le pagine web.
Grazie all’integrazione con Spring (ma lo stesso discorso si fa con gli EJB) riusciamo a disaccoppiare elegantemente la parte modulare che implementa le interfacce grafiche (Web 2.0) e la parte modulare che implementa la business logic.
Adesso leghiamo il bean “helloService” al Controller MyController [3]. Basta dichiarare un elemento della classe MyController che si chiami esattamente “helloService” (Autowiring by name):
package org.mokabyte.zk;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.util.GenericForwardComposer;
import org.zkoss.zul.Label;
import org.zkoss.zul.Textbox;
public class MyController extends GenericForwardComposer {
//Valorizzato automaticamente, senza definire get/set
protected IHelloService helloService;
protected Label lMessage;
protected Textbox txMessage;
public void onClick$okButton(Event event) {
String message = txMessage.getValue();
lMessage.setValue(helloService.processMessage(message));
}
}
Adesso installiamo il DelegatingVariableResolver per Spring sulla window corrispondente.
Ecco come diventa il file index.zul:
apply="org.mokabyte.zk.MyController" width="200px" closable="true"
sizable="true">
Hello World Message:
Allegato all’articolo troverete il progetto definitivo dell’Hello World!
Adesso il progetto Hello World! rispetta una classica architettura web Java EE a 3 strati:
- Strato View: è composto da componenti grafici di pagine web definite tramite un linguaggio dichiarativo (ZUML);
- Strato Controller: è composto da classi Java che catturano gli eventi dell’utente scatenati sull’interfaccia grafica e la modificano dinamicamente via Ajax;
- Strato Model: è composto da servizi business (e dalle classi entità che formano il nostro dominio) che effettuano le operazioni richieste dal controller (via Spring o EJB).
Nonostante la sua semplicità, la piccola applicazione Hello World! che abbiamo scritto dimostra come implementare in modo elegante il pattern MVC in ZK.
Inoltre dimostra che le applicazioni web 2.0 basate su ZK possono essere implementate in modo estremamente veloce: la quantità di codice scritta per implementare il progetto è molto bassa e divisa in moduli indipendenti tra loro (legati da interfacce, come IHelloService); inoltre ZK risulta non essere invasivo ed è presente solamente nelle classi di raccordo tra i servizi business e la vista scritta in file XHTML.
Conclusioni
Questi articoli introduttivi hanno inteso dimostrare come ZK sia un ottima alternativa a framework più conosciuti come JSF o GWT, permette di scrivere pagine web con poco codice, elegantemente e senza utilizzare JavaScript. Riprende parecchi concetti delle JSF (sono molte le similitudini) ma li implementa in modo più semplice e diretto permettendo di usare un solo linguaggio di programmazione: Java. Pur essendo nato come server-centrico, dalla nuova versione 5 (ancora in beta) sarà anche client-centrico (server+client fusion [6]) includendo una nuova libreria JavaScript.
In definitiva ZK è un robusto e maturo framework direct RIA che apporta i seguenti benefici:
- veloce prototipazione;
- ricchi componenti grafici;
- apprendimento veloce e facile;
- aggiornamento automatico della vista (file ZUL);
- comunicazioni sicure;
- nessuna necessità di scrivere codice che accede ai dati (live data);
- manutenzione minima.
ZK ha inoltre un numero elevato di caratteristiche quali il binding automatico di liste di oggetti; se aggiungiamo poi i tanti componenti già pronti all’uso come un ottimo Calendario, SpreadSheet di Excel, Gmaps, Captcha, JasperReports, SMILE Timeline e Timeplot, Wikipedia, e tanti altri, ci rendiamo conto del valore di questo strumento.
Con la sua capacità di supportare tutti i maggiori browser, di poter essere utilizzato con Java ME Phones, Google Android, BlackBerry, i suoi 3 anni di vita, oltre 1.000.000 di download, dozzine di clienti che fanno parte di “Fortune 500”, ZK si candida a essere uno dei prodotti più innovativi nel mondo delle applicazioni RIA che merita sicuramente attenzione e studio.
Riferimenti
[1] Henri Chen – Robbie Cheng, “ZK: Ajax without the Javascript Framework”, Apress Com, 2007, ISBN10: 1-59059-901-2
http://www.apress.com/book/view/1590599012
[2] ZK team, “ZK Home Page”
[3] Simon Massey, “ZK With Spring JPA And A Model-View-Controller Pattern”, 2008
http://www.zkoss.org/smalltalks/mvc4/
[4] Integrazione di ZK con i prodotti di RedHat: Seam, JBoss EJB e JSF
[5] Tutorial per l’integrazione di ZK con JBoss
http://www.zkoss.org/smalltalks/jndi/
[6] Introduzione al nuovo ZK
http://www.zkoss.org/news/zk5.dsp