|
<taglib:tutorial lesson="15"/>
In this part of the tutorial, we will look at what a SimpleTag is and how it can be utilized within our Taglibrary
1 Lesson 15, Simple Tag Handlers
In this part of the tutorial we will look at the new SimpleTag interface and accompanying SimpleTagSupport class that came along with JSP 2.0. We will continue to use the
setup previously defined for this tutorial. During this lesson, you will implement your first SimpleTag based Tag and a view that can be used to try it out.
2 What is a SimpleTag?
The SimpleTag interface was introduced in JSP 2.0 and allows for a faster and easier way to develop Tag Handlers than earlier. Due to the major change of how Tags can be implemented the Expert Group behind JSP 2.0 decided to branch the classes into two branches, each extending a new super interface called JspTag.
 Figure 1. The Simple Tag Handlers and the Classic Tag Handlers
The old branch containing Tag, IterationTag, BodyTag and others is now referred to as Classic Tag Handlers while the new branch containing SimpleTag and others is referred to as Simple Tag Handlers.The new branch also encompasses the new Tagfiles that will be covered in their own tutorial.
 Figure 2. The SimpleTag interface
While the old Tag and BodyTag interfaces had a number of lifecycle related methods (such as doStartTag(), doEndTag(), release() and so forth) the SimpleTag only has one, the doTag() mehtod.. The thought here is that the SimpleTag would act more like a general Java class, and take care of reevaluation programatically in the doTag() method by itself, utilizing the JspFragment or parent JspTag (notice that this differs from the old Tag implementation who has a Tag as parent, but more on this later). As Simple Tag Handlers are not intended to be cached by the Container, there is no release() method either.
 Figure 3: A sequence diagram showing the interaction between the Container and an SimpleTag implementation.
As seen in figure 3 above, when a JSP page is parsed and a tag is encountered, the Container will create a new instance and:
-
Use the setJspContext() of the SimpleTag to set the current JspContext for it to use.
-
Use the setParent() method if there is a parent to the encountered SimpleTag (otherwise this method is not called at all).
-
Set any attributes defined to be given to the Tag.
-
If the SimpleTag contains a body, the setJspBody() is used to set the body of the SimpleTag as a JspFragment (otherwise this method is not called at all).
-
Call the doTag() method where all logic, iteration, body evaluations, etc. occurs.
While the Classic Tag Handler was given a PageContext (see
lesson 1 for details), the SimpleTag is given a JspContext. The JspContext abstracts all the information that is not specific to Servlets, so that Simple Tag Handler can be used outside the context of request/response Servlets.
 Figure 4. The abstract JspContext class
The JspContext can be used as a single point to access the various namespaces (
PAGE_SCOPE,
REQUEST_SCOPE,
SESSION_SCOPE and
APPLICATION_SCOPE) through methods such as its
findAttribute(String name)method, that can be used to try and locate a named Object in all the scopes in order and return the Object if its bound to the specified name, or null if no Object is bound by that name.
Other usages for the JspContext can be to get programmatic access to the Expression Language evaluator through the
getExpressionEvaluator() method that returns a ExpressionEvaluator, and the
getVariableResolver() method that returns a VariableResolver thats needed for handling JSP variables implicit objects.
As will be covered in lesson x, the Simple Tag Handlers parent is not a Tag as it were with the Classic Tag Handler, but of course a SimpleTag. When a Simple Tag Handler wraps a Classic Tag Handler the container will use the TagAdapter class to wrap the Simple Tag Handler in order for it to look like a Tag for the Classic Tag Handler.
 Figure 5. The TagAdapter class
When a SimpleTag has a body, the container will set the JspFragment through the setJspBody() method. The JspFragment can be evaluated any number of times as well as be passed along to other Simple Tag Handlers. It can even be parameterized by setting PAGE-scoped attributes in the JspContext associated with the fragment.
As can be seen in figure 5 below, the JspFragment only holds two methods:
 Figure 6. The abstract JspFragment class
JspFragments are covered in detail in lesson 16.
Just as with Classic Tag Handlers, there is a utility class called
SimpleTagSupport that implements the SimpleTag interface and provides some utility methods. This class serves as an excellent base implementation for SimpleTag developers such as ourselfs.
 Figure 7. The SimpleTagSupport class
As can be seen in figure 7 above, the SimpleTagSupport class provides getter methods for the
JspContext and
JspFragment through the methods
getJspContext() and
getJspBody().
For some reason the SimpleTagSupport class does not define the default id field that TagSupport of the Classic Tag Handlers did.
The SimpleTagSupport class also has a Simple Tag Handler version of the
TagSupport method
findAncestorWithClass(javax.servlet.jsp.tagext.Tag) (see
lesson 2 for details) through the method
findAncestorWithClass(javax.servlet.jsp.tagext.JspTag from, Class klass). This method behaves more or less like the classic version of method, with the main difference that the
from parameter should be set to the instance from where the search should begin. SimpleTagSupport will then traverse up through the hierarchy of Handlers through the usage of the
getParent() method of the
Tag and/or
SimpleTag interface until a match for the
klass parameter is found. If no match is found, null will be returned. As the Container is responsible for wrapping any encountered
SimpleTag implementations with a
TagAdapter wrapper, such instances will be matched through the usage of the adapters
getAdaptee() method. If this is a match, the wrapped SimpleTag will be returned as an JspTag.
With this ends the introduction of the SimpleTag interface. If you want to learn more or get a deeper understanding about the SimpleTag interface, consult the
JSP 2.0 API or the
JSP 2.0 specification.
3 Creating the SimpleTag
It is time to write our first Simple Tag Handler, or in other words, a class implementing the
SimpleTag interface. This new Simple Tag Handler will be used to retrieve the contents of a specified URL and output this to the Page by using the JspWriter gained from the JspContext.
 Figure 8. The RemoteIncludeTag implementation extending the SimpleTag class
