MokaByte 72- Marzo 2003  
JSP e Web User Interface
II parte: Java Server Faces
di
Lavinio Cerquetti
L'articolo di questo mese conclude la nostra analisi di Java Server Faces [1], il framework Java per la realizzazione di interfacce utente ad applicazioni Web e distribuite. In particolare, dopo averne esaminati nel numero precedente [2] obiettivi e motivazioni, porteremo a termine la presentazione dei componenti strutturali di JSF e ne sperimenteremo sul campo le possibilitÓ di integrazione, utilizzandolo per dotare NetView - la nostra applicazione Web di esempio - di un semplice pannello di configurazione. Per la massima comprensione dei contenuti che andremo a trattare si consiglia di fare frequente riferimento sia al precedente articolo [2] sia all'applicazione NetView, i cui sorgenti commentati sono liberamente disponibili e scaricabili dalla sezione Risorse del presente articolo.

Gli elementi di interfaccia utente lato client
Ogni 'modello di interazione' lato server, per poter venire effettivamente utilizzato, deve venire associato ad uno o più elementi di interfaccia utente, selezionati in base alle caratteristiche della piattaforma client e compatibili con lo schema di comportamento desiderato.
Tali gruppi di elementi GUI lato client vengono in gergo JSF denominati RenderKit e costituiscono, in ottica Model-View-Controller, i componenti view di JSF.
L'implementazione Early Access Release 2 di JSF - sulla quale sono basati i contenuti di questa serie articoli - fornisce un RenderKit in HTML standard, ed è ragionevole presumere che nuovi RenderKit verso ulteriori linguaggi di markup (XML, DHTML, light-HTML o WAP per dispositivi wireless) verranno realizzati da produttori indipendenti successivamente al rilascio definitivo di Java Server Faces.

Si noti che per ogni modello di interazione lato server possono esistere una o più rappresentazioni a livello di interfaccia utente, denominate Renderer. In ogni tag JSF vengono quindi specificati sia il modello di interazione lato server richiesto sia il Renderer desiderato. Questa separazione di ruoli permette di adattare facilmente la presentazione della Web UI alle caratteristiche della piattaforma client di fruizione e di mantenere effettivamente separati i compiti degli autori di componenti da quelli dei grafici Web e degli sviluppatori di applicazioni.

Il suddetto HTML RenderKit fornisce un numero estremamente ampio di componenti, in grado di realizzare tutti i modelli di interazione lato server precedentemente esaminati. Analizziamo i principali:

Si noti come il nome di ogni componente lato client identifichi in maniera univoca il modello di interazione lato server cui esso è associato.
La lista appena fornita, che rappresenta comunque un sottoinsieme dei componenti disponibili, è destinata ad espandersi in maniera significativa già a partire dall'imminente Early Access Release 3 di Java Server Faces, per la quale è previsto un congruo incremento dei componenti lato server (e, conseguentemente, di quelli lato client) con l'implementazione di funzionalità più generiche di input e di output, di rappresentazione di immagini e di selezioni multiple da un ventaglio di possibilità.
Una delle caratteristiche di maggiore interesse del framework Java Server Faces è inoltre dato dalla sua estensibilità: a partire dalla suddetta EA 3 verranno infatti documentate le API che permettono agli sviluppatori di estendere le funzionalità di JSF attraverso la modellazione di nuovi schemi di interazione lato server e la codifica dei corrispondenti componenti lato client.

 

I model object
Un elemento fondamentale dell'architettura Java Server Faces è dato da quegli oggetti cui spetta la responsabilità di modellare e gestire le informazioni di stato associate agli elementi di interfaccia. Tali oggetti, denominati model object in gergo JSF, vengono implementati come oggetti JavaBean.
Nell'attuale versione EA Release 2 di Java Server Faces la loro implementazione, peraltro tipicamente elementare e basata sui classici accessori getXXX() e setXXX(), è di responsabilità dello sviluppatore. Tale situazione è comunque destinata a mutare nei successivi rilasci di JSF, che saranno dotati di meccanismi evoluti di gestione e conversione dello stato associato ai componenti, ed in cui la codifica diretta di model object rappresenterà l'eccezione anziché la regola.
L'accoppiamento tra model object realizzati dallo sviluppatore e componenti di interfaccia è possibile nel rispetto dei relativi vincoli di type compatibility, riepilogati nella seguente tabella:


