|
<taglib:tutorial lesson="10">
In this lesson, we will take a look at the new IterationTag interface and how we can utilize that as Tag developers.
1 Lesson 1, The IterationTag interface
In this lesson, we will take a look at the new IterationTag interface and how we can utilize that as Tag developers. We will then rewrite the IterateTag of lesson 5 in order to take advantage of the features IterationTag gives us.
Throughout this lesson, We will continue to use the setup previously defined for this tutorial. You should feel comfortable about the Tag interface, the TagSupport class and BodyTags before starting on this lesson.
2 What is the IterationTag interface?
The IterationTag interface was added to the TagLibrary API with JSP 1.2. It is quite cleverly added as a extension to the Tag interface and is in it's turn extended by the BodyTag interface (that previously extended Tag)
 Figure 1. The IterationTag interface
As seen in figure 1 above, the IterationTag interface adds the method doAfterbody previously found in BodyTag and the new return value EVAL_BODY_AGAIN. The doAfterBody() method is first invoked if the doStartTag() method returns EVAL_BODY_INCLUDE (or possibly EVAL_BODY_BUFFERED if it's a BodyTag). The doAfterBody() method should in it's turn return either EVAL_BODY_AGAIN or SKIP_BODY. As long as EVAL_BODY_AGAIN is returned, the doAfterBody() method will be invoked. When finally SKIP_BODY is returned the doEndTag() method will be invoked and the Tag (or BodyTag) usage will end.
The value of EVAL_BODY_AGAIN is the same as for the BodyTag's EVAL_BODY_TAG (now deprecated) so that old JSP 1.1 Tag libraries will still work properly.
In JSP 1.1, the Tag Developer was forced to write a BodyTag in order to re-evaluate the body of the Tag. In JSP 1.2, the IterationTag adds the necessary functionality to do simple re-evaluations that does not involve manipulation of the body contents. If however, the body content needs to be manipulated, the BodyTag would be required.
As the basic interfaces has changed, so have the utility classes TagSupport and BodyTagSupport, as show in figure 2 below.
 Figure 2: The TagSupport and BodyTagSupport helper classes.
As seen in figure 2 above, TagSupport now extends IterationTag instead of Tag (as it was in JSP 1.1). As BodyTagSupport extends TagSupport both Support classes now inherit the IterationTag iterative functionality.
Finally, let's have a look at the lifecycle of a Tag implementing the IterationTag interface shown in figure 3 below.
 Figure 3: A sequence diagram showing the interaction between the Container and an IterationTag implementation.
As seen in figure 3 above, when a JSP page is parsed and a tag is encountered, the Container will:
-
Use the setPageContext() method of the Tag to set the current PageContext for it to use.
-
Use the setParent() method to set any parent of the encountered Tag (or null if none).
-
Set any attributes defined to be given to the Tag.
-
Call the doStartTag() method. This method can either return EVAL_BODY_INCLUDE (EVAL_BODY_BUFFERED for BodyTags) or SKIP_BODY. If EVAL_BODY_INCLUDE is returned, the Tags body will be evaluated. If SKIP_BODY is returned, the Container will not evaluate the body of the Tag.
-
Call the doAfterBody() method after every body evaluation. This method can either return EVAL_BODY_AGAIN or SKIP_BODY. If EVAL_BODY_AGAIN is returned, the Tags body will be re-evaluated. If SKIP_BODY is returned, the Container will not re-evaluate the body of the Tag, but call doEndTag instead.
-
Call the doEndTag() method. This method can either return EVAL_PAGE or SKIP_PAGE. IF EVAL_PAGE is returned, the Container will continue to evaluate the JSP page when done with this Tag. If SKIP_PAGE is returned, the Container will stop evaluating the page when it's done with this Tag.
-
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 6 above).
With this ends the introduction of the IterationTag interface. If you want to learn more or get a deeper understanding about the IterationTag class, consult the JSP 1.2 API or the JSP 1.2 specification.
3 Writing the Iteration Tag
We will now write a JSP 1.2 version of the IterateTag that we created back in lesson 5. Back then, in JSP 1.1, we had to implement the tag as a BodyTag and take responsibility of the body content although all we really wanted to do was to re-evaluate it a number of times. As figure 4 below shows, this time we will write the Tag based on the TagSupport class that in its turn implements the IterationTag interface.
 Figure 4: The IteratorTag class
