Classic custom tag



Almost every developer has his own library of methods. And I wonder that few use their own tags on JSP page called custom tags. Any custom tag developer can reuse like any other method.
In the first part of my article I’d like to describe Classic Custom tags.
When you create Classic Custom tag than your class may implement one of three interfaces: Tag, IterationTag, and BodyTag or extends one of two classes TagSupport or BodyTagSupport. I advise you to use classes because in this case you should not implement all methods from interfaces.
Classes and interfaces from servlet.jsp.tagext package have the following hierarchy:
 

Tag    
|    
IterationTag   TagSupport
|    
BodyTag   BodyTagSupport

You can create very simple tags if your class implements Tag interface. This tag does not allow to analyze and manipulate tag body (text between open and closed tag <mytag:tag> body </mytag:tag>) or use iterations to display body. First I will show how JSP container processes implemented tag called a tag handler and than I will write first simple tag.
1. setPageContext(PageContext pc) – we need PageContext to get JspWriter object for output
2. setParent(Tag t) – this method will help to get the predecessor of tag if necessary
3. setAttr (. . .) – to set and get attributes if our tag has it (<mytags:tag attr=”value”/>)
4. int doStartTag() – use this method to show something before body
if EVAL_BODY_INCLUDE returned – [JSP container processes body contents from opening and closing tags]
if SKIP_BODY returned – [skip body and go to doEndTag(), no output of body will be present]
5. int doEndTag() - use this method to show something after body
if EVAL_PAGE returned - [JSP processes the rest of page after the tag]
if SKIP_PAGE returned - [JSP container does nothing with the rest of the page after the tag]

To create the simplest custom tag need to execute four essential steps:
1. Write tag handler
2. Define the tag within a tag library definition (TLD) file
3. Provide details of where to find the TLD file in the deployment descriptor web.xml
4. Referencing the TLD file in JSP page and use tag

The simple tag just will output on page “Simple tag”.
1. As I sad before I will use class TagSupport instead of Tag interface.

public class SimpleTag extends TagSupport {
   public int doStartTag() throws JspException {
   try {
       pageContext.getOut().print("Simple.");
   } catch (Exception ex) {
       throw new JspTagException("SimpleTag: " +ex.getMessage());
   }
   return SKIP_BODY;
   }
}

2. The TLD file will be in /WEB-INF/tags/mytags.tld and will contain

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">

<tlib-version>1.0</tlib-version>
<short-name>MyTagLib</short-name>
<uri>http://www.java-soft.org/mytags.tld</uri>
<tag>
<name>simple</name>
<tag-class>tags.SimpleTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>

I’d like to bring the special attention to elements <body-content>. It may have 4 different values empty, scriptless, tagdependent, JSP. The tag from example will not have body and I set it as empty. Tagdependent means that everything inside body of tag is considered as template text and jsp container does not evaluate it. Scriptless - the body of the tag does contain regular JSP source, but no scripting language. JSP – any kind of JSP.
The second important element is <attribute>. It is sub element of <tag> and I will use it in the next example. It shows what kind attributes may have custom tag.
<attribute>
<name>attributeName </name>
<required>false</required>
<rtexprvalue>true</rtexprvalue> - if set to “true” the value of attribute may be EL expression
</attribute> 3. add reference to web.xml

<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<jsp-config>
 <taglib>
   <taglib-uri>http://www.java-soft.org/taglibs/mytags</taglib-uri>
   <taglib-location>/WEB-INF/tags/mytags.tld</taglib-location>
 </taglib>
</jsp-config>

4. JSP page custom-tag.jsp

<%@page contentType="text/html"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<%@ taglib prefix="mytags" uri="http://www.java-soft.org/taglibs/mytags" %>
<body>
The simplest tag with TagSupport <br>
<mytags:simple /> <br>
</body>
</html>

Now I will show what brings IterationTag interface. It adds a method doAfterBody() which may return EVAL_BODY_AGAIN. We need this interface if we would like to use body of tag more than once.
Processing of JSP container IterationTag Interface
1. setPageContext(PageContext pc)
2. setParent(Tag t)
3. setAtr(. . .)
4. int doStartTag()
if EVAL_BODY_INCLUDE returned - [container processes body contents]
if SKIP_BODY returned – skip body and go to doEndTag()
5. doAfterBody()
if EVAL_BODY_AGAIN returned - [JSP processes body contents again ]
if SKIP_BODY returned - [exit from loop and go to doEndTag]
6. int doEndTag()
if EVAL_PAGE returned - [ JSP processes remainder of page]
if SKIP_PAGE returned - [ JSP container does nothing with the rest of the page]

The example with iteration will be tag mytags:iterate that print all elements of a collection in a new line.
The Jsp code will be as

<% java.util.ArrayList list = new java.util.ArrayList();
list.add("one");
list.add("two");
list.add("three");
%>
<mytags:iterate collection ="<%= list%>">
Value ${item} <br>
</mytags:iterate>

Tag handler class will have name SimpleIterateTag. I’d like to notice that the first element of collection will print in doStartTag and others in doAfterBody method.

public class SimpleIterateTag implements TagSupport {
 private Collection collection;
 private Iterator iterator;
 public Collection getCollection() {
   return collection;
 }
 public void setCollection(Collection collection) {
   this.collection = collection;
 }
 @Override
 public int doStartTag() throws JspException {
   if (collection != null) {
     iterator = collection.iterator();
   if (iterator.hasNext()) {
     pageContext.setAttribute("item", iterator.next());
   }
   return EVAL_BODY_INCLUDE;
   } else {
     return SKIP_BODY;
   }
 }
 @Override
 public int doAfterBody() throws JspException {
   if (iterator.hasNext()) {
     pageContext.setAttribute("item", iterator.next());
     return EVAL_BODY_AGAIN;
   } else {
   return SKIP_BODY;
  }
 }
}

In TLD the description of tag will be as

<tag>
<name>iterate</name>
<tag-class>tags.SimpleIterateTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>collection</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>

Of cause you can use JSTL library core with the same effect but I repeat that it’s just example and I sure that your creativity will help to invent very interesting and necessary tags.

<c:forEach items="<%= list%>" var="its">
value2 = ${its} <br>
</c:forEach>

The third interface BodyTag helps to get body content in tag handler. The main object of BodyTag interface is the BodyContent object. A new return type for this interface is EVAL_BODY_BUFFERED. We use it in doStartTag() to create BodyContent object.
BodyContent has method getString() that returns the tag's body.
And getEnclosingWriter() returns a type of JspWriter, with an important distinction: The contents are buffered.
The example for this interface will be more interesting. For division operation
EL convert float number to double and the result of ${9.21 / 3} =
3.0700000000000003
I will implement <mytags:divideNumber>${9.21 / 3} </mytags:divideNumber> = 3.07

Create DivideNumbers tag handler:

public class DivideNumbers extends BodyTagSupport {
@Override
public int doStartTag() throws JspException {
return EVAL_BODY_BUFFERED;
}
@Override
public int doAfterBody() throws JspException {
 BodyContent bc = getBodyContent();
 String body = bc.getString();
 String firstNumber = "", secondNumber = "";
 firstNumber = body.substring(body.indexOf("${")+2, body.indexOf("/")).trim();
 secondNumber = body.substring(body.indexOf("/")+1, body.indexOf("}")).trim();
 float fn = Float.parseFloat(firstNumber);
 float sn = Float.parseFloat(secondNumber);
 try {
  bc.getEnclosingWriter().print(fn/sn);
 } catch (IOException ex) {
  System.err.println(ex.getMessage());
 }
 return SKIP_BODY;
 }
}

Description divideNumber tag in TLD:

<tag>
<name>divideNumber</name>
<tag-class>ch08.DivideNumbers</tag-class>
<body-content>tagdependent</body-content>
</tag>

The other examples of using BodyTag interface are tags with sql query:
<mytags:execSQL>select * from products</mytags:execSQL>
Or convert body of tag to lower case.
<mytags:tolowercase> tO loWeR CaSe </mytags:tolowercase>

The last example of this article shows how to use getParent method of Tag interface. User can implement dependency of tags (cooperating tags) when inner tag depends on outer tag.
For example,

<mytags:redColor message="hello">
<mytags:message />
</mytags:redColor>

Tag “message” prints value of attribute message of redColor tag. And redColor tag add <font size='10' color='blue'> … </fonr> text. If “message” tag has two possible outer tags (redColor and blueColor) developer should use static method findAncestorWithClass or instanceof in tag handler. With findAncestorWithClass can get parent, or grandparent, or great-great-grandparent of inner tag.
Tag handler for “message” tag is SimpleMessage.java

public class SimpleMessage extends TagSupport {
@Override
public int doEndTag() throws JspException {
try {
ColorBlueTag parent = (ColorBlueTag)TagSupport.findAncestorWithClass(this,
Class.forName("ch08.ColorBlueTag"));
if (parent!=null)
pageContext.getOut().print(parent.getMessage());
} catch (ClassNotFoundException ex) {
} catch (IOException ex) {
}
try {
ColorRedTag parent = (ColorRedTag)TagSupport.findAncestorWithClass(this,
Class.forName("ch08.ColorRedTag"));
if (parent!=null)
pageContext.getOut().print(parent.getMessage());
} catch (ClassNotFoundException ex) {
} catch (IOException ex) {
}
return EVAL_PAGE;
}
}

Tag handlers for ColorBlueTag and ColorRedTag

public class ColorRedTag extends TagSupport {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public int doEndTag() throws JspException {
try {
pageContext.getOut().print("</font>");
} catch (IOException ex) {
}
return EVAL_PAGE;
}
@Override
public int doStartTag() throws JspException {
try {
pageContext.getOut().print("<font size='10' color='red'>");
} catch (IOException ex) {
}
return EVAL_BODY_INCLUDE;
}
}

TLD looks like:

<tag>
<name>message</name>
<tag-class>tags.SimpleMessage</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>redColor</name>
<tag-class>tags.ColorRedTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>message</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>