Introduzione
L'articolo di questo mese conclude la nostra analisi
delle Custom Tag Library nel contesto della versione
1.2 di Java Server Pages, completando il quadro delle
conoscenze che applicheremo nel prossimo numero all'implementazione
di una tag library in seno all'applicazione d'esempio
NetView.
In particolare dopo aver analizzato in [1] e [2] i principali
elementi strutturali di una CTL ed in [3] gli schemi
di gestione di attributi, variabili di scripting e tag
nesting, intendiamo ora discutere le caratteristiche
e le opportunità di utilizzo di due feature particolarmente
significative per quanto concerne la robustezza e l'integrabilità
di soluzioni software distribuite, vale a dire eccezioni
ed eventi.
In chiusura di articolo passeremo quindi in breve rassegna
le principali novità destinate ad essere introdotte
nei prossimi aggiornamenti dell'ambiente Java Server
Pages e delle Servlet API.
Eccezioni
I meccanismi di validazione formale offerti dal framework
Java Server Pages attraverso il Tag Library Descriptor
e gli oggetti custom validator permettono di verificare
in translation time gran parte degli errori e delle
inconsistenze che si possono verificare in fase di creazione
ed utilizzo di Custom Tag Library e di applicazioni
JSP.
È tuttavia ragionevole attendersi che diverse
condizioni di errore si manifesteranno unicamente in
sede di run time, ponendo al tag handler il problema
di come reagire in tali situazioni. Sostanzialmente
sono identificabili due strategie di gestione degli
errori:
-
Si è presentata una condizione di errore critico,
a fronte del quale è impossibile o indesiderabile
per il tag procedere nella propria elaborazione; se
il tag corrente riveste una significativa importanza
all'interno della pagina JSP corrente, potrebbe per
quest'ultima essere impossibile produrre un output
corretto o in linea con le attese dell'utente. In
questo caso, la soluzione consiste usualmente nell'interrompere
l'intero processing della pagina: il tag handler solleva
un'eccezione javax.servlet.jsp.JspTagException, la
quale porta alla generazione di una pagina di errore
eventualmente customizzata;
- Si
è manifestata una condizione di errore secondario,
la quale non preclude in linea di massima la generazione
di un output corretto; il tag produrrà tipicamente
un output nullo o contenente una segnalazione di errore
ed imposterà eventualmente dei flag di errore
per mezzo di opportune variabili di scripting, delegando
la scelta definitiva sul da farsi a dei tag di livello
superiore o direttamente alla logica principale di
controllo della pagina JSP corrente.
Le
API 1.2 del framework JSP introducono un nuovo, terzo
schema di gestione degli errori, basato sull'interfaccia
javax.servlet.jsp.tagext.TryCatchFinally , implementando
la quale ogni tag handler può reagire ad un'eventuale
eccezione sollevata da un altro tag handler. Tale interfaccia
consta di due metodi:
public
void doCatch(java.lang.Throwable t)
public void doFinally()
doCatch()
viene invocata dal motore JSP se un qualsiasi tag handler
solleva un'eccezione - sia checked che unchecked - durante
il processing di un body content, ovvero dall'interno
dei metodi doStartTag(), doEndTag(), doAfterBody() e
doInitBody(). Si noti che doCatch() non viene invocata
qualora l'eccezione sia stata sollevata dai metodi setParent(),
setPageContext(), setBodyContent() o release().
Il tag handler può, all'interno del metodo doCatch(),
gestire l'eccezione ed impedire così che essa
raggiunga i tag handler di livello superiore ed eventualmente
la logica JSP della pagina corrente. In alternativa
esso può rigenerare la medesima o un'altra eccezione,
propagandola così al livello superiore.
In ogni caso anche se doCatch() risolve il problema
segnalato dall'eccezione sollevata, il motore JSP non
invocherà ulteriori metodi di callback sul tag
corrente.
Il
senso del metodo doFinally(), come si può evincere
dal nome, consiste nel permettere ad ogni tag handler,
anche in caso di un'eccezione, di rilasciare in modo
corretto tutte le risorse acquisiti nel corso della
propria elaborazione.
Se presente, il metodo doFinally() di un tag handler
viene sempre invocato al termine dell'attività
di un tag handler, sia che essa avvenga normalmente
- in questo caso doFinally() verrà attivato successivamente
al metodo doEndTag() - sia che essa avvenga per causa
di una situazione di errore non gestita.
L'interfaccia
TryCatchFinally, che per motivi di completezza non abbiamo
potuto esimerci dal trattare, va considerata alla sorta
di una vera e propria extrema ratio, cui ricorrere in
situazioni particolari e ben definite.
Tale interfaccia, oltre a duplicare in maniera inelegante
il meccanismo delle eccezioni già presente nel
linguaggio Java, sottintende l'idea che i tag handler
possano utilizzare durante il loro intero ciclo di vita
connessioni a risorse critiche e di cui quindi vada
necessariamente garantito il rilascio in caso di interruzione
del processing della pagina JSP, quali in prima istanza
connessioni a banche dati.
Sarà qui il caso di chiarire una volta di più
come tale concezione - allineata a quello che molti
sviluppatori considerano essere il fine dei componenti
DB della libreria JSTL da noi trattati in [10] - non
sia da considerarsi valida in generale.
È certamente lecito, come da noi già fatto
notare, utilizzare a tale fine il framework JSTL in
ambienti di prototipazione o per la realizzazione di
applicazioni a basso budget - tipicamente sviluppate
in regime di concorrenza nei confronti della soluzione
.NET di Microsoft - ma tale schema di utilizzo non può
venire esteso a regola generale, nella misura in cui
tende a caricare gli strati di interfaccia utente JSP
e JSTL dei compiti propri degli strati di business logic,
quali Enterprise Java Beans e Java Data Objects.
Eventi
L'ultimo componente di una Custom Tag Library sul quale
vogliamo soffermarci rappresenta una integrale novità
introdotta a partire dalla versione 2.3 delle Servlet
API, intimamente legate alla versione 1.2 del framework
Java Server Pages. Stiamo parlando degli eventi a livello
di applicazione, comunemente detti application lifecycle
events. In maniera esattamente analoga alle normali
applicazioni Swing è ora possibile per un tag
handler qualificarsi come listener e ricevere notifica
di uno o più eventi.
Gli
eventi generati dalle servlet API 2.3 vengono suddivisi
in due principali categorie: gli eventi legati al servlet
context e gli eventi di tipo HTTP session.
Il
trigger della prima classe di eventi, rappresentati
dalla classe javax.servlet.ServletContextEvent e dalle
sue sottoclassi, avviene contestualmente alle transizioni
di stato del servlet context associato alla web application
corrente. A questo fine vengono definite due interfacce:
-
javax.servlet.ServletContextListener, tramite la quale
un oggetto listener riceve notifica dei seguenti eventi
globali a livello di servlet context:
- public
void contextInitialized(javax.servlet.ServletContextEvent
sce): notifica della creazione del servlet context
e dell'attivazione della web application corrente;
- public
void contextDestroyed(javax.servlet.ServletContextEvent
sce): notifica della prossima distruzione del
servlet context corrente e dello shut down della
relativa web application;
- javax.servlet.ServletContextAttributeListener,
deputata a notificare gli oggetti listener di ogni
modifica intercorsa alla tabella di attributi del
servlet context corrente tramite i seguenti eventi
(si noti che tutti i seguenti metodi vengono invocati
a modifica degli attributi già avvenuta):
- public
void attributeAdded(javax.servlet.ServletContextAttributeEvent
scae): un nuovo attributo, i cui dati sono disponibili
come proprietà dell'oggetto ServletContextAttributeEvent
passato al gestore di eventi, è stato aggiunto
alla tabella di attributi del servlet context
corrente;
- public
void attributeRemoved(javax.servlet.ServletContextAttributeEvent
scae): un attributo, i cui dati sono ancora accessibili
tramite il parametro di evento, è stato rimosso
dalla tabella di attributi del servlet context corrente;
- public
void attributeReplaced(javax.servlet.ServletContextAttributeEvent
scae): un attributo è stato modificato ed
il suo precedente valore è accessibile tramite
l'oggetto ServletContextAttributeEvent.
Le
nuove JSP API permettono tanto ad ogni web application
quanto ad ogni Custom Tag Library di registrarsi come
listener per i suddetti eventi; questa funzionalità
può effettivamente rivelarsi estremamente utile
in tutti quei casi in cui una CTL si trovi a dover gestire
una risorsa condivisa non a livello di applicazione,
ma a livello globale di tag library.
Laddove sino ad ora l'unica possibilità sarebbe
consistita nel far acquisire e rilasciare la risorsa
in ogni pagina JSP dal singolo tag handler - soluzione
non corretta da un punto di vista teorico e fonte di
probabili problemi a livello di performance - la versione
1.2 del framework Java Server Pages, combinata alle
servlet API 2.3, permette di risolvere il problema in
maniera semplice ed elegante, implementando all'interno
della Custom Tag Library in oggetto un ServletContextListener,
il quale provveda ad acquisire e rilasciare la risorsa
condivisa rispettivamente all'attivazione ed alla distruzione
del servlet context associato all'applicazione web.
Come
è lecito attendersi, all'implementazione di un
listener a livello di sorgente Java deve corrispondere
una sua dichiarazione all'interno del Tag Library Descriptor,
la quale assume la seguente forma:
<listener>
<listener-class>
nome completo della classe listener
</listener-class>
</listener>
Secondo
quanto abbiamo già avuto modo di vedere in [2],
la suddetta dichiarazione va inserita all'interno del
tag <taglib> della Custom Tag Library, prima degli
elementi <tag> e successivamente all'eventuale
elemento opzionale <validator>.
Gli
eventi di tipo HTTP session, implementati tramite istanze
della classe javax.servlet.http.HttpSessionEvent o di
sue sottoclassi, scattano invece in funzione delle fasi
del ciclo di vita dell'oggetto HttpSession corrente,
il quale permette di identificare e tracciare gli utenti
di un'applicazione web; anche in questo caso ci troviamo
di fronte due interfacce, perfettamente parallele alla
ServletContextListener ed alla ServletContextAttributeListener
esaminate in precedenza:
-
javax.servlet.http.HttpSessionListener, il cui fine
consiste nel notificare il listener degli eventi globali
nell'ambito del ciclo di vita di una sessione HTTP:
- public
void sessionCreated(javax.servlet.http.HttpSessionEvent
hse): una nuova sessione HTTP, accessibile tramite
il parametro di tipo HttpSessionEvent, è
stata creata;
- public
void sessionDestroyed(javax.servlet.http.HttpSessionEvent
hse): una sessione HTTP è stata invalidata;
- public
void javax.servlet.http.HttpSessionAttributeListener,
il quale notifica al listener ogni modifica della
tabella degli attributi di una sessione HTTP (anche
in questo gli eventi vengono fatti scattare a modifica
avvenuta):
- public
void attributeAdded(javax.servlet.http.HttpSessionBindingEvent
hsbe): un nuovo attributo - i cui dati sono accessibili
tramite il parametro di evento - è stato
aggiunto alla sessione HTTP;
- public
void attributeRemoved(javax.servlet.http.HttpSessionBindingEvent
hsbe): un attributo, i cui dati sono ancora accessibili
tramite il parametro evento, è stato eliminato
dalla sessione HTTP;
- public
void attributeReplaced(javax.servlet.http.HttpSessionBindingEvent
hsbe): un attributo di sessione HTTP è
stato modificato ed i suoi precedenti dati possono
venire recuperati tramite l'oggetto HttpSessionBindingEvent.
Parallelamente
a quanto discusso per i servlet context event, anche
nel caso di eventi di tipo HTTP session è possibile
per web application e CTL operanti in un contesto JSP
1.2 registrarsi come listener. Va comunque notato che
l'utilità pratica legata all'intercettazione
degli HttpSessionEvent tende ad assumere connotazioni
piuttosto verticalizzate, tipicamente legate all'esecuzione
di 'meta-azioni' a livello globale di web application
o di application server.
Gestori di eventi HTTP session vengono, a titolo di
esempio, utilizzati per implementare sistemi di monitoraggio
delle performance, di statistiche del traffico e della
frequenza degli accessi e per l'implementazione e l'enforcing
di politiche di licensing basate su tetti massimi di
utenti.
Le
novità di JSP 2.0 e della Servlet API 2.4
La presente serie di articoli, incentrata sul tema delle
Web User Interface in applicazioni Java, prende in esame
tutt'una serie di API e strumenti software 'satelliti'
della versione 1.2 del framework Java Server Pages e
della versione 2.3 delle Servlet API.
Non è tuttavia sensato trascurare le importanti
novità maturate su questo fronte da Ottobre -
data di uscita del primo numero di questa serie - sino
ad oggi, in particolare per quanto concerne i nostri
due framework di riferimento.
Intendiamo analizzare brevemente le principali proposte
in cantiere per la release 2.4 delle Servlet API e per
la versione 2.0 del framework Java Server Pages, la
cui disponibilità è attesa per quest'estate
in sincronia con la versione 1.4 delle specifiche J2EE.
Nel caso delle Servlet API è da notare come la
solidità oramai raggiunta da questo prodotto
traspaia dalle richieste di modifiche contenute nell'attuale
documento di specifiche - al momento della scrittura
di questo articolo, il Proposed Final Draft 3 [4] -
tutte in prima istanza votate al consolidamento ed all'evoluzione
delle strutture esistenti.
Presentano particolare interesse le seguenti proposte
di modifica:
-
Le Servlet API 2.4 richiedono servlet container allineati
alla versione 1.1 del protocollo HTTP ed alla versione
1.3 di J2SE;
- In
linea con le recenti evoluzioni nel mondo J2EE la
definizione del deployment descriptor non viene più
affidata ad un DTD, ma ad un documento XML Schema
[5], la cui superiore ricchezza ed espressività
semantica garantiscono maggiore espandibilità
ed al contempo migliori funzionalità di verifica
e di controllo; i deployment descriptor caratteristici
delle versioni 2.2 e 2.3 della Servlet API rimangono
ovviamente supportati per ragioni di backwards compatibility;
-
Viene definita una nuova classe di application lifecycle
event, rappresentati dalle interfacce ServletRequestEvent
e ServletRequestAttributeEvent nonché dalle
rispettive interfacce listener, tramite le quali un'applicazione
o una Custom Tag Library può reagire alle richieste
HTTP processate dal servlet container;
- L'interfaccia
ServletRequest dispone dei nuovi metodi getLocalAddr(),
getLocalName(), getLocalPort() e getRemotePort() rivolti
all'acquisizione di informazioni circa le connessioni
lato client e server;
- Un'importante
attività di razionalizzazione e riordino è
stata eseguita sui request dispatcher, i quali beneficiano
inoltre di alcune nuove e significative funzionalità;
in particolare il nuovo tag <dispatcher> definito
a livello di deployment descriptor permette di attivare
l'esecuzione di uno o più filtri in seguito
all'invocazione dei metodi forward() o include() di
un request dispatcher;
- I
meccanismi di internazionalizzazione ed il supporto
di charset differenti sono stati oggetto di importanti
chiarificazioni ed espansioni, sia a livello di API
attraverso le interfacce ServletResponse e ServletResponseWrapper
sia per quanto riguarda l'introduzione del nuovo elemento
<locale-encoding-mapping-list> nel deployment
descriptor;
- L'interfaccia
SingleThreadModel, utilizzata per impedire che un
servlet container richiami da più thread concorrenti
il metodo service() di un servlet programmato in maniera
non rientrante, viene considerata deprecated;
- Viene
reso ufficiale ed obbligatorio il supporto - già
presente in diversi application server - di welcome
file generati in maniera dinamica.
Le
novità introdotte dalla versione 2.0 del framework
Java Server Pages - la cui bozza di specifiche è
anch'essa arrivata al Draft 3 [6] - sono invece ben
più corpose, per quanto già largamente
annunciate:
-
Le specifiche JSP 2.0 richiedono la presenza di J2SE
1.4 all'interno di contesti J2EE versione 1.4; viceversa,
nel caso di servlet container stand-alone, è
richiesta la versione 1.3 di J2SE;
- Prerequisito
del framework JSP 2 è la versione 2.4 delle
Servlet API;
- Come
già anticipato la libreria JSTL (JSP Standard
Tag Library) ed il linguaggio EL (Expression Language)
- entrambi trattati in maniera approfondita nella
presente serie di articoli da [7] a [10] - sono ora
parte integrante di JSP;
- Stretta
integrazione con il framework Java Server Faces, già
oggetto della nostra attenzione in [11] - [12], destinato
a diventare lo standard di riferimento per la realizzazione
di Web User Interface in Java ed attualmente arrivato
al Proposed Final Draft 2 / Early Access 4 [13];
- Viene
introdotta un'API semplificata per la definizione
di tag handler basata sull'estensione della classe
javax.servlet.jsp.tagext.SimpleTagSupport e sull'override
del solo metodo public void doTag();
- E'
contemplata la possibilità, destinata a personale
privo di specifici skill di programmazione, di realizzare
semplici custom tag facendo uso della sola sintassi
JSP;
il ruolo e le potenzialità del formalismo XML
di documenti JSP sono stati significativamente estesi
e potenziati;
- Espressioni
in linguaggio EL possono venire liberamente utilizzate
all'interno di pagine JSP, senza dover necessariamente
ricorrere al tag <c:out>;
la classe JspTagException è stata dotata di
costruttori allineati alla classe padre JspException,
i quali rendono possibile sollevare eccezioni dotate
di informazioni significative di contesto senza dover
ricorrere a manipolazioni dello stack trace.
Conclusione
Con la discussione dei meccanismi di eventi ed eccezioni
abbiamo nel presente articolo portato a conclusione
l'analisi di tutti i principali elementi costitutivi
di una Custom Tag Library, analisi in cui abbiamo voluto
trattare con speciale interesse le novità sintattiche
e semantiche introdotte nel quadro delle CTL a partire
dalla release 1.2 di JSP.
Abbiamo infine ritenuto opportuno effettuare un breve
excursus sulle particolarità di maggior rilievo
destinate a caratterizzare i futuri rilasci di due prodotti
per noi particolarmente significativi, vale a dire la
versione 2.0 del framework Java Server Pages e delle
Servlet API.
Nel prossimo numero intendiamo applicare in pratica
le conoscenze così acquisite, procedendo al design
ed all'implementazione di una Custom Tag Library rivolta
ad un'estensione funzionale della nostra applicazione
d'esempio NetView.
Bibliografia
[1] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - I parte", Mokabyte N. 73 - Aprile 2003
[2] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - II parte", Mokabyte N. 74 - Maggio 2003
[3] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - III parte", Mokabyte N. 74 - Giugno 2003
[4] Servlet API 2.4 - Proposed Final Draft 3: http://jcp.org/aboutJava/communityprocess/first/jsr154/
[5] W3C XML Schema - http://www.w3.org/XML/Schema
[6] Java Server Pages 2.0 - Proposed Final Draft 3:
http://jcp.org/aboutJava/communityprocess/first/jsr152/
[7] Lavinio Cerquetti: "JSP 1.2: JSTL - I parte",
Mokabyte N. 67 - Ottobre 2002
[8] Lavinio Cerquetti: "JSP 1.2: JSTL - II parte",
Mokabyte N. 68 - Novembre 2002
[9] Lavinio Cerquetti: "JSP 1.2: JSTL - III parte",
Mokabyte N. 69 - Dicembre 2002
[10] Lavinio Cerquetti: "JSP 1.2: JSTL - IV parte",
Mokabyte N. 70 - Gennaio 2003
[11] Lavinio Cerquetti: "JSF: Java Server Faces
- I parte", Mokabyte N. 71 - Febbraio 2003
[12] Lavinio Cerquetti: "JSF: Java Server Faces
- II parte", Mokabyte N. 72 - Marzo 2003
[13] JavaServer Faces - Proposed Final Draft 2 / Early
Access 4: http://java.sun.com/j2ee/javaserverfaces/download.html
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
|