MokaByte 76 - Luglio Agosto 2003 
JSP e Web User Interface
Custom Tag Library in ambienti J2EE
IV parte
di
Lavinio Cerquetti
Meccanismi di eccezioni ed eventi in JSP 1.2 e novità di JSP 2.0 e Servlet API 2.4

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

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