Rivestono poi un ruolo importante nel contesto dei model object e del loro dialogo con i diversi componenti di un'applicazione i meccanismi di validazione e di data conversion forniti da Java Server Faces.
Tale framework dispone infatti di strutture automatizzate rivolte alla validazione dello stato dei componenti prima ancora che esso venga notificato ai model object e basate su di un insieme standard di tag ed attributi, tramite i quali risulta possibile imporre vincoli precisi ai valori di input.

Le funzionalità predefinite di validazione sono rappresentate dai seguenti tag:

Il criterio di estensibilità che domina le specifiche di JSF si applica anche ai componenti di validazione e permette agli sviluppatori di definire nuovi criteri di verifica e controllo preventivo dei dati tramite l'implementazione di classi e tag appositi.

Discorso analogo vale per le funzionalità di conversione, intese come quei meccanismi che regolano il flusso dei dati tra model object e componenti di presentazione. Tipicamente i primi manterranno le informazioni di stato in oggetti semanticamente affini ai dati da modellare, mentre i secondi avranno l'esigenza di convertire - tanto in lettura quanto in scrittura - tali informazioni in formati di presentazione facilmente comprensibili e gestibili dall'utente.
Java Server Faces fornisce agli sviluppatori numerosi meccanismi automatici di conversione, tramite i quali risulta possibile delegare il processo di conversione tra view e model layer direttamente a JSF. In particolare sono supportate in maniera nativa le conversioni da e verso tipi numerici, java.util.Date, java.util.Time e java.util.DateTime a partire da stringhe formattate in logica java.text.DateFormat, java.text.TimeFormat e java.text.NumberFormat.
Per far fronte a necessità particolari JSF supporta infine la definizione ed implementazione di meccanismi di conversione ad hoc attraverso la codifica di appositi oggetti Converter.

 

L'oggetto ApplicationHandler e la gestione degli eventi
Nell'ottica del rispetto degli standard esistenti e della minimizzazione dei tempi di apprendimento, la gestione degli eventi in contesto JSF segue schemi già collaudati e familiari agli sviluppatori Java ed è basata sull'usuale combinazione di classi Listener ed Event.
In risposta alle azioni dell'utente i componenti generano degli eventi, dei quali un'applicazione Java Server Faces può venire notificata tramite la registrazione di adeguati oggetti Listener.
Il framework Java Server Faces conosce tre classi di eventi:

eventi di tipo value-changed: vengono generati all'atto della modifica dello stato di un componente di tipo UITextEntry, UISelectOne o UISelectBoolean e gestiti da oggetti di classe ValueChangedListener; un classico esempio è dato dalla selezione di una checkbox da parte di un utente;
eventi di tipo action: i componenti UICommand generano un evento di questa classe in seguito alla loro attivazione da parte dell'utente, tipicamente tramite un click su di un bottone o di un hyperlink; gli eventi di questa classe vengono gestiti da oggetti ActionListener;
eventi a livello di applicazione: sostanzialmente analoghi agli action event, vengono generati in seguito ad un'azione i cui effetti si applicano ad un intero albero di componenti. Un tipico esempio è dato dal click sul bottone submit di un form, che provoca l'aggiornamento dello stato di tutti i componenti innestati.

Particolarmente importanti sono gli eventi dell'ultimo tipo, i cui effetti si ripercuotono sull'intero stato dell'applicazione. Essendo per loro stessa natura 'globali', la gestione di tali eventi è delegata ad un'apposita classe singleton che implementa l'interfaccia javax.faces.lifecycle.ApplicationHandler.
Tale classe, componente necessario di ogni sistema software basato su Java Server Faces, ha il ruolo di recepire gli application event, di coordinarne l'impatto a livello globale - sincronizzandoli se necessario con lo stato dei componenti - e di gestire la navigazione dell'utente all'interno dell'applicazione.
Si noti che nel presente articolo, così come nell'applicazione d'esempio allegata, lo spazio riservato ai meccanismi di gestione degli eventi è volutamente limitato. Ciò è dovuto al fatto che, per quanto già decisa nelle sue generali linee semantiche, la relativa logica di gestione è ancora soggetta ad evoluzioni a livello sintattico.

 

