Home

MassLight presents

Chapter 3. Tag Libraries

Goals After completing this chapter, the student will be able to
  • make a simple custom tag.
  • make a complex custom tag.
Prerequisites In order to complete this chapter successfully, the student must understand
  • JSP directives.
  • how to construct a JSP.
  • how to construct and call JavaBeans.
Objectives The purpose of this chapter is to provide the student with the necessary information about tags and tag libraries.

What Are Tags?

Tags provide another way for a JSP developer to separate the presentation of an application from the logic of the application. The implementation of a tag differs from the implementation of a JavaBean. A tag's class must implement methods unique to tag classes in order for the tag to be executed properly in the JSP. Also, the tags in an application require a tag library descriptor XML file that contains information about each of the tags. A tag class extends javax.servlet.jsp.tagext.TagSupport or javax.servlet.jsp.tagext.BodyTagSupport.


Using Tags in JSP

In a Java Server Page, a tag is initialized with a declaration that looks like this:

<%@ taglib uri="WEB-INF/lib/tag_library_name.tld" prefix="prefix_name" %>

The tag_library_name.tld, used in the declaration of the tag, is the name of the tag library that has the information about the tag called tag_name. In JBoss, the tag_library_name.tld must be located in the /WEB-INF/lib pathway in order to be located by the JBoss engine. To use a very simple tag in the JSP:

<prefix_name:tag_name/>

A tag can contain a body:

<prefix_name:tag_name>
   this is called the body of the tag
</prefix_name:tag_name>

A tag can also have attributes:

<prefix_name:tag_name attributeOne="hey" />

Creating a simple tag class

SKIP_BODY versus EVAL_BODY_INCLUDE and SKIP_PAGE versus EVAL_PAGE

SKIP_BODY is returned at the end of doStartTag to tell the JSP to not output the content contained in the body of the tag. The EVAL_BODY_INCLUDE is returned at the end of the doStartTag if the content in the body of the tag should be outputted. The SKIP_PAGE is returned from the doEndTag to tell the JSP to skip the rest of the content of the JSP, while the EVAL_PAGE signifies that the JSP should evaluate the rest of the contents of the page. The default values returned are SKIP_BODY and EVAL_PAGE.

doStartTag Called when the open tag is read in the JSP - returns either SKIP_BODY or EVAL_BODY_INCLUDE
doEndTag Called when the close tag is called in the JSP - returns either SKIP_PAGE or EVAL_PAGE
release Called when the JSP is finished with the tag - resets the state of the tag

The tag library descriptor file

The tag library descriptor file helps a JSP map a tag to a Java class. It is an XML file with a .tld suffix.

Elements used in the .tld file to describe tags:

taglib signifies that a tag library will be described - required
tlibversion the tag library version - required
jspversion the version of JSP that will be used
shortname the name of the tag library - required
uri the Uniform Resource Identifier for the tag library
info the comment tag for the developer
tag signifies that a tag located in the taglib will be described - see following table for elements of a tag

Elements used in the tag tag:

name the name of the tag - required
tagclass the path information to the tag's class - required
teiclass the path information of the subclass of TagExtraInfo - this is not discussed in this chapter
bodycontent specifies the content type of the tag - can be empty, JSP, or tagdependent - empty means that the tag has no body, JSP means that there is a body that can interpreted as JSP, and tagdependent means that the tag will interpret the body as non-JSP content
info for comments
attribute signifies that an attribute of the tag will be described - see following table

Elements used in the attribute tag

name the name of the attribute that the tag might need in the declaration - required
required boolean value to specify if the attribute is required - can be either true or false
rtexprvalue specifies if the attribute can take a scriptlet expression as a value, which allows the attribute's value to determined when the attribute is set - if this element is not specified, the value is false - can be either true or false

SimpleTag: a simple tag-based web application

(If you have not already done so, you can download this and other examples used in this course. Mac OS X or other UNIX users click here instead.)

Do this:

  1. Create the directory structure. Create a SimpleTag directory, then create the usual WEB-INF and classes, then create the directory structure that represents the package structure, which in this example is com.masslight.tagExampleClasses.
code/Chapter3/SimpleTag
SimpleTag
  |
  +-- tagExample.jsp (*)
  |
  +-- build.xml (*)
  |
  +-- WEB-INF
        |
        +-- web.xml (*)
        |
        +-- tagExampleLib.tld (*)
        |
        +-- classes
              |
              +-- com
                    |
                    +-- masslight
                          |
                          +-- tagExampleClasses
                                |
                                +-- HelloWorldTag.java (*)

