Article
Use Custom Tags to Aggregate RSS Feeds into JSP-Based Web Apps
Reading RSS Feeds from JSP
For the purposes of this article, I’m going to assume that you’ve chosen to build your Web application using Java Web technologies and, specifically, that you’re going to use JavaServer Pages (JSP). One of the great things about this technology is that it makes the injection of dynamic behaviour into your pages easy -- all you need to do is add a little Java here and there. For example, we could use the classes we've just built in a JSP page:
<%
RssReader reader = new RssReader();
RssFeed rssFeed = reader.read("http://www.acme.com/rss.xml");
Iterator it = rssFeed.getItems().iterator();
while (it.hasNext()) {
RssItem rssItem = (RssItem)it.next();
%>
<a href="<%= rssItem.getLink() %>"><%= rssItem.getTitle() %></a>
<br />
<%
}
%>
This code grabs the RSS feed from the specified URL and, using the standard java.util.Iterator class, loops over each item displaying a hyperlink back to the full story.
While embedding Java code as a scriptlet is useful, it can soon become problematic -- particularly if you need to reuse that code on other pages within your Web applications. After all, there is no easy way to reuse such code; to simply copy and paste the code throughout your application will eventually lead to maintainability issues, as changes need to be replicated in every occurrence of that script. Ideally, we want to reuse code at the component level, taking a given component and using it wherever necessary. JSP custom tags are the answer.
Wrapping the RSS Reader in a JSP Custom Tag
JSP custom tags are a means to wrap common and recurring logic into a form that’s reusable across the pages of your Web applications. In the current version of the JSP specification (1.2), the behaviour of a custom tag is implemented as a Java class that activates a specific interface, in much the same way you’d implement a servlet, for example. This Java class is generally called the tag handler.
The key difference between custom tags and regular Java classes lies in the way they’re used within JSP pages. Where Java code is simply embedded in the page, custom tags are used with an XML syntax. For example, here’s how the custom tag will be used when we’ve finished building it. Notice that here we have a starting tag, some body content, then the ending tag.
<rss:rssFeed url="http://www.acme.com/rss.xml">
<a href="<%= rssItem.getLink() %>"><%= rssItem.getTitle() %></a>
<br />
</rss:rssFeed>
This will achieve exactly the same result as the scriptlet code we saw before -- the tag provides the iteration over each item in the feed. Essentially, the tag is now the looping construct and the body content of the tag is evaluated for each iteration, in the same way that the content of a while loop is evaluated for each iteration. Custom tags provide us with a way to build cleaner, more concise JSP pages that benefit from the advantages of reusing components -- increased maintainability, quality, reliability, and so on.
Building a Tag Handler Class
Now that you have an understanding of why custom tags are useful, let’s take a look at how to build one. As I said before, the behaviour is wrapped up as a regular Java class that implements a specific interface. In the case of custom tags, the interface that must be implemented (at a minimum) is Tag, from the javax.servlet.jsp.tagext package. This interface is fairly straightforward and provides a number of callback methods that will be executed when the tag is used on a JSP page. At runtime, the JSP page creates for a given custom tag a new instance of the tag handler class, and calls the callback methods. This might sound complicated at first, but it becomes fairly straightforward once you’ve built a couple of tags for yourself.
For convenience, the JSP specification also provides a basic implementation of this interface, called TagSupport, which is an ideal starting point from which to build your own tags. The following code snippet shows the start of the source code for the tag handler, including all the necessary imports. It also shows a couple of attributes -- we’ll see where these are used later on.
package tagext;
import java.util.Collection;
import java.util.Iterator;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
import rss.RssFeed;
import rss.RssReader;
public class RssFeedTag extends TagSupport {
private String url;
private Iterator iterator;
In the tag usage example I presented earlier, we saw that there was a starting tag, some body content, and the ending tag. These different aspects of the tag are important because they define when the JSP page will fire the callback methods that we write in our tag handler class. The functionality we need to implement is identical to that shown before; we need to read in an RSS feed from a URL, then iterate over each item in the feed so that a hyperlink can be generated. With the TagSupport class, the three callback methods that are available to us are doStartTag(), doAfterBody() and doEndTag(). Let’s look at each of these in turn.
The doStartTag() method is called when the starting tag is encountered on the JSP page, and is called only once for any given custom tag.
public int doStartTag() throws JspException {
RssReader reader = new RssReader();
RssFeed feed = reader.read(url);
iterator = feed.getItems().iterator();
if (iterator.hasNext()) {
pageContext.setAttribute("rssItem", iterator.next());
return EVAL_BODY_INCLUDE;
} else {
return SKIP_BODY;
}
}
Since this code is only called once per tag, and is the first of the callback methods to be fired, it’s here that we can read the RSS feed and set up an iterator to loop over the collection of items. If you think of this method as the start of the while loop, the first step is to check that there are items in the collection. If there are, we want to make the first item available for use in the JSP page, so that we can utilise it within the body content of the tag. To do this, we set an attribute on the JSP PageContext to refer to the first item in the collection. Next, we must tell the JSP page that the body content of the tag should be evaluated, which is achieved by returning a constant value of EVAL_BODY_INCLUDE. If, however, there aren’t any items in the collection, we tell the JSP page that it should skip evaluating the body content by returning the constant value of SKIP_BODY.
The next callback method of interest is the doAfterBody() method, which is called after the body content of the tag has been evaluated.
public int doAfterBody() throws JspException {
if (iterator.hasNext()) {
pageContext.setAttribute("rssItem", iterator.next());
return EVAL_BODY_AGAIN;
} else {
return SKIP_BODY;
}
}
Once the body content is evaluated, the next step is to see whether there are any more items in the collection. If there are, we want to make the new item available to the JSP page and indicate that the body content should be re-evaluated, by returning a constant value of EVAL_BODY_AGAIN. After this, the doAfterBody() method is called again, to see if yet another evaluation is required. This sequence repeats until there are no more items in the collection, in which case a constant value of SKIP_BODY is returned.
When all the evaluations have been performed, the final callback method is executed.
public int doEndTag() throws JspException {
return EVAL_PAGE;
}
This implementation simply tells the JSP page that the remainder of the page should be processed as normal. In fact, the implementation of the TagSupport class contains the same implementation of this method, meaning we don’t actually need to implement it. However, I’ve shown it here for completeness.
The final method we need to implement is a setter for the URL. If you look back to the example of how the tag will be used on the page, you’ll notice that the URL of the RSS feed is specified as an attribute of the custom tag. To make this information available to the tag handler class, we need to write a setter method in the same way we’d write setter methods for JavaBean properties. Any setter methods that correspond to attributes of a custom tag are called before the callback methods, so that their values are available for use within those callback methods.
public void setUrl(String url) {
this.url = url;
}
}