© Copyright Marcus Green 2007
10.1) 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.
Custom tags allow the creation of Java classes that extend the tags available for building JSP files. This brings the benefit of being able to build functionality into pages without using scriptlets or accessing beans, which makes pages more maintainable for non programmers. It is possible to be a serious real world JSP programmer without ever writing your own custom tags. This is because there is a significant library of pre-built custom tags available. The JSP Standard Tag Library (covered in objective 9.3) provides most custom tags you are ever likely to need. However for the purpose of the exam you must understand how to create your own custom tags from first principle.
Custom tags are are used in a similar way to any standard tag, except they use a prefix. So they take the form
<prefix:methodcall>optionalbody</prefix:methodcall>
For many (possibly most) purposes the introduction of the SimpleTagSupport class with JSP 2.0 (covered in objective 10.4) has made the classic custom tag obsolete. However there is a large amount of existing code that uses the classic approach and so it has been retained for the purpose of the exam. Classic custom tags are created by extending the javax.servlet.jsp.tagext.TagSupport class. T
You need to understand the purpose and use of the three methods as given in the objective.
As you might guess these are container callback methods that are called by the container during the stages of the tags lifecycle rather than called directly from your own code. One of the complicating factors of the classic event model is that you must memorize the possible return values of the methods and these values are not particularly intuitive. Each of the method returns an int value which are given allegedly intuitive names to indicate the purpose. These values are constants defined in the Tag class. The following code shows an example of a trivial classic custom tag that simply outputs the text Hello World whenever it is invoked.

