Thursday, August 18, 2005

Extending the struts custom JSP taglib

In which I take my first plunge into the struts source and come out holding my own shiny new Jsp tag library

ApacheThe Kansas EMS license renewal application, a struts servlet has been on my desk for a few weeks now. I am about one third of the way finished with this app, and so far so good. Today, the hurdle of the day was to figure out how to get an input field for which the user had entered bad data to be highlighted. Like this. I already had a stylesheet for it, and it looked like I needed to do something like this in the html: [code lang="xml"]
[/code]

Fine, except I only wanted that class to show up for input fields with errors associated with them. That requires logic, and the only way I could figure out how to do this with stock struts was either through lots of nasty logic tags surrounding my div's or through tags inside of the div's. Both solutions were unacceptable. The right way to do this is to create a custom JSP tag.

Dustin Engelhaupt, a fellow I work with entered the picture at this point, and we both sat down to work on this same problem. My first hunch was that we could save ourselves lots of trouble If we could just extend the struts tag libraries to inclued an html:div tag. It turns out happily, that that is exactly what we did. Here is how. Download the struts source. Look in struts-1.2.7-src/src/share/org/apache/struts/taglib/html in there is all the Java Code you will need to do a custom div tag. We initially started by extending the BaseHandlerTag class. However, Dustin pointed out to me that we were going to need access to the property element of the struts tag, becuase that is what the errors are acutally associated with. So an error aware div tag really needs to extend BaseInputTag. We did that like this:[code lang="java"]
/*
* DivTag.java
* Dustin Engelhaupt and josh cronemeyer
*/
package org.j.jsp.tag;

import javax.servlet.jsp.JspException;
import org.apache.struts.taglib.TagUtils;
import org.apache.struts.taglib.html.BaseInputTag;

/**
*
* A Class that extends BaseInputTag
* So we can borrow the property functionality
*/
public class DivTag extends BaseInputTag {
private static final long serialVersionUID = 1L;

/**
* Render the beginning of this select tag.
*


* Support for indexed property since Struts 1.1
*
* @exception JspException
* if a JSP exception has occurred
*/
public int doStartTag() throws JspException {
StringBuffer results = new StringBuffer();

results.append(" results.append(prepareStyles());
TagUtils.getInstance().write(pageContext, results.toString());

return (EVAL_BODY_INCLUDE);
}

/**
* Render the end of this form.
*
* @exception JspException
* if a JSP exception has occurred
*/
public int doEndTag() throws JspException {

StringBuffer results = new StringBuffer();
results.append("

");
TagUtils.getInstance().write(pageContext, results.toString());
return (EVAL_PAGE);

}

/**
* Release any acquired resources.
*/
public void release() {
super.release();
}
}
[/code]
There is no magic there, we just implemented the required methods for extending that class and the only code we had to write was the word "div". Heck, all of the code in that class was borrowed from the class for a select element. After that you just need a tld. Here the only trick was to recognize that this tag would have something in the body. We did this:
[code lang="xml"]




0.1
1.1
jsp-html
http://66.249.24.98/jsp-html


div
org.j.jsp.tag.DivTag
JSP

property
false
false


style
false
false


styleClass
false
false


styleId
false
false


errorStyle
false
false


errorStyleClass
false
false


errorStyleId
false
false



[/code]
Here is an example of usage:
[code lang="xml"]
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>
<%@ taglib uri="http://66.249.24.98/jsp-html" prefix="jsp-html" %>




[/code]
With an error in the zip code field the jsp gets rendered like this:
[code lang="xml"]




[/code]

Done! Then we just packaged everything up, put it in our maven repository, and went around the office giving out high fives because we couldn't believe how easy it had been.

References:
http://jakarta.apache.org/tomcat/tomcat-5.0-doc/jspapi/
http://www.javaworld.com/javaworld/jw-08-2000/jw-0811-jsptags.html

1 comment:

Shlomo said...

Oops. I forgot a line of code in the DivTag class. in the doStartTag() method I need to add results.append("&gt;"); right after the line results.append(prepareStyles()); otherwise the tag won't always close off correctly.