A JSP custom tag example: random splash images 

Joined:
08/13/2009
Posts:
164

April 01, 2010 22:24:58    Last update: April 02, 2010 02:49:38
In this note I'll show you how to create and package a JSP custom tag.

The purpose of this tag is to display a random splash image for a home page, among a set of images. We should be able to add or delete candidate splash images from the WAR archive without the need to change the JSP. This is the intended use of the tag:

<%@ taglib uri="http://custom.tag.com/demo" prefix="cust"%>
<cust:splash file="/images/splash*.png" alt="splash"/>


In the above example you provide a set of images named splash*.png (e.g., splash1.png, spalsh2.png, ...), and the tag will pick a random one to display when the JSP is rendered.

Let's get started. I'll use Maven for this purpose.
  1. Create the standard Maven directory structure
    ./pom.xml
    ./src
    ./src/main
    ./src/main/java
    ./src/main/java/tagdemo
    ./src/main/java/tagdemo/SplashTag.java
    ./src/main/resources
    ./src/main/resources/META-INF
    ./src/main/resources/META-INF/splashtag.tld
    

  2. pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>tag-demo</groupId>
        <artifactId>splash</artifactId>
        <packaging>jar</packaging>
        <version>1.0</version>
        <name>JSP Custom tag demo</name>
        <url>http://custom.tag.com</url>
    
        <repositories>
    	<repository>
    	    <id>maven2-repository.dev.java.net</id>
    	    <name>Java.net Repository for Maven</name>
    	    <url>http://download.java.net/maven/2/</url>
    	    <layout>default</layout>
    	</repository>
        </repositories>
    
        <dependencies>
    	<dependency>
    	    <groupId>javax</groupId>
    	    <artifactId>javaee-api</artifactId>
    	    <version>6.0-SNAPSHOT</version>
    	    <scope>provided</scope>
    	</dependency>
        </dependencies>
    </project>
    

  3. SplashTag.java
    package tagdemo;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Random;
    import java.util.Set;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.JspWriter;
    import javax.servlet.jsp.PageContext;
    import javax.servlet.jsp.tagext.TagSupport;
    
    public class SplashTag extends TagSupport {
        private String align;
        private String alt;
        private String border;
        private String height;
        private String onclick;
        private String ondblclick;
        private String file;
        private String style;
        private String styleClass;
        private String id;
        private String title;
        private String width;
    
        public void setAlign(String align) {
            this.align = align;
        }
    
        public String getAlign() {
            return align;
        }
    
        public void setAlt(String alt) {
            this.alt = alt;
        }
    
        public String getAlt() {
            return alt;
        }
    
        public void setBorder(String border) {
            this.border = border;
        }
    
        public String getBorder() {
            return border;
        }
    
        public void setHeight(String height) {
            this.height = height;
        }
    
        public String getHeight() {
            return height;
        }
    
        public void setOnclick(String onclick) {
            this.onclick = onclick;
        }
    
        public String getOnclick() {
            return onclick;
        }
    
        public void setOndblclick(String ondblclick) {
            this.ondblclick = ondblclick;
        }
    
        public String getOndblclick() {
            return ondblclick;
        }
    
        public void setFile(String file) {
            this.file = file;
        }
    
        public String getFile() {
            return file;
        }
    
        public void setStyle(String style) {
            this.style = style;
        }
    
        public String getStyle() {
            return style;
        }
    
        public void setStyleClass(String styleClass) {
            this.styleClass = styleClass;
        }
    
        public String getStyleClass() {
            return styleClass;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getId() {
            return id;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public String getTitle() {
            return title;
        }
    
        public void setWidth(String width) {
            this.width = width;
        }
    
        public String getWidth() {
            return width;
        }
    
        // called at start of tag
        public int doStartTag() throws JspException {
            String file = getFile();
            if ((file == null) || (file.trim().length() == 0)) {
                throw new JspException("file attribute must be specified!");
            }
    
            StringBuffer sb = new StringBuffer("<img");
            HttpServletResponse resp = (HttpServletResponse) pageContext.getResponse();
            prepareAttribute(sb, "src", resp.encodeURL(getSrc()));
            prepareAttribute(sb, "align", getAlign());
            prepareAttribute(sb, "border", getBorder());
            prepareAttribute(sb, "width", getWidth());
            prepareAttribute(sb, "height", getHeight());
            prepareAttribute(sb, "onclick", getOnclick());
            prepareAttribute(sb, "ondblclick", getOndblclick());
            prepareStyles(sb);
            sb.append("/>");
    
            JspWriter out = pageContext.getOut();
            try {
                out.print(sb.toString());
            }
            catch (java.io.IOException e) {
                throw new JspException("IOException while writing to client: " + e);
            }
    
            return SKIP_BODY;
        }
    
        // called at end of tag
        public int doEndTag() {
            return EVAL_PAGE;
        }
    
        private String getSrc() {
            HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
    
            String file = getFile();
            String contextPath = request.getContextPath();
    
            int widx = file.indexOf('*');
            int pidx = file.lastIndexOf('/');
            if ((widx < 0) || (pidx > widx)) {
                return file.startsWith("/") ? contextPath + file : file;
            }
    
            String path;
            if (file.startsWith("/")) {
                path = contextPath + file.substring(0, pidx + 1);
            }
            else { // relative path
                String uriPath = request.getRequestURI();
                int idx = uriPath.lastIndexOf('/');
                if (idx >= 0) {
                    uriPath = uriPath.substring(0, idx + 1);
                }
                else {
                    uriPath = "/";
                }
    
                if (pidx >= 0) {
                    path = uriPath + file.substring(0, pidx + 1);
                }
                else {
                    path = uriPath;
                }
            }
    
            String pattern = file.replaceAll("\\.", "\\\\.").replaceAll("\\*", ".*");
    
            ServletContext ctx = request.getSession().getServletContext();
            path = path.substring(contextPath.length());
            Set rcs = ctx.getResourcePaths(path);
            List matchingFiles = new ArrayList();
            if (rcs != null) {
                for (Iterator i = rcs.iterator(); i.hasNext(); ) {
                    String f = (String) i.next();
                    if (f.matches(pattern)) {
                        matchingFiles.add(f);
                    }
                }
            }
    
            if (matchingFiles.size() > 0) {
                return contextPath + matchingFiles.get(new Random().nextInt(matchingFiles.size()));
            }
            else {
                return null;
            }
        }
    
        private void prepareStyles(StringBuffer sb) {
            prepareAttribute(sb, "id", getId());
            prepareAttribute(sb, "style", getStyle());
            prepareAttribute(sb, "class", getStyleClass());
            prepareAttribute(sb, "title", getTitle());
            prepareAttribute(sb, "alt", getAlt());
        }
    
        private void prepareAttribute(StringBuffer sb, String name, String value) {
            if ((value != null) && (value.trim().length() > 0)) {
                sb.append(" ");
                sb.append(name);
                sb.append("=\"");
                sb.append(value);
                sb.append("\"");
            }
        }
    }
    

  4. Create the TLD (splashtag.tld)
    <?xml version="1.0" encoding="UTF-8"?>
    
    <!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>cust</short-name>
        <uri>http://custom.tag.com/demo</uri>
        <display-name>Custom Tag Example</display-name>
        <description>Custom tag examples</description>
    
        <tag>
    	<name>splash</name>
            <tagclass>
                tagdemo.SplashTag
            </tagclass>
            <bodycontent>empty</bodycontent>
            <description>
                <![CDATA[
                <p><strong>Render a splash image.</strong></p>
                This tag supports the normal HTML attributes. The file attribute is used to
                locate the splach image under the current servlet context. If you specify a
                wildcard in the page attribute, such as "splash*.jpg", a random image among
                all images matching the specified name will be displayed.
                ]]>
            </description>
            <attribute>
                <name>align</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>Where the image is aligned to.  Can be one of the
                      following attributes:</p>
                      <ul>
    		    <li>left - left justify, wrapping text on right</li>
                        <li>right -right justify, wrapping test on left</li>
                        <li>top - aligns the image with the top of the text on
                            the same row</li>
                        <li>middle - aligns the image's vertical center with the
                            text base line</li>
                        <li>bottom - aligns the image with the bottom of the
                            text's base line</li>
                        <li>texttop - aligns the image's top with that of the
                            text font on the same line</li>
                        <li>absmiddle - aligns the image's vertical center with the
                            absolute center of the text</li>
                        <li>absbottom - aligns the image with the absolute bottom
                            of the text font on the same row</li>
                      </ul>
                      ]]>
                </description>
            </attribute>
            <attribute>
                <name>alt</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>And alternative text to be displayed in browsers that
                         don't support graphics.  Also used often as type of
                         context help over images.</p>
                    ]]>
                </description>
            </attribute>
            <attribute>
                <name>border</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>The width of the border surrounding the image.</p>
                      ]]>
                </description>
            </attribute>
            <attribute>
                <name>height</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>The height of the image being displayed.  This parameter
                         is very nice to specify (along with <code>width</code>)
                         to help the browser render the page faster.</p>
                      ]]>
                </description>
            </attribute>
            <attribute>
                <name>onclick</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                    JavaScript event handler executed when this element receives a
                    mouse click.
                    ]]>
                </description>
            </attribute>
            <attribute>
                <name>ondblclick</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                    JavaScript event handler executed when this element receives a
                    mouse double click.
                    ]]>
                </description>
            </attribute>
            <attribute>
                <name>file</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      The servlet context relative path.
                    ]]>
                </description>
            </attribute>
            <attribute>
                <name>style</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>CSS styles to be applied to this element.</p>
                    ]]>
                </description>
            </attribute>
            <attribute>
                <name>styleClass</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      CSS stylesheet class to be applied to this HTML element
                      (renders a "class" attribute).
                      ]]>
                </description>
            </attribute>
            <attribute>
                <name>id</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                    Identifier to be assigned to this HTML element (renders
                    an "id" attribute).
                ]]>
                </description>
            </attribute>
            <attribute>
                <name>title</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>The advisory title for this element.</p>
                      ]]>
                </description>
            </attribute>
            <attribute>
                <name>width</name>
                <required>false</required>
                <rtexprvalue>true</rtexprvalue>
                <description>
                    <![CDATA[
                      <p>The width of the image being displayed.  This parameter
                         is very nice to specify (along with <code>height</code>)
                         to help the browser render the page faster.</p>
                      ]]>
                </description>
            </attribute>
        </tag>
    </taglib>
    

  5. Package and install to local repository
    mvn install
    

  6. Use it in your web project by declaring as a dependency (pom.xml)
    <dependencies>
    	<dependency>
    	    <groupId>tag-demo</groupId>
    	    <artifactId>splash</artifactId>
    	    <version>1.0</version>
    	    <scope>runtime</scope>
    	</dependency>
    </dependencies>
    


Share |
| Comment  | Tags