Custom Tags 3 – Skills for Classic Tag handlers


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

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

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

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

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

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

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

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

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:

  1. EVAL_BODY_INCLUDE = evaluate the body once.
  2. 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:

  1. EVAL_BODY_AGAIN = evaluate the body again.
  2. SKIP_BODY = just go on, stop evaluating the body.

doEndTag method is called last. It may return:

  1. SKIP_PAGE = skip the rest of the page.
  2. EVAL_PAGE = proceed normally to the rest of the page.

2 Responses to Custom Tags 3 – Skills for Classic Tag handlers

  1. […] Skills for Classic Tag handlers […]

  2. nice…explanation… great…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: