ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button
JavaServer Pages, 2nd Edition

JSTL 1.0: What JSP Applications Need, Part 3

by Hans Bergsten, author of JavaServer Pages, 2nd Edition
10/30/2002

Previous installments in this series gave you an overview of JSTL--the new specification of commonly needed JSP tag libraries--and showed you how to use the core, internationalization, and database JSTL actions, as well as how to use JSTL effectively in an MVC application. In this final installment, we'll look at how you can leverage the JSTL classes when you develop your own custom actions. To understand what I describe here, you need to be a Java programmer and also know a thing or two about how to develop JSP custom actions in general.

Accepting EL Expressions as Attribute Values

The JSTL specification introduces an Expression Language (EL) that can be used to set JSTL action attributes to values computed at runtime, as you have seen in the previous parts of this series. A common question is "Can I also use the EL for setting attribute values in my custom actions?" The answer is: yes and no.

A JSP 1.2 container doesn't know anything about EL expressions, so they are evaluated by code in the JSTL tag handlers. JSTL 1.0 doesn't define a public API for this evaluation code, so there's no way to let custom tag handlers do the same in a way that works with all JSTL implementations. You can, however, pick one JSTL implementation and code to its API. For instance, if you're willing to be dependent on the JSTL Reference Implementation (RI) developed in the Apache Taglibs project (see the Resource section), you can use this org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager method in your tag handler:

public static Object evaluate(String attributeName,
  String expression,
  Class expectedType,
  Tag tag,
  PageContext pageContext);

This method takes an EL expression and evaluates it in the specified PageContext and converts (coerces) the result to the specified expected type, according to the rules defined by the JSTL 1.0 specification. The other parameters are used to include details in a possible error message, such as the name of the custom action and the attribute where the invalid expression is used.

In This Series

JSTL 1.0: What JSP Applications Need, Part 2 -- Part 2 of our JSTL series focuses on internationization, localization, and database access.

JSTL 1.0: Standardizing JSP, Part 1 -- JSTL offers a set of standardized JSP custom actions to handle common tasks. This article, the first in a series, provides an overview and shows how to use the most common tags.

You must call this method in one of the main methods in the tag handler (e.g. doEndTag()), never in the attribute setter method. The reason for this is that the setter method may not be called every time the tag handler is used, as I describe in my article, "JSP 1.2: Great News for the JSP Community, Part 2" (in the Tag handler life cycle and instance reuse section).

Here's a tag handler that accepts an EL expression as the value of its name attribute:

package com.ora.jstl;

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;

public class HelloTag extends TagSupport {
   private String nameEL;

   public void setName(String name) {
      nameEL = name;
   }

   public int doEndTag() throws JspException {
      String name = (String)
      ExpressionEvaluatorManager.evaluate("name", nameEL, 
          String.class, this, pageContext);
      if (name == null || name.length() == 0) {
         name = "World";
      }
      try {
         pageContext.getOut().write("Hello " + name + "!");
      }
      catch (IOException e) {}
      return EVAL_PAGE;
   }
}

Note that to compile and use this tag handler, you must have the JSTL RI ExpressionEvaluatorManager in the classpath; it's available in the standard.jar file that's part of the RI download.

Related Reading

JavaServer Pages
By Hans Bergsten

If you can hold your horses a bit and wait for JSP 2.0, you don't have to do anything in your tag handlers to accept EL expression attribute values. JSP 2.0 (currently at the Proposed Final Draft stage, expected to be released Q1 2003) will include a somewhat extended version of the EL and will evaluate EL expressions before calling tag handler attribute setter methods. Hence, EL expressions can be used with any tag handler that is declared in the TLD to accept a runtime value. JSP 2.0 will also accept EL expressions anywhere in the template text.

Developing JSTL-Style Conditional Custom Actions

The JSTL specification group realized that no matter how many custom actions JSTL defines, there will always be a need for application-dependent custom actions. We tried to make it as easy as possible to develop custom actions that integrate nicely with the actions defined by the JSTL specification by including a number of public interfaces and base classes in the specification. The following sections show you some examples of how to use these classes and interfaces, starting with custom conditional actions.

The generic <c:if> and <c:when> actions, using the Boolean value of an EL expression as the condition, work great in many scenarios, but not in all. For instance, say you want to conditionally add some content depending on the time of day. You could create your own bean with Boolean properties suitable for use in an EL expression, but a custom action like this may be more convenient to use:

<xmp:ifAfternoon>
   Sorry, we only accept delivery requests before noon.
</xmp:ifAfternoon>

It's very easy to implement such a custom action, thanks to the extendable JSTL classes. Here's the complete tag handler code for the <xmp:ifAfternoon> action:

package com.ora.jstl;

import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.servlet.jsp.jstl.core.ConditionalTagSupport;

public class IfAfternoonTag extends ConditionalTagSupport {
   public boolean condition() {
      Calendar now = new GregorianCalendar();
      return now.get(Calendar.AM_PM) == Calendar.PM;
   }
}

The tag handler class extends the JSTL javax.servlet.jsp.jstl.core.ConditionalTagSupport class, which provides implementations for all standard JSP tag handler methods and calls the condition() method implemented by the subclass to decide what to do. It also includes setter methods for var and scope attributes, so a subclass like the one shown here behaves just like the <c:if> action: if the condition() method returns true, the custom action's body is processed; if it doesn't have a body, the value can be saved as a Boolean in variable and scope specified by the var and scope attributes.

You may expect there to be a similar base class for developing custom actions to be used, the same as a <c:when> action within a <c:choose> block, but there isn't. The reason is this: to ensure that custom actions cannot interfere with the somewhat complex interaction between the <c:choose> action and its nested actions, only <c:when> and <c:otherwise> actions are allowed as direct children of the <c:choose> action. But you can combine your own conditional actions with a <c:choose> like this to get the same multiple-choice effect:

<xmp:ifAfternoon var="isAfternoon" />
<c:choose>
   <c:when test="${isAfternoon}">
     Good day!
   </c:when>
   <c:otherwise>
     Good morning!
   </c:otherwise>
</c:choose>

Simply save the custom conditional result, using the var attribute, and then use this result in the EL expression for a <c:when> action in the block.

Pages: 1, 2

Next Pagearrow