Java Server Faces e NetView
Esaminati i componenti fondamentali e l'architettura generale di JSF siamo in grado di applicare le nostre nuove conoscenze ad un esempio pratico.
Supporremo infatti che il committente di NetView - la sempre più fantomatica multinazionale ACME - ci abbia richiesto di dotare la nostra Web Application di funzionalità di configurazione relative alla specifica di alcuni parametri globali che influenzano il comportamento dell'applicazione.
Il nostro cliente non manca di informarci del fatto che la quantità e complessità dei dati di configurazione è destinata ad evolversi fortemente nel tempo, così come lo spettro dei dispositivi client cui tali funzionalità dovranno risultare accessibili.
Alla luce di queste esigenze la scelta di Java Server Faces appare ben fondata: la sua completa estensibilità, il supporto per Renderer diversi e la futura integrazione con sistemi RAD di design e sviluppo di interfacce utente Web coprono in maniera soddisfacente tutte le aree funzionali che costituiscono dei fattori discriminanti per il nostro committente.
Implementeremo quindi il nostro form di configurazione tramite la Early Access Release 2 di Java Server Faces, il rilascio più aggiornato disponibile al momento della realizzazione del presente articolo. L'implementazione delle funzionalità richieste si articolerà su quattro punti principali:

  • l'integrazione delle funzionalità di configurazione all'interno di NetView;
  • la realizzazione dello strato view - ossia la Web UI - relativo al form di configurazione;
    l'implementazione dei model object delegati a rappresentare e modellare le informazioni di configurazione;
  • la codifica dell'oggetto ApplicationHandler - responsabile del trattamento degli eventi a livello di applicazione e della user navigation - e la gestione del suo ciclo di vita.

 

L'analisi del problema
Le attività di analisi legate alla richiesta del committente sono, in questo caso, piuttosto elementari e si limitano all'identificazione dei parametri di configurazione desiderati e dei rispettivi vincoli sintattici e semantici. In seguito alle usuali sessioni di analisi operate congiuntamente con il cliente emerge il bisogno di gestire le seguenti informazioni:

  • due descrizioni del sistema software NetView - la prima estremamente concisa, la seconda più dettagliata - adatte ad identificare l'applicazione in caso di gestione remota o di dialogo con servizi terzi; tali descrizioni sono semplicemente composte di caratteri alfanumerici;
  • una master password SNMP, utilizzata per la comunicazione con router e dispositivi di rete remoti; tale password non deve, ovviamente, risultare visibile agli utenti;
  • l'impostazione della modalità di log desiderata, che può essere delegata ad un demone esterno in protocollo syslog o venire eseguita direttamente da NetView su file XML ovvero database relazionali in formato SQL;
  • l'imposizione di un limite giornaliero di traffico, al superamento del quale si rende necessario contattare un amministratore di sistema; tale soglia non può comunque essere inferiore ai 100 MB giornalieri;
  • la selezione della modalità di notifica all'amministratore di una condizione di traffico eccessivo; le possibilità da supportare sono via E-mail, ICQ o SMS.

Tali informazioni verranno coagulate in una pagina JSF composta da un form, ad ogni elemento del quale corrisponderanno un parametro di configurazione ed una property del model object models.ConfigurationBean, in base alla seguente logica:

  • per le due descrizioni di NetView utilizzeremo rispettivamente i componenti textentry_input e textentry_textarea, vale a dire un campo di input single-line ed un'area di input multilinea;
  • rappresenteremo la password SNMP in un componente textentry_secret, che implementa in maniera nativa la semantica richiesta (campo di input single-line e no-echo);
  • modelleremo la modalità di log attraverso il componente selectone_radiogroup, il quale implementa la semantica della mutua esclusione dei valori possibili tramite un gruppo di bottoni radio;
  • l'input del limite giornaliero di traffico verrà gestito tramite un normale campo di input textentry_input; in questo caso sfrutteremo le funzionalità di validazione di Java Server Faces per impedire all'utente di proporre soglie di traffico inferiori al limite dei 100 MB giornalieri;
  • la selezione della notifica all'amministratore di sistema avverrà tramite il componente selectone_optionlist, tradotto dal Renderer in una drop-down listbox;
  • infine le informazioni testuali da fornire all'utente all'interno della pagina JSF verranno rappresentate da componenti output_text.