(*) denotes a file

  1. Create the JSP in the SimpleTag directory
code/Chapter3/SimpleTag/tagExample.jsp
<%@ page language="java" %>
<!-- declare the tag -->
<%@ taglib uri="WEB-INF/tagExampleLib.tld" prefix="greeter" %>

<html>
   <body>
     <!-- use the tag -->
     <greeter:Hello/>
   </body>
</html>

  1. Create the web.xml file in WEB-INF
code/Chapter3/SimpleTag/WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
  <taglib>
    <taglib-uri>/WEB-INF/tagExampleLib.tld</taglib-uri> 
    <taglib-location>/WEB-INF/tagExampleLib.tld</taglib-location> 
  </taglib>
</web-app>

  1. Create the Java file in WEB-INF/classes/com/masslight/tagExampleClasses/
code/Chapter3/SimpleTag/WEB-INF/classes/com/masslight/tagExampleClasses/HelloWorldTag.java
package com.masslight.tagExampleClasses;

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

public class HelloWorldTag extends javax.servlet.jsp.tagext.TagSupport {
    public int doStartTag() throws JspException {
        try {
            pageContext.getOut().print("Hello, World!");
        } catch (Exception ex) {
            throw new JspException("IO problems");
        }
        return SKIP_BODY;
    }
}

  1. Create the tag library descriptor file in WEB-INF. This maps each tag used in tagExample.jsp to a specific Java class, which in this example is com.masslight.tagExampleClasses.HelloWorldTag.
code/Chapter3/SimpleTag/WEB-INF/tagExampleLib.tld
<?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-jsptaglib_1_1.dtd">

<taglib>
     <tlibversion>1.0</tlibversion>
     <jspversion>1.1</jspversion>
     <shortname>utility</shortname>
     <info>
       A simple tag library for the examples
     </info>
     <tag>
       <name>Hello</name>
       <tagclass>com.masslight.tagExampleClasses.HelloWorldTag</tagclass>
       <bodycontent>empty</bodycontent>
       <info>
         Print Hello World
       </info>
     </tag>
</taglib>

  1. Finally, add the build.xml file, which we will use to automate building and deploying the web application. build.xml goes in the root SimpleTag directory, next to the JSPs.
