MokaByte 67 - 8bre 2002 
JSP 1.2: JSTL
La JSP Standard Tag Library - I parte
di
Lavinio Cerquetti
La standardizzazione ed il rilascio della JSP Standard Tag Library ha segnato un punto di svolta nell'evoluzione del framework JSP: analizziamo insieme le caratteristiche di questo nuovo ed importante strumento.

Introduzione
Avete mai provato ad avvicinarvi, amichevolmente, ad un programmatore Java ed a sussurrargli all'orecchio la parola 'JSP' ? Non fareste altro che provocare, in lui come in ogni altro membro della sua specie, una reazione di aperta ostilità.

Il framework JSP [1] - acronimo di JavaServer Pages - introdotto da Sun in tutta fretta alcuni anni or sono per dotarsi di uno strumento analogo al protocollo ASP di Microsoft, ha infatti avuto una vita tormentata nel panorama dei prodotti e protocolli Java. A lungo - e giustamente - criticata per via delle sue numerose lacune architetturali, questa tecnologia è stata considerata una sorta di 'pecora nera' nell'ambito del mondo J2EE, e per anni le sono stati preferiti framework di templating indipendenti - quali FreeMarker [2], Velocity [3] e WebMacro [4] - o più specificatamente votati all'implementazione di architetture Model-View-Controller come Jade [5] e Struts [6].
Le principali critiche mosse a JSP prendono spunto dal fatto che, per via del suo ridotto time-to-market iniziale, esso non risulti ben integrato con le linee guida e l'insieme di best practice e design pattern caratterizzanti lo sviluppo di software distribuito e multi-tier, e che la sua struttura porti alla realizzazione di applicazioni scarsamente manutenibili ed inerentemente non scalabili, caratterizzate da un'insufficiente separazione di ruoli logici e responsabilità funzionali tra i diversi software layer.
A queste considerazioni si aggiunga come, in seguito alle evoluzioni strutturali del panorama di API e protocolli Java ed alla sempre maggiore disponibilità di soluzioni alternative, il ruolo di JSP nella realizzazione di applicazioni Java Enterprise e le sue effettive possibilità ed opportunità di integrazione con strumenti di valore già noto ed assodato siano risultati a lungo poco chiari ed abbiano costituito una continua fonte di dubbio per la stessa comunità degli sviluppatori.

Sun, riconoscendo i limiti che hanno impedito al framework JSP di giocare un ruolo di primo piano nell'implementazione di sistemi software Java-based, si è ben presto messa al lavoro allo scopo di identificarne e risolverne tanto le lacune di design quanto i problemi tecnici. Un primo risultato è stato raggiunto, due anni or sono, con l'introduzione del JSP Model 2, approccio strutturale volto a rendere compatibile il framework JSP con architetture Model-View-Controller e con i pattern fondamentali utilizzati nello sviluppo di strati di presentazione per software distribuito (Business Delegate, Composite View, Service to Worker e View / Helper).
Tale chiarimento 'filosofico' del ruolo di JSP è stato accompagnato, a partire dalla versione 1.1 delle specifiche, da innovazioni tecniche che hanno costituito il presupposto per l'evoluzione presente e futura di questa tecnologia, da un lato nell'ottica di un generale miglioramento della sua integrabilità ed user-friendliness, dall'altro nel senso di un suo effettivo inquadramento all'interno dell'architettura J2EE come software layer deputato alla gestione del presentation tier in client Web-based a servizi remoti e componenti distribuiti.
Delle nuove possibilità offerte da JSP la libreria JSTL [7] - discussa in quest'articolo - costituisce al contempo un esempio ed un'applicazione fondamentale: tale Custom Tag Library, rilasciata nella sua versione 1.0 nel mese di Giugno, diverrà ufficialmente standard con l'imminente specifica 2.0 di JSP, di cui è già disponibile il Proposed Final Draft [8], e costituisce il tanto atteso punto di svolta nell'evoluzione di questo framework, al punto che non è errato asserire che esistano due JSP: un JSP ante-JSTL ed un JSP post-JSTL.

 