In un contesto reale alla gestione del form di configurazione si accompagnerebbe la codifica dei relativi comportamenti all'interno di NetView; nel nostro esempio, focalizzato unicamente sullo strato di interfaccia utente, tralasceremo tali attività implementative. Parimenti non ci porremo il problema della persistenza delle informazioni di configurazione, che verranno semplicemente mantenute nel model object deputato, andando perdute allo shutdown dell'applicazione.

 

Integrazione in NetView
Le scelte architetturali che caratterizzano la nostra applicazione si rivelano valide, e rendono triviale il problema dell'integrazione delle nuove funzionalità, la cui soluzione consiste nella definizione di una nuova azione "config" a livello di FrontControllerServlet e nella definizione di un dispatcher, ConfigDispatcher, la cui unica attività consiste nell'invocare la view "config.jsp" contenente la definizione della Web UI del form di configurazione in formato JSF.
Il secondo ed ultimo passo dell'integrazione in NetView delle nuove funzionalità consiste nella modifica del deployment descriptor secondo quanto richiesto dalle attuali specifiche Java Server Faces:

Definizione della classe listener NetViewServletContextListener, la cui funzione - come vedremo - consiste nel gestire il ciclo di vita dell'oggetto ApplicationHandler attraverso i seguenti tag:

<listener>
<listener-class>
NetViewServletContextListener
</listener-class>
</listener>

L'attivazione delle funzionalità Java Server Faces attraverso la dichiarazione del Faces Servlet e la sua assegnazione alle URL /faces/*:

<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>

La Web UI
L'interfaccia utente che implementa le funzionalità di configurazione richieste dal cliente è contenuta nella view "config.jsp", che passiamo ora ad analizzare in dettaglio.

Le pagine che utilizzano i componenti JSF dichiarano la rispettiva tag library con la seguente sintassi:

<%@ taglib prefix="faces"
uri="http://java.sun.com/j2ee/html_basic/" %>

Il model object models.ConfigurationBean associato ai componenti UI Java Server Faces utilizzati da NetView viene istanziato come un normale JavaBean tramite una direttiva useBean:

<jsp:useBean id="configurationBean"
class="models.ConfigurationBean" scope="session" />

Segue quindi l'apertura del tag <faces:usefaces>, chiuso al termine della view appena prima dell'inclusione di "bottombar.jsp"; all'interno di tale tag è possibile utilizzare liberamente i componenti JSF.

I nostri elementi di interfaccia JSF vengono raggruppati in un unico form, denominato "configForm" e dichiarato con la seguente sintassi:

<faces:form id="configForm" formName="configForm">

All'interno del form provvediamo ad emettere le necessarie informazioni testuali destinate all'utente con dei tag del tipo:

<faces:output_text id="titleMsg" text="Descrizione breve:"
key="titleMsg" />

Tali informazioni si sarebbero ovviamente potute presentare a video in maniera più diretta; tuttavia, codificando ogni messaggio in un apposito tag faces eseguiamo quell'attività di formalizzazione dell'output che ci permetterà in futuro di implementare con facilità sofisticate funzionalità di internazionalizzazione e localizzazione.

Passiamo quindi alla rappresentazione dei parametri di configurazione, che viene effettuata con la massima semplicità attraverso gli elementi di interfaccia utente selezionati in fase di analisi.

Le descrizioni di NetView vengono modellate come campi di input textentry_input e textentry_textarea. Si noti che, grazie all'esplicita associazione con le relative property dei model object, lo sviluppatore è completamente sgravato dal compito di gestire lo stato dell'applicazione Web. JSF sincronizzerà automaticamente componenti view e model object in risposta alle azioni dell'utente.

