$KK(Aufbau von Simple Classic Tag Libraries)
$R(Objective)
Describe the semantics of the "Simple" custom tag event model when the event
method (doTag) is executed; write a tag handler class; and explain the constraints
on the JSP content within the tag.
$R\
$KKK(Vergleich mit den klassischen Tag Interfaces)
Das SimpleTag Interface ist seit JSP 2.0 eingeführt, und vereinfacht die Programmierung
von eigengeschreibenen Tags.
Es hat folgende Vorteile:
* einfacheres Interface
* es ermöglicht beliebig komplexe Tags zu entwickeln
* einheitliches Interface, egal für welche Art von Tags
Es hat auch ein paar Nachteile:
* Erst gültig ab JSP 2.0 also mit J2EE 1.4
* es können keine Skriplets im Body sein
* Es wird bei jedem Aufruf eine neue Instanz des TagHandlers erzeugt. Man kann denselben
TagHandler nicht cachen.
$KKK(Das SimpleTag Interface)
Der Programmierer schreibt Klassen, die das SimpleTag Interface erfüllen. Meist entwickelt er
eine Unterklasse der abstrakten Klasse SimpleTagSupport. Diese Unterklasse überschreibt
dann meistens nur die doTag() Methode.
$B(Bilder,tagSupport.gif,Klassenhierarchie Simple Tag Support)
Beachte: Das Simple Tag Interface erbt nicht vom Tag Interface. Die Custom TagHandler und
die Simple TagHandler haben ausser Object keine gemeinsamen Klassen in der Vererbungshierarchie.
Während bei den Classic Custom Tags es verschiedene Arten von Events gibt (doStartTag(),
doEndTag() und doAfterBody() wird bei dieser Version nur der doTag() bei der
Bearbeitung des Bodys ausgelöst.
$B(Bilder,eventsSimpleTag.gif,Events bei Bearbeitung mit SimpleTag)
I.a. wird der Programmierer eine Unterklasse von SimpleTagSupport schreiben. In dieser
Unterklasse schreibt er für jedes übergebene Attribut eine entsprechende setter-Methode und
überschreibt die doTag() Methode.
Die Klasse SimpleTagSupport bietet einige Methoden, die die Implementierung des Tags
erleichtern.
* public void doTag() throws JspExeption, SkipPageException, java.io.Exception
Dies ist i.a. die einzigste Methode die der Programmierer überschreibt, und wird beim
Lesen des Bodys des Tags aufgerufen. Mit dem Werfen einer SkipPageException wird
veranlasst dass der Rest der JSP Seite nicht weiter bearbeitet wird (entspricht TAG.SKIP_BODY
Konstante, bei den Classic Custom Tag Interfaces).
* public JspTag getParent()
Dies gibt den TagHandler des übergeordneten Tags zurück. JspTag ist das Interface das alle
TagHandler erfüllen, hat aber keine eigenen Methoden. D.h der Programmierer muss nach Anwendung
der getParent() Methode das erhaltene Objekt auf die konkrete TagHandler Klasse casten. Hat
der Tag keinen übergeordneten Tag, so wird null zurückgegeben
* public void setParent(JspTag parent)
Diese Methode wird meistens nur vom Container verwendet.
* public static final JspTag findAncestorWithClass(JspTag from, Class klass)
Findet den nächsten Vater des Tags from, der der Klasse klass entspricht. Intern wird die
getParent() Methode verwendet.
* public JspFragment getJspBody()
Enthält den Body des Tags in Form eines JspFragment Tags. Die Verwendung wird weiter unten
erklärt
* public void setJspBody(JSPFragment body)
Diese Methode wird meistens nur vom Container verwendet.
* public JspContext getJspContext()
Dies ist eine abstrakte Klasse. Die Klasse PageContext ist i.a. die einzigste konkrete Unterklasse
von JspContext. JspContext dient zum Zugriff auf die Attribute der Scopes, und mit getOut() erhält man
die aktuelle Ausgabe. Diese Methode wird sehr häufig angewendet.
* public void set JspContext setJspContext(JspContext context)
Diese Methode wird vom Container verwendet, und selten vom Programmierer direkt benutzt.
$KKK(Beispiel für die Verwendung eines SimpleTag Interfaces)
Es wird bewusst ein Beispiel mit einem Tag ohne Body genommen.
Der Tag hat folgenden Aufbau
$S()
$S\
Es wird ausgegeben:
$S()
Hallo
Hallo Klaus
Hallo Herr Meucht
Hallo Frau Meucht
$S\
Der TagHandler wird folgendermassen programmiert
$S()
public class GrussTag extends SimpleTagSupport(){
private String name,sex ;
// Für jedes Attribut benoetigt eine setter Methode
public void setName(String name){
this.name = name;
}
public void setSex(String mOrf){
this.sex = mOrf;
}
// die doTag() Methode ist die einzigste Event-Methode mit SimpleTag Interfaces
public void doTag() throws JspException, IOException{
PageContext pageContext = (PageContext) getJspContext();
HttpServletResponse resp = ( HttpServletResponse) pageContext.getResponse();
PrintWriter pw = resp.getWriter();
// Alternative JspWriter pw = getJspContext().getOut();
// JspWriter funktioniert wie PrintWriter, kann zusaetzlich Daten zwischenspeichern.
if (name == null){
pw.println("Hallo");
return ;
}
if (sex == null){
pw.prinln("Hallo " + name );
return ;
}
if ( sex.compareToIngoreCase("m")== 0 ){
pw.println("Hallo Herr " + name );
}else{
pw.println("Hallo Frau " + name );
}
}
}
$S\
$KKK(Zugriff auf den Body des Tags)
Ein TagHandler der das SimpleTag Interface erfüllt, getJspBody() und sollte ein JspFragment
Objekt zurückgeben. Das JspFragment kapselt den Body und hat nur 2 Methoden.
* getJspContext()
* invoke(Writer)
Die Methode invoke(Writer) schreibt die Auswertung des Body in das Argument Writer.
Ist der Wert des Arguments null so wo wird der Body, in den Writer, der sich durch
getJspContext().getOUt() ergibt, ausgegeben. In diesem Fall wird der Body in die
normale Ausgabe geleitet. Immer dann wenn den Body selbst nicht bearbeiten will, übergibt
man den null Wert als Argument der invoke() Methode.
Immer dann wenn man den Body bearbeiten will, kann man ein eigenes Writer Objekt erzeugen,
und darin die Ausgabe puffern, und dann in die Ausgabe zurückgeben.
$S()
...
StringWriter evalResult = new StringWriter();
StringBuffer buffer = evalResult.getBuffer();
body.invoke(evalResult);
// Die Auswertung des Body steht nun in buffer
bearbeite(buffer);
getJspContext().getOut().print(buffer);
...
$S\
$KKK(Schleifen mit dem SimpleTag Interface)
Schleifen werden intern in der doTag() Methode implementiert. Ein einfaches Beispiel verdeutlicht
dies.
$S()
$S\
Der entsprechende TagHandler kann folgendermassen implementiert werden:
$S()
// imports werden weggelassen
puclic class ForTokenTagHandler extends SimpleTagSupport{
private Collection items ;
private String var ;
public setItems(Collection items){
this.items = items ;
}
public setVar(String var){
this.var = var ;
}
public void doTag() throws JspException,IOException {
JspFragment body = getJspBody();
if (body != null){
Iterator iter = items.getIterator();
while (iter.hasNext()){
Object currentValue = iter.next();
getJspContext().setAttribute(var, currentValue);
body.invoke(null);
}
}
}
}
$S\
Beachte:
* Die Iteration wird in der doTag() Methode abgehandelt.
* In der doTag() Methode wird am Beginn der Iteration, ein Attribut im PageScope gesetzt.
Das Attribut hat als key den Wert der Variable var (im Beispiel "current").
Der Wert des Attribut ist das aktuelle Token in der Iteration.
* Bei der Auswertung des Bodys, durch die Methode invoke(null), wird der Wert des
Attributs "current" ausgegeben.