$K(Aufbau eigener Tag Libraries) $KK(Aufbau von Classic Tag Libraries) $R(Objective) Describe the semantics of the "Classic" custom tag event model when each event method (doStartTag, doAfterBody, and doEndTag) is executed, and explain what the return value for each event method means; and write a tag handler class. $R\ $KKK(Überblick über die Tag Interfaces) Mit Einführung der JSP 2.0 sind die Classic Tag Libraries unbedeutender geworden, da mit den Simple Tag Libraries eine einfachere Möglichkeit zur Bildung eigener Tags eingeführt werden. Für jedes eigene Tag, muss man eine Java Klasse beschreiben, die ein bestimmtes Interface erfüllen muss. In den TLD - Dateien wird der Bezug von den in der JSP verwendeten Tags und den Java Klassen hergestellt. Je nach Komplexität der Tags wird ein anderes Interface verwendet. $B(Bilder,tagInterfaces.gif,Die Tag Interfaces) Hier ein Überblick * Das TagInterface ist das einfachste Interface, und reicht für die meisten Tags aus * Das IterationTag Interface erweitert das Tag Interface, um die Eigenschaft den Body einer Iteration mehrfach mehrfach auszuführen. * Das BodyTagInterface erweitert das Iteration Tag Interface. Es wird immer dann genommen wenn der Body der Aktion nicht einfach an die Antwort weitergereicht, sondern während der Ausführung der Aktion bearbeitet werden soll. Für das Iteration Tag Interface und das Body Tag Interface gibt es Standard Implementierungen. Der Programmierer kann Unterklassen dafür bilden, um nicht alle notwendigen Methoden der Interfaces neu implementieren zu können. $KKK(Das TagInterface) Jeder TagHandler ist eine Java Klasse und muss alle Methoden des TagInterface implementieren. Hier eine Auflistung der Methoden und Konstanten des Tag Ingerfaces: $T(caption,ll,25.75) Methode | Beschreibung || int doStartTag() | Wird nach dem Lesen des StartTags ausgeführt || int doEndTag() | Wird nach dem Lesen des EndTags ausgeführt || Tag getParent() | Gibt den TagHandler des direkt Eltern Tags zurück || void release() | Wird vom TagHandler aufgerufen, wenn der Container den Handler nicht mehr benötigt || void setPageContext (PageContext) | Dies wird nach dem Instantiieren eines TagHandlers aufgerufen Mit dem PageContext hat man Zugriff auf alle impliziten Objekten, und den Variablen in den Scopes || void setParent(Tag) | Wird bei verschachtelten Tags verwendet, um auf den Handler des übergeordneten Tags zuzugreifen || $T\ $T(caption,ll,30.70) Konstante | Beschreibung || EVAL_BODY_INCLUDE | Rückgabewert für das doStartTag()
Der Body des Tags wird ausgewertet und in den Ausgabe eingefügt || SKIP_BODY | Rückgabewert für das doStartTag()
Der Body des Tags wird nicht ausgewertet || EVAL_PAGE | Rückgabewert für das doEndTag()
Nach Auswertung des Tags wird der Rest der JSP Seite auch ausgewertet || SKIP_PAGE | Rückgabewert für das doEndTag()
Verhindert die Auswertung der Rest der JSP Seite || $T\ Die folgende Abbildung zeigt, wann welche Methode bei der Bearbeitung eines Tags aufgerufen wird: $B(Bilder,eventsTagInterface.gif,Events beim Tag Interface) Entscheident sind die die Methoden doStartTag() und doEndTag(). Beide Methoden können eine JspException werfen. Die Methode doStartTag() wird u.a. zum initialisieren des TagHandlers verwendet. Sie sollte eine von 2 Integerkonstanten zurückgeben. Ist der Rückgabewert der Integer Tag.EVAL_BODY_INCLUDE so wird der Body der Aktion ausgewertet und in die Ausgabe eingefügt. Ist der Rückgabewert der Integer Tag.SKIP_BODY wird der Body nicht ausgewertet. Dies wird zum Beispiel bei der Implementierung eines if Tags benutzt. Die Methode doEndTag() hat auch 2 mögliche Rückgabewerte. Bei Tag.EVAL_PAGE wird der Rest der JSP Seite ausgewertet. Ansonsten bei Rückgabewert Tag.SKIP_PAGE wird die weitere Auswertung der JSP Seite ignoriert. Das folgende Bild fasst den Kontrollfluss bei Auswertung eines Tags zusammen: $B(Bilder,tagInterfaceFlow.gif, Flusskontrolle bei Abarbeitung eines Tag Interfaces) $KKK(Das Iteration Tag Interface) Das IterationTag Interface erweitert das Tag Interface, um nur eine Methode und einer Konstante $T(caption,ll,25.75) Methode / Konstante | Beschreibung || int doAfterBody() | Dies Methode wird nach der Ausführung des Bodys aufgerufen. Als möglicher Rückgabewert ist entweder der Integer IterationTag.EVAL_BODY_AGAIN oder Tag.SKIP_BODY || EVAL_BODY_AGAIN | Möglicher Rückgabewert von doAfterBody(). Bei diesem Rückgabewert wird die Auswertung des Bodys wiederholt || $T\ Der Methodenfluss wird duch die folgende Abbildung deutlich: $B(Bilder,iterationTagInterfaceFlow.gif,Flusskontrolle bei Abarbeitung eines IterationTag Interfaces) Beispiel: Zu entwickeln ist ein Tag loop das den Body mehrfach entsprechend der Variable count mehrfach ausgeführt wird. $S() <%@ taglib prefix="test" uri="/WEB-INF/sampleLib.tld" %> Hello World!
$S\ Es muss eine Klasse mit dem IterationTag Interface implementiert werden. Die Klasse soll LoopTag heissen. Die Zuordnung des Tags zur Klasse LoopTag wird weiter unten erläutert. $S() package sampleLib; import javax.servlet.jsp.* ; import javax.servlet.jsp.tagext.* ; // Beachte dass TagSupport das Interface IterationTag implementiert. // Von der Klasse TagSupport werden u.a. die Methoden int doEndTag(), // setParent(), getParent(), setPageContext(), release() beerbt public class LoopTag extends TagSupport { // Für alle Attribute muss eine setter Methode definiert werden private int count = 0; public void setCount(int count){ this.count = count; } public int doStartTag() throws JspExpression{ if (count>0) return EVAL_BODY_INCLUDE; else return SKIP_BODY; } public int doAfterBody() throws JspExpression{ if (--count > 0) return EVAL_BODY_AGAIN; else return SIP_BODY; } // Die Methode doEndTag() muss in diesem Fall nicht // reimplementiert werden, da sie standardmaessig von der // Oberklasse TagSupport den Integer EVAL_PAGE zurückgeben } $S\ Die Zuordnung des tags zur Klasse LoopTag muss in der TLD-Datei definiert werden: $S() loop sampleLib.LoopTag JSP count true true $S\ $KKK(Das BodyTag Interface) Das BodyTag Interface erweitert das IterationTag Interface. Es ermöglicht den Body, bevor er zur Ausgabe gesendet wird, zu bearbeiten. Das BodyTag Interface erweitert das IterationTag um folgende Methoden und Konstanten: $T(caption,ll,35.65) Methode / Konstante | Beschreibung || void setBodyContent() | Setzt eine Instanz der Klasse BodyContent.BodyContent enthält den Inhalt des Bodys, und hat Methoden um diesen zuzugreifen. || void doInitBody() | Dies erlaubt bevor der Body bearbeitet wird, den BodyContent zu bearbeiten. Diese Methode wird direkt nach setBodyContent() aufgerufen. Diese Methode wird häufig reimplementiert. || EVAL_BODY_BUFFERED | Möglicher Rückgabewert von doStartTag() und doAfterBody(). Der Inhalt der Auswertung des Bodys wird gepuffert. Die Auswertung des Bodys wird nochmals wiederholt, allerdings mit dem Body der der Auswertung der letzten Iteration entspricht || $T\ Das folgende Bild zeigt, wann die Methoden setBodyContent() und doInitBody() vom Container ausgelöst werden. $B(Bilder,eventsBodyTagInterface.gif,Events beim BodyTag Interface) $B(Bilder,bodyTagInterfaceFlow.gif,Flussdiagramm BodyTag Interface) Als konkrete Implementation des BodyTag Interfaces wird meistens eine Unterklasse von der Klasse BodyTagSupport gebildet. Die Klasse BodyTagSupport bietet u.a. folgende Methoden: $T(caption,ll,25.75) setBodyContent( BodyContent ) | Setzt ein BodyContent Objekt || BodyContent getBodyContent() | Gibt den BodyContent des Tags zurück || JSPWriter getPreviousOut() | Gibt einen Writer zurück, um den Body zu bearbeiten. Dies entspricht bodyContent.getEnclosingWriter(). Der Inhalt dieses Writers wird nicht sofort ausgegeben, sondern erstmal für die Weiterverarbeitung (in der nächsten Iteration) gepuffert || $T\