Illustration 1: TagSupport Sequence Diagram
/**
* @author Marcus Green
* May 2006
* A trivial classic custom
* tag. For SCWCD objective 10.1
*/
package com.examulator;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class ClassicTagDemo extends TagSupport {
public int doStartTag(){
try{
JspWriter out = pageContext.getOut();
out.print("Hello World");
}catch(IOException ioe){}
return EVAL_BODY_INCLUDE;
}
}
Create a TagLib descriptor file with the following content
<?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>
<shortname>ClassicTagDemo</shortname>
<uri>http://www.mycompany.com/classictagdemo</uri>
<info>An example classic tag library</info>
<tag>
<name>ClassicTagDemo</name>
<tagclass>com.examulator.ClassicTagDemo</tagclass>
<body-content>empty</body-content>
<info>Just Says Hello</info>
</tag>
</taglib>
The tag can be used with the following JSP page.
<%@ taglib uri="WEB-INF/tlds/ClassicTagDemo.tld" prefix="h" %>
<html>
<head>
<h:ClassicTagDemo/>
</body>
</html>
And the requested page should output the text “Hello World”.
As you saw in the previous code you can get the implicit out object via a call to getPageContext.getOut(). But you can also use it for other purposes such as getting attributes in the differing scopes.
|
|
The only implicit object available to a classic tag is PageContext, but this can be used to get all other implicit objects. |
Thus you can get an application scope object via a call to
pageContext.getAttribute(“attributeName”,PageContext.APPLICATION_SCOPE).
For exam purposes you don't need to memorize thes constants, just be aware that you don't have direct access to the standard JSP implicit objects but that they can be accessed via pageContext calls.
The real exam may well contain questions that show a fragment of a TLD and you need to know what will be output by a custom tag that uses that TLD. The body-content tag has a very direct impact on what will be output. Here is a direct quote from the JSP specification appendix JSP.C
“tagdependent The body of the tag is interpreted by the tag implementation itself, and is most likely in a different "language", e.g. embedded SQL statements.
JSP The body of the tag contains nested JSP syntax.
“empty” The body must be empty
“scriptless” The body accepts only template text, EL Expressions, and JSP action elements. No scripting elements are allowed.”
The peculiar one of these values is tagdependent. The container effectively ignores the content but it may be used by the tag for its own purposes.
|
|
You need to memorize the method return values for the classic tag methods |
Like the name implies, the doStart method is the first method invoked when the tag is called. The possible return values of doStart are
SKIP_BODY or EVAL_BODY_INCLDE
If SKIP_BODY is returned the body of the tag (the bit between the first occurrence of the tag and when the tag is closed with </prefix:tagname> ) is simply ignored. As the name implies the EVAL_BODY_INCLUDE return value means that processing will evaluate the body of the tag. The evaluation of the body is dependent on more than the return value of doStart. For the body to be evaluated the tag must not be declared to have an empty body in the deployment descriptor, and it must not be invoked with an empty body in the jsp page.
The doAfterBody method is specified by the IterationTag interface which is implemented by the TagSupport class. To quote from the API docs
“The doAfterBody() method is invoked after every body evaluation to control whether the body will be reevaluated or not. If doAfterBody() returns IterationTag.EVAL_BODY_AGAIN, then the body will be reevaluated. If doAfterBody() returns Tag.SKIP_BODY, then the body will be skipped and doEndTag() will be evaluated instead “
http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/TagSupport.html#doAfterBody()
When you see the doAfterBody method thing IterationTag and when you think IterationTag think looping (as in iterating through each element of a collection).
Understandably doAfterBody is not invoked if the doStart method returns SKIP_BODY. An example of using doAfterBody is to create a tag that generates multiple rows of a table based on the attribute of a tag and the body of a tag. For example the following tag combination JSP code would generate a table with 5 empty rows.
<mytag:loop count=5>
<tr><td> </td></tr>
</mytag:loop>
For a tag like this to work the doAfterBody method would have to return EVAL_BODY_AGAIN for each iteration of the loop.
The following code sample loops through each element of the fruit array.
/**
* @author Marcus Green
* July 2006
* A looping tag, note that
* TagSupport implements
* IterationTag which brings the
* doAfterBody method
* For SCWCD objective 10.1
*/
package com.examulator;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class IterationTagDemo extends TagSupport {
int iCounter;
String[] fruit = new String[] {"apples","oranges","pears"};
public int doStartTag()throws JspException{
return EVAL_BODY_INCLUDE;
}
public int doAfterBody()throws JspException{
if(iCounter < fruit.length){
try{
JspWriter out = pageContext.getOut();
out.print(fruit[iCounter]);
}catch(IOException ioe){}
iCounter++;
return EVAL_BODY_AGAIN;
}
return SKIP_BODY;
}
}
To make this custom tag work use the following entries in the TLD
<tag>
<name>IterationTagDemo</name>
<tagclass>com.examulator.IterationTagDemo</tagclass>
<body-content>JSP</body-content>
<info>a looping tag</info>
</tag>
And to show it in action the following use the following JSP code.
<%@ taglib uri="/WEB-INF/taglib.tld" prefix="h" %>
<html>
<h:IterationTagDemo>
</h:IterationTagDemo>
</html>
The output when this work will simply be
apples oranges pears
But a little programmer ingenuity would allow you to modify it to generate a table dynamically or some other task that required iteration. This is a very contrived example and in the real world you would probably be doing something like getting the data from a database. Note that the tag will not work in the form
<h:IterationTagDemo/>
You need it to have a body, even if that body is not used for anything.
The doEndTag method is invoked at the end of the tag and has possible return values of
SKIP_PAGE or EVAL_PAGE
If the method returns SKIP_PAGE then the rest of the JSP is ignored (skipped), which is probably only required in the minority of situations. If the method returns EVAL_PAGE then the rest of the page is processed.
For most programming purposes the only methods you will be concerned with is your versions of doStartTag, doAfterBody and doEndTag. However for the purpose of the exam you need to know the SimpleTag lifecycle and what methods are guaranteed to be called, in what order. The following table illustrates this sequence.
|
Classic tag life cycle |
|
setPageContext(PageContext) |
|
If the tag is nested call setParent(Tag) |
|
doStartTag() |
|
If the there is body content and it is evaluated call doAfterBody |
|
doEndTag() |

