MokaByte 88 - 7mbre 2004 
MokaPackages
Il framework MVC di MokaByte
II parte: MBTL la custom tag library
di
Giovanni
Puliti

Dopo il primo articolo della serie in cui si mostrava il funzionamento di base dei principali componenti del framework, questo mese parliamo della custom tag library di MokaByte (MBTL). Questo pezzo di framework contiene alcuni custom tag JSP che, pur non essendo più semplici e limitati in numero rispetto a quanto offerto dall'equivalente library di Struts o di JSTL, sono più sufficienti per la realizzazione della maggior parte delle applicazioni JSP. Ad oggi in molte delle applicazioni scritte con MokaPackages non si sono evidenziate grosse carenze o mancanze da parte dei tag della libreria, ne tanto meno si è sentita l'esigenza dei tag presenti nelle tag library concorrenti. Questo non significa certo che la MBTL sia potente quanto quelle presenti in altri prodotti, ma è vero che se si segue la logica del "tutto sul server" e del "tutto nel model di MVC", spesso diminuisce radicalmente la necessità di disporre di un numero elevato di tag custom. In questo articolo presentiamo i tag attualmente disponibili, consci del fatto che al momento MBTL non è completa e che alcuni pezzi verranno implementati prossimamente.

La MokaByte Tag Library
I tag che compongono la library permettono essenzialmente di svolgere le seguenti operazioni:

  • Gestione di un sistema di template JSP: tramite alcuni semplici tag è possibile definire un template JSP all'interno del quale sono poi definite alcune zone. Le zone vengono poi popolate tramite altri tag. Questo sistema (molto semplice ma flessibile) è il punto di forza di tutta la library. Data la sua estrema semplicità offre numerosi vantaggi rispetto alla concorrenza, probabilmente più potente ma anche un più macchinosa.

  • Iterazione su liste: questo tag consente di scorrere iterativamente un elenco di elementi e di impaginarli in HTML. La lista degli articoli trovati dopo una ricerca, gli articoli aggiunti al carrello della spesa sono due semplici esempi di liste di elementi che possono essere implementati tramite questo tag. Il tag può essere considerato come una specie di ciclo for che consente l'iterazione su elementi passati dallo strato di business logic.

  • Inclusione condizionale di pezzi di HTML o di pagine esterne: molte volte può essere necessario includere pezzi di HTML o pagine esterne in funzione di alcune condizioni logiche (vero,falso). Ad esempio se un utente sta procedendo al pagamento di un acquisto ed ha scelto di pagare con carta di credito potrebbe essere necessario visualizzare informazioni circa determinati aspetti legati alla sicurezza. Tali messaggi non verranno visualizzati per coloro che scelgono il pagamento con contrassegno.

  • Paginazione: se una lista di elementi è troppo lunga per essere visualizzata in una singola pagina, allora è necessario effettuare una paginazione. Come accade comunemente in tutti i motori di ricerca in fondo alla pagina che mostra i risultati della ricerca appare una tabellina con la quale è possibile andare a visualizzare le pagine successive. Il tag in questione è al momento in fase di rifacimento essendo piuttosto scomodo da usare. Lavora in combinazione con il tag iterate.

  • Menu condizionali: questo tag è in fase di realizzazione e rappresenta una evoluzione del tag di inclusione condizionale. Esso mostra alcune voci in base ad alcune regole logiche (es. la voce di menu "logout" appare solo se l'utente si è già loggato) e permette di specificare il ruolo utente da associare a determinate voci di menu (solo se un utente si è loggiato con ruolo utente = "administrator" potrà visualizzare un menu riservato)

  • Navigazione: in questa categoria sono inseriti alcuni tag utili per la navigazione web, come ad esempio il tag back(permette di andare indietro nella history della applicazione in un punto preciso) o jumpto che consente di inviare l'utente ad un url particolare fra quelli che ha percorso in precedenza. Per il momento questi tag non verranno affrontati perché sono ancora in fase di completamento.

Per poter utilizzare i tag elencati brevemente qui sopra si deve specificare che si stanno utilizzando dei custom tag facenti parte della MBTL: la specifica JSP dice che tale informazione può essere specificata tramite il tag <taglib>. Ad esempio nel caso di MBTL si deve inserire la riga

<%@ taglib uri='mbtl' prefix='mbtl' %>

in ogni pagina JSP della applicazione. L'attributo prefix specifica il prefisso che sarà utilizzato per tutti i tag della pagina. Ad esempio in una pagina JSP che non usa tag custom ma solo quelli definiti dalla JSP API, il prefix è jsp, e difatti in una comune pagina JSP si è abituati a incontrare cose del tipo

<jsp:include ….>

L'attributo uri invece specifica la locazione del file di definizione della libreria. Si può in questo caso specificare un URL assoluto, oppure uno relativo (come nel caso in esame).
Citando direttamente il paragrafo del Manuale Pratico di Java (vedi [MPJ]) edito da MokaByte, ecco la definizione di tale attributo

"[…] L'attributo uri specifica la posizione del TLD associato alla Custom Tag Library, mentre l'attributo prefix comunica al motore JSP il prefisso con il quale si desidera fare riferimento ai tag della Custom Tag Library nella pagina corrente. Si noti che il prefisso associato a una CTL non rappresenta una proprietà della tag library stessa, ma può essere liberamente scelto dall'autore della pagina JSP. Dal momento che ciò può rendere il codice confuso e difficilmente comprensibile, si consiglia di scegliere e utilizzare i prefissi delle CTL in maniera logica e coerente, attenendosi alla relativa documentazione. Uno standard comunemente accettato consiste nell'utilizzare prefissi chiari e significativi, facendo possibilmente uso al loro interno del nome della propria azienda o organizzazione - in maniera sostanzialmente analoga a quanto avviene per i package Java - al fine di evitare possibili conflitti nella nomenclatura delle Custom Tag Library.
Vale qui la pena di notare come i prefissi jsp:, jspx:, java:, javax:, servlet:, sun: e sunw: siano da considerarsi riservati e non possano venire assegnati a tag library di terze parti."

Per altre informazioni ed approfondimenti relativi a come si realizzano tag library, a come si installano in una web application ed a come si usano, si possono trovare nel capitolo su JSP del Manuale Pratico di Java (vedi [MPJ]).

 

Gestione dei template
Questo tag permette di gestire un sistema di template per le pagine JSP della applicazione. Il meccanismo si basa su due parti: nel file di template si specificano le sezioni che dovranno definire le parti del template stesso tramite il tag <mbtl:define> come mostrato nel seguente codice relativo ad un semplicissimo template JSP

<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<body bgcolor="#FFFFFF" text="#000000">
<table width="700" border="1" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="center">
<mbtl:define section="title" printable="true"> </mbtl:define>
</div>
</td>
</tr>
<tr>
<td>
<div align="center">
<mbtl:define section="body" printable="true"> </mbtl:define>
</div>
</td>
</tr>
<tr>
<td>
<div align="center">
<mbtl:define section="footer" printable="false"> </mbtl:define>
</div>
</td>
</tr>
</table>
</body>
</html>

L'attributo section permette di specificare il nome della sezione che si vuole definire, mentre printable=true|false consente di specificare se si dovrà riempire la zona con del testo da inserire direttamente come HTML oppure se dovrà essere inserita una risorsa esterna.
Per capire meglio il funzionamento del template è utile passare a vedere il funzionamento del tag template

In ogni pagina JSP che voglia usare il template definito dovrà usare il tag <mbtl:template> per indicare quale template debba essere usato, ed il tag <mbtl:insert> per riempire le varie parti del template header, title, menu, body, footer..).
Supponendo che il template visto in precedenza si chiami template.jsp, una pagina che utilizzi tale template potrebbe essere così definita:

