The JSTL conditional actions should be sufficient for nearly all your conditional code needs, but just in case they're not, JSTL provides the infrastructure that you need to implement your own conditional actions. That infrastructure consists of one class ” ConditionalTagSupport ”that resides in the javax.servlet.jsp.jstl. core package. This section shows you how to use that class to implement conditional custom actions. The JSP page listed in Listing 3.15 on page 139 used the <c:if> action to test whether a color preference bean's background and foreground colors were the same, like this: <html> ... <body bgcolor='<c:out value="${param.bgcolor}"/>'> ... <%-- If the bean's foreground and background colors are the same... --%> <c:if test='${bean.background == bean.foreground}'> <%-- ...store an error message in session scope and...--%> <c:set var='colorErrorMessage' scope='session'> Sorry, but you can't specify the same colors for the foreground and background because you won't be able to see anything at <c:out value='${sessionScope.lastPage}'/> </c:set> <%-- ...go back to set_colors.jsp --%> <jsp:forward page='set_colors.jsp'/> </c:if> ... </body> </html> The preceding code fragment tests to see if the bean's background and foreground colors are the same, but what it's really testing for is an inadequate combination of background and foreground colors. It would be better to encapsulate that test in a custom action so that the definition of inadequate combination of background and foreground colors can change over time; for example, we might want to extend that definition to include background and foreground color combinations that are difficult to read, such as black on blue or yellow on orange. The following code fragment shows a custom action that replaces the <c:if> action in the preceding code fragment. <html> ... <body bgcolor='<c:out value="${param.bgcolor}"/>'> <%@ taglib uri='WEB-INF/core-jstl.tld' prefix='core-jstl'%> ... <%-- If the bean's foreground and background colors are the same... --%> <core-jstl:ifBadColorCombination target='bean'> <%-- ...store an error message in session scope and...--%> <c:set var='colorErrorMessage' scope='session'> Sorry, but you can't specify the same colors for the foreground and background because you won't be able to see anything at <c:out value='${sessionScope.lastPage}'/> </c:set> <%-- ...go back to set_colors.jsp --%> <jsp:forward page='set_colors.jsp'/> </core-jstl:ifBadColorCombination> ... </body> </html> The <core-jstl:ifBadColorCombination> action has one attribute, named target , which specifies a color preference bean. The action compares the background and foreground colors of the specified bean. Implementing the <core-jstl:ifBadColorCombination> custom action used in the preceding code fragment is a simple two-step procedure. First, we implement the action's tag handler, which is listed in Listing 3.17. Listing 3.17 WEB-INF/classes/tags/IfBadColorCombinationAction.javapackage tags; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.jstl.core.ConditionalTagSupport; import beans.ColorPreferences; public class IfBadColorCombinationAction extends ConditionalTagSupport { private String targetName; // Setter method for the target attribute, which is a string public void setTarget(String targetName) { this.targetName = targetName; } // Compare bean colors and return true if it's a bad // combination; otherwise, return false protected boolean condition () throws JspTagException { ColorPreferences bean = (ColorPreferences) pageContext.findAttribute(targetName); return bean.getBackground().equals(bean.getForeground()); } } Implementing the tag handler could not be much simpler. We simply extend ConditionalTagSupport and implement the abstract condition method. That method returns true if the condition ”in this case, whether the background and foreground colors are equal ”is true and returns false otherwise. The second step in implementing the custom action is creating a tag library descriptor, which describes the tag library and its lone action. The preceding tag library descriptor declares the <core-jstl:ifBadColorCombination> action and its attributes. Notice that, in addition to the target attribute, the preceding tag library descriptor also declares var and scope attributes. Those attributes are declared because they are supported by the ConditionalTagSupport class, which means that the <core-jstl:ifBadColorCombination> action can also be used like this: <html> ... <body bgcolor='<c:out value="${param.bgcolor}"/>'> <%@ taglib uri='WEB-INF/app-tlds/app.tld' prefix='core-jstl'%> ... <core-jstl:ifBadColorCombination target='bean' var='badColorCombo' scope='page'/> <c:if test='${badColorCombo}'> <%-- ...store an error message in session scope and...--%> <c:set var='colorErrorMessage' scope='session'> Sorry, but you can't specify the same colors for the foreground and background because you wont be able to see anything at <c:out value='${sessionScope.lastPage}'/> </c:set> <%-- ...go back to set_colors.jsp --%> <jsp:forward page='set_colors.jsp'/> </c:if> ... </body> </html> In the preceding code fragment, the <core-jstl:ifBadColorCombination> action stores the boolean value returned from the tag handler's condition method in a page-scoped variable specified with the var and scope attributes. That scoped variable is subsequently used with a <c:if> action. The preceding code fragment is functionally equivalent to the code fragment that precedes it. You should realize that in order for your custom action to use the infrastructure provided by the ConditionalTagSupport class for the var and scope attributes, you must declare those attributes in your tag library descriptor. Because of that requirement, it's always a good idea to declare the var and scope attributes in your tag library descriptor unless you want to explicitly prevent their use, as shown in Listing 3.18. Listing 3.18 WEB-INF/core-jstl.tld<?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"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>Core JSTL Custom Actions</short-name> <display-name> Core JSTL Custom Actions for the Conditional Actions chapter </display-name> <description> A library containing a custom action that determines whether colors stored in a bean are incompatible </description> <tag> <name>ifBadColorCombination</name> <tag-class>tags.IfBadColorCombinationAction</tag-class> <body-content>JSP</body-content> <description> This action decides whether colors stored in a bean are incompatible. This action leverages JSTL functionality by extending the javax.servlet.jsp.jstl.core.ConditionalTagSupport class. </description> <attribute> <name>target</name> <required>true</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>var</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> <attribute> <name>scope</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag> </taglib> |