<faces:textentry_input id="appTitle" modelReference="${configurationBean.appTitle}" />

<faces:textentry_textarea id="appDesc" modelReference="${configurationBean.appDesc}" />

Va rilevato come la dichiarazione dell'attributo modelReference avvenga in sintassi JSTL: in effetti, qualora ce ne fossimo dimenticati, la Custom Tag Library Java Server Faces è completamente integrata con JSP e JSTL, e dal suo interno è possibile utilizzare tutta la potenza e flessibilità di questi due framework.

Per la password SNMP utilizziamo invece un campo di input textentry_secret:

<faces:textentry_secret id="snmpPassword"
modelReference="${configurationBean.snmpPassword}" />

La modalità di log viene presentata all'utente come un gruppo di bottoni radio:

<faces:selectone_radiogroup id="logMode"
modelReference="${configurationBean.logMode}">
<faces:selectitems id="logModesList"
modelReference="${configurationBean.logModesList}"/>
</faces:selectone_radiogroup>

Si noti che in questo caso, a titolo di esempio, abbiamo scelto di non specificare i possibili valori della property logMode all'interno della pagina JSP, ma di renderli parte del model object models.configurationBean. Essi risultano quindi completamente indipendenti dallo strato di interfaccia utente.

Il traffico massimo giornaliero viene impostato dall'utente attraverso un campo textentry_input cui è associato un LongRangeValidator che controlla l'ammissibilità del valore inserito:

<faces:textentry_input id="maxDailyTraffic"
modelReference="${configurationBean.maxDailyTraffic}"
size="10" >
<faces:validator
className=
"javax.faces.validator.LongRangeValidator" />
<faces:attribute
name=
"javax.faces.validator.LongRangeValidator.MINIMUM"
value="100" />
</faces:textentry_input>

Per l'impostazione della notifica all'amministratore di sistema operiamo una scelta opposta rispetto alla modalità dei log. In questo caso i possibili valori di input non fanno parte del model object, ma vengono specificati a livello di interfaccia utente come sottotag <faces:selectitem> del tag <faces:selectone_optionlist>, il quale permette all'utente di operare la sua scelta da una drop-down listbox.

<faces:selectone_optionlist id="alarmMode"
modelReference="${configurationBean.alarmMode}">
<faces:selectitem value="email"
label="Notifica via E-mail" />
<faces:selectitem value="icq" label="Notifica via ICQ" />
<faces:selectitem value="sms" label="Notifica via SMS" />
</faces:selectone_optionlist>

Segue quindi il tag <faces:command_button>, grazie al quale l'utente ha la possibilità di confermare le nuove impostazioni inviando il form al server; tale tag verrà rappresentato dal Renderer sotto forma di bottone:

<faces:command_button id="ok" label="Ok" key="okButton" commandName="configOk" />

La sezione Java Server Faces della nostra view JSP termina quindi con la chiusura del form e del container tag JSF:

</faces:form>
</faces:usefaces>

L'implementazione dei model object
I model object rappresentano lo stato dell'applicazione Web ed hanno il compito di fornire servizi di persistenza ai componenti di Web UI JSF. Nel nostro caso sarà sufficiente codificare un unico model object, models.ConfigurationBean, delegato a rappresentare i parametri di configurazione impostati dall'utente attraverso la view "config.jsp"; come è lecito attendersi, si tratterà di un JavaBean le cui proprietà corrisponderanno perfettamente agli elementi di interfaccia utente analizzati nel paragrafo precedente.

L'implementazione delle descrizioni di NetView, della password SNMP e della soglia di traffico è elementare e consta semplicemente di quattro membri privati supportati dai rispettivi accessori:

private String appTitle="NetView versione 1.2";
private String appDesc="Web application di esempio "+
"per MokaByte. "+
"Campo di test per JSP, JSTL e JSF";
private String snmpPassword="qwerty";
private int maxDailyTraffic=500;

public String getAppTitle() { return appTitle; }
public void setAppTitle(String appTitle) {
this.appTitle=appTitle;
}