code/Chapter3/SimpleTag/build.xml
<project name="SimpleTag" default="dist" basedir=".">

 <!-- set global properties for this build -->
 <property environment="env"/>
 <property name="top" value="."/>
 <property name="src" value="."/>
 <property name="build" value="build"/>
 <property name="dist" value="dist"/>
 <property name="war_dir" value="${dist}/lib"/>
 <property name="war_file" value="${war_dir}/SimpleTag.war"/>

 <property name="webinf" value="${top}/WEB-INF"/>
 <property name="web.xml" value="${webinf}/web.xml"/>
 <property name="classes" value="${webinf}/classes"/>
 <property name="lib" value="${top}/WEB-INF/lib"/>
 <property name="servlet.jar" value="${env.TOMCAT_HOME}/lib/servlet.jar"/>
 <property name="deploy" value="${env.JBOSS_HOME}/deploy"/>

 <target name="clean">
   <!-- Delete our the ${build} and ${dist} directory trees -->
   <delete dir="${build}"/>
   <delete dir="${dist}"/>
   <delete dir="${war_dir}"/>
 </target>

 <target name="init">
   <!-- Create the build directory structure used by compile and dist -->
   <mkdir dir="${build}"/>
   <mkdir dir="${dist}"/>
   <mkdir dir="${war_dir}"/>
 </target>

 <target name="compile" depends="init">
   <!-- Compile the java code from ${src} into ${build} -->
   <javac
     srcdir="${top}/${src}"
     destdir="${build}"
     classpath="${servlet.jar}"/>
 </target>

 <target name="dist" depends="compile">
   <!-- Put everything in a war file -->
   <war warfile="${war_file}" webxml="${web.xml}">
     <!-- include all JSPs in root level -->
     <fileset dir="${top}/${src}">
       <include name="*.jsp"/>
     </fileset>

     <!-- include all tag libraries in WEB-INF,
          but not web.xml (that's handled separately) -->
     <webinf dir="${webinf}">
       <include name="*.tld"/>
     </webinf>

     <!-- include all compiled classes -->
     <classes dir="${build}"/>
   </war>
 </target>

 <target name="deploy">
   <!-- Copy the war file to the JBoss deploy directory -->
   <copy file="${war_file}" todir="${deploy}"/>
 </target>

 <target name="all" depends="clean,dist,deploy"/>

</project>

  1. Do not manually compile the Java files. Instead, use Ant to compile. Start at the root SimpleTag directory and call Ant with the compile argument. You should see output like this:
c:\j2ee\code\Chapter3\SimpleTag> ant compile
Buildfile: build.xml

init:
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\build
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\dist
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\dist\lib

compile:
    [javac] Compiling 1 source file to C:\j2ee\code\Chapter3\SimpleTag\build

BUILD SUCCESSFUL

Total time: 2 seconds
  1. Do not manually create the .war distribution file. Instead, use Ant to create it.
c:\j2ee\code\Chapter3\SimpleTag> ant dist
Buildfile: build.xml

init:

dist:
      [war] Building war: C:\j2ee\code\Chapter3\SimpleTag\dist\lib\SimpleTag.war

BUILD SUCCESSFUL

Total time: 2 seconds
  1. Do not manually copy the .war file into your JBoss deploy directory. Instead, use Ant to deploy it.
c:\j2ee\code\Chapter3\SimpleTag> ant deploy
Buildfile: build.xml

deploy:
     [copy] Copying 1 file to C:\j2ee\jboss\deploy

BUILD SUCCESSFUL

Total time: 0 seconds
  1. Test the application at http://localhost:8080/SimpleTag/tagExample.jsp

Why Ant rocks

It doesn't look like Ant is much better than doing things manually, but's only because we intentionally did each step we could see what it looked like. In fact, Ant can easily combine steps, by specifying in the build.xml file that a particular step requires other steps to be performed in succession:

<target name="all" depends="clean,dist,deploy"/>

And you execute it like this:

c:\j2ee\code\Chapter3\SimpleTag> ant all
Buildfile: build.xml

clean:
   [delete] Deleting directory C:\j2ee\code\Chapter3\SimpleTag\build
   [delete] Deleting directory C:\j2ee\code\Chapter3\SimpleTag\dist

init:
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\build
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\dist
    [mkdir] Created dir: C:\j2ee\code\Chapter3\SimpleTag\dist\lib

compile:
    [javac] Compiling 1 source file to C:\j2ee\code\Chapter3\SimpleTag\build

dist:
      [war] Building war: C:\j2ee\code\Chapter3\SimpleTag\dist\lib\SimpleTag.war

deploy:
     [copy] Copying 1 file to C:\j2ee\jboss\deploy

all:

BUILD SUCCESSFUL

Total time: 2 seconds

Voila! A completely clean compile and deployment in one easy step!

Output of SimpleTag application


Tag Attributes

Attributes must be declared in the tag library descriptor, set as a class wide variable in the tag class with an accessor that uses the same name as declared in the tag library descriptor, and if the attribute is required, given a value when the tag is initialized in the JSP. If the tag in the tag library descriptor looked like this:

<tag>
 <name>exampleTagName</name>
 <tagclass>com.masslight.tags.ExampleTag</tagclass>
 <bodycontent>empty</bodycontent>
 <info>This is an example tag to demonstrate how attributes work</info>
 <attribute>
    <name>attributeOne</name>
    <required>true</required>
 </attribute>
 <attribute>
    <name>attributeTwo</name>
    <required>false</required>
 </attribute>
</tag>

then the class would need to include the following code:

public class ExampleTag extends TagSupport {
 int attributeOne = 0;
 String attributeTwo = 0;
   ....
   ....
 public void setAttributeOne(String tempAttributeOne) {
    attributeOne = Integer.valueOf(tempAttributeOne).intValue();
 }
 public void setAttributeTwo(String tempAttributeTwo) {
    attributeTwo = tempAttributeTwo;
 }
  ....
  ....

and the JSP might look something like this - remember that attributeTwo was not required:

<%@ taglib uri="WEB-INF/lib/tagLibraryName.tld" prefix="example" %>

<example:exampleTagName attributeOne="1"/>

AttributeTag: using attributes in tag libraries

Do this:

  1. Create the directory structure. Create an AttributeTag directory, then WEB-INF, classes, and the directory structure com/masslight/tagExampleClasses.
code/Chapter3/AttributeTag
AttributeTag
  |
  +-- tagExample.jsp (*)
  |
  +-- build.xml (*)
  |
  +-- WEB-INF
        |
        +-- web.xml (*)
        |
        +-- tagExampleLib.tld (*)
        |
        +-- classes
              |
              +-- com
                    |
                    +-- masslight
                          |
                          +-- tagExampleClasses
                                |
                                +-- GreetingAttributeTag.java (*)

(*) denotes a file

  1. Create the JSP in the AttributeTag directory.
code/Chapter3/AttributeTag/tagExample.jsp
<%@ page language="java" %>
<%@ taglib uri="WEB-INF/tagExampleLib.tld" prefix="greeter" %>

<html>
   <body>
      <greeter:Greeting greeting="Hey" />
   </body>
</html>

  1. Create the web.xml file in WEB-INF
code/Chapter3/AttributeTag/WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
  <taglib>
    <taglib-uri>
    </taglib-uri>
    <taglib-location>
    </taglib-location>
  </taglib>
</web-app>

  1. Create the Java file in WEB-INF/classes/com/masslight/tagExampleClasses/
code/Chapter3/AttributeTag/WEB-INF/classes/com/masslight/tagExampleClasses/GreetingAttributeTag.java
package com.masslight.tagExampleClasses;

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

public class GreetingAttributeTag extends javax.servlet.jsp.tagext.TagSupport {
   public String greeting = "Hello";
   public int doStartTag() throws JspTagException {
       try {
           pageContext.getOut().print(greeting);
       } catch (Exception ex) {
           throw new JspTagException("IO problems");
       }
       return SKIP_BODY;
   }
   public void setGreeting(String newGreeting) {
       greeting = newGreeting;
   }
}

  1. Create the tag library descriptor file in WEB-INF
code/Chapter3/AttributeTag/WEB-INF/tagExampleLib.tld
<?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-jsptaglib_1_1.dtd">

<taglib>
    <tlibversion>1.0</tlibversion>
    <jspversion>1.1</jspversion>
    <shortname>utility</shortname>
    <info>
      A simple tag library for the examples
    </info>
    <tag>
      <name>Greeting</name>
      <tagclass>com.masslight.tagExampleClasses.GreetingAttributeTag</tagclass>
      <info>Print a greeting specified by the greeting attribute</info>
      <bodycontent>empty</bodycontent>
      <attribute>
        <name>greeting</name>
        <required>true</required>
      </attribute>
    </tag>
</taglib>

  1. Create the build.xml file in the root AttributeTag directory.
code/Chapter3/AttributeTag/build.xml
<project name="AttributeTag" default="dist" basedir=".">

 <!-- set global properties for this build -->
 <property environment="env"/>
 <property name="top" value="."/>
 <property name="src" value="."/>
 <property name="build" value="build"/>
 <property name="dist" value="dist"/>
 <property name="war_dir" value="${dist}/lib"/>
 <property name="war_file" value="${war_dir}/AttributeTag.war"/>

 <property name="webinf" value="${top}/WEB-INF"/>
 <property name="web.xml" value="${webinf}/web.xml"/>
 <property name="classes" value="${webinf}/classes"/>
 <property name="lib" value="${top}/WEB-INF/lib"/>
 <property name="servlet.jar" value="${env.TOMCAT_HOME}/lib/servlet.jar"/>
 <property name="deploy" value="${env.JBOSS_HOME}/deploy"/>

 <target name="clean">
   <!-- Delete our the ${build} and ${dist} directory trees -->
   <delete dir="${build}"/>
   <delete dir="${dist}"/>
   <delete dir="${war_dir}"/>
 </target>

 <target name="init">
   <!-- Create the build directory structure used by compile and dist -->
   <mkdir dir="${build}"/>
   <mkdir dir="${dist}"/>
   <mkdir dir="${war_dir}"/>
 </target>

 <target name="compile" depends="init">
   <!-- Compile the java code from ${src} into ${build} -->
   <javac
     srcdir="${top}/${src}"
     destdir="${build}"
     classpath="${servlet.jar}"/>
 </target>

 <target name="dist" depends="compile">
   <!-- Put everything in a war file -->
   <war warfile="${war_file}" webxml="${web.xml}">
     <!-- include all JSPs in root level -->
     <fileset dir="${top}/${src}">
       <include name="*.jsp"/>
     </fileset>

     <!-- include all tag libraries in WEB-INF,
          but not web.xml (that's handled separately) -->
     <webinf dir="${webinf}">
       <include name="*.tld"/>
       <exclude name="web.xml"/>
     </webinf>

     <!-- include all compiled classes -->
     <classes dir="${build}"/>
   </war>
 </target>

 <target name="deploy">
   <!-- Copy the war file to the JBoss deploy directory -->
   <copy file="${war_file}" todir="${deploy}"/>
 </target>

 <target name="all" depends="clean,dist,deploy"/>

</project>

  1. ant all to compile, jar, and deploy. You should see output like this:
C:\work\j2ee\code\Chapter3\AttributeTag> ant all
Buildfile: build.xml

clean:

init:
    [mkdir] Created dir: C:\work\j2ee\code\Chapter3\AttributeTag\build
    [mkdir] Created dir: C:\work\j2ee\code\Chapter3\AttributeTag\dist
    [mkdir] Created dir: C:\work\j2ee\code\Chapter3\AttributeTag\dist\lib

compile:
    [javac] Compiling 1 source file to C:\work\j2ee\code\Chapter3\AttributeTag\build

dist:
      [war] Building war: C:\work\j2ee\code\Chapter3\AttributeTag\dist\lib\AttributeTag.war

deploy:
     [copy] Copying 1 file to C:\j2ee\jboss\deploy

all:

BUILD SUCCESSFUL

Total time: 8 seconds
  1. Go to http://localhost:8080/AttributeTag/tagExample.jsp to test your application

Using Scope Objects in Tags

It is important to note that pageContext, session, and application objects can be accessed from a tag class. This means that attributes from any and all of the different scopes can be used in a tag class.

Creating a complex tag class

The tag class that extends TagBody allows the developer to execute code before and after the body of the tag. Instead of returning SKIP_BODY or EVAL_BODY_INCLUDE, the doStartTag method returns SKIP_BODY or EVAL_BODY_TAG. The doAfterBody method returns either the SKIP_BODY or the EVAL_BODY_TAG which allows the tag to loop through the tag's body until some condition is met. The content of the tag's body can be accessed by a call to getBodyContent() which returns a BodyContent object. The developer needs to write the contents of the body to the output stream by making a call to the writeOut() method of the BodyContent object. To write out the content of the body, one must write out contents of the getPreviousOut() method. If the developer does not make this call, then nothing from the body of the tag will be shown. The doInitBody method returns void and is not such an important method as the doAfterBody method.
doInitBody Called when the JSP enters the body of the tag - returns nothing
doAfterBody Called when the JSP leaves the body of the tag - returns SKIP_BODY or EVAL_BODY_TAG

Do this:

  1. Create the directory structure. The root directory is named ComplexTag; the rest is the same as the previous examples.
  2. Create tagExample.jsp, RepeatHelloTag.java, web.xml, tagExampleLib.tld, and build.xml
code/Chapter3/ComplexTag
ComplexTag
  |
  +-- tagExample.jsp (*)
  |
  +-- build.xml (*)
  |
  +-- WEB-INF
        |
        +-- web.xml (*)
        |
        +-- tagExampleLib.tld (*)
        |
        +-- classes
              |
              +-- com
                    |
                    +-- masslight
                          |
                          +-- tagExampleClasses
                                |
                                +-- RepeatHelloTag.java (*)

(*) denotes a file

code/Chapter3/ComplexTag/tagExample.jsp
<%@ page language="java" %>
<%@ taglib uri="WEB-INF/tagExampleLib.tld" prefix="greeter" %>
<html>
    <body>
      <greeter:RepeatHello>
        Hello Again<br>
      </greeter:RepeatHello>
    </body>
</html>

code/Chapter3/ComplexTag/WEB-INF/classes/com/masslight/tagExampleClasses/RepeatHelloTag.java
package com.masslight.tagExampleClasses;

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

public class RepeatHelloTag extends javax.servlet.jsp.tagext.BodyTagSupport {
    int count = 1;
    int numberOfIterations = 3;
    String greeting = new String("Hello <BR>");
    public int doStartTag() throws JspTagException {
        try {
            pageContext.getOut().print(greeting);
        } catch (Exception ex) {
            throw new JspTagException("IO problems");
        }
        return EVAL_BODY_TAG;
    }
    public int doAfterBody() throws JspTagException {
        try {
            if (count < numberOfIterations) {
                count++;
                return EVAL_BODY_TAG;
            }
            else {
		BodyContent bodyContent = getBodyContent();
                bodyContent.writeOut(getPreviousOut());
                return SKIP_BODY;
            }
        }
        catch (Exception e) {
            throw (new JspTagException("error"));
        }
    }
}

code/Chapter3/ComplexTag/WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
  "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">

<web-app>
  <taglib>
    <taglib-uri>/WEB-INF/tagExampleLib.tld</taglib-uri> 
    <taglib-location>/WEB-INF/tagExampleLib.tld</taglib-location> 
  </taglib>
</web-app>

code/Chapter3/ComplexTag/WEB-INF/tagExampleLib.tld
<?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-jsptaglib_1_1.dtd">

<taglib>
     <tlibversion>1.0</tlibversion>
     <jspversion>1.1</jspversion>
     <shortname>utility</shortname>
     <info>
       A simple tag library for the examples
     </info>
     <tag>
       <name>RepeatHello</name>
       <tagclass>com.masslight.tagExampleClasses.RepeatHelloTag</tagclass>
       <bodycontent>JSP</bodycontent>
       <info>Print Hello Multiple Times</info>
     </tag>
</taglib>

code/Chapter3/ComplexTag/build.xml
<project name="ComplexTag" default="dist" basedir=".">

 <!-- set global properties for this build -->
 <property environment="env"/>
 <property name="top" value="."/>
 <property name="src" value="."/>
 <property name="build" value="build"/>
 <property name="dist" value="dist"/>
 <property name="war_dir" value="${dist}/lib"/>
 <property name="war_file" value="${war_dir}/ComplexTag.war"/>

 <property name="webinf" value="${top}/WEB-INF"/>
 <property name="web.xml" value="${webinf}/web.xml"/>
 <property name="classes" value="${webinf}/classes"/>
 <property name="lib" value="${top}/WEB-INF/lib"/>
 <property name="servlet.jar" value="${env.TOMCAT_HOME}/lib/servlet.jar"/>
 <property name="deploy" value="${env.JBOSS_HOME}/deploy"/>

 <target name="clean">
   <!-- Delete our the ${build} and ${dist} directory trees -->
   <delete dir="${build}"/>
   <delete dir="${dist}"/>
   <delete dir="${war_dir}"/>
 </target>

 <target name="init">
   <!-- Create the build directory structure used by compile and dist -->
   <mkdir dir="${build}"/>
   <mkdir dir="${dist}"/>
   <mkdir dir="${war_dir}"/>
 </target>

 <target name="compile" depends="init">
   <!-- Compile the java code from ${src} into ${build} -->
   <javac
     srcdir="${top}/${src}"
     destdir="${build}"
     classpath="${servlet.jar}"/>
 </target>

 <target name="dist" depends="compile">
   <!-- Put everything in a war file -->
   <war warfile="${war_file}" webxml="${web.xml}">
     <!-- include all JSPs in root level -->
     <fileset dir="${top}/${src}">
       <include name="*.jsp"/>
     </fileset>

     <!-- include all tag libraries in WEB-INF,
          but not web.xml (that's handled separately) -->
     <webinf dir="${webinf}">
       <include name="*.tld"/>
       <exclude name="web.xml"/>
     </webinf>

     <!-- include all compiled classes -->
     <classes dir="${build}"/>
   </war>
 </target>

 <target name="deploy">
   <!-- Copy the war file to the JBoss deploy directory -->
   <copy file="${war_file}" todir="${deploy}"/>
 </target>

 <target name="all" depends="clean,dist,deploy"/>

</project>

  1. ant all to compile, jar, and deploy.
  2. Go to http://localhost:8080/ComplexTag/tagExample.jsp to test your application

Exercises

Exercise 1. Fibonacci

Make an application that calculates the Fibonacci sequence with a tag that uses a repeating body. The application should produce the first n elements of the arithmetic sequence, using a tag that takes an attribute specifying the value of n. The actual element should be calculated using a JavaBean. The JavaBean method should be in the body of the tag. The tag would look something like this:

<arithmetic_sum:first_sequence numberOfElements = "7">
 <%= bean.calculateElement() %>
</arithmetic_sum:first_sequence>