The TagSupport class that we are extending is a default implementation of the Tag interface that we will utilize when writing Tags, just as we did back in lesson 2.
-
In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'IteratorTag.java' with the following content:
package com.acme.tag;
import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.util.*;
public class IteratorTag extends TagSupport { private Iterator iterator; private String type;
|
Listing 1: Define the variables that the tag will need.
Above we define the two variables that our BodyTag will need. The third variable is "id" and is already defined in TagSupport.
-
Define a constructor:
public IteratorTag() { super(); }
|
Listing 2: Adding the constructor
-
Now, add the following method:
public void setCollection(Collection collection) { if(collection.size()>0) iterator = collection.iterator(); }
|
Listing 3: Adding a method to set the Collection
Our Container will call the method above to set the Collection passed to the Tag. We do a check to see if the Collection passed in really hold any elements, just as we did in the original IterateTag.
-
After that, the old IterateTag had a method to set the name of the scripting variable, but as we will use the "id" variable already defined in TagSupport we leave that out in our new implementation.
-
Continue with the following:
public void setType(String type) { this.type=type; }
|
Listing 4: Adding a method to set the type of the scripting variable.
This method will be used by the container to set the class type of the scripting variable, and we still need to do this in our new implementation.
-
Add the following method:
public int doStartTag() throws JspException { if (iterator != null) { if (hasNext()) return EVAL_BODY_INCLUDE; } return SKIP_BODY; }
|
Listing 5: Overriding the doStartTag method
The method above gets called at the start of the Tag. It first makes sure that we have an Iterator, and then calls the hasNext() method that will add the next element of the Iterator to the PageContext, using the name previously passed in as the "id" parameter to the Tag. The method will return EVAL_BODY-INCLUDE if the Iterator contained another element. Otherwise, it will return SKIP_BODY. The hasNext() method is a slightly modified version of the addNext() method of the IterateTag, as will be further explained below.
-
Now add the following method:
public int doAfterBody() throws JspException { if (hasNext()) return EVAL_BODY_AGAIN; else return SKIP_BODY; }
|
Listing 6: Overriding the doAfterBody method
The method above gets called after every evaluation of the body of the Tag and will call the previously mentioned hasNext() method. The body of the Tag will be re-evaluated as long as this method return EVAL_BODY_AGAIN, which replaces the deprecated EVAL_BODY_TAG return value of JSP 1.1 BodyTags.
-
After that, the old IterateTag overrides the doEndTag() method as it had to mess with the body content of the Tag, which we don't have to care about now that we are using the IterationTag instead of the BodyTag of the old implementation.
-
Finish off the BodyTag with the following method:
private boolean hasNext() { if (iterator.hasNext()) { this.pageContext.setAttribute(id, iterator.next(), PageContext.PAGE_SCOPE); return true; } return false; } }
|
Listing 7: Add method to check for more elements in the Iterator
The method above will check if there are any more elements in the Iterator. If there are more elements, the next element will be added to the page scope with the given id and the method will return true, which will tell the Tag that the body of the Tag should be evaluated. If the Iterator holds no more elements, the method returns false and the Tag will return SKIP_BODY which will make the Container continue with the doEndTag() method.
The slight change in implementation originates from the deprecation of EVAL_BODY_TAG that formerly could be returned from both BodyTag.doAfterBody() and Tag.doStartTag(). In JSP 1.2 however, IterationTag.doAfterBody() should return EVAL_BODY_AGAIN (has the same value as the former BodyTag.doAfterBody()) or SKIP_BODY while Tag.doStartTag() should return EVAL_BODY_INCLUDE or SKIP_BODY (although BodyTags can also return EVAL_BODY_BUFFERED). Therefore, the actual return value needed to be computed in the calling method.
|
Your IteratorTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as IteratorTag.java
|
-
Compile the Tag.
4 Creating the TEI class
As our Tag will be adding scripting variables to the page we need to provide our Tag with a accompanying TEI class. If you have already gone through lesson 5 you will notice that this TEI will be very similar to the IterateTEI we developed then.
 Figure 5. The IteratorTEI