As can be seen in figure 8 above, the SimpleTag will contain only two methods;
setLocation(java.lang.String location) that will be used by the Container to set the handlers only attribute and
doTag(), that will contain our behaviour.
-
In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'RemoteIncludeTag.java' with the following content:
package com.acme.tag;
import javax.servlet.jsp.tagext.SimpleTagSupport; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import java.io.IOException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL;
public class RemoteIncludeTag extends SimpleTagSupport { private String location;
public void setLocation(String location) { this.location=location; }
|
Listing 1: the getter for the location attribute
In the listing above we define our single variable location that will hold the URL attribute specified by the page author when using the SimpleTag. The Container will use the setLocation(java.lang.String location) method to set this variable.
-
Continue with the doTag() implementation that will contain our handlers logic:
public void doTag() throws JspException, IOException { URL resource = new URL(location); BufferedReader in = new BufferedReader(new InputStreamReader(resource.openStream())); String inputLine; JspWriter out = this.getJspContext().getOut(); while ((inputLine = in.readLine()) != null) out.print(inputLine); in.close(); }
|
Listing 2: the logic of the handler
In the code above, we read the contents of the specified URL and use the JspWriter that we accuire from the JspContext to output the result to the client response.
Notice, that as oposed to the Classic Tag Handler, the Simple Tag Handler does not return any status code such as the Tag.SKIP_PAGE. Such behaviour would be handled by throwing a SkipPageException as previously mentioned.
|
By now, your RemoteIncludeTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as RemoteIncludeTag.java
|
-
Compile the SimpleTag. If needed, details are given here. The result should be a file named RemoteIncludeTag.class in the /WEB-INF/classes/com/acme/tag/ directory.
4 Creating the Tag Library Descriptor
We should now describe our new SimpleTag in a new JSP 2.0 Tag library descriptor. As all descriptors are using Schemas in J2EE 1.4, so does the Taglibrary descriptors.
-
Create a text file called taglib2.0.tld in your '/WEB-INF/' directory
-
Start with the following XML header:
<?xml version="1.0" encoding="UTF-8" ?> <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 web-jsptaglibrary_2_0.xsd" version="2.0">
|
Listing 3: The XML header.
In the listing above we define what namespaces and XML Schema document that shoud be used for the XML document.
-
Continue by describing the Taglibrary:
<description>My third Taglibrary</description> <tlib-version>1.0</tlib-version> <short-name>mt</short-name> <uri>http://www.orionserver.com/tutorials/mytags3</uri>
|
Listing 4: Describing the Taglibrary
In the listing above we specify that the default short-name is "mt", that it's the first version (tlib-version) and that the unique identifier for the Taglibrary is "http://www.orionserver.com/tutorials/mytags3". This all looks very much like the old Taglibrary descriptors of JSP 1.2 and earlier.
-
Continue by describing the SimpleTag:
<tag> <name>include</name> <tag-class>com.acme.tag.RemoteIncludeTag</tag-class> <body-content>empty</body-content> <attribute> <name>location</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
|
Listing 5: Describing the SimpleTag
Above we describe the SimpleTag just as any other Tag we have described previously in this tutorial and with that we end the descriptor.

|
By now, your taglib2.0.tld should look like this. Store the descriptor in the /WEB-INF/ directory as taglib2.0.tld.
|
5 Reference your Tag library
As Containers compatible with JSP 2.0 will autodetect unpackaged Taglibraries as well as packaged, we do not need to add a reference to the Web-modules descriptor.
6 Presenting the new Handler
In order to see our new Handler in action, we will need a JSP page that uses it.
-
Create a file called include.jsp and add the following lines:
<%@ taglib uri="http://www.orionserver.com/tutorials/mytags3" prefix="mt" %> <hr> <mt:include location="http://www.orionserver.com"/> <hr>
|
Listing 6: The include.jsp page
In the JSP page above, we use the
include Handler to include the respone returned from
http://www.orionserver.com in this page.
|
By now, your include.jsp should look like
this. Store the file in the
taglib-tutorial-web/ directory as
include.jsp.
|
7 Using your new Tag
8 Extending with cache
This Tag Handler could be made more useful by adding error and cache handling to it. Lets take a look at how this could be done.
 Figure 9. A caching mechanism
RemoteLocationManagerLoader would be a ServletContextListener responsible for adding a single RemoteLocationManager bean to the Servlet context.
RemoteLocationManager would hold a HashMap where it would store content with the URL as key. When the content of a certain location would be asked for, it would check if it already got the content and make sure it hadn't timed out (by calling the expired() method of the RemoteLocation bean), or it would retreive the content from the location and store it before returning it to the client.
RemoteLocation would represent a specific location. By keeping track of Its creation time and the specified timeout period it would be able to tell if the content would still be valid or not.
RemoteIncludeTag would be given an aditional attribute, timeout that could be used to specify how many seconds content should be considered valid before it has to be fetched anew. The Handler would use the findAttribute(String name) of the JspContext to get the RemoteLocationManager from the Servlet context and ask it for the specified content.
As an exercicse, try implementing this solution. Or better yet, think up your own caching mechanism and implement that!
Continue with
lesson 16", "Fragments as attributes".
Copyright ©
2005 IronFlare AB
|