<%@ taglib uri='mbtl' prefix='mbtl' %>
< !-- si specifica quale template JSP si deve usare -->
<mbtl:template name='pageTemplate' content='template.jsp'>

< !-- si inserisce il titolo della pagina tramite la definizione di testo direttamente nel template-->
<mbtl:insert section='pagetitle' printable='true'>
Una pagina di prova di uso dei template
</mbtl:insert>

< !-- si inserisce il corpo della pagina tramite la definizione di testo direttamente nel template-->
<mbtl:insert section='body' printable='true'>
Questa pagina usa un template per la composizione grafica
</mbtl:insert>

< !-- si inserisce il footer tramite l'inclusione di una pagina JSP esterna -->
<mbtl:insert section='footer' element='footer.jsp'/>

</mbtl:template>


Da notare che il tag <mbtl:insert> accetta come parametro l'attributo section con il quale si specifica la porzione del template che si desidera popolare, e l'attributo printable che accetta i valori "true|false": nel primo caso verrà inserito del testo direttamente nel template. Se invece si usa printable=false, dovrà essere specificato il nome del file JSP (o HTML) da usare per riempire la porzione indicata, tramite l'attributo element.

Si noti il differente uso del tag <mbtl:insert> usato per inserire del testo direttamente nella pagina, oppure per inserire un file JSP come mostrato nella sezione footer.

 

