Introduzione
In questo numero iniziamo la trattazione dell'argomento
conclusivo della nostra serie di articoli dedicati 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, analizzeremo le opportunità
e le potenzialità offerte agli sviluppatori J2EE
dall'implementazione di Tag Library aggiuntive nel contesto
della versione 1.2 del framework Java Server Pages.
Custom
Tag Library
Per Custom Tag Library - in breve CTL - si intende un
gruppo di classi Java che, unitamente ad un apposito
document descriptor, implementano un'estensione della
sintassi JSP consistente in uno o più tag XML-like.
Tali tag donano allo sviluppatore accesso ad un insieme
di nuove funzionalità e di comportamenti originali
che egli può utilizzare e combinare in maniera
libera e creativa con altre Tag Library all'interno
delle proprie pagine JSP.
Il meccanismo delle CTL - introdotto a partire dalla
versione 1.1 di Java Server Pages - è estremamente
flessibile e generico, e garantisce una potenza espressiva
sostanzialmente illimitata, come testimoniato dall'assoluta
varietà strutturale ed eterogeneità funzionale
delle Custom Tag Library disponibili sul mercato.
Tra i campi in cui le CTL hanno trovato maggior utilizzo
vanno sicuramente citati l'impiego come componenti di
presentazione in applicazioni HTML ed il ruolo di information
provider nei confronti degli strati di interfaccia utente,
funzionalità spesso ottenute tramite accesso
diretto e non mediato al data layer del sistema applicativo.
Tali modelli di utilizzo - i quali hanno sicuramente
svolto un ruolo positivo ed a volte insostituibile nel
corso dell'evoluzione tecnica e strutturale che ha caratterizzato
il paradigma J2EE in questi ultimi anni - sono tuttavia
da considerarsi ormai sorpassati e introducono la questione
dell'attuale ruolo delle Custom Tag Library in contesti
J2EE.
Ruolo
e finalità delle Custom Tag Library in ambienti
Java Server
L'attuale maturità e solidità strutturale
del paradigma J2EE, così come l'emergere di Tag
Library funzionalmente evolute e da considerarsi a tutti
gli effetti come dei veri e propri 'building block'
standard dei quali gli sviluppatori possono usufruire
per costruire le proprie soluzioni software in tempi
sempre più rapidi, richiedono una chiarificazione
delle finalità delle Custom Tag Library all'interno
del panorama delle tecnologie Java lato server. In sostanza
si pone la questione di quale debba essere il ruolo
di questa tecnologia in ambiti J2EE, e di come la sua
indubbia - talvolta persino eccessiva - potenza possa
venire sfruttata al meglio e nel rispetto dell'ormai
consolidata architettura che caratterizza le soluzioni
software multi-tier in Java.
Come
già fatto notare, tra i principali utilizzi storici
delle CTL riveste un ruolo di primo piano la generazione
di contenuto HTML / XHTML, che le ha viste sfruttate
come veri e propri elementi di interfaccia utente in
applicazioni Web. Questo impiego delle Custom Tag Library
è oggi assolutamente sconsigliato, da un lato
in quanto poco flessibile ed in contrasto con il principio
di separazione delle responsabilità proprio dell'architettura
n-tier J2EE e dall'altro in quanto in sovrapposizione
con uno standard ben più ambizioso e tecnicamente
evoluto, qual è Java Server Faces - che già
abbiamo analizzato in [1] e [2] - alla luce del quale
ha ben poco senso per lo sviluppatore tentare di 'reinventare
la ruota', concependo e realizzando l'ennesimo framework
di interfaccia utente HTML basato su JSP.
Egualmente
sconsigliabile ed obsoleto è l'utilizzo di CTL
per la realizzazione di sistemi di templating in HTML
/ XHTML / XML, non solo per l'enorme varietà
dell'attuale offerta in tal senso, quanto soprattutto
per la disponibilità di uno strumento open-source,
riconosciuto come standard ed estremamente completo
ed estensibile qual è la JSP Standard Tag Library,
cui abbiamo rivolto la nostra attenzione in [3] e [4].
Non
meno criticabile e pericoloso è l'impiego di
CTL in ruoli di controllo dell'accesso e come strumento
per la realizzazione di 'business layer intermedi' che
spesso predano paradigmi consolidati - quali EJB, JDO,
il pattern Controller Servlet o i filter servlet disponibili
a partire dalla versione 2.3 delle Servlet API - e scavalcano
i rispettivi layer software stabilendo comunicazioni
dirette con il data repository del sistema applicativo.
Un tale approccio alle CTL risulta ammissibile solamente
in circostanze estremamente particolari e tipicamente
in fase di prototipazione: inoltre, persino la necessità
di provvedere alla codifica diretta di tali comportamenti
è venuta nella grande maggioranza dei casi definitivamente
meno in seguito al rilascio del componente SQL della
JSP Standard Tag Library, da noi commentato in [5].
È
invece certamente corretto l'utilizzo delle Custom Tag
Library per la realizzazione di moduli funzionali strettamente
coesi, tipicamente dedicati all'implementazione di funzionalità
generiche e riusabili che si desiderano rendere disponibili
agli strati di interfaccia utente in JSP. Tuttavia anche
in questo caso il mercato offre un'ampia scelta di soluzioni
pronte all'uso, standard e di verificata solidità
ed affidabilità: a partire dalle Tag Library
'ponte' verso il mondo XML ed i servizi di internazionalizzazione
descritte nella nostra serie di articoli - e precisamente
in [5] e [6] - per arrivare all'odierna vasta disponibilità
di prodotti commerciali ed open-source, come i componenti
realizzati nel quadro del progetto Taglibs dal gruppo
Jakarta / Apache [7].
Da
quanto detto risulta quindi chiaro come l'evoluzione
dell'architettura J2EE da un lato e l'affermarsi del
modello open-source dall'altro abbiano provveduto a
delimitare con una certa precisione quelli che sono
gli attuali campi di utilizzo delle Custom Tag Library,
ed al contempo a fornire soluzioni 'chiavi in mano'
che sempre di più liberano gli sviluppatori dalla
necessità di ricorrere in prima persona a questa
tecnologia.
All'iniziale
questione del ruolo delle CTL siamo quindi in grado
di fornire una risposta chiara e sensata: l'implementazione
di nuove Custom Tag Library è oggi da considerarsi
come uno strumento di utilizzo limitato e destinato
ad una precisa frangia di sviluppatori, vale a dire
ai tool developer, cui spetta il compito di avvalersi
di tale tecnologia per realizzare componenti che incapsulino
funzionalità generiche e riusabili o comportamenti
estremamente verticalizzati e problem-oriented. Viceversa
le Custom Tag Library risultano completamente trasparenti
agli sviluppatori di applicazioni, il cui ruolo consiste
nel produrre sistemi software avvalendosi di ed assemblando
- nella massima misura possibile - strumenti e preesistenti.
Le Tag Library rappresentano dunque per gli application
developer una tipologia di componenti 'black box' che
essi valutano ed utilizzano in maniera funzionale, indipendentemente
dalla loro natura standard (JSTL, Java Server Faces
e così via) o custom.
Analizzati
quindi il ruolo e le finalità delle Custom Tag
Library in ambito J2EE, passiamo all'analisi delle caratteristiche
di questa tecnologia.
Struttura
di una Custom Tag Library
Una Custom Tag Library è costituita da tre componenti
principali:
- Un
insieme di classi Java dedicate all'implementazione
delle funzionalità dei tag, denominate tag
handler;
- un
tag library descriptor, vale a dire un documento XML
contenente le specifiche funzionali della CTL;
- un
sistema opzionale di validazione - rappresentato da
una o più classi Java - il cui compito consiste
nel verificare la correttezza sintattica delle pagine
JSP che utilizzeranno la CTL.
Oltre
ai punti sopra menzionati varrà anche la pena
di rivolgere la nostra attenzione ai temi del deployment,
della gestione degli attributi, degli errori, degli
eventi, del tag nesting e dell'integrazione in contesto
JSP / JSTL delle Custom Tag Library.
I
tag handler
Per tag handler si intende una classe Java cui spetta
il compito di fornire l'implementazione dei comportamenti
associati ad uno specifico tag al JSP engine corrente
e di comunicare con esso nel rispetto di una sequenza
precisa di callback. Si noti che alle classi tag handler
- diversamente da quanto accade per i servlet - non
viene richiesto di essere rientranti: infatti, anche
se il motore JSP ha il diritto di riutilizzare oggetti
tag handler già istanziati, in ogni caso esso
non può servirsi del medesimo tag handler per
processare due tag contemporaneamente.
Java
Server Pages 1.2 identifica tre categorie di tag handler
- cui corrispondono altrettante interfacce definite
nel package javax.servlet.jsp.tagext - differenziate
in base alla complessità ed alla natura delle
operazioni che svolgono sul contenuto delle pagine JSP:
i tag handler base, i quali implementano l'interfaccia
javax.servlet.jsp.tagext.Tag, i tag handler iterativi
- associati all'interfaccia javax.servlet.jsp.tagext.IterationTag
- ed i tag handler di contenuto, vincolati all'interfaccia
javax.servlet.jsp.tagext.BodyTag.
I
tag handler base
I tag handler base sono caratterizzati da un'interazione
ridotta con la pagina JSP al cui interno agiscono; in
particolare essi non effettuano alcuna manipolazione
del loro body content, vale a dire del codice HTML /
JSP contenuto all'interno dei rispettivi tag di apertura
e chiusura. Tali tag handler, come già visto,
implementano l'interfaccia javax.servlet.jsp.tagext
e sono caratterizzati da un meccanismo di callback estremamente
semplice e basato sui metodi doStartTag() e doEndTag(),
che andiamo ad analizzare:
int
doStartTag() throws javax.servlet.jsp.JspException
doStartTag()
viene invocato ad ogni utilizzo all'interno di una pagina
JSP del tag rappresentato dal tag handler e comunica
con il motore JSP tramite il suo valore di ritorno:
javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE:
il JSP engine procede alla normale valutazione del corpo
del tag e di ogni eventuale subtag;
javax.servlet.jsp.tagext.Tag.SKIP_BODY: il corpo
del tag viene interamente ignorato dal motore JSP, che
salta direttamente al relativo tag di chiusura.
È
anche possibile per il metodo doStartTag() generare
un'eccezione figlia di javax.servlet.jsp.JspException,
al fine di segnalare una condizione di errore grave:
in questo caso il JSP engine interromperà il
processo di valutazione dell'intera View JSP, usualmente
ritornando al browser una pagina d'errore.
int
doEndTag() throws javax.servlet.jsp.JspException
doEndTag()
viene invocato in corrispondenza del tag di chiusura
sull'oggetto tag handler corrispondente al tag corrente.
Anche in questo caso la comunicazione con il motore
JSP è affidata ad un semplice valore di ritorno:
javax.servlet.jsp.tagext.Tag.EVAL_PAGE: il JSP
engine procede normalmente al processing del resto della
pagina;
javax.servlet.jsp.tagext.Tag.SKIP_PAGE: la valutazione
della pagina corrente viene interrotta.
Il
ciclo di vita di un tag handler consiste dunque in coppie
di invocazioni dei suddetti metodi doStartTag() e doEndTag(),
seguiti da una chiamata finale al metodo release(),
in risposta al quale il tag handler è tenuto
a rilasciare immediatamente tutte le risorse in proprio
possesso ed a predisporsi alla finalizzazione.
Si noti che all'atto dell'invocazione di doStartTag()
il tag handler può fare affidamento sulla corretta
inizializzazione del proprio contesto, consistente nell'esecuzione
preventiva da parte del JSP engine dei seguenti passi:
-
La proprietà pageContext del tag handler viene
impostata, tramite l'apposito metodo setPageContext()
dell'interfaccia javax.servlet.jsp.tagext.Tag, all'oggetto
contenente le informazioni di contesto relative alla
pagina JSP corrente;
- in
caso di tag innestati la proprietà parent del
tag handler punta al relativo tag handler padre;
- qualora
al tag siano associati degli attributi essi vengono
impostati correttamente nell'istanza di tag handler.
Figura 1 - Ciclo di vita di un tag handler base
Dal
momento che buona parte dei metodi definiti nell'interfaccia
Tag viene di norma codificata in maniera identica in
ogni tag handler, il package javax.servlet.jsp.tagext
mette a disposizione la convenience class TagSupport,
la quale fornisce un'implementazione standard di ogni
metodo d'interfaccia. Il definire i propri tag handler
base a partire dalla classe TagSupport permette agli
sviluppatori di evitare la codifica diretta degli accessori
per le proprietà parent e pageContext, nonché
tipicamente l'implementazione del metodo release(),
consentendo loro di concentrarsi sui soli metodi doStartTag()
e doEndTag().
I
tag handler iterativi
L'interfaccia javax.servlet.jsp.tagext.IterationTag
rappresenta una delle novità della versione 1.2
del framework Java Server Pages e consente un'ìmplementazione
estremamente semplificata di tag iterativi, vale a dire
di quei tag che hanno bisogno di valutare ripetutamente
il proprio body content sul modello del tag <c:forEach>
di JSTL.
Tale interfaccia estende javax.servlet.jsp.tagext.Tag,
aggiungendovi un unico metodo:
int
doAfterBody() throws javax.servlet.jsp.JspException
doAfterBody()
viene invocato al termine di ogni valutazione del contenuto
del tag - dopo il doStartTag() iniziale e prima del
doEndTag() finale - e comunica con il motore JSP tramite
il suo valore di ritorno:
javax.servlet.jsp.tagext.IterationTag.EVAL_BODY_AGAIN:
il motore JSP effettuerà un'altra iterazione
sul tag, valutandone nuovamente il body e gli eventuali
subtag;
javax.servlet.jsp.tagext.Tag.SKIP_BODY: la valutazione
di questo tag è da ritenersi conclusa ed il JSP
engine può procedere al processing del resto
della pagina.
Figura 2 - Ciclo di vita di un tag handler iterativo
Anche
nel caso dei tag handler iterativi è possibile
per lo sviluppatore risparmiare parte del lavoro di
codifica definendo la propria classe come child class
di javax.servlet.jsp.tagext.TagSupport; sarà
quindi sufficiente, nella gran parte dei casi, limitarsi
all'implementazione dei metodi doStartTag(), doAfterBody()
e doEndTag().
I
tag handler di contenuto
Un'interazione più complessa caratterizza i tag
handler di contenuto, rappresentati da classi che implementano
l'interfaccia javax.servlet.jsp.tagext.BodyTag.
Tale interfaccia - basata su javax.servlet.jsp.tagext.Tag
nella versione 1.1 di Java Server Pages - estende invece
in JSP 1.2 javax.servlet.jsp.tagext.IterationTag e fornisce
un insieme di metodi addizionali rivolti alla gestione
del body content di un tag.
Il
metodo doStartTag() supporta nel caso di tag handler
di contenuto un insieme esteso di valori di ritorno:
-
javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE: il
JSP engine procede alla normale valutazione del corpo
del tag e di ogni eventuale subtag;
- javax.servlet.jsp.tagext.Tag.SKIP_BODY:
il corpo del tag viene interamente ignorato dal motore
JSP, che salta direttamente al relativo tag di chiusura;
- javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_BUFFERED:
laddove le funzionalità dei due precedenti
codici di ritorno corrispondono perfettamente a quanto
visto nel caso dei tag handler base, il valore EVAL_BODY_BUFFERED
permette la gestione in modalità bufferizzata
del risultato della valutazione del body content del
tag.
Si
noti che a partire dalla versione 1.2 del framework
Java Server Pages l'utilizzo del valore di ritorno javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_TAG,
impiegato in JSP 1.1 - in funzione del contesto - con
la medesima semantica di EVAL_BODY_AGAIN o di EVAL_BODY_BUFFERED
è ufficialmente sconsigliato.
In
caso di ritorno del valore EVAL_BODY_BUFFERED il motore
JSP provvede ad invocare immediatamente sul tag handler
due metodi aggiuntivi definiti nell'interfaccia javax.servlet.jsp.tagext.BodyTag:
void
setBodyContent(BodyContent bodyContent)
A
setBodyContent() spetta semplicemente la responsabilità
di impostare la proprietà bodyContent del tag
handler al buffer utilizzato per memorizzare il contenuto
del tag. Tale buffer viene rappresentato da un'istanza
della classe javax.servlet.jsp.tagext.BodyContent, child
class di javax.servlet.jsp.JspWriter.
int
doInitBody() throws javax.servlet.jsp.JspException
Questo
metodo viene invocato per dare al tag handler la possibilità
di effettuare specifiche attività di inizializzazione
in seguito all'impostazione del body content e di interrompere,
in caso di condizione di errore critico, il processing
dell'intera pagina corrente.
Nel
ciclo di vita di un tag handler di contenuti seguono
quindi una o più chiamate al metodo doAfterBody()
- la cui semantica è identica a quella già
analizzata per l'interfaccia IterationTag - ed una chiamata
finale al metodo doEndTag(), con la quale si conclude
il processing del tag iniziato con l'invocazione del
metodo doStartTag(). L'ultimo atto nella vita di un
tag handler di contenuti è rappresentato dalla
chiamata da parte del JSP engine del suo metodo release(),
a fronte del quale il tag handler è tenuto a
rilasciare tutte le risorse a propria disposizione,
predisponendosi per la garbage collection.
Figura 3 - Ciclo di vita di un tag handler di contenuto
in modalità bufferizzata
Qualora
il tag handler abbia richiesto in sede di doStartTag()
un processing buffer-based dei contenuti del tag tramite
il valore di ritorno EVAL_BODY_BUFFERED è sua
diretta responsabilità provvedere all'output
del body content tramite il Writer associato, operazione
tipicamente svolta nel metodo doEndTag().
Grazie a questa gestione dell'output in modalità
lazy risulta possibile per il tag handler - in qualsiasi
momento del suo ciclo di vita - applicare nuove trasformazioni
al body content o addirittura sopprimerlo interamente
semplicemente evitando di inviarlo al Writer.
Anche
nel caso dei tag handler di contenuti è possibile
per gli sviluppatori utilizzare le implementazioni standard
per diversi metodi d'interfaccia definendo la propria
classe a partire dalla convenience class javax.servlet.jsp.tagext.BodyTagSupport.
Conclusione
Nel presente articolo abbiamo introdotto il tema delle
Custom Tag Library, analizzandone in particolare il
ruolo e le finalità in ambienti J2EE ed iniziando
la trattazione delle caratteristiche tecniche di questa
API nel contesto della versione 1.2 del framework Java
Server Pages.
La presentazione di questa tecnologia proseguirà
nel prossimo articolo con la trattazione dei suoi rimanenti
principali aspetti strutturali.
Bibliografia
[1] Lavinio Cerquetti: "JSF: Java Server Faces
- I parte", Mokabyte N. 71 - Febbraio 2003
[2] Lavinio Cerquetti: "JSF: Java Server Faces
- II parte", Mokabyte N. 72 - Marzo 2003
[3] Lavinio Cerquetti: "JSP 1.2: JSTL - I parte",
Mokabyte N. 67 - Ottobre 2002
[4] Lavinio Cerquetti: "JSP 1.2: JSTL - II parte",
Mokabyte N. 68 - Novembre 2002
[5] Lavinio Cerquetti: "JSP 1.2: JSTL - IV parte",
Mokabyte N. 70 - Gennaio 2003
[6] Lavinio Cerquetti: "JSP 1.2: JSTL - III parte",
Mokabyte N. 69 - Dicembre 2002
[7] Jakarta Taglibs: http://jakarta.apache.org/taglibs
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
|