This post presents the basic skills of classic tag handling for the JSP technology.
Here’s an overview of the hierarchy. The arrows denote an IS-A relationship.

Hierarchy of Classic Tag handlers
Step 1. Write a TagSupport and provide its doStartTag() method.
package my;
public class Classic extends TagSupport {
public int doStartTag() throws JspException {
try {
pageContext.getOut().print("Hello from a classic tag handler!!");
} catch (IOException e) {
e.printStackTrace();
}
return SKIP_BODY;
}
}
Step 2. Declare it in a TLD.
<taglib ...>
<uri>nikojava</uri>
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
Step 3. Call it!
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic />
</body>
</html>

Invoking a classic tag
Process its body
Just return EVAL_BODY_INCLUDE to make the body evaluated,
public class Classic extends TagSupport {
public int doStartTag() throws JspException {
try {
pageContext.getOut().print("This is my body: ");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_BODY_INCLUDE;
}
}
as long as the tag is declared to have a body.
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>scriptless</body-content>
</tag>
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic>Really useful contents!</show:classic>
</body>
</html>

Accessing the body of a classic tag
Define a body attribute
It’s easy to define attributes right inside the body of the tag.
public class Classic extends TagSupport {
public int doStartTag() throws JspException {
pageContext.setAttribute("friend", "Nikos");
return EVAL_BODY_INCLUDE;
}
}
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic>Hello my friend ${friend}!!</show:classic>
</body>
</html>

Using an attribute inside the body of a classic tag
Define a tag attribute
An attribute is defined as a setter method,
public class Classic extends TagSupport {
private String friend;
public int doStartTag() throws JspException {
try {
pageContext.getOut().append("Hey you " + friend + "!!");
} catch (IOException e) {
e.printStackTrace();
}
return EVAL_BODY_INCLUDE;
}
public void setFriend(String friend) {
this.friend = friend;
}
}
that is also declared in the TLD.
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>empty</body-content>
<attribute>
<name>friend</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic friend="Niko" />
</body>
</html>

Using a tag attribute
Dynamic attributes
To process such attributes you should implement the DynamicAttributes and its single method.
public class Classic extends TagSupport implements DynamicAttributes {
private Map<String, Object> map = new HashMap<String, Object>();
public void setDynamicAttribute(String uri, String name, Object value) {
map.put(name, value);
}
public int doStartTag() throws JspException {
try {
JspWriter out = pageContext.getOut();
out.append("These are the dynamic attributes:");
out.append("<ul>");
for (Map.Entry<String, Object> element : map.entrySet()) {
out.append("<li>");
out.append(element.getKey() + " ⇒ " + element.getValue());
out.append("</li>");
}
out.append("</ul>>");
} catch (IOException e) {
e.printStackTrace();
}
return SKIP_BODY;
}
}
The doStartTag() method simply displays the name and value of each dynamic attribute.
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>empty</body-content>
<dynamic-attributes>true</dynamic-attributes>
</tag>
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic custom="tag" open="source" javafx="cool" />
</body>
</html>

Dynamic attributes in a classic tag
Reevaluate the body
When the doStartTag() method returns EVAL_BODY_INCLUDE, we can evaluate the body again and again. This is possible using the doAfterBody() method.
public class Classic extends TagSupport {
private int counter;
public int doStartTag() throws JspException {
counter = 0;
return EVAL_BODY_INCLUDE;
}
public int doAfterBody() throws JspException {
while (counter < 3) {
counter++;
return EVAL_BODY_AGAIN;
}
return SKIP_BODY;
}
}
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>scriptless</body-content>
</tag>
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
<show:classic>Hello </show:classic>
</body>
</html>

Iterating over the body of a classic tag again and again
Skip the rest of the page
This is accomplished by overriding the doEndTag() method.
public class Classic extends TagSupport {
public int doStartTag() throws JspException {
return EVAL_BODY_INCLUDE;
}
public int doEndTag() throws JspException {
return SKIP_PAGE;
}
}
<tag>
<name>classic</name>
<tag-class>my.Classic</tag-class>
<body-content>scriptless</body-content>
</tag>
<%@ taglib prefix="show" uri="nikojava" %>
<html>
<body>
(Start of page)
<show:classic>Hello from a classic tag!</show:classic>
(End of page)
</body>
</html>

Skipping the rest of the page from a classic tag
Indeed, the last part of the page is never sent to the client.
Review
doStartTag method is called first. It may return:
- EVAL_BODY_INCLUDE = evaluate the body once.
- SKIP_BODY = go on, do not evaluate the body of the tag.
doAfterBody method is called only if doStartTag() returns option 1. It may return:
- EVAL_BODY_AGAIN = evaluate the body again.
- SKIP_BODY = just go on, stop evaluating the body.
doEndTag method is called last. It may return:
- SKIP_PAGE = skip the rest of the page.
- EVAL_PAGE = proceed normally to the rest of the page.