Il ruolo di JSTL nell'utilizzo odierno di JSP
JSP, essenzialmente, può venire descritto come un ambiente per la produzione di contenuti Web dinamici che si materializzano grazie alla possibilità di innestare, all'interno di componenti statici di presentazione - tipicamente implementati tramite pagine HTML - comportamenti aggiuntivi i cui esiti vengono risolti solamente a run-time.
Tali comportamenti sono stati espressi, nelle prime versioni di JSP, attraverso dei brani di codice Java inseriti direttamente nelle pagine HTML e denominati scriptlet, ovvero tramite dei tag proprietari (action in gergo JSP) normalmente associati al namespace jsp ed usualmente utilizzati per accedere a proprietà e metodi di oggetti esterni.
Purtroppo tale utilizzo di JSP, come già fatto notare nell'introduzione di questo articolo, oltre ad essere caratterizzato da una quantità di problematiche irrisolte a livello di design, porta a delle pagine HTML estremamente difficili da gestire e manutenere, rendendo nella pratica difficilmente realizzabile quella separazione di ruoli tra sviluppatori software e grafici Web che è alla base delle moderne pratiche collaborative di software development in architetture complesse e multi-tier.
Il framework JavaServer Pages, a partire dalla versione 1.1, ha introdotto la possibilità per gli sviluppatori di arricchire il contesto di esecuzione delle pagine JSP di nuovi comportamenti, espressi tramite tag aggiuntivi e redatti sotto forma di classi Java raggruppate in contenitori denominati 'Custom Tag Library', ovvero 'JSP Tag Extensions'; da qui alla formalizzazione di una libreria di action standard, con la quale fornire ai programmatori un patrimonio comune di tag in grado da un lato di garantire la sostanziale compatibilità delle pagine JSP al variare del Web Container e dall'altro di fornire quei costrutti di programmazione necessari per svincolare il framework di Sun dal continuo ricorso agli scriptlet Java, il passo è stato breve.

Tale libreria di tag, sviluppata in seno al Java Community Process [9] dall'Apache Group, è appunto JSTL. Tecnicamente parlando, essa consiste in una collezione di Custom Tag Library, organizzate e suddivise per categorie funzionali.
Si noti che JSTL utilizza funzionalità ed API delle Custom Tag Library introdotte a partire dalla versione 1.2 di JSP, e non risulta pertanto compatibile con Web Container che implementino versioni precedenti di questo framework.
Come già detto, JSTL diverrà un componente standard di JSP - e quindi dei differenti J2EE Server - a partire dalla versione 2.0 di JavaServer Pages; sino ad allora sarà necessario provvedere esplicitamente alla sua installazione, usualmente copiandone la distribuzione nella directory WEB-INF/lib delle singole applicazioni J2EE.

 

Componenti fondamentali di JSTL
JSTL si compone di quattro Custom Tag Library, ognuna delle quali viene mappata in namespace (detti anche prefix in gergo JSP) ed associata ad URI differenti e stabiliti per convenzione:

  • core: tale libreria, specificatamente oggetto di quest'articolo, fornisce tag sostanzialmente paralleli ai costrutti strutturati di programmazione in Java, al fine di ridurre al minimo il bisogno di innestare scriptlet direttamente all'interno delle pagine JSP. La libreria core implementa inoltre alcune utility action volte alla manipolazione di URL e contenuti esterni;
  • XML processing: libreria orientata alla gestione di documenti XML e XSLT;
  • I18N capable formatting: libreria di tag rivolta alla localizzazione delle applicazioni;
  • relational db access (SQL): libreria di tag rivolta all'utilizzo di connessioni JDBC dall'interno delle pagine JSP; si noti che tale libreria, in maniera piuttosto evidente, non rispetta la separazione dei ruoli tipici delle applicazioni multi-tier, dal momento che consente di integrare sezioni di business logic all'interno di pagine JSP, vale a dire del presentation layer. Tuttavia la disponibilità di facility per la gestione diretta di database dall'interno dello strato di interfaccia utente gioca un ruolo importante nell'implementazione di sistemi prototipo e di applicazioni di complessità elementare - oltre ad avere un preciso appeal a livello di marketing - ragion per cui questa libreria è stata inclusa come componente standard nella versione 1.0 di JSTL.

Ogni libreria viene dichiarata nelle pagine JSP che ne richiedono l'utilizzo tramite la sintassi:

<%@ taglib prefix="<namespace>" uri="<URI>" %>

Ad esempio la dichiarazione per la libreria core leggerà:

<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>

Per quanto le URI ed i prefissi associati alle singole librerie siano da intendersi solamente come raccomandazioni formali, è tuttavia buona pratica attenersi agli standard indicati per due ordini di motivi:

  1. Seguendo tali standard si contribuisce ad incrementare la comprensibilità e la riusabilità del codice;
  2. l'utilizzo degli URI segnalati permette ai singoli J2EE Server di 'riconoscere' le librerie utilizzate e di implementare eventuali politiche di ottimizzazione.

 

Gli Expression Language
Perché una pagina JSP risulti di una qualche utilità è indispensabile che essa sia in grado di rapportarsi alla ricca Object API che contraddistingue il mondo Java; sorge in altre parole il problema di come sia possibile accedere ad oggetti esterni e combinarne le proprietà in espressioni semanticamente significative. A questo problema sono state date, nel corso dell'evoluzione di JSTL, due risposte differenti:

