<taglib:tutorial lesson="3"/>

In this part of the tutorial, we will look at what a BodyTag is, and develop a BodyTag

1 Lesson 3, Writing a BodyTag

    In this part of the tutorial, we will look at what a BodyTag is, and develop a BodyTag that can be used for handling loops in our JSP pages. We will continue to use the setup previously defined for this tutorial. At the end of this tutorial, you will have created and properly described a BodyTag. In order to try it out, you will also have written 2 beans and a JSP page.

2 What is a BodyTag?

    One of the most common things you would like to do in a JSP page is a Iteration of something, such as order rows, search results etc. As described in lesson 1, the body of a simple Tag is evaluated once. In order to evaluate a Tags body multiple times, we need to use a BodyTag.


    Figure 1: The BodyTag interface extends the Tag interface

    A BodyTag interface extends the Tag interface and gives us a couple of new methods that we will look at shortly. It also introduces us to a new class, the BodyContent class. In short, a BodyTag gives us the possibility to evaluate the body of a Tag multiple times.

    Lets have a look at how the Container will interact with a BodyTag when such is encountered in a JSP Page:


    Figure 2: BodyTag interaction

    1. Call the setPageContext() method of the BodyTag to set the current PageContext for it to use.

    2. Call the setParent() method to set any parent of the encountered Tag (or null if none).

    3. Set any attributes defined to be given to the BodyTag.

    4. Call the doStartTag() method of the BodyTag. If this method returns SKIP_BODY, the doEndTag() method should be called (see 9 below). If EVAL_BODY_TAG is returned, continue below.

    5. Call the setBodyContent() method of the BodyTag to set the current BodyContent for it to use (if there is at least one evaluation of the body of the BodyTag).

    6. Call the doInitBody() method of the BodyTag. This is where we will normally put any instructions that should be taken care of before the body of the BodyTag is evaluated for the first time.

    7. Call the doAfterBody() method of the BodyTag after each evaluation of the BodyTags body. If this method returns EVAL_BODY_TAG, the body of the BodyTag should be evaluated anew, and then this method should be called again. If this method returns SKIP_BODY, continue below.

    8. Call the doEndTag() method of the BodyTag after the last evaluation of the BodyTags body. If this method returns EVAL_PAGE, the container will evaluate the rest of the JSP page. If this method returns SKIP_PAGE, the Container will not evaluate the rest of the JSP page.

    9. Call the release() method. This method can be used by the Tag developer to release any resources that the Tag was using. Please notice that it is up to the Container to call the release() method when seemed fit, so you can't rely on this method being called at any specific time. In theory, this method could be called 12 days after the Tag was used. For this reason, any code that must be executed at the end of the Tag usage should be called from the doEndTag() method (see 8 above).

    As previously said, a BodyTag is given a BodyContent class by the Container. The BodyContent class looks like in Figure 3 below:


    Figure 3: The BodyContent class.

    The BodyContent class extends the JspWriter class and can be used to process body evaluations so they can be retrieved later on. The content of a BodyContent class can be read with the Reader returned by the getReader() method. The content can also be read as a String by calling the getString() method. The BodyContent's content can be cleared by calling the clearBody() method. In order to write content to the BodyContent, the writeOut() method can be called with a writer (such as the JspWriter returned by the getEnclosingWriter() method).

    With this said about the BodyTag, we should now try to create one. If you want to learn more or get a deeper understanding about the BodyTag, consult the JSP 1.1 API or the JSP 1.1 Specification.

3 Create a BodyTag

    Now its time to develop our first BodyTag. We are going to develop a BodyTag that can be used for looping.


    Figure 4: The LoopTag.

    The BodyTag will have an attribute called iterations that will hold the number of times that we want to evaluate the body of the BodyTag.

    1. In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'LoopTag.java' with the following content:


      package com.acme.tag;

      import javax.servlet.jsp.*;
      import javax.servlet.jsp.tagext.*;

      public class LoopTag implements BodyTag
      {
      private Tag parent;
      private BodyContent bodyContent;
      private PageContext pageContext;
      private int iterations=0;
      Listing 1: Start of the BodyTag

      Above, we specify that our new class will implement the BodyTag interface. After that, we make sure to keep track of the parent Tag, the BodyContent and the PageContext that the Container will give us. We also define an attribute to hold the number of iterations that we should do.

    2. Add the constructor:


      public LoopTag()
      {
      super();
      }
      Listing 2: The constructor.

    3. Now, add the following method:


      public void setPageContext(PageContext PageContext)
      {
      this.pageContext=pageContext;
      }
      Listing 3: Implementing the setPageContext method.

      The method above will be used by the Container to set the BodyTags PageContext.

    4. Continue with the following method:


      public void setParent(final javax.servlet.jsp.tagext.Tag parent)
      {
      this.parent=parent;
      }
      Listing 4: Implementing the setParent method.

      The method above will be used by the Container to set the parent Tag.

    5. Continue with the following method:


      public void setIterations(int iterations)
      {
      this.iterations=iterations;
      }
      Llisting 5: A way to set the number of itterations.

      The method above will be called by the Container to set the iterations attribute.

    6. Continue with the following:


      public int doStartTag() throws JspTagException
      {
      if(iterations>0)
      {
      return EVAL_BODY_TAG;
      }
      else
      {
      return SKIP_BODY;
      }
      }
      Listing 6: Overriding the doStartTag method.

      The method above will get called at the start of the Tag. The method will verify that more iteration should be performed.

    7. Continue with the following method:


      public void setBodyContent(BodyContent bodyContent)
      {
      this.bodyContent=bodyContent;
      }
      Listing 7: Implementing the setBodyContent method.

      The method above will be called by the Container if there will be at least one evaluation of the BodyTags body, and is used by the Container to set the BodyContent for the BodyTag.

    8. Continue with the following:


      public void doInitBody() throws JspTagException{}
      Listing 8: Implementing the doInitBody method.

      The Container will call the method above before the first evaluation of the body of the BodyTag is performed. As there are no special initialisations to do for our LoopTag, we just leave it empty.

    9. Continue with the method shown below:


      public int doAfterBody() throws JspTagException
      {
      if(iterations>1)
      {
      iterations--;
      return EVAL_BODY_TAG;
      }
      else
      {
      return SKIP_BODY;
      }
      }
      Listing 9: Implementing the doAfterBody method.

      The method above will get called after each evaluation the BodyTags body. Every time, we decrease the number of iterations left to do by one and return EVAL_BODY_TAG as long as the number of iterations left to do are more than one.

    10. Continue with the following method:


      public int doEndTag() throws JspTagException
      {
      try
      {
      if(bodyContent != null)
      bodyContent.writeOut(bodyContent.getEnclosingWriter());
      }
      catch(java.io.IOException e)
      {
      throw new JspTagException("IO Error: " + e.getMessage());
      }
      return EVAL_PAGE;
      }
      Listing 10: Implementing the doEndTag method

      The method above gets called at the end of the BodyTag. In the method we check if any bodyContent was written during the evaluations of the body and if so write it to the enclosing writer.

    11. Continue with the following method:


      public void release() {}
      Listing 11: Implementing the release method.

      The method above gets called to release any resources held by the BodyTag. As we don't use any specific resources, there is nothing for us to clear.

    12. Finish off the BodyTag with the following:


      public javax.servlet.jsp.tagext.Tag getParent()
      {
      return parent;
      }
      }
      Listing 12: Implementing the getParent() method.

      The method above is used to get the parent Tag. We will look more at this method and why its there in lesson 4.

      By now, your LoopdTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as LoopTag.java

    13. Compile the BodyTag.

4 Update the Tag Library Descriptor

    We should now describe our new Tag in the previously created Tag library descriptor.

    1. Open your 'taglib.tld' from your '/WEB-INF' directory with your favourite editor.

    2. Add the following description for your new Tag:


      <tag>
      <name>loop</name>
      <tagclass>com.acme.tag.LoopTag</tagclass>
      <bodycontent>JSP</bodycontent>
      <info>A BodyTag for looping</info>
      <attribute>
      <name>iterations</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      </attribute>
      </tag>
      Listing 13: The new Tag entry

      This will tell our JSP container that the new BodyTag can accept an attribute called iterations and that the BodyTags body can contain JSP that should be evaluated. The <rtexprvalue> that is set to true will tell the Container that the name iterations will be evaluated at runtime (i.e. can be a dynamic value).

    By now, your taglib.tld should look like this. Store the descriptor in the /WEB-INF/ directory as taglib.tld.

5 Creating a presentation

    In order to test our new BodyTag, we need to write a JSP page that uses it.

    1. Create a new file called 'loop.jsp' in your '/taglib-tutorial-web/' directory with the following content:


      <%@ taglib uri="mytags" prefix="mt" %>
      <HTML>
      <HEAD>
      <TITLE>Loop Test</TITLE>
      </HEAD>
      <BODY BGCOLOR="#FFFFFF">
      <HR>
      <mt:loop iterations="5">
      Hello<BR>
      </mt:loop>
      <HR>
      </BODY>
      </HTML>
      Listing 14: A sample JSP page.

      In the page above, we first tell the Container a reference to our Taglib descriptor. We then use the LoopTag by using its defined name ('loop') with the iterations attribute set to 5.

    By now, your loop.jsp should look like this. Store the file in the taglib-tutorial-web/ directory as loop.jsp.

6 Using your new BodyTag

    Its now time to test your new BodyTag.

    Open the URL http://localhost/taglib/loop.jsp in a normal web browser. Hopefully the result looks like this.

    Continue with lesson 4, "Writing Collaborating Tags"

Copyright © 2005 IronFlare AB