public String getAppDesc() { return appDesc; }
public void setAppDesc(String appDesc) {
this.appDesc=appDesc;
}

public String getSnmpPassword() { return snmpPassword; }
public void setSnmpPassword(String snmpPassword) {
this.snmpPassword=snmpPassword;
}

public int getMaxDailyTraffic() { return maxDailyTraffic; }
public void setMaxDailyTraffic(int maxDailyTraffic) {
this.maxDailyTraffic=maxDailyTraffic;
}

È da rilevare come nessuna operazione esplicita ci venga richiesta per la gestione del tipo della property maxDailyTraffic: JSF si prende automaticamente cura della conversione in intero di quanto inserito dall'utente nel form di input.

Incredibilmente semplice è la gestione della property alarmMode, in cui verrà memorizzata la modalità di notifica all'amministratore; essa viene infatti codificata come una semplice String property - in maniera assolutamente identica ad appTitle, appDesc e snmpPassword. Il nostro model object è infatti completamente ignaro dell'esistenza di una lista di valori ammissibili per questa proprietà, funzionalità che viene integralmente gestita da Java Server Faces dietro le quinte:

private String alarmMode="email";

public String getAlarmMode() { return alarmMode; }
public void setAlarmMode(String alarmMode) {
this.alarmMode=alarmMode;
}

Appena più complicata è l'implementazione della property associata alla modalità dei log. In questo caso, infatti, abbiamo scelto di rendere le possibili impostazioni di questa proprietà parte integrante del model object.
Provvediamo quindi a modellare tramite un'elementare non-mutable data class la nozione di 'modalità di log' come insieme di due valori stringa, pari rispettivamente al codice della classe di log ed alla sua rappresentazione visuale (descrizione):

public class LogMode {
private String value;
private String label;

public LogMode(String value,String label) {
this.value=value;
this.label=label;
}

public String getValue() { return value; }
public String getLabel() { return label; }
}

Dotiamo quindi il nostro model object della conoscenza di tutte le modalità di log supportate; in considerazione del carattere esemplificativo della nostra applicazione decidiamo di innestare nel codice i dati corrispondenti:

private LogMode logModes[]=new LogMode[] {
new LogMode("syslogd","Esterna syslogd") ,
new LogMode("xml","Interna XML") ,
new LogMode("sql","Interna SQL")
};

Nel costruttore del model object provvediamo alla conversione del vettore di oggetti LogMode nel formato gestito da Java Server Faces, vale a dire una lista di oggetti javax.faces.component.SelectItem:

private ArrayList logModesList; // lista di oggetti
// SelectItem

public ConfigurationBean() {
// Popoliamo il vettore delle modalita' di log,
// creando un oggetto SelectItem per ogni LogMode
LogMode lm;

logModesList=new ArrayList(logModes.length);
for (int i=0;i<logModes.length;++i) {
lm=logModes[i];
logModesList.add(
new SelectItem(lm.getValue(),lm.getLabel(),
lm.getLabel())
);
}
.
.
.
}

Implementiamo quindi la property logMode come semplice String property; Java Server Faces - sulla scorta degli oggetti SelectItem da noi specificati - provvederà in maniera autonoma a gestire l'interazione con l'utente fornendo direttamente al model object models.ConfigurationBean il codice della modalità di log impostata via Web UI:

// Modalita' di log corrente in formato JSF
// (value del LogMode corrispondente)
private String logMode;

public String getLogMode() { return logMode; }
public void setLogMode(String logMode) {
this.logMode=logMode;
}

Infine ci assicuriamo di fornire un default valido per la modalità di log, specificando un opportuno valore all'atto della creazione del model object:

public ConfigurationBean() {
.
.
.
// Impostiamo la modalita' di log corrente a syslogd,
// memorizzando in logMode (proprieta' JSF) il valore
// del LogMode corrispondente
logMode=logModes[0].getValue();
}

 

L'oggetto ApplicationHandler
Come già fatto notare, ogni Web Application in ambiente Java Server Faces deve possedere una classe singleton che implementi l'interfaccia javax.faces.lifecycle.ApplicationHandler, la cui responsabilità consiste nel dirigere la navigazione dell'utente all'interno dell'applicazione in risposta agli eventi di tipo application level. Nel nostro caso l'implementazione di tale classe sarà particolarmente semplice, non dovendo gestire la nostra applicazione che un unico evento globale, corrispondente alla conferma da parte dell'utente dei dati inseriti nel form di configurazione.

Il fulcro di un oggetto ApplicationHandler è rappresentato dal suo metodo processEvent() che - in logica vagamente JDK 1.0 - viene notificato allo scattare di qualsiasi evento. Esso provvede quindi ad identificare l'evento ricevuto e, in base allo stato dell'applicazione, aggiorna i componenti del sistema e guida se necessario la navigazione dell'utente all'interno delle View JSF / JSP:

public class NetViewApplicationHandler implements
ApplicationHandler {

// Metodo di gestione degli eventi JSF; in NetView esiste
// un unico evento, "configOk", generato alla conferma del
// form di configurazione
public boolean processEvent(FacesContext context,
FacesEvent facesEvent) {

boolean returnValue=false;
String treeId=null;

if (facesEvent instanceof FormEvent) {
// Abbiamo a che fare con un evento generato da
// un form
FormEvent formEvent=(FormEvent)facesEvent;

if (formEvent.getCommandName().
equals("configOk")) {
// L'utente ha confermato le modifiche
// al form di configurazione; torniamo
// alla pagina principale di NetView
treeId="/main";
}
}

.
.
.

return returnValue;
}
}

È responsabilità dello sviluppatore gestire il ciclo di vita dell'oggetto ApplicationHandler, istanziandolo alla creazione del ServletContext dell'applicazione e rilasciandolo alla sua distruzione.
Questo ruolo viene svolto in NetView dalla classe NetViewServletContextListener, che abbiamo visto venire dichiarata come listener a livello di deployment descriptor:

public class NetViewServletContextListener
implements ServletContextListener {

public NetViewServletContextListener() {
}

public void contextInitialized(ServletContextEvent e) {
// Costruiamo ed attiviamo l'ApplicationHandler
// di NetView

ApplicationHandler handler=
new NetViewApplicationHandler();
.
.
.
lifecycle.setApplicationHandler(handler);
}

public void contextDestroyed(ServletContextEvent e) {
}

}

Conclusione
Con il presente articolo si conclude la trattazione di Java Server Faces, il framework Java per la realizzazione di interfacce utente ad applicazioni Web e distribuite: insieme ne abbiamo esaminato la struttura generale ed i componenti fondamentali, cosa che ci ha permesso di apprezzare le virtù di loosely coupling, componentizzazione, riusabilità ed estensibilità di questa API.
Successivamente abbiamo applicato le conoscenze così ottenute ad una situazione pratica che, per quanto limitata, ha chiarito come la qualità del design di Java Server Faces si accompagni ad una notevole semplicità d'uso e di comprensione.
Il prossimo mese approcceremo l'ultimo degli argomenti di questa lunga serie di articoli dedicata al tema delle Web UI in Java. In particolare, dopo esserci sino ad ora concentrati sullo studio delle due fondamentali Tag Library JSTL - nelle sue sottolibrerie Core, XML, DB e I18N - e Java Server Faces, vedremo come sia possibile per lo sviluppatore implementare ed utilizzare nuove Custom Tag Library, con le quali estendere le funzionalità del framework Java Server Pages.

Bibliografia
[1] JSF - Java Server Faces: http://java.sun.com/j2ee/javaserverfaces
[2] Lavinio Cerquetti: "JSF: Java Server Faces - I parte", Mokabyte N. 71 - Febbraio 2003

Risorse
Scarica qui il codice presentato nell'articolo (NetView versione 1.2).
L'implementazione di esempio di NetView è stata testata sotto JBoss 3.0.3 e Tomcat 5 (Milestone 5.0.0) in ambiente Linux con database IBM DB2.

Lavinio Cerquetti si occupa di design e sviluppo del software in ambienti distribuiti ed in architetture J2EE multi-tier. Può essere contattato all'indirizzo di e-mail lcerquetti@mokabyte.it

 

MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it