Iterazione
Il tag iterate permette di eseguire un ciclo for all'interno di una pagina JSP, funzione che tipicamente è utilizzabile per creare pezzi di HTML in modo ricorsivo sulla base di n elementi appartenenti ad una lista. Nella applicazione di esempio allegata, viene realizzato un semplice ciclo di iterazione con lo scopo di creare una tabella HTML che mostra alcuni libri di una ipotetica vetrina online.
Il tag iterate si definisce in questo modo

<mbtl:iterate type="com.mokabyte.testmvc.shop.BookItem" list="<%= itemsManager.getBookList()%>" name="item">
<!-- iterazione -->
</mbtl:iterate>

All'attributo list viene assegnata una lista di oggetti confezionati all'interno di un oggetto LinkedList: in questo caso la lista proviene dal metodo getBookList() del bean com.mokabyte.testmvc.beans.ItemsManagerBean il quale svolge la funzione di semplice gestore di serie di oggetti. Il tipo (classe Java) degli elementi contenuti all'interno della lista deve essere specificato con l'attributo type: in questo caso ogni elemento della lista è un BookItem, oggetto creato ad hoc e presente nella applicazione. Tramite name si specifica il nome che verrà assegnato ad ogni oggetto della lista.
Il risultato finale è

<table width="100%" border="0" >
<!-- Stampa la prima riga con le intestazioni delle colonne -->
<TR>
<TD><font face="Arial,Helvetica" size=-1><b>Titolo</b></font></TD>
<TD><font face="Arial,Helvetica" size=-1><b>Autore</b></font></TD>
<TD><font face="Arial,Helvetica" size=-1><b>Casa Editrice</b></font> </TD>
</TR>

<!-- Stampa le altre righe una per ogni libro appartenente alla lista -->
<mbtl:iterate type="com.mokabyte.testmvc.shop.BookItem" list="<%= itemsManager.getBookList()%>"
name="item">
<TR>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getTitle() %></font></font></TD>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getAuthor() %></font></font></TD>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getPublisher() %></font></font></TD>
</TR>
</mbtl:iterate>
</table>


Il servlet engine inserirà tante volte il testo inserito fra i due tag <mbtl:iterate> e </mbtl:iterate> quanti sono gli elementi appartenenti alla lista.
All'interno della coppia <mbtl:iterate></mbtl:iterate> si potranno utilizzare i libri della lista per stampare ad esempio una tabella, dato che ad ogni iterazione l'elemento item è istanziato con un elemento differente della lista.
Come sia caricata la lista con i libri è un dettaglio che non interessa in questo contesto: potrebbe essere stata caricata da un database oppure creata in un qualsiasi altro modo. In questo caso la lista viene semplicemente istanziata all'interno del costruttore del bean ItemsManagerBean:

public ItemsManagerBean() {
// crea 8 oggetti BookItem
BookItem book1 = new BookItem("Manuale Pratico di Java - Prima Edizione","aa.vv.","MokaByte Ed.");
BookItem book2 = new BookItem("Manuale Pratico di Java - Seconda Edizione vol. 1","aa.vv.","MokaByte Ed.");
BookItem book3 = new BookItem("Manuale Pratico di Java - Seconda Edizione vol. 2","aa.vv.", "MokaByte Ed.");
BookItem book4 = new BookItem("UML ed ingegneria del software","Luca Vetti Tagliati","MokaByte Ed.");
BookItem book5 = new BookItem("Da Visual Basic a Java","Massimiliano Bigatti","MokaByte Ed.");
BookItem book6 = new BookItem("Applicazioni J2EE","Giovanni Puliti","MokaByte Ed.");
BookItem book7 = new BookItem("Java Micro Edition","Pierluigi Grassi","MokaByte Ed.");
BookItem book8 = new BookItem("Java per esempi","P.Grassi- G.Puliti","MokaByte Ed.");

// li aggiunge alla lista dei libri
bookList.add(book1);
bookList.add(book2);
bookList.add(book3);
bookList.add(book4);
bookList.add(book5);
bookList.add(book6);
bookList.add(book7);
bookList.add(book8);
}

 

Conditional include
Questo semplice tag permette di inserire del testo HTML in maniera condizionale a seconda che una determinata condizione sia rispettata. Ad esempio in una pagina si potrebbe scrivere

<!-- ricava un libro dal manger della applicazione -->
<%
BookItem book = ItemsManagerBean.findBookById("3233-233-455");
%>

<!-stampa l'intestazione della tabella -->
<table width="100%" border="0" >
<!-- Stampa la prima riga con le intestazioni delle colonne -->
<TR>
<TD><font face="Arial,Helvetica" size=-1><b>Titolo</b></font></TD>
<TD><font face="Arial,Helvetica" size=-1><b>Autore</b></font></TD>
<TD><font face="Arial,Helvetica" size=-1><b>Casa Editrice</b></font> </TD>
</TR>


<!-- stampa la riga con la visualizzazione dei dati del libro solo se è diverso da nullo -->
<mbtl:ConditionalInclude condition="<%=!(book == null)%>" printable='true'>
<TR>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getTitle() %></font></font></TD>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getAuthor() %></font></font></TD>
<TD><font face="Arial,Helvetica"><font size=-1><%= item.getPublisher() %></font></font></TD>
</TR>
</mbtl:ConditionalInclude>
</table>


I messaggi di errore e gestione delle eccezioni
Il tag <mbtl:messages> consente di visualizzare i messaggi di errore e/o di avvertimento che si sono verificati durante l'esecuzione di una particolare azione.
Ad esempio nella applicazione di esempio è stato inserito un link che causa l'esecuzione di FakeAction (letteralmente azione-falsa) un'azione che volutamente genera una eccezione. Ecco l'implementazione di FakeAction

public class FakeAction extends ActionImpl {
  // il metodo perform in questo caso genera volutamente una eccezione
  
   public Routing perform(HttpServlet httpServlet,
                          HttpServletRequest httpServletRequest,
                          HttpServletResponse httpServletResponse)
                          throws ActionException {

     throw new ActionException("Un errore generato appositamente per mostrare il
                               funzionamento della gestione degli errori in
                               MokaPackages");
   }
}


La azione viene eseguita dal controller (ActionServlet) il quale intercetta tutte le eccezioni che si generano all'interno delle azioni: per ogni eccezioni viene creato un oggetto Message ed aggiunto alla sessione.
Il tag <mbtl:messages> impagina iterando in un HTML molto semplice i messaggi trovati in sessione (nell'attributo messages).
Una limitazione attuale del tag è che l'HTML utilizzato per elencare tutti i messaggi di errore viene prodotto direttamente all'interno del tag, per cui non è possibile modificare la struttura (una lista puntata creata con il tag HTML <ul>).
Una possibile evoluzione di questo tag dovrebbe prevedere la possibilità di parametrizzare l'HTML da usare per la impaginazione dei messaggi.

 

Prossimamente
I prossimi passi nella evoluzione di MBTL prevedono l'aggiunta di ulteriori tag, l'ampliamento delle funzionalità di quelli esistenti ed una maggiore flessibilità come ad esempio la possibilità di internazionalizzare alcune parti.
Il progetto Open Source dovrebbe evolvere grazie al supporto del gruppo di lavoro che si sta costituendo in questo momento.

 

Bibliografia
[MPJ] Manuale Pratico di Java - www.mokabyte.it/manualejava2
[MVC] "MokaShop il negozio online di MokaByte: Progettare applicazioni J2EE multicanale. I parte: il modello MVC, la View ed il Controller" - di Giovanni Puliti, MokaByte 60 Febbraio 2002 - http://www.mokabyte.it/2002/02/devj2ee_1.htm


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