EL: tale acronimo sta semplicemente per Expression Language, un linguaggio estremamente immediato ed user-friendly per l'accesso ad oggetti e per l'utilizzo delle loro proprietà a run-time dall'interno di pagine JSP. EL, per la sua sintassi semplificata - volutamente ispirata ad ECMAScript e XPath - ed in virtù del fatto che non richiede conoscenze specifiche in area Java, rappresenta lo strumento consigliato nell'utilizzo di JSTL, ed è l'Expression Language su cui ci soffermeremo nel corso di quest'articolo;
RT (Request-time expression language): questo linguaggio, ormai obsoleto, consente di utilizzare all'interno di tag JSTL espressioni specificate direttamente nel linguaggio di scripting della pagina, vale a dire usualmente in linguaggio Java, in maniera assai simile a quanto permesso dall'ormai famigerato tag "<%=".

Espressioni scritte in un Expression Language possono venire utilizzate sia negli attributi di tutti i tag JSTL - con l'eccezione dei soli attributi var e scope - sia negli attributi di eventuali Custom Tag Library di terze parti o proprietarie.

 

Il linguaggio EL
Come anticipato, la sintassi del linguaggio EL è sorprendentemente semplice: ogni espressione EL è racchiusa all'interno delle sequenze di caratteri '${' e '$}', ed è possibile accedere alle proprietà di un oggetto sia secondo la tradizionale sintassi basata sull'operatore '.' sia considerando l'oggetto alla stregua di un vettore associativo, le cui proprietà costituiscono le chiavi del vettore. Ad esempio, per accedere alla proprietà id dell'oggetto customer (implementata dai metodi getId() e setId()) è possibile utilizzare le seguenti sintassi:

${customer.id}$
${customer["id"]}$

Il vantaggio della seconda sintassi - utilizzabile anche per estrarre valori da oggetti che implementano l'interfaccia java.util.Map - risiede, in maniera abbastanza ovvia, nella possibilità di decidere a runtime la proprietà cui si desidera accedere, memorizzandone il nome in una variabile ed accedendovi tramite una sintassi del tipo:

${customer[propertyName]}$

L'immediatezza di EL si manifesta anche nella sintassi per l'accesso ad oggetti di tipo vettore, vale a dire array Java ovvero oggetti che implementino l'interfaccia java.util.List:

${customerList[0]}$

La lista dei rimanenti operatori di EL non riserva parimenti alcuna sorpresa: è interessante notare come per alcuni operatori matematici e booleani siano definiti dei sinonimi al fine di mantenere la compatibilità sia con ECMAScript che con XPath e per evitare il bisogno di ricorrere alle entity qualora si utilizzi JSP in modalità XML:

Come è lecito attendersi gli operatori booleani di confronto lavorano su oggetti String in modalità per valore.

Ogni oggetto definito in uno scope JSP valido viene automaticamente riconosciuto e può venire utilizzato liberamente all'interno delle espressioni EL; gli scope JSP sono esaminati, alla ricerca degli oggetti specificati dall'utente, nel seguente ordine:

Scope di pagina;
scope di richiesta HTTP;
scope di sessione;
scope di applicazione.

EL definisce inoltre una serie di oggetti cosiddetti impliciti:

EL riconosce, oltre ad oggetti e variabili, costanti espresse nei formati consueti:

  • Costanti stringa: sequenze di caratteri racchiuse tra apici singoli o doppi, al cui interno il carattere di backslash viene utilizzato per identificare dei caratteri di controllo convenzionali ('\n', '\t', etc.); per inserire un carattere di backslash all'interno di una costante stringa, lo stesso deve essere preceduto da un altro backslash;
  • costanti intere: sequenze numeriche precedute da uno specificatore opzionale di segno ('+' o '-');
  • costanti decimali: sequenze numeriche precedute da uno specificatore opzionale di segno e composte di una parte intera e di una parte decimale, separate tra di loro dal punto decimale '.'; la parte decimale può venire espressa in notazione esponenziale;
  • costanti booleane: 'true' e 'false'.

 

La libreria JSTL core
Laddove EL definisce un linguaggio per la specifica di espressioni, la libreria JSTL core definisce i tag che implementano i controlli di flusso ed i costrutti strutturati grazie ai quali è possibile esprimere algoritmi, all'interno di pagine JSP, senza più dover ricorrere al tag di escape in Java "<%".

Nello spirito di JSTL, anche i tag sono caratterizzati da una notevole immediatezza d'uso e facilità di comprensione, al punto da risultare facilmente intellegibili anche senza conoscerne in dettaglio le caratteristiche. A titolo di esempio la visualizzazione dei nominativi di tutti i contatti memorizzati in un ipotetico address book potrebbe venire realizzata con un codice simile al seguente (il namespace c si riferisce, come da convenzione, alla libreria JSTL core):

