Introduzione
JSP
(Java Server Pages) è una tecnologia sviluppata da Sun per la realizzazione
di pagine Web dinamiche in cui il contenuto del documento HTML o WML viene
generato dinamicamente; la caratteristica più interessante delle
pagine JSP consiste nell'incapsulare i dettagli di rendering. Nel mondo
XML il linguaggio XSLT permette di trasformare documenti XML e uno dei
suoi utilizzi più diffusi consiste nel trasformare i documenti in
pagine da visualizzare in un browser. La possibilità di incapsulare
i dettagli di rendering in uno stylesheet XSL apre la strada, potenzialmente,
a qualsiasi tipo di browser o device come palmari, Web-TV e cellulari WAP.
L'unione
fra le tecnologie JSP e XML/XSLT è quindi naturale: in questo articolo
si approfondirà l'utilizzo delle pagine JSP nelle applicazioni J2EE
vedendo come si inserisce XML nell'architettura; quindi si vedrà
un esempio specifico di semplice applicazione Web con pagine JSP e trasformazioni
XSL.
Evoluzione dell'architettura
MVC
L'architettura
J2EE fornisce allo sviluppatore tutti gli strumenti, architetturali e tecnologici,
per la realizzazione di applicazione enterprise su Web. Più precisamente
-
i servlet
assumono il ruolo di gestori di richieste, o controller;
-
i componenti
EJB incapsulano la logica applicativa e l'accesso a database;
-
le pagine
JSP permettono di gestire gli aspetti di rendering delle pagine Web (HTML
o altro).
In questo
modo è possibile realizzare un'architettura
Model-View-Controller
in cui modello dei dati, la loro rappresentazione e la gestione delle richieste
sono completamente separati.
Quali
potrebbero essere i punti all'interno di questa architettura in cui usare
XML e le tecnologie correlate ? Se ne possono individuare almeno due
Rappresentazione
del modello dei dati. In questo modo è possibile astrarre dalla
particolare sorgente dati utilizzata; questa potrebbe essere un database,
un file di testo o un altra applicazione che espone informazioni in formato
XML.
Rendering
delle informazioni. Anche se i dati non sono esposti in formato XML
è comunque possibile convertirli in questo formato ed eseguire il
rendering mediante un'opportuna trasformazione XSL.
E' appunto
il rendering delle pagine Web che costituisce il principale campo di applicazione
delle tecnologie XML e JSP, e da questo punto di vista l'introduzione di
una tecnologia come XML permetta di ottenere notevoli vantaggi architetturali:
si consideri ad esempio la possibilità di separare la generazione
di un documento dalla sua visualizzazione.
Come
si può realizzare in concreto con tecnologia Java-based ? Si supponga
di voler visualizzare su Web le informazioni contenute in un database;
riprendendo l'architettura MVC si avranno
-
un componente
che legge i dati;
-
una pagina
JSP che mostra i dati, applicando una trasformazione XSL al documento ottenuto;
-
un servlet
che coordina il flusso di esecuzione;
La prossima
sezione
presenta in dettaglio una semplice applicazione di Web publishing con pagine
JSP e XML.
Web publishing
di documenti XML
Si
è visto in precedenza l'architettura di un'applicazione Web J2EE;
riportando l'attenzione sull'uso di XML sorge un problema: in che formato
vengono esposti i dati dal componente di middleware?
Potrebbe
essere XML oppure no; si possono individuare al momento le seguenti possibilità
-
come collezione
di Javabean
-
come documento
DOM
Nel primo
caso si dovrebbe prevedere una serie di utility per il marshalling/unmarshalling
in XML. Il vantaggio principale nell'utilizzo di una collezione di javabean
consiste nella possibilità di eseguire un binding automatico fra
il bean e la pagina JSP.
Per
la presentazione si hanno le seguenti possibilità:
-
usare
i Javabean
-
usare
una trasformazione XSL
Nel caso
in cui i dati fossero esposti in formato XML e si volesse usare il binding
fra bean e pagine JSP si dovrebbe provvedere in un qualche modo al popolamento
della collezione di bean. Si vuole invece qui approfondire una soluzione
completamente basata su XML che faccia uso di XSL per generare il documento
finale.
Come
semplice case-study si implementerà un report XML di dati presenti
su database. Il componente server si occuperà quindi dell'estrazione
dei dati e della loro conversione in documento DOM. Per semplicità
il componente che legge i dati per questo esempio non sarà implementato
come EJB ma come semplice classe Java ; non verrà inoltre implementato
alcun servlet per gestire la logica di interazione sempre per mantenere
l'esempio semplice.
L'applicazione
mostra i dati di una tabella che mantiene memorizzate le informazioni su
alcuni libri come codice, autore e titolo. Per visualizzare il report è
necessario eseguire un logon all'applicazione mediante una pagina JSP con
associato un relativo bean. Il rendering avviene mediante una trasformazione
XSL avendo come input un documento DOM ritornato dal bean. Per le trasformazioni
XSL si userà Xalan, l'engine dell'XML Apache Group.
Ecco
Segue ora il codice del bean LogonForm
public
class LogonForm {
// user name
private String usrName;
// password
private String password;
// flag che indica se il logon non è
// stato eseguito correttamente
private boolean logonFailed;
public LogonForm(){
usrName = "";
password = "";
logonFailed= false;
}
public String getUsrName(){
return usrName;
}
public void setUsrName(String usrName) {
this.usrName = usrName;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
/**
* Questo metodo controlla se le informazioni inserite
* sono corrette.
* Per semplicità user name e password sono cablate
* nel codice; tutti i dettagli di una reale
* implementazione sarebbero comunque incapsulati
* in questo metodo.
*
* @return boolean true se l'utente è autorizzato,
*
false altrimenti.
*/
public boolean process() {
if ((usrName.trim().equals("moka")) &&
(password.trim().equals("moka"))) {
return true;
}
else {
logonFailed = true;
return false;
}
}
/**
* Questo metodo genera un documento DOM corrispondente al bean.
*
* @return Document il documento DOM corrispondente a
questo bean.
*/
public Document toXML() {
try {
DocumentBuilderFactory dbf;
dbf=DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.newDocument();
Element root = doc.createElement("LOGON_FORM"),
usrNameEl = doc.createElement("USR_NAME"),
passwordEl = doc.createElement("PASSWORD");
usrNameEl.appendChild(doc.createTextNode(usrName));
passwordEl.appendChild(doc.createTextNode(password));
root.appendChild(usrNameEl);
root.appendChild(passwordEl);
if (logonFailed) {
Element errorEl = doc.createElement("ERROR");
errorEl.appendChild(doc.createTextNode("Logon failed"));
root.appendChild(errorEl);
}
doc.appendChild(root);
return doc;
}
catch (Exception e) {
return null;
}
}
}
Oltre
alle normali property per user name e password la classe precedente contiene
il metodo process() per l'autenticazione (per semplicità cablata
nel codice) e il più interessante metodo toXML() che ritorna un
documento DOM con le informazioni della form.
Per
ottenere un'istanza del parser XML si usa JAXP, la API Sun per l'elaborazione
dei documenti XML; in questo modo non si ha alcun riferimento specifico
al particolare parser utilizzato (che in questo caso è Xerces di
Apache). Il documento DOM viene quindi costruito usando la API standard
DOM appendendo i campi con le informazioni di logon e sull'eventuale errore
verificatosi.
Segue
ora il codice della pagina JSP
<%@
page language="java" %>
<%@
page import="org.apache.trax.*" %>
<%@
page import="org.xml.sax.InputSource" %>
<jsp:useBean
id="logon" scope="page" class="LogonForm">
<jsp:setProperty name="logon" property="*"/>
</jsp:useBean>
<%
if (logon.getUsrName() != "" && logon.process()) {
// l'utente ha effettuato un corretto login
response.sendRedirect("books.jsp");
}
Processor processor = Processor.newInstance("xslt");
Templates templates = processor.process(new
InputSource("http://" +
request.getServerName() +
":" + request.getServerPort() +
request.getContextPath() +
"/logon.xsl"));
Transformer transformer = templates.newTransformer();
transformer.transformNode(logon.toXML(), new Result(out));
%>
La
pagina precedente, oltre ai tag per il binding con il bean, contiene anche
la logica per la gestione delle richieste in quanto i dati, una volta inseriti,
vengono inviati con un POST alla stessa pagina.
L'
esempio è abbastanza semplice e la logica è altrettanto semplice:
se i dati inseriti sono corretti il browser viene rediretto alla pagina
con il report, altrimenti viene ripresentata la pagina di logon. In quest'ultimo
caso il documento XML corrispondente avrà anche un elemento di errore
e questo verrà visualizzato dalla pagina. Si osservi che per semplicità
il codice che esegue la trasformazione XSL è stato inserito nella
pagina; in un'applicazione più ingegnerizzata si sarebbe potuto
realizzare un'apposito tag JSP.
Un'altro
aspetto importante è relativo allo stylesheet XSL: in questo caso
si usa un unico file XSL che trasforma i dati in HTML mentre un'applicazione
realmente
multi-device avrebbe previsto l'utilizzo di diversi stylesheet
in funzione del client.
Per
completare il quadro questo è lo stylesheet XSL usato per la form
di logon
<?xml
version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>The Books demo - logon</TITLE>
</HEAD>
<BODY STYLE="{font-family:verdana; font-size:16px; font-style:normal;
color:black;}">
<xsl:apply-templates select="LOGON_FORM"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="LOGON_FORM">
<xsl:apply-templates select="ERROR"/>
<FORM name="logon" id="logon" method="POST" action="logon.jsp">
<TABLE border="0" cellpadding="0" cellspacing="0" align="center">
<TR><TD align="center">User name</TD></TR>
<TR><TD><INPUT type="text" name="usrName" id="usrName">
<xsl:attribute name="value">
<xsl:value-of select="USR_NAME"/>
</xsl:attribute>
</INPUT></TD></TR>
<TR><TD align="center">Password</TD></TR>
<TR><TD><INPUT type="password" name="password" id="password">
<xsl:attribute name="value">
<xsl:value-of select="PASSWORD"/>
</xsl:attribute>
</INPUT></TD></TR>
<BR/>
<TR><TD align="center"><INPUT type="submit" value="Submit"/></TD></TR>
</TABLE>
</FORM>
</xsl:template>
<xsl:template match="ERROR">
<center><font color="red"><xsl:value-of select="."/></font></center>
</xsl:template>
</xsl:stylesheet>
Lo
stylesheet XSL formatta una semplice form HTML mostrando l'eventuale messaggio
d'errore nel caso in cui il logon non sia stato eseguito con successo.
I dati
per il report vengono prelevati da una classe che li espone come documento
DOM usando codice analogo a quello visto in precedenza: la classe si chiama
Books e il suo metodo query() incapsula questo procedimento
public Document query() throws Exception {
Connection c = null;
Statement stm = null;
ResultSet rs = null;
Document result = null;
try {
// carica il driver JDBC
Class.forName(jdbcDriver).newInstance();
} catch (Exception e) {
System.err.println("Unable to load driver");
return null;
}
try {
// crea il parser XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
result = builder.newDocument();
Element books = result.createElement("BOOKS");
c = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);
stm = c.createStatement();
rs = stm.executeQuery("SELECT code, author, title FROM books");
while (rs.next()) {
// per ogni record crea un corrispondente elemento DOM
Element book = result.createElement("BOOK"),
code = result.createElement("CODE"),
author = result.createElement("AUTHOR"),
title = result.createElement("TITLE");
code.appendChild(result.createTextNode(rs.getString("code")));
author.appendChild(result.createTextNode(rs.getString("author")));
title.appendChild(result.createTextNode(rs.getString("title")));
book.appendChild(code);
book.appendChild(author);
book.appendChild(title);
books.appendChild(book);
}
result.appendChild(books);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Exception reading and
formatting data");
throw e;
} finally {
try {
// clean up everything
if (rs != null) { rs.close(); }
if (stm != null) { stm.close(); }
if (c != null) { c.close(); }
} catch (SQLException sqle) {}
}
return result;
}
Il
codice precedente esegue una query su database, preleva i dati dal resultset
e costruisce un documento DOM. Si osservi che l'accesso diretto a database
potrebbe essere sostituito dall'utilizzo di appositi oggetti, ad esempio
EJB.
La
pagina JSP riceverà come input il documento restituito dal metodo
precedente e genererà un documento HTML ancora attraverso una trasformazione
XSL. Segue ora il codice della pagina
<%@
page language="java" %>
<%@
page import="org.apache.trax.*" %>
<%@
page import="org.xml.sax.InputSource" %>
<jsp:useBean
id="books" scope="page" class="Books">
<jsp:setProperty name="books" property="jdbcDriver"
value="org.enhydra.instantdb.jdbc.idbDriver"/>
<jsp:setProperty name="books" property="jdbcUrl" value="jdbc:idb=sample.prp"/>
<jsp:setProperty name="books" property="jdbcUser" value="sa"/>
<jsp:setProperty name="books" property="jdbcPassword" value=""/>
</jsp:useBean>
<%
Processor processor = Processor.newInstance("xslt");
Templates templates = processor.process(new InputSource("http://" +
request.getServerName() + ":" + request.getServerPort() +
request.getContextPath() + "/books.xsl"));
Transformer transformer = templates.newTransformer();
transformer.transformNode(books.query(), new Result(out));
%>
La
classe Books è un bean ed espone una serie di property per la configurazione
dell'accesso a database; in questo caso è stato usato InstantDB.
Segue ora il codice dello stylesheet utilizzato per generare la pagina
HTML
<?xml
version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<HTML>
<HEAD><TITLE>Books report</TITLE></HEAD>
<BODY>
<xsl:apply-templates select="BOOKS"/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match="BOOKS">
<HR/>
<TABLE width="100%">
<TH>Code</TH><TH>Author</TH><TH>Title</TH>
<xsl:for-each select="BOOK">
<xsl:apply-templates select="."/>
</xsl:for-each>
</TABLE>
<HR/>
</xsl:template>
<xsl:template match="BOOK">
<TR>
<TD><xsl:value-of select="CODE"/></TD>
<TD><xsl:value-of select="AUTHOR"/></TD>
<TD><xsl:value-of select="TITLE"/></TD>
</TR>
</xsl:template>
</xsl:stylesheet>
Lo
stylesheet è molto semplice e converte il documento in una tabella
HTML. In questo esempio non ci si è preoccupati del look'n feel
delle pagine HTML; le varie informazioni di rendering (font, dimensioni,
colori, ...) andrebbero comunque specificate in un file CSS come per le
normali pagine Web.
Conclusioni
XML,
fra i suoi vari utilizzi, è particolarmente utile per il Web publishing
e il suo utilizzo con le pagine JSP è quindi una tappa obbligata
per sviluppare applicazioni Web. In questo articolo si è visto solo
un semplice esempio di reporting ma comunque significativo. La librerie
e i framework esistenti sono comunque in continua evoluzione e anche l'architettura
J2EE sta integrando XML; ad esempio l'ultimo draft presentato per la versione
1.2 di JSP prevede che una pagina JSP sia un documento XML descritto da
un apposito schema. XML è inoltre alla base della nuova iniziativa
ONE presentata recentemente da Sun.
I sorgenti
presentati nell'articolo sono disponibili qui.
|