TagSupport Life cycle flowchart .:
Although it is not mentioned in the objective, I am fairly confident that the real exam contains questions that covers this topic. I recommend you pay close attention as although it is not particularly complex, it is not especially obvious either.
One thing that TagSupport does not give you is the ability to get at the contents of the body of a tag, thus if have the body-content tag set to tagdependent, the implication is that your tag is going to do some manipulation of the the body. The BodyTagSupport class is a handy implementation of the BodyTag interface which allows manipulation of the body content (The bit between the opening and closing tags, e.g. <mytag>bodycontent</mytag>).
The BodyTagSupport class is very much like the TagSupport class except that it adds two new methods and a constant. The new constant is EVAL_BODY_BUFFERED, which is the for BodyTagSupport is the default return value of doStartTag. As the word BUFFERED implies this means that the body content will not automatically be sent to the output (as it would with EVAL_BODY_INCLUDE). It is buffered for later use. The BodyTagSupport adds the getBodyContent method and the doInitBody method methods.
|
|
The BodyTagSupport class adds the getBodyContent and doInitBody methods and the EVAL_BODY_INCLUDE constant. |
When the contents of the body has been buffered because doStartTag has returned EVAL_BODY_BUFFERED the contents can be retrieved by a call to getBodyContent. The getBodyContent method returns a BodyContent object, which has a getString method for accessing the content. The doInitBody method is called by the JSP container after calling setBodyContent, so you might get a question on the exam that asks about what methods are invoked for a BodyContent tag and in what order.
Note that because EVAL_BODY_BUFFERED is the default return value of doStartTag as implemented by BodyTagSupport, the following code would work just as well if there was no doStartTag method implemented.
package com.examulator;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class BodyTagSupportDemo extends BodyTagSupport {
public int doStartTag(){
return EVAL_BODY_BUFFERED;
}
public int doEndTag(){
/*getBodyContent suppplied by BodyTag interface */
BodyContent bc= getBodyContent();
String sBody = bc.getString();
JspWriter out;
try{
out = pageContext.getOut();
/* just to show it has been manipulated */
out.print("+++"+sBody+"++++");
}catch(IOException ioe){
}
return EVAL_PAGE;
}
}
If this custom tag is configured in the TLD with the <body-content> set to tagdependent it will take the body content and append the + characters as given in the code. Thus the following JSP page
<%@ taglib uri="/WEB-INF/taglib.tld" prefix="h" %>
<html>
<h:BodyTagSupportDemo>BodyContent</h:BodyTagSupportDemo>
</html>
Will result in an output of
+++BodyContent++++
The SkipPageException allows you to abandon the processing of the page that contains the current tag. You might want to do this if your tag has come across some problem during its processing. Of course you could throw some other exception, but this would halt the process the whole page, whereas you want the output of the page so far to be displayed. The following code demonstrates how it can be used.
/**
*@author Marcus Green
*January 2007
*demonstrating SkipPageException
**/
package com.examulator;
import java.io.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class SkipPageExceptionDemo extends SimpleTagSupport {
public void doTag() throws JspException{
JspFragment body = getJspBody();
PageContext pageContext = (PageContext) getJspContext();
String skip= pageContext.getRequest().getParameter("skip");
if(skip != null && skip.equals("true")){
throw new SkipPageException();
}
}
}
The tag can be invoked from a JSP page as follows
<%@ taglib uri="/WEB-INF/tlds/SimpleTagDemo" prefix="kpe" %>
<html>
Start of page
<kpe:SkipPageExceptionDemo/>
More of the page
</body>
</html>
If the page is requested with no query string the part after the tag will be displayed as
More of the page
If the page is requested with the query string
?skip=true
The text
More of the page
Will not appear
Other sources
API docs for TagSupport
http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/TagSupport.html
API docs for BodyTagSupport http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/tagext/BodyTagSupport.html
Taglibs according to the Jakarta tutorial
http://jakarta.apache.org/taglibs/tutorial.html#tag_handler
Custom Tags in the J2EE Tutorial
http://java.sun.com/javaee/5/docs/tutorial/doc/JSPIntro9.html#wp73314
According to Mikalai Zaikin
http://java.boot.by/wcd-guide/ch10.html#c10s1