<table border="1">
<tr>
<td>Contatto</td>
</tr>
<c:forEach var="contact" items="${addressBook.contacts}$">
<tr>
<td>
<c:out value="${contact.name$}" />
</td>
</tr>
</c:forEach>
</table>

Tale codice, utilizzando le tradizionali pratiche di programmazione JSP basate su scriptlet Java, avrebbe un aspetto simile al seguente:

<jsp:useBean id="addressBook" scope="..." />
<table border="1">
<tr>
<td>Contatto</td>
</tr>
<%
Iterator i=addressBook.getContacts().iterator();

while (i.hasNext()) {
Contact contact=(Contact)i.next();
%>
<tr>
<td>
<%= contact.getName()%>
</td>
</tr>
<%
}
%>
</table>

I vantaggi in termini di leggibilità, manutenibilità ed interoperabilità sono immediatamente evidenti. Si noti anche come l'utilizzo di EL e della sua funzionalità automatica di ricerca degli oggetti nella catena degli scope correnti ci dispensi dall'utilizzo dei tag "<jsp:useBean>".

Tornando all'analisi dei tag della libreria JSTL core, possiamo raggrupparli da un punto di vista logico in tre macrocategorie:

  1. Tag di supporto al linguaggio di espressioni: il fine di questi tag è quello di fornire un 'ponte' tra il linguaggio di espressioni utilizzato e la libreria JSTL core. Appartengono a questo gruppo i seguenti tag:
    1. out: utilizzato per valutare un espressione - specificata nell'attributo value - ed inviarne il risultato al JspWriter corrente, in maniera analoga a quanto accade con il tag "<%=";
    2. set: imposta il valore di un attributo JSP o di una proprietà di un oggetto;
    3. remote: elimina un attributo / oggetto dallo scope specificato;
    4. catch: permette di gestire errori non critici direttamente dall'interno della pagina JSP.
  2. Tag di controllo di flusso: il fine di questi tag è di fornire versioni JSTL dei costrutti di iterazione e di scelta:
    1. if: implementa un costrutto di scelta analogo allo statement if del linguaggio Java;
    2. choose, when ed otherwise: questi tag implementano un costrutto di scelta multipla in maniera simile agli statement Java switch, case e default;
    3. forEach: realizza un costrutto di looping, sia basato su iteratore (come nell'esempio visto in precedenza) sia - in base agli attributi forniti al tag - in forma più generica, analogamente allo statement for di Java; si noti che forEach è in grado di iterare automaticamente su array di tipi primitivi, Collection, Iterator ed Enumeration;
    4. forTokens: implementa un costrutto di iterazione tramite parsing di una stringa in maniera simile a quanto realizzato dalla classe StringTokenizer.
  3. Tag di gestione di URL:
    1. import: utilizzato per rendere disponibile sotto forma di variabile il contenuto di un'URL; questo tag può venire utilizzato semplicemente per includere il contenuto di un'URL esterna all'applicazione nella pagina JSP corrente - azione non supportata dal tag "<jsp:include>" - ovvero per importare e processare dati remoti, magari in formato XML, con l'ausilio della libreria JSTL XML processing;
    2. url: permette la costruzione di URL a run-time, in base agli attributi specificati ed al contesto dell'applicazione corrente;
    3. redirect: provoca una browser redirection.

 

Conclusioni
In questo articolo abbiamo fornito una visione d'insieme dei fini e delle funzionalità di JSTL - ed in maniera più dettagliata di due suoi componenti fondamentali, l'Expression Language EL e la libreria JSTL core - nell'ambito dell'evoluzione e degli odierni campi di utilizzo ed integrazione del framework JSP in contesti applicativi distribuiti e multi-tier.
Nel prossimo articolo, avvalendoci delle conoscenze teoriche appena introdotte, metteremo JSTL alla prova realizzando un semplice Web Client JSP-based per un'ipotetica applicazione corporate, che successivamente provvederemo ad internazionalizzare sfruttando le funzionalità della libreria JSTL I18N capable formatting e quindi ad integrare - grazie alla libreria JSTL XML processing - con servizi XML esterni.


Bibliografia
[1] JSP - JavaServer Pages: http://java.sun.com/products/jsp
[2] FreeMarker: http://www.freemacro.org
[3] Velocity: http://jakarta.apache.org/velocity
[4] WebMacro: http://www.webmacro.org
[5] Jade: http://sourceforge.net/projects/salmon
[6] Struts: http://jakarta.apache.org/struts
[7] JSTL - JSP Standard Tag Library: http://java.sun.com/products/jsp/jstl
[8] JavaServer Pages 2.0 Specification - Proposed Final Draft: http://jcp.org/aboutJava/communityprocess/first/jsr152/
[9] JCP - Java Community Process: http://jcp.org

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