The only difference between the TEI developed in lesson 5 and this one would be the name of the attribute that is now id (we used name back then).
-
In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'IteratorTEI.java' with the following content:
package com.acme.tag;
import javax.servlet.jsp.tagext.TagExtraInfo; import javax.servlet.jsp.tagext.VariableInfo; import javax.servlet.jsp.tagext.TagData;
public class IteratorTEI extends TagExtraInfo {
public IteratorTEI() { super(); }
public VariableInfo[] getVariableInfo(TagData data) { return new VariableInfo[] { new VariableInfo(//the variables name data.getAttributeString("id"), //the variables type data.getAttributeString("type"), //if the variable is new or not true, //the scope of the variable VariableInfo.NESTED ) }; } }
|
Listing 8: The IteratorTEI
Above, we use the TagData object to retrieve the value of the id and type attributes that was passed into the IteratorTag. We also tell the Container to treat the added variable as if it was a new variable, and that the variable should be available from the start of the Tag to the end.
|
Your IteratorTEI.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as IteratorTEI.java
|
-
Compile the TEI-class. If needed, details are given here. The result should be a file named IteratorTEI.class in the /WEB-INF/classes/com/acme/tag/ directory.
5 Creating the Tag Library Descriptor
We should now describe our new Tag in a new JSP 1.2 Tag library descriptor. With JSP 1.2 comes a new DTD for Tag libraries that not only hold new elements, it has also renamed most of the old elements to conform better to the overall J2EE descriptor style.
-
Create a text file called taglib1.2.tld in your '/WEB-INF/' directory
-
Start with the following XML header:
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
|
Listing 8: The XML header.
The only item of interest above would be that we are using the DTD for JSP 1.2 Tag Libraries instead of the old 1.1.
-
Start describing your Tag library:
<taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>mt2</short-name> <uri>http://www.orionserver.com/tutorials/mytags2</uri> <description>My Second Tag library</description>
|
Listing 9: Describing the Tag Library.
The <tlib-version> tag (formerly known as <tlibversion>) is used to specify the version of this Tag Library implementation. As this is our first take on this Tag Library let's be conservative and give it a value of "1.0".
<jsp-version> (formerly known as <jspversion>) is used to specify what JSP version the Tag Library requires in order to work properly. A value of "1.2" would be correct for JSP 1.2 Tag Libraries.
The <short-name> tag (known as <shortname> in JSP 1.1 Tag Library descriptors) is mainly used to give page authoring software an idea of a suitable nickname when referencing the Tag Library. It could for instance be used to set the default prefix when generating JSP pages. In this case, let's go with "mt2"
The <uri> tag is used to give this version of this Tag Library a unique identifier, just as in JSP 1.1 Tag Library descriptors. A value of "http://www.orionserver.com/tutorials/mytags2" will make it unique as far as this Tutorial goes.
The formerly used <into> tag has been replaced by a <description> tag, but it still serves the purpose of describing the Tag Library.
Now that the Library itself is fully described, let's move on to the IterationTag descriptor.
-
Describe the IteratorTag:
<tag> <name>iterate</name> <tag-class>com.acme.tag.IteratorTag</tag-class> <tei-class>com.acme.tag.IteratorTEI</tei-class>
<body-content<JSP>/body-content> <description>A simple Iterator</description>
|
Listing 10: Describing the IteratorTag.
The <name> tag is used to decide by what name the Tag should be referenced. In our case the name will be "iterate".
The <tag-class> tag is used (just as the old <tagclass> tag) to specify the implementation class of the Tag.
The <tei-class> tag is used (just as the old <teiclass> tag) to specify the TagExtraInfo class for the Tag.
The <body-content> tag was formerly known as <bodycontent>, and specifies what kind of content the Tag is supposed to contain. Valid values are "tagdependent", "JSP" and "empty", just as in JSP 1.1 Tag Libraries. In this case, the Tag will most probably contain content that needs further evaluation, so the value should be "JSP".
The <description> tag (named <info> in JSP 1.1 Tag Libraries) is used to describe the Tag.
-
Describe the attributes:
<attribute> <name>collection</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>id</name> <required>true</required> </attribute> <attribute> <name>type</name> <required>true</required> </attribute>
|
Listing 11: Describing the Tags attributes.
In listing 11 above, we describe each attribute our Tag has, just as with JSP 1.1 Tab Libraries (this was covered in lesson 2).
-
End your Tag library descriptor:
Listing 12: Ending the Tag Library descriptor.

|
By now, your taglib1.2.tld should look like this. Store the descriptor in the /WEB-INF/ directory as taglib1.2.tld.
|
6 Reference your Tag library
In order to use our Tag library from a JSP page, the Tag library has to be referenced. This can be done in a number of ways, as covered in lesson 1.
As we previously defined a reference to the Taglib descriptor from the Web-modules descriptor, let's do so again.
-
Open the 'web.xml' file found in the '/WEB-INF/' directory of your web-application.
-
Add the following lines right after the old Tag library reference:
<taglib> <taglib-uri>mytags2</taglib-uri> <taglib-location>/WEB-INF/taglib1.2.tld</taglib-location> </taglib>
|
Listing 13: Adding another Tag library reference to the Web-modules descriptor.
Notice that as we are not about to package our Tag library, we point out the taglib.tld file instead of any JAR file.
-
Make sure that you save the 'web.xml' file.
|
By now, your web.xml should look like this. Store the descriptor in the /WEB-INF/ directory as web.xml.
|
7 Creating some Beans
If you haven't already gone through lesson 5, you should now do so now as we will reuse the beans created there.
You can get the source for the Company bean here, and the source for the Contact bean is here.
Make sure that you compile the beans and put them in your '/WEB-INF/classes/com/acme/bean/' directory if you haven't got them there already.
8 Presenting the new Tag
In order to use your new Tag so that you can see your IteratorTag in action, you will need a JSP page that uses it.
If you haven't already gone through lesson 5, you should do so now as we will reuse the JSP page created there.
You can get the source for the JSP page here. Copy the "iterate.jsp" file into a file named "iterator.jsp". Now change the Tag Library reference to utilize our new Tag Library instead by changing the following line in iterator.jsp:
<%@ taglib uri="mytags" prefix="mt" %>
|
Listing 14: The line to change.
so that it looks like in listing 15 below instead:
<%@ taglib uri="mytags2" prefix="mt" %>
|
Listing 15: The changed line.
|
By now, your iterator.jsp should look like
this. Store the file in the
taglib-tutorial-web/ directory as
iterator.jsp.
|
9 Using your new Tag
We are now ready to use your new Tag.
|
Open the URL
http://localhost/taglib/iterator.jsp in a normal web browser. Hopefully the result looks like
this.
|
Continue with lesson 11", "Using the TryCatchFinallyInterface".
Copyright ©
2005 IronFlare AB
|