Come invocare EJB da pagine JSP utilizzando custom tag: esempio pratico di creazione di tag handler per l'invocazione di session bean.
Nell'articolo [CEJB] sono state presentate varie tipologie di client EJB al fine di utilizzare l'EJB session stateless Concat [SEJB].
In particolare sono stati portati come esempi un'applicazione client stand-alone, un Servlet ed una pagina JSP utilizzante una Java Bean.
In [CEJB] si è ricordato che nella versione JSP 1.1 non è possibile invocare un EJB direttamente da una pagina JSP mediante l'utilizzo delle action standard JSP, ma si deve utilizzare scriptlet o la mediazione di un worker Java bean.
L'invocazione mediante scriptlet avviene includendo il codice Java tra i tag <% ed %>, come riportato in seguito:
L'utilizzo dello scriptlet è però sconsigliato perché non permette una netta divisione tra la logica di programmazione e quella di visualizzazione ed inoltre non favorisce il riutilizzo del codice.
È possibile tuttavia creare custom tag mediante i quali si possono definire nuove action da usare all'interno delle pagine JSP estendendo il set dei tag di default dei tag JSP.
Scopo dell'articolo è realizzare un tag proprietario al fine di localizzare la home interface di un EJB per ridurre l'utilizzo di scriptlet all'interno della pagina JSP.
Cos'è un custom tag?
Il tag extension è un meccanismo, introdotto nella versione JSP 1.1, che permette di definire dei tag personalizzati estendendo il set dei tag di default JSP.
In questo modo è possibile costruire tag i cui compiti sono decisi dal programmatore in base alle sue specifiche esigenze: questi tag personalizzati prendono il nome di custom tag.
Un insieme di custom tag viene chiamato tag library.
Il custom tag `myEjbTag`
Iniziamo con il definire le caratteristiche del custom tag myEjbTag che si intende costruire.
Al fine di localizzare la home interface dell'EJB, il tag myEjbTag richiede la presenza di tre attributi: jndiName, homeInterface e homeVar, che identificano rispettivamente il nome JNDI dell'EJB, il nome della Home interface ed il nome del reference dell'interfaccia home.
Una volta specificati i valori degli attributi è possibile, mediante scriptlet, reperire un riferimento alla Remote interface di un EJB mediante l'invocazione del metodo create sulla variabile homeVar. Questa operazione viene effettuata all'interno del tag e prende il nome di body, cioè corpo del tag.
In questo modo si può procedere ad invocare direttamente i metodi di business dell'EJB direttamente da scriptlet JSP utilizzando la variabile concatRemote.
Il risultato che si ottiene è una pagina JSP che utilizza elementi di script in congiunzione con il custom tag myEjbTag.
<% Concat concatRemote = null; %>
<myJ2ee:myEjbTag
jndiName="java:comp/env/ejb/MyConcat"
homeInterface="ConcatHome"
homeVar="concatHome">
<% concatRemote = concatHome.create(); %>
</myJ2ee:myEjbTag>
<%= concatRemote.concat("Hello EJB World ","from my JSP tag lib!") %>
Come si definisce un custom tag?
Si definisce ora il custom tag myEjbTag con i suoi attributi, il body e la gestione dell'interazione con la variabile di script concatRemote.
Bisogna quindi creare una classe tag handler che gestisca il tag, una classe di informazione sul contenuto del tag ed un descrittore del tag library, il Tag Library Descriptor.
La classe tag handler
La classe tag handler è la classe che permette la gestione del custom tag da parte del JSP container.
Le classi di supporto per l'implementazione dei tag proprietari sono contenute nel package javax.servlet.jsp.tagext.
Per implementare un custom tag si deve definire una classe tag che implementi o l'interfaccia Tag o BodyTag. Queste interfacce rappresentano il meccanismo di comunicazione con il JSPContainer e sono implementate rispettivamente dalle classi concrete TagSupport e BodyTagSupport, quest'ultima derivata da TagSupport.
Figura 1: Gerarchia delle classi e interfacce per i custom tag
La scelta dell'utilizzo di una o dell'altra classe/interfaccia dipende dalla tipologia del custom tag che si vuole realizzare, vedere [MJSP] e [JTAG].
Dato che il tag myEjbTag possiede un body, la sua classe tag handler deve implementare l'interfaccia BodyTag.
Piuttosto che implementare l'interfaccia BodyTag è più comodo ereditare dalla classe BodyTagSupport in modo da non dover implementare tutti i metodi dell'interfaccia ma solamente effettuare l'overriding dei metodi di interesse.
Rispetto alla classe TagSupport, la classe BodyTagSupport aggiunge tre metodi per la gestione del body del tag: setBodyContent, doInitBody e doAfterBody.
Per interagire con il body (<% concatRemote = concatHome.create(); %>) nel nostro caso basta implementare il metodo doInitBody, utilizzando per gli altri metodi le implementazioni di default della classe BodyTagSupport.
Nel metodo doInitBody inseriamo le operazioni tipiche di un client EJB, cioè la localizzazione ed il narrow della home interface.
L'oggetto homeRef viene memorizzato come attributo, avente il nome specificato dalla proprietà homeVar, che nel nostro caso specifico è concatHome, nel contesto della pagina JSP mediante il metodo setAttribute(name, Object) invocato sulla variabile pageContext.
La variabile pageContext è utilizzabile all'interno della classe tag handler essendo ereditata dalla classe TagSupport con modalità d'accesso protected.
pageContext.setAttribute(homeVar, homeRef);
In questo modo si rende visibile con scope di pagina la variabile di script concatHome mediante la quale è possibile invocare i metodi create dell'EJB direttamente all'interno del body del myEjbTag.
Per ogni attributo del myEjbTag si deve definire una proprietà in stile Java Bean nella classe tag handler associando un metodo get ed uno set per rendere accessibile la proprietà dal JSP container.
`MyEjbTag.java`: la classe tag handler del tag `myEjbTag`
import javax.rmi.PortableRemoteObject;
import javax.naming.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class MyEjbTag extends BodyTagSupport {
/** Proprietà Tag */
private String jndiName = null;
private String homeVar = null;
private String homeInterface = null;
public MyEjbTag() {
super();
addItem("Constructore MyEjbTag : ...");
}
public String getJndiName() {
addItem("MyEjbTag.getJndiName : return " + this.jndiName);
return this.jndiName;
}
public void setJndiName(String jndiName) {
addItem("MyEjbTag.setJndiName : " + jndiName);
this.jndiName = jndiName;
}
public String getHomeVar() {
addItem("MyEjbTag.getHomeVar : return " + this.homeVar);
return this.homeVar;
}
public void setHomeVar(String homeVar) {
addItem("MyEjbTag.setHomeVar : " + homeVar);
this.homeVar = homeVar;
}
public String getHomeInterface() {
addItem("MyEjbTag.getHomeInterface : return " + this.homeInterface);
return this.homeInterface;
}
public void setHomeInterface(String homeInterface) {
addItem("MyEjbTag.setHomeInterface : " + homeInterface );
this.homeInterface = homeInterface;
}
// doInitBody
public void doInitBody() throws JspException {
try {
addItem("MyEjbTag.doInitBody : ...");
InitialContext ic = new InitialContext();
addItem("MyEjbTag.doInitBody : BEFORE lookup ["+jndiName+"]...");
Object homeRef = ic.lookup(jndiName);
homeRef = PortableRemoteObject.narrow(homeRef,Class.forName(homeInterface));
addItem("MyEjbTag.doInitBody : setAttribute homeVar["+homeVar+
"] homeRef["+homeRef+"]...");
// Memorizzazione nel Page context dell'oggetto homeRef con il nome
// specificato dalla proprietà homeVar
pageContext.setAttribute(homeVar, homeRef);
} catch (NamingException ex) {
addItem("MyEjbTag.doInitBody : Unable to lookup home["+jndiName+ "] : "+ex);
throw new JspTagException("MyEjbTag.doInitBody : Unable to lookup home["+jndiName+ "] : "+ex);
} catch (ClassNotFoundException ex) {
addItem("Class ["+homeInterface+"] not found !" + ex);
throw new JspTagException("Class ["+homeInterface+"] not found !" + ex);
}
}
private void addItem(String s)
{
s = new java.util.Date().toString() + "-" + s;
System.out.println(s);
}
}
La classe tag info
La variabile concatHome è una variabile di scripting disponibile all'interno del body ed è valorizzata nel metodo doInitBody della classe tag handler MyEjbTag.
Questa variabile, detta variabile di scripting, deve essere descritta da un'apposita classe detta Tag Extra Info, TEI. Mediante la TEI è possibile oltre che descrivere la variabile di scripting anche effettuare un controllo sulla sua valorizzazione in fase di traduzione da parte del JSP container.
Il motore JSP invoca il metodo getVariableInfo per scoprire la presenza di variabili di scripting associate al tag che sta interpretando, ed il metodo isValid per verificare la validità del valore in fase di compilazione della pagina JSP.
Il metodo getVariableInfo viene invocato dal JSP Container solo se il metodo isValid ritorna true, cioè se il valore dell'attributo del custom tag è valido.
`MyEjbExtraInfo.java`
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.util.Date;
public class MyEjbExtraInfo extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data)
{
return new VariableInfo[]{
new VariableInfo(
(String)data.getAttribute("homeVar"),
(String)data.getAttribute("homeInterface"),
true,
VariableInfo.NESTED)
};
}
public boolean isValid(TagData data)
{
return true;
}
}
La sequenza delle chiamate, life cycle, da parte del JSP container ai metodi della classe MyEjbExtraInfo e MyEjbTag può essere così schematizzata:
MyEjbExtraInfo info = new MyEjbExtraInfo();
info.isValid(...);
info.getVariableInfo(...);
MyEjbTag t = new MyEjbTag();
t.setPageContext(...);
t.setParent(...);
t.setJndiName(...);
t.setHomeInterface(...);
t.setHomeVar(...);
t.doStartTag();
t.setBodyContent(...);
t.doInitBody();
t.doAfterBody();
t.doEndTag();
t.release();
Tag Library Descriptor
Prima di potere utilizzare il tag myEjbTag all'interno di una pagina JSP, bisogna costruire il relativo tag library descriptor, TLD.
Il TLD è un file XML che descrive i custom tag, sintassi, attributi e classi Java correlate, di una tag library e viene utilizzato dal JSP container per interpretarli.
Tra i tag <taglib> bisogna specificare la versione della taglib <tlibversion>, la versione JSP <jspversion> e l'URI.
Mediante il tag <info> è possibile inserire un testo arbitrario contenente informazioni sulla libreria.
Per ogni tag bisogna dichiarare una sezione, contenuta tra <tag> e </tag>, per descriverne le proprietà:
<name>: nome del custom tag, myEjbTag;
<tagClass>: nome della classe Java tag handler, MyEjbTag;
<teiClass>: nome della classe TEI, MyEjbExtraInfo;
<bodycontent>: indica il tipo di contenuto del body, nel nostro caso scriptlet JSP;
<info>: descrizione informativa del tag.
Per ogni attributo, quindi sia per jndiName, homeInterface che homeVar, attraverso il tag <attribute> bisogna specificare:
<name>: nome dell'attributo;
<required>: indica se l'attributo è obbligatorio;
<rtexprvalue>: indica se l'attributo può essere valorizzato dinamicamente mediante scriptlet;
<type>: indica il tipo di ritorno dell'espressione JSP, presente solo in concomitanza del tag <rtexprvalue>.
`myejbtaglib.tld`
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<uri></uri>
<info>
Tag library for EJB support
</info>
<tag>
<name>myEjbTag</name>
<tagclass>MyEjbTag</tagclass>
<teiclass>MyEjbExtraInfo</teiclass>
<bodycontent>JSP</bodycontent>
<info>
Tag JSP per lookup di un EJB
</info>
<attribute>
<name>jndiName</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>String</type>
</attribute>
<attribute>
<name>homeInterface</name>
<required>true</required>
</attribute>
<attribute>
<name>homeVar</name>
<required>true</required>
</attribute>
</tag>
</taglib>
Utilizzo del tag `myEjbTag` all'interno di una pagina JSP
Dopo avere sviluppato le classi per la gestione del tag ed il TLD, è finalmente possibile inserire il tag myEjbTag nelle pagine JSP.
Per prima cosa bisogna specificare l'identificatore del TLD sotto forma di URI, Universal Resource Identificator, cioè indicare dove il JSP engine deve reperire il file TLD.
L'attributo prefix assegna una label al tag permettendo di distinguere eventuali tag anonimi presenti in altre librerie, cioè il namespace.
Mediante il tag <myJ2ee:ejb> si provvede ad inizializzare le tre proprietà del custom tag specificando il JNDI name del Session Stateless bean Concat [SEJB], la sua interfaccia di Home e definendo il nome per la variabile di script.
si può procedere all'installazione sull'application server, che nel nostro caso è Tomcat 3.2.
Come primo passo si crea una WebApplication, WA, di nome mywebapp: <tomcat home>/webapps/mywebapp. Per dettagli fare riferimento alle specifiche delle Servlet 2.2.
Bisogna quindi posizionare in modo opportuno i file CustomWithMyTagLib.jsp, MyEjbTag.class, MyEjbExtraInfo.class e myejbtaglib.tld.
La pagina JSP la si copia nella root della WA, <tomcat home>/mywebapp; i file .class nella directory classes di WEB-INF, mywebapp/WEB-INF/classes; mentre il file TLD nella WEB-INF stessa.
Inoltre bisogna portare il Jar contenente gli stub dell'EJB concat nella directory lib della WA, mywebapp/WEB-INF/lib, insieme al j2ee.jar.
L'ultimo passo da effettuare riguarda il Deployment Descriptor, <tomcat home>/mywebapp/WEB-INF/web.xml, della WA all'interno del quale bisogna referenziare la tag library mediante il tag <taglib>:
Figura 3: Configurazione della WebApplication e del deployment descriptor
Una volta avviato l'application server Sun RI, <j2ee home>/bin/j2ee, e successivamente Tomcat, <tomcat home>/bin/startup, è possibile accedere alla pagina JSP mediante l'URL:
dove al posto di <SERVER> bisogna inserire il nome o l'indirizzo IP della macchina server, localhost per testare in locale.
In figura 4 viene mostrato il risultato dell'invocazione.
Figura 4: Risultato dell'invocazione della pagina JSP
Conclusioni
Con questo articolo si conclude la breve rassegna di esempi di client EJB.
Si è visto come invocare un EJB mediante servlet, scriptlet, proxy bean ed infine custom tag, cercando di mettere in risalto pro e contro di ogni soluzione.
Il custom myEjbTag è un semplice esempio di tag per invocare EJB, adatto laddove non si richieda il mantenimento di stato tra un'invocazione della pagina JSP e la successiva.
Bibliografia
-
[CEJB] S. Rossini - "Client EJB", Mokabyte N. 53, Giugno 2001
-
[SEJB] S. Rossini - "Session EJB: un esempio applicativo", Mokabyte N. 46, Novembre 2000
-
[MJSP] P. Aiello - MokaBook: Java Server Pages
-
[JTAG] M. Carli - "Java Server Pages", Computer Programming N. 101, Aprile 2001
[JEED] J2SDKEE 1.2 documentation: Accessing Enterprise Beans Through JSP Tag Libraries
-
[JAPI] J2SDKEE 1.2 documentation: API Documentation
-
[WDJ] G. Puliti - "Web dinamico con JSP", Mokabyte N. 29, Aprile 1999
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