Introduzione
Con questo numero inizia l'ultima parte della lunga
serie di articoli intitolata "JSP e Web User Interface",
nel corso della quale abbiamo rivolto la nostra attenzione
ad alcune fondamentali tecnologie legate alla realizzazione
dello strato di interfaccia utente di applicazioni Web:
la JSP Standard Tag Library (JSTL), analizzata nei numeri
[1] - [4], Java Server Faces ([5]-[6]) ed infine le
Custom Tag Library (CTL), trattate in [7]-[10].
In particolare, dopo aver analizzato in [7] e [8] i
principali elementi strutturali di una CTL, in [9] gli
schemi di gestione di attributi, variabili di scripting
e tag nesting, ed in [10] i meccanismi di gestione di
eccezioni ed eventi, intendiamo nel presente e nel successivo
articolo applicare le conoscenze così acquisite
al design, all'integrazione ed all'implementazione di
una Custom Tag Library rivolta ad un'estensione operativa
della nostra applicazione d'esempio NetView.
Per
la massima comprensione dei contenuti che andremo a
trattare si consiglia di fare frequente riferimento
all'applicazione NetView, i cui sorgenti commentati
sono liberamente disponibili e scaricabili dalla sezione
Risorse del presente articolo.
Il
problema
Come sicuramente ricorderete, NetView è stata
realizzata dietro richiesta della famigerata multinazionale
ACME per venire incontro alle sue esigenze di gestione
remota e web-based del proprio parco hardware e software.
La buona prova che il team di sviluppo di NetView ha
dato di sé sembra avere stimolato ACME, che ci
commissiona uno studio di fattibilità - con successiva
implementazione - concernente un significativo ampliamento
funzionale dell'applicativo.
Viene richiesta l'implementazione in NetView di una
feature di accesso ed interrogazione diretta dei singoli
dispositivi monitorati, al fine di fornire all'utente
le principali impostazioni di configurazioni e statistiche
di attività di ogni nodo, aggiornate in tempo
reale. In un futuro non immediato tale sottosistema
software sarebbe presumibilmente destinato a venire
esteso, affiancando alle possibilità di query
analoghe funzionalità di configurazione dei dispositivi
sotto controllo.
Analisi
del problema
Risulta immediatamente evidente la complessità
della proposta di ACME: i diversi nodi monitorati sono
infatti raggiungibili, interrogabili e gestibili tramite
un ampio spettro di protocolli, diversi per struttura
e caratteristiche di base.
Volendo fare qualche esempio, NetView dovrebbe essere
in grado di utilizzare il protocollo SNMP per accedere
ad un router, mentre la gestione di un database server
avverrebbe tramite un apposito set di comandi SQL o
simil-SQL inviati in contesto JDBC; ancora diverse sarebbero
le metodologie di amministrazione di server di rete,
application server e directory server.
Tuttavia il team di sviluppo di NetView, le cui core
competence sono indirizzate allo sviluppo di soluzioni
Java in ambito distribuito, non possiede una così
vasta ed approfondita esperienza di protocolli e problematiche
sistemistiche, e si trova quindi nell'impossibilità
di fatto di venire incontro alle esigenze del cliente.
Tale insieme di conoscenze è, d'altronde, proprio
del settore IT della stessa ACME, il quale per impostazione
professionale è in possesso sia degli skill teorici
sia della necessaria esperienza sul campo, trovandosi
ogni giorno a dover gestire tale parco hardware e software.
Una ottimale soluzione alle richieste del cliente può
quindi, nel nostro esempio, risultare solamente dallo
sfruttamento sinergico delle conoscenze dei due diversi
gruppi di lavoro: al reparto di IT di ACME, in possesso
delle necessarie competenze, dovrebbe venire demandata
l'implementazione dei meccanismi di comunicazione e
gestione dei dispositivi, la cui integrazione all'interno
dell'applicativo - tanto dal punto di vista funzionale
quando di interfaccia utente - spetterebbe al team di
sviluppo di NetView.
Scendendo nel dettaglio, apposite sessioni di analisi
- estese a rappresentanti del settore IT di ACME - individuano
in una Custom Tag Library la soluzione ideale al problema.
In particolare risultano decisive le seguenti considerazioni:
L'utilizzo di una CTL permette ai due gruppi di lavoro
di mantenere la massima autonomia e consente loro di
focalizzarsi unicamente su un aspetto del problema,
valorizzando ed esaltando i propri skillset;
la separazione delle attività dei due gruppi
di lavoro consente la difesa e la salvaguardia dei rispettivi
patrimoni di conoscenze;
il contesto di API nel quale sono inquadrate le Custom
Tag Library è caratterizzato da una notevole
semplicità. In particolare non si richiede all'autore
di una CTL di comprendere e padroneggiare concetti avanzati
di programmazione parallela o distribuita, né
viene richiesta una conoscenza approfondita della struttura
di J2EE e delle sue API più caratterizzanti,
quali EJB, JMS e JCA;
alla luce della precedente considerazione lo sviluppo
di CTL può venire intrapreso con successo anche
da gruppi di lavoro in possesso di una conoscenza moderata
del linguaggio Java; di più, se necessario, gli
opportuni skillset possono venire trasmessi in numero
limitato di ore-uomo;
le Custom Tag Library così realizzate e distribuite
in archivi JAR indipendenti rappresentano a tutti gli
effetti dei componenti completamente scissi dalle particolarità
dell'applicazione al cui interno vengono utilizzate
e, se basate su di un design sufficientemente curato,
risultano utilizzabili con efficacia e semplicità
all'interno di nuovi progetti.
Decisa
quindi la divisione di compiti tra il reparto IT di
ACME ed il team di sviluppo di NetView per quanto riguarda,
rispettivamente, l'implementazione della Custom Tag
Library e la sua integrazione all'interno dell'applicativo,
i due gruppi di lavoro passano alla fase di messa a
punto congiunta del design della CTL.
Design
della Custom Tag Library
Alla luce della volontà comune di separare il
layer di comunicazione verso i dispositivi da quello
di gestione dello strato di presentazione, si decide
- secondo le linee da noi espresse in [7] - di liberare
completamente il reparto IT da ogni problematica di
interfaccia utente.
Tale obiettivo viene raggiunto già in fase di
design, stabilendo che i tag non genereranno alcun output,
ma utilizzeranno quale unico strumento di comunicazione
con la vista JSP delle variabili di scripting, trattate
in [9] e tramite le quali gli sviluppatori NetView saranno
in grado di utilizzare i contenuti generati dalla CTL
con la massima libertà ed in funzione delle necessità
applicative.
Si noti che, in virtù del fine formativo di questo
articolo, ammetteremo una deroga a tale norma limitatamente
al solo tag <sendCommand>, come avremo modo di
discutere in seguito.
La Custom Tag Library che implementa i necessari comportamenti
di query dei dispositivi remoti - denominata nvtags
- è basata su di un numero ristretto di tag,
che andiamo ora ad esaminare.
Il
tag fondamentale è <nodeInfo>, tramite
cui una pagina JSP stabilisce una connessione ad un
dispositivo e ne ottiene delle informazioni di base.
Il dispositivo viene identificato attraverso i due attributi
obbligatori nodeId e catId, contenenti il primo il codice
del nodo ed il secondo il suo codice di categoria.
Il tag <nodeInfo>, facendo uso del protocollo
più adatto - i cui dettagli tecnici risultano
comunque completamente invisibili a NetView - provvede
a contattare il dispositivo ed a ritornarne a JSP in
tempo reale la configurazione sotto forma di variabili
di scripting.
Nella nostra limitata implementazione di esempio ci
limiteremo a due variabili di scripting: la stringa
productName, contenente il nome completo del prodotto,
ed una variabile di tipo java.util.Date denominata lastBoot,
la quale specifica la data di ultimo boot del nodo.
Al fine di semplificare l'utilizzo della Custom Tag
Library si decide di avvalersi delle funzionalità
di tag nesting supportate da JSP e da noi analizzate
in [9] per definire il concetto di nodo corrente. L'utilizzo
di un tag <nodeInfo> renderà quindi corrente
il nodo specificato attraverso gli attributi nodeId
e catId; i successivi tag di gestione, innestati all'interno
del tag <nodeInfo>, faranno implicitamente riferimento
al medesimo dispositivo, senza che sia necessario dichiararne
nuovamente codice e categoria.
Si noti che gli attributi nodeId e catId verranno valorizzati
solamente a run-time, in base al nodo selezionato in
maniera dinamica dall'utente; come vedremo in seguito,
questa funzionalità viene attivata a livello
di Tag Library Descriptor impostando l'attributo <rtexprvalue>
a true.
Data la sua semplicità <nodeInfo> può
venire implementato come un tag base, rispondente all'interfaccia
javax.servlet.jsp.Tag.
Il
secondo tag definito in nvtags è <interfaceIterator>,
il quale espone alla vista JSP informazioni concernenti
le interfacce di rete di un nodo di tipo router o network
server. Il nome del tag ne tradisce già un'importante
caratteristica: disponendo in linea di principio un
nodo di un numero a piacere di interfacce di rete, <interfaceIterator>
dovrà essere in grado di ritornare alla pagina
JSP un insieme strutturato di dati. Tale requisito viene
rispettato implementando il tag <interfaceIterator>
come tag iterativo (interfaccia javax.servlet.jsp.IterationTag).
Ad ogni iterazione verranno resi disponibili alla vista
JSP sotto forma di variabili di scripting i dati di
configurazione di una particolare interfaccia di rete
e l'iterazione proseguirà sino all'avvenuta enumerazione
di tutte le interfacce.
Secondo quanto stabilito in precedenza <interfaceIterator>
viene sempre innestato all'interno di un tag <nodeInfo>,
dal quale ottiene i dati del dispositivo su cui operare.
L'implementazione d'esempio del tag <interfaceIterator>
conosce due variabili di scripting: ipAddress e snMask,
rappresentanti rispettivamente l'indirizzo IP e la subnet
mask di un'interfaccia.
Il
terzo ed ultimo tag implementato dalla Custom Tag Library
nvtags è <sendCommand>, il quale implementa
una feature di utilizzo generale, consistente nell'invio
ad un dispositivo - tramite il protocollo più
confacente - di un comando a piacere, specificato come
corpo del tag. Dovendo il tag <sendCommand> operare
sul proprio contenuto, esso viene implementato come
content tag, secondo gli schemi dell'interfaccia javax.servlet.jsp.BodyTag.
Esattamente come nel caso di <interfaceIterator>
anche <sendCommand> non possiede attributi propri
nodeId e catId, ma va sempre utilizzato in congiunzione
ad un tag <nodeInfo>, al cui interno viene innestato.
Si noti che nella nostra implementazione, a fini d'esempio,
<sendCommand> non comunica con la pagina JSP tramite
variabili di scripting: esso è infatti l'unico
tag della nostra CTL a generare output, inviando direttamente
al motore Java Server Pages i risultati di esecuzione
del comando.
Per
tutte le variabili di scripting definite dai suddetti
tag si decide di far uso dello scope NESTED, il cui
utilizzo viene generalmente raccomandato; esso limita
la visibilità di tali variabili all'interno del
body dei rispettivi tag e minimizza il rischio di conflitti
con altri tag o Custom Tag Library JSP.
Ultimato
il design della CTL nvtags, passiamo ad analizzarne
gli aspetti pratici. Seguendo una tradizionale logica
top-down astrarremo la sua esistenza e ci concentreremo
ora sulle sue modalità di utilizzo dall'interno
di una web application, rimandando al prossimo articolo
la discussione della sua implementazione.
Application
Developer: utilizzo di una Custom Tag Library
Nel processo di ampliamento ed integrazione dell'applicativo
oggetto del presente articolo, il ruolo svolto dal team
di sviluppo di NetView coincide con quello di Application
Developer identificato a livello di specifiche J2EE:
in sostanza gli autori di NetView si configurano come
utenti della Custom Tag Library nvtags.
Avendo
i due gruppi di lavoro in sede di design - ed in linea
con quanto da noi consigliato in [8] - optato per la
distribuzione della CTL sotto forma di archivio JAR
autonomo, la sua integrazione in NetView a livello architetturale
è elementare, e si limita all'installazione dell'archivio
JAR all'interno della struttura di directory dell'applicativo,
tipicamente nella directory WEB-INF/lib. A questo punto
sarà sufficiente dichiarare tale libreria in
tutte le viste JSP che intendano farne uso.
Si noti, in particolare, che non è richiesto
alcun intervento a livello di deployment descriptor
(file web.xml) il quale rimane totalmente inalterato.
L'implementazione
in NetView delle modifiche richieste si basa sostanzialmente
sulla definizione della nuova vista JSP getinfo.jsp,
la quale - come vedremo nella prossima sezione - provvede
all'estrazione ed alla presentazione dei dati di configurazione
di un dispositivo. La struttura della nostra applicazione
rende quindi banale l'integrazione di tale pagina all'interno
dello scheletro generale di NetView, per cui è
sufficiente definire una nuova azione getinfo a livello
di FrontControllerServlet ed implementare il dispatcher
GetInfoDispatcher, il quale invoca la view getinfo.jsp
fornendole come attributi di richiesta HTTP i seguenti
parametri, tutti di tipo String:
A
livello di interfaccia desideriamo collegare la vista
getinfo.jsp al resto dell'applicazione a partire dalla
view nodes.jsp, la quale fornisce all'utente un elenco
di nodi. Implementiamo quindi, accanto ai preesistenti
link di modifica e cancellazione, un nuovo link informativo,
attraverso il quale l'utente potrà attivare la
pagina getinfo.jsp per ottenere dati di configurazione
in tempo reale su di un nodo a sua scelta.
Questa funzionalità si concretizza, in nodes.jsp,
nella semplice aggiunta di un elemento href alla tabella
che provvede a visualizzare i dispositivi in base alla
selezione corrente, avendo l'accortezza di passare a
getinfo.jsp, ovvero al suo dispatcher, il codice del
nodo da esaminare nel parametro id:
<td>
<a href="/netview/main?action=getinfo&id=<c:out
value='${node.id}' />" title="Informazioni">
<img src="Information24.gif" border="0"
alt="Informazioni" /></a\>
</td>
La
vista JSP getinfo.jsp: integrazione di Custom Tag Library
Procediamo ora all'analisi della vista JSP getinfo.jsp,
la quale sfrutta la CTL nvtags per implementare le seguenti
funzionalità:
Visualizzazione dei dati generali di configurazione
di un nodo productName e lastBoot, descritti in sede
di analisi ed ottenuti per via del tag <nodeInfo>;
per i soli nodi di tipo router e network server, enumerazione
delle interfacce di rete e visualizzazione delle relative
impostazioni grazie al tag <interfaceIterator>;
per i nodi di tipo network server elenco degli utenti
attualmente collegati, ottenuto attraverso il tag <sendCommand>;
per i nodi di tipo database server lista dei database
attivi, anch'essa risultante dall'utilizzo del tag <sendCommand>.
In
apertura viene dichiarato l'utilizzo della libreria
JSP nvtags:
<%@
taglib prefix="nvtags" uri="/WEB-INF/lib/nvtags.jar"
%>
L'attributo
uri punta all'archivio JAR contenente la Custom Tag
Library, il cui percorso viene specificato a partire
dalla root directory dell'applicazione web.
Come prefisso può, al solito, venire utilizzata
una stringa a piacere. Nel nostro caso rispettiamo la
convenzione secondo la quale il prefisso collima con
l'attributo <short-name> dichiarato nel Tag Library
Descriptor della CTL, che avremo modo di esaminare nel
prossimo numero.
Seguono
quindi le usuali definizioni di testata, l'inclusione
di topbar.jsp e la visualizzazione dei dati del nodo
corrente; per quest'ultima funzionalità vengono
impiegati i parametri di request di getinfo.jsp:
<tr>
<td width="150">Nodo:</td>
<td width="300"><b><c:out value="${id}"
/> (<c:out value="${desc}" />)</b></td>
</tr>
<tr>
<td width="150">Categoria:</td>
<td width="300"><b><c:out value="${catId}"
/> (<c:out value="${catDesc}" />)</b></td>
</tr>
Rendiamo
poi disponibili a livello di JSP sotto forma di variabili
di scripting i parametri di request id e catId, che
dovremo fornire al tag <nodeInfo>:
<jsp:useBean
id="id" scope="request" class="String"/>
<jsp:useBean id="catId" scope="request"
class="String" />
Facciamo
uso del tag <nodeInfo> per ricevere nelle variabili
di scripting productName e lastBoot le informazioni
di configurazione del nodo specificato, che provvediamo
quindi a visualizzare.
Si notino in particolare sia l'utilizzo degli attributi
nodeId e catId, valorizzati dinamicamente al valore
delle variabili di scripting id e catId - corrispondenti
agli omonimi parametri di request in virtù dei
precedenti tag <useBean> - sia il fatto che il
tag <nodeInfo> venga volutamente lasciato aperto.
Sarà infatti al suo interno, in modalità
innestata, che utilizzeremo i tag <interfaceIterator>
e <sendCommand> per estrarre ulteriori informazioni
dal dispositivo.
Avendo
in sede di design stabilito di utilizzare lo scope NESTED
per le nostre variabili di scripting, la view getinfo.jsp
si preoccupa di impiegarle solamente all'interno dei
rispettivi tag.
<nvtags:nodeInfo
nodeId='<%=id%>' catId='<%=catId%>' >
<tr>
<td width="150">Nome prodotto:</td>
<td width="300"><b><%=productName%></b></td>
</tr>
<tr>
<td width="150">Data ed ora di boot:</td>
<td width="300"><b><%=lastBoot%></b></td>
</tr>
Successivamente,
se abbiamo a che fare con un router o un network server
- corrispondenti rispettivamente alle categorie 1 e
2 - ne visualizziamo la configurazione delle interfacce
di rete nelle variabili di scripting ipAddress e snMask
grazie al tag iterativo <interfaceIterator>. Si
noti come sintassi e semantica di questo tag ricordino
da vicino quelle del tag <for> di JSTL: l'utilizzo
ripetuto dei medesimi idiomi, che nel tempo diventano
familiari agli sviluppatori, è uno dei punti
di forza del paradigma JSP.
Come
stabilito in fase di design il tag <interfaceIterator>
si avvale delle funzionalità di tag nesting di
JSP: innestato all'interno di un tag <nodeInfo>
ne eredita automaticamente gli attributi nodeId e catId,
che non vanno così ripetuti.
Si
noti infine che il test di uguaglianza sul parametro
catId viene eseguito in modalità alfanumerica,
venendo quest'ultimo passato alla vista JSP sotto forma
di stringa.
<c:choose>
<c:when test="${catId=='1' or catId=='2'}">
<tr>
<td colspan="2" width="450">
Interfacce di rete:
</td>
</tr>
<nvtags:interfaceIterator>
<tr>
<td width="150" align="center">
<%=ipAddress%>
</td>
<td width="150" align="center">
<%=snMask%>
</td>
</tr>
</nvtags:interfaceIterator>
</c:when>
</c:choose>
Provvediamo
quindi ad estrarre ulteriori informazioni dal dispositivo:
se abbiamo a che fare con un network server (categoria
2) vogliamo visualizzare l'elenco degli utenti collegati,
funzionalità che otteniamo utilizzando il tag
<sendCommand> per inviare al server remoto un
comando "who" e presentarne il risultato all'utente.
Si noti che la Custom Tag Library nvtags ci permette
di astrarre completamente dalle modalità fisiche
di invio di tale comando, che nel nostro caso potrebbe
nella realtà delle cose avvenire tramite ssh,
rlogin o telnet.
Come
abbiamo già fatto notare, a fini esemplificativi
l'implementazione proposta del tag <sendCommand>
non comunica alla vista JSP il risultato del comando
tramite un'apposita variabile di scripting, ma provvede
in prima persona all'invio dell'output all'engine Java
Server Pages, che racchiudiamo in un tag <pre>
onde evitare problemi di formattazione.
<c:choose>
<c:when test="${catId=='2'}">
<tr>
<td colspan="2" width="450">
Utenti collegati:
</td>
</tr>
<tr>
<td colspan="2" width="450">
<pre>
<nvtags:sendCommand>
who
</nvtags:sendCommand>
</pre>
</td>
</tr>
</c:when>
In
maniera analoga qualora il nodo selezionato sia un database
server (categoria 4) utilizziamo il tag <sendCommand>
per inviare al nodo il comando fittizio "LIST DABASES",
a fronte del quale viene generato in output l'elenco
dei database attivi.
<c:when
test="${catId=='4'}">
<tr>
<td colspan="2" width="450">
Database attivi:
</td>
</tr>
<tr>
<td colspan="2" width="450">
<pre>
<nvtags:sendCommand>
LIST DATABASES
</nvtags:sendCommand>
</pre>
</td>
</tr>
</c:when>
</c:choose>
Avendo
completato la presentazione di tutte le informazioni
richieste possiamo considerare concluso il processing
del dispositivo e provvediamo quindi a chiudere il tag
<nodeInfo> e con esso il contesto del nodo corrente.
</nvtags:nodeInfo>
Conclusioni
Terminata lo scorso mese la trattazione teorica delle
JSP API concernenti le Custom Tag Library abbiamo iniziato
nel presente articolo a mettere in pratica le conoscenze
acquisite, dedicandoci al design, integrazione ed utilizzo
di una CTL rivolta ad un'estensione funzionale della
nostra applicazione d'esempio NetView.
In particolare abbiamo in questo numero voluto concentrare
la nostra attenzione sulle fasi di progettazione ed
integrazione, analizzando le motivazioni e le scelte
operate in fase di design e le modalità di utilizzo
di una nuova Custom Tag Library all'interno di una web
application preesistente, mettendo in luce la chiarezza
e l'intuitività dei passi richiesti, così
come la loro confortante assonanza con sintassi ed idiomi
a noi noti e consueti nel mondo JSTL.
Nel prossimo numero - con il quale giunge al termine
la presente serie di articoli "JSP e Web User Interface"
- concluderemo l'esempio pratico qui iniziato, soffermandoci
sull'attività pratica di codifica di una Custom
Tag Library, la quale nel paradigma J2EE caratterizza
il ruolo del Tool Developer.
Bibliografia
e riferimenti
[1] Lavinio Cerquetti: "JSP 1.2: JSTL - I parte",
Mokabyte N. 67 - Ottobre 2002
[2] Lavinio Cerquetti: "JSP 1.2: JSTL - II parte",
Mokabyte N. 68 - Novembre 2002
[3] Lavinio Cerquetti: "JSP 1.2: JSTL - III parte",
Mokabyte N. 69 - Dicembre 2002
[4] Lavinio Cerquetti: "JSP 1.2: JSTL - IV parte",
Mokabyte N. 70 - Gennaio 2003
[5] Lavinio Cerquetti: "JSF: Java Server Faces
- I parte", Mokabyte N. 71 - Febbraio 2003
[6] Lavinio Cerquetti: "JSF: Java Server Faces
- II parte", Mokabyte N. 72 - Marzo 2003
[7] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - I parte", Mokabyte N. 73 - Aprile 2003
[8] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - II parte", Mokabyte N. 74 - Maggio 2003
[9] Lavinio Cerquetti: "Custom Tag Library in ambienti
J2EE - III parte", Mokabyte N. 74 - Giugno 2003
[10] Lavinio Cerquetti: "Custom Tag Library in
ambienti J2EE - IV parte", Mokabyte N. 74 - Luglio-Agosto
2003
Risorse
Scarica qui il codice
presentato nell'articolo (NetView versione 1.3).
L'implementazione di esempio di NetView è stata
testata sotto JBoss 3.0.3 e Tomcat 5 (Milestone 5.0.0)
in ambiente Linux con database IBM DB2.
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
|