j Custom Tags PDF

download j Custom Tags PDF

of 43

Transcript of j Custom Tags PDF

  • 8/7/2019 j Custom Tags PDF

    1/43

    Mastering custom JSP tagsSkill Level: Introductory

    Rick Hightower ([email protected])J2EE DeveloperArcMind

    01 Jun 2004

    Interested in adding custom tags to your JavaServer Pages (JSP) applications? Thistutorial will show you how to use these tags to write custom actions that are similar tothose built in to JSP technology, such as jsp:useBean, jsp:getProperty, and

    jsp:forward. Learn how you can extend the JSP syntax with your very own customactions that are specific to your domain's presentation logic.

    Section 1. About this tutorial

    Purpose of this tutorial

    Are you interested in adding custom tags to your JavaServer Pages (JSP)applications? This tutorial shows you how to use these tags to write custom actionsthat are similar to those built in to JSP technology, such as jsp:useBean,jsp:getProperty, and jsp:forward. Learn how you can extend the JSP syntaxwith your very own custom actions that are specific to your domain's presentationlogic.

    The ability to add custom tagsto JSP applications will allow you to focus your effortson a document-centric approach to development. You can keep Java code out ofyour JSP pages, which makes those pages easier to maintain. (I know fromexperience, when too much Java code is put into a JSP page it can be a codemaintenance nightmare.) This tutorial will get you developing custom tags in no time.And once you learn the benefits of JSP custom tag development, you may besurprised that programmers don't use them more often.

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 1 of 43

    mailto:[email protected]://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/mailto:[email protected]
  • 8/7/2019 j Custom Tags PDF

    2/43

    In this tutorial, I'll cover the basics of using custom tags. You'll learn how to usecustom tags to create reusable presentation components and avoid introducing Javascriptlets into your JSP pages.

    Over the course of this tutorial, you'll:

    Define a JSP custom tag architecture.

    Explain simple tags.

    Define nested tags.

    Explain tags with BodyContent.

    Add attributes to tags.

    Add scriptlet variables to tags.

    Implement control flow with custom tags. Use Struts to simplify tag development.

    Should I take this tutorial?

    If you find yourself adding a lot of Java scriptlets to your JSP applications, then thisis the tutorial for you. After reading this tutorial, you should have the information youneed to keep Java code out of your JSP pages.

    This tutorial assumes that you are familiar with the Java platform, JavaServer Pages

    (JSP) technology, the MVC pattern, the Reflection API, Model 2, and, optionally, theStruts framework. In addition, you'll need a good background in using custom taglibraries to get the most out of this tutorial. (See Resources for more information.)

    Section 2. Custom tag architecture: An introduction

    Tag handlers

    Before you can create a custom tag, you need to create a tag handler. A tag handleris a Java object that performs the action of a custom tag. When you use a customtag, you import a tag library-- that is, a list of tag/tag handler pairs. You import alibrary by declaring it in the Web application deployment descriptor, then importing itinto a JSP page using the taglib directive. If the JSP container encounters the use

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 2 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    3/43

    of a custom tag at translation time, it looks up the appropriate tag handler byinspecting the tag library descriptor(TLD) file. A TLD file is to custom tag handlerswhat a Web deployment descriptor is to servlets.

    At runtime, the servlet generated by the JSP page gets an instance of the tag

    handler class corresponding to the tag used in the page. The generated servletinitializes the tag handler with any attributes that you pass.

    The tag handler implements life cyclemethods. The generated servlet uses thesemethods to inform the tag handler that the custom tag's action should start, stop, orbe repeated. The generated servlet calls these life cycle methods to perform thefunctionality of the tag.

    Types of tags

    You can define two types of tags:

    javax.servlet.jsp.tagext.Tag

    javax.servlet.jsp.tagext.BodyTag

    Tags that operate on their body-- that is, on the material between the opening andclosing tags -- must implement the BodyTag interface. In this tutorial, we'll refer tothese tags as body tags. We'll call tags that do not operate on their body simpletags. Simple tags can implement the Tag interface, though they aren't required to doso. Keep in mind that a tag that does not operate on its body still hasa body;however, its tag handler cannot read that body.

    Section 3. Simple tags

    An example of a simple tag

    There are several custom tag libraries that ship with the Struts Framework (seeResources for a link to more information on Struts). One of the tags from theselibraries allows you to create a link that supports rewriting URLs and encoding therewritten link with the jsessionid.

    There's a problem, though: If you want to pass a list of request parameters (a querystring, for instance), you may have to create a Java scriptlet to do so. What a mess!The following listing (search_results.jsp) illustrates a JSP page that by necessity

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 3 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    4/43

    includes such a scriptlet. POOP.

    delete

    The search_results.jsp creates a hashmap and passes that map two properties. Inthe next few sections, we are going to create a custom tag that does this workwithout Java code. Our tag will define a hashmap as follows:

    delete

    This will allow us to create small maps easily.

    This example will demonstrate several key concepts, including working with nestedtags and defining scriptlet variables. First I'll explain how this simple tag works, then

    you'll build on these concepts in later sections, and learn how to write variations ofthis tag that work with their bodies and control execution flow.

    Steps to building a simple tag

    Let's create a tag that defines a HashMap scriptlet variable. In order to do this, youwill need to implement the tag handler interface (javax.servlet.jsp.tagext.Tag). Thus,

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 4 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    5/43

    this first tag we will create will be a simple tag.

    The tag will instantiate a map. A developer using the tag can specify the type of mapthat will be instantiated -- a HashMap, TreeMap, FastHashMap, or FastTreeMap.The FastHashMap and FastTreeMap are from the Jakarta Commons Collection

    library (see Resources for a link). The developer will also be able to specify thescope -- whether it be page, request, session, or application scope -- into which thetag should be placed.

    In order to build this simple tag, we will have to walk through the following steps:

    1. Create a tag handler class that implements the Tag interface(javax.servlet.jsp.tagext.Tag, to be exact).

    2. Create a TLD file.

    3. Create attributes in the tag handler Java class.

    4. Define attributes in the TLD file that correspond to the attributes defined inthe tag handler Java class.

    5. Declare scriptlet variables in the TLD file.

    6. Implement the doStartTag() method. In the tag handler class, set avalue into the scriptlet variable based on the attributes.

    If you're like me, you like to read the end of the book long before you get to it, so

    check the Appendix for the complete listing of our tag handler class to see how thisprocess is going to end up.

    Over the course of the next few sections, we will look at the implementation of theMapDefineTag and see how we can get to this point.

    Step 1: Create a tag handler that implements the Tag interface

    In order to write a tag handler, you must implement the Tag interface. As notedearlier, this interface is for simple tag handlers that do not manipulate their tag body.As the J2EE API docs (see Resources for a link) put it: The Tag interface definesthe basic protocol between a tag handler and JSP page implementation class. Itdefines the life cycle and the methods to be invoked at start and end tag.

    The tag handler interface has the following methods:

    Method Purpose

    int doStartTag() throws JspException Process the start tag

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 5 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    6/43

    int doEndTag() throws JspException Process the end tag

    Tag getParent()/void setParent(Tag t) Get/set the parent of the tag

    void setPageContext(PageContext pc) Setter method for the pageContext property

    void release() Release any resources that were obtained

    TagSupport

    Now, you don't have to implement the Tag interface directly; instead, yourmap-defining tag will subclass the TagSupport class. This class implements the Taginterface with sensible default methods, thus making it easier to develop customtags. (See Resources for a link to TagSupport's API documentation.) For example,the TagSupport class defines get/setParent() and setPageContext(), whichwould be nearly the same for all tag handlers The get/setParent() methodsallow tags to be nested. The TagSupport class also defines a pageContextinstance variable (protected PageContext pageContext) that can be used by

    subclasses; this variable is set by the setPageContext() method.

    By default, TagSupport implements doStartTag() so that it returns theSKIP_BODY constant, meaning that the tag body will not be evaluated. In addition,the doEndTag() method by default returns EVAL_PAGE, which means that the JSPruntime engine should evaluate the rest of the page. Lastly, TagSupport implementsrelease(), which sets the pageContext and parent to null.

    The TagSupport class also implements the IterationTag interface andimplements doAfterBody() so that it returns SKIP_BODY. I'll explain this in moredetail later when I cover tags that iterate (see Control flow with custom tags ).

    Without further ado, let's implement the Tag interface by subclassing TagSupport asfollows:

    ...

    import javax.servlet.jsp.tagext.TagSupport;

    ...

    public class MapDefineTag extends TagSupport {

    ...

    Now that we have defined the tag handler, we'll need to add the mapping from thehandler to the tag in the TLD file. We'll tackle this in the next sections. Later, we'll fillin the rest of the code for MapDefineTag.

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 6 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    7/43

    Step 2: Create a TLD file

    A TLD file fills the same role for custom tag handlers that a Web deploymentdescriptor fills for servlets. The TLD file lists mappings from tag names to tag

    handlers. Most of the data in the file is used at JSP page translation time. TLD filesare usually kept in the WEB-INF directory of a Web application and then declared inthe web.xml file. They usually end with a .tld extension.

    A TLD file has a preamble, where we identify the version of JSP technology and taglibraries that we are using. This preamble usually looks something like this:

    1.0

    1.2

    map

    Let's look at these tags in more detail:

    The root element the TLD file is taglib. A taglib describes a taglibrary-- that is, a list of tag/tag handler pairs.

    The tlib-version and short-name elements are required in thisexample, because we are using JSP version 1.2.

    The tlib-version element corresponds to the tag libraries version.

    The jsp-version corresponds to the version of JSP technology onwhich our tag library depends.

    Theshort-name

    element defines a simple name for the tag library thatcan be used by IDEs and other development tools.

    The taglib element contains many tag elements, one for each tag inthe tag library.

    Because we just created our class, we will go ahead and declare that class in theTLD file, as follows:

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 7 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    8/43

    ...

    mapDefine

    trivera.tags.map.MapDefineTag

    JSP

    ...

    The tag element is used to map custom tags to their custom tag handlers. The tagelement in the listing above maps the custom tag mapDefine to the handlertrivera.tags.map.MapDefineTag. Thus, whenever the translation engine runs

    across mapDefine, it will invoke trivera.tags.map.MapDefineTag.

    Now that we have defined the tag in the TLD, we'll next define some attributes forthat tag in the tag handler class.

    Step 3: Create attributes in the tag handler Java class

    We want to specify three attributes for the mapDefine tag, as follows:

    Attribute Description

    id The name of the new scriptlet variable.

    scope The scope where we will put the new scriptletvariable.

    type The type the new scriptlet variable will be(HashMap, FastHashMap, TreeMap, orFastTreeMap.) If type is set to hash, then aHashMap will be created. If type is set tofasthash, then a FastHashMap will becreated.

    When we use our tag in a JSP page, it will look like this:

    ...

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 8 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    9/43

    This tag will create a HashMap called editParams in session scope.

    In order to create attributes in a tag handler, you need to define correspondingJavaBean properties. Thus, every attribute will have a corresponding setter methodin the tag handler, as follows:

    public class MapDefineTag extends TagSupport {

    ...

    private String type = FASTTREE;

    private String id;

    private String scope;

    public void setType(String string) {

    type = string;

    }

    public void setId(String string) {

    id = string;

    }

    public void setScope(String string) {

    scope = string;

    }

    The translation engine will set the properties of our tag with either hardcodedconfiguration data or runtime expressions. We'll discuss this in more detail in Step 4:Define attributes in the TLD file.

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 9 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    10/43

    In Step 5: Implementing the doStartTag() method, we'll use these attributes in ourtag handler's doStartTag() method.

    Step 4: Define attributes in the TLD file

    Custom tag attributes are defined by declaring JavaBean properties, as we did in thelast section, and then declaring the attributes in the TLD file. The name of eachJavaBean property must match the name of the corresponding custom tag attribute.Every attribute defined in the TLD must match a JavaBean property, though you canhave JavaBean properties that don't match up with tag attributes.

    Here are the attribute declarations for MapDefineTag:

    mapDefine

    trivera.tags.map.MapDefineTag

    JSP

    ...

    id

    true

    false

    The id attribute

    scope

    false

    false

    The scope attribute

    type

    false

    false

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 10 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    11/43

    Specifies the type of map valid values are fasttree, fasthash, hash, tree

    The name element specifies the name of the attribute. The required elementspecifies whether the attribute is required (the default value is false). Thertexprvalue element indicates whether the attribute is hardcoded based on thevalue at translation time or if it allows runtime scriptlet expressions.

    Remember, the MapDefineTag class must define a JavaBean property for eachattribute described above; we took care of this in Step 3: Create attributes in the taghandler Java class.

    Step 5: Implementing the doStartTag() method

    The doStartTag() method is called when the tag starts -- from the developer'sperspective, this happens when the engine runs into . IfdoStartTag() returns SKIP_BODY, then the body tag will not be processed. If itreturns an EVAL_BODY_INCLUDE, then the body will be processed.

    The doStartTag() method of the MapDefine class does the following:

    Determines the type of map to create, based on the type attribute

    Determines where to put the new map object into scope, based on thescope attribute

    Determines the name of the scope into which the new map object shouldbe placed, based on the id attribute

    Let's look at this process in more detail. The MapDefine class checks to see if thetype

    attribute was set toFASTTREE

    ,HASH

    ,TREE

    , orFASTHASH

    . It then creates thecorresponding map, as follows:

    /* String constants for the different types of maps we support */

    public static final String FASTHASH = "FASTHASH";

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 11 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    12/43

    public static final String FASTTREE = "FASTTREE";

    public static final String HASH = "HASH";

    public static final String TREE = "TREE";

    /** The map we are going to create */

    private Map map = null;

    /** The member variable that holds the type attribute */

    private String type = FASTTREE;

    ...

    public int doStartTag() throws JspException {

    /** Based on the type attribute, determines which type of Map to create */

    if (type.equalsIgnoreCase(FASTTREE)) {

    map = new FastTreeMap();

    } else if (type.equalsIgnoreCase(HASH)) {

    map = new HashMap();

    } else if (type.equalsIgnoreCase(TREE)) {

    map = new TreeMap();

    } else if (type.equalsIgnoreCase(FASTHASH)) {

    map = new FastHashMap();

    }

    Next, the id and scope attributes are used to set the hashmap into a given scopewith a given name:

    private String id;

    private String scope;

    public int doStartTag() throws JspException {

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 12 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    13/43

    ...

    if (scope == null){

    pageContext.setAttribute(id, map);

    }else if("page".equalsIgnoreCase(scope)){

    pageContext.setAttribute(id, map);

    }else if("request".equalsIgnoreCase(scope)){

    pageContext.getRequest().setAttribute(id, map);

    }else if("session".equalsIgnoreCase(scope)){

    pageContext.getSession().setAttribute(id, map);

    }else if("application".equalsIgnoreCase(scope)){

    pageContext.getServletContext().setAttribute(id, map);

    }

    return EVAL_BODY_INCLUDE;

    }

    If the scope attribute is null, then the map will be put into page scope. Otherwise,

    the parameter will be put into the scope corresponding to the scope name passedvia the scope attribute.

    So far, we have a pretty simple tag that has three attributes: id, scope, and type.We've put the map into a scope with a given name. One thing we haven't done yet,however, is declare a scriptlet variable. In order to create to do so, we need to addone more entry to the TLD, and that's what we'll do in the next section.

    Step 6: Declare scriptlet variables

    To understand scriptlet variables, you have to understand the role of the TLD file.This file is largely a repository of metadata that tags use while a JSP page is beingtranslated into a servlet. The scriptlet variables become local variables in thegenerated servlet. In order for the JSP translation engine to know the types thatthese variables should be declared, you need to add entries like the following to theTLD file:

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 13 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    14/43

    id

    java.util.Map

    AT_BEGIN

    The above code snippet is placed in the TLD file after the body-content elementand before the attribute elements. Under the variable element, we havedeclared three sub-elements: name-from-attribute, variable-class, andscope. name-from-attribute specifies that the value of the id attribute is thename of the scriptlet variable that the translation engine will define.

    variable-class is the class type of the variable that the translation will define.scope specifies when the variable will be available: it can be nested inside of thebody of the tag (NESTED), after the end of the tag (AT_END), or from the beginning ofthe tag (AT_BEGIN). For scope, we opted for AT_BEGIN, which means that thevariable will be available from the start of the tag to the end of the current JSP page.

    Now you have a sense of how a simple custom tag is put together. In the nextsection, we'll look at our tag's life cycle methods to understand what happens as ourJSP page is actually run.

    Life cycle overview of a simple tag

    If you are like I was when I first started with tags, you probably find it a little difficultto map the translation engine life cycle on to what actually happens at runtime. Likeme, you've probably seen a lot of diagrams that try to clear these concepts up; thesediagrams probably look a lot like the one below.

    Diagram

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 14 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    15/43

    The diagrams did not make much sense to me, but the generated code did, so we'lltake a look at that code in this section. (The diagrams make sense to me now, but Ifound the code much more revealing; you might want to examine that diagram againwhen we're done with this section.)

    As you may recall, JSP pages are really servlets in disguise. Your JSP files are

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 15 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    16/43

  • 8/7/2019 j Custom Tags PDF

    17/43

    ...

    There are other ways to import tags. I find this method the most useful, as it allows

    you to assign a short name for the URI, and short names are easy to remember.Notice that the taglib is described in the context of its TLD file. Our map.tld file,located in the WEB-INF directory, looks like this:

    1.0

    1.2

    map

    mapDefine

    trivera.tags.map.MapDefineTag

    JSP

    ...

    When the JSP translator runs into the use of the custom tag mapDefine, it will lookup the TLD file based on the taglib directive and the TLD file specified in theweb.xml file. It then adds code like the following to the generated servlet:

    public class _testmapdefine__jsp extends ...JavaPage{

    public void _jspService(HttpServletRequest request,HttpServletResponse response) throws...{

    trivera.tags.map.MapDefineTag tag0 = null;

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 17 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    18/43

    java.util.Map employee = null;

    try {

    ...

    if (tag0 == null) {

    tag0 = new trivera.tags.map.MapDefineTag();

    tag0.setPageContext(pageContext);

    tag0.setParent((javax.servlet.jsp.tagext.Tag) null);

    tag0.setId("employee");

    }

    int includeBody = tag0.doStartTag();

    if (includeBody != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {

    employee = (java.util.Map)pageContext.findAttribute("employee");

    out.print("
    \n The employee is "+ (employee) +"
    \n");

    employee.put("firstName", "Kiley");

    employee.put("lastName", "Hightower");

    employee.put("age", new Integer(33));

    employee.put("salary", new Float(22.22));

    out.print("
    \n The employee is "+ (employee) +"
    \n");

    }

    employee = (java.util.Map)pageContext.findAttribute("employee");

    ...

    } catch (java.lang.Throwable _jsp_e) {

    pageContext.handlePageException(_jsp_e);

    ...

    }

    ...

    }

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 18 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    19/43

    The generated JSP servlet declares a local variable of typetrivera.tags.map.MapDefineTag called tag0. It then creates a instance of atag, sets the page context, sets the parent to null, and sets the ID to employee.Next, the generated servlet calls the doStartTag() method. It checks to see if thereturn type is set to Tag.SKIP_BODY. If it is, the container does not evaluate the

    body of the tag -- the if block, in this case. If it returns EVAL_BODY_INCLUDE, asour tag will, the container will process the body. You can use this technique toconditionally include the body of a tag -- that is, to control flow.

    Notice that the generated servlet has a local variable called employee, based onthe id attribute of the tag being set to employee. Thus, the translation enginedefines a local variable called employee at translationtime, not at runtime. This is aconcept that confuses a lot of novices.

    Section 4. Nested tags

    Understanding nested tags

    Our previous JSP page example used JSP scriptlets to add items to an employeemap. It would be nice if we could do this with another tag instead. Let's define anested tag called MapEntryTag that will get its parent tag by calling getParent()and casting it to a MapDefineTag.

    The MapDefineTag defines a getMap() method that returns the newly createdmap. The nested MapEntryTag in doEndTag() uses MapDefineTag's getMap()method to add a value to the map, as follows:

    public class MapEntryTag extends TagSupport {

    String type = "java.lang.String";

    String id;

    String value;

    String name;

    String property;

    String scope;

    public int doEndTag() throws JspException {

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 19 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    20/43

    /* Grab the MapDefineTag using the getParent

    method and cast it to a MapDefineTag.*/

    MapDefineTag mapDef = (MapDefineTag) this.getParent();

    Object objectValue = null;

    ...

    /* Instantiate a new String, Integer or Float based on the type. */

    if (type.equals("java.lang.String")) {

    objectValue = value;

    } else if (type.equals("java.lang.Integer")) {

    Integer intValue = Integer.valueOf(value);

    objectValue = intValue;

    } else if (type.equals("java.lang.Float")) {

    Float floatValue = Float.valueOf(value);

    objectValue = floatValue;

    }

    /* Put the new entry into the map. */

    mapDef.getMap().put(id,objectValue);

    return EVAL_PAGE;

    Based on the above code, and assuming that we add the necessary entries to theTLD file, we could use our tag like this:

    Test Map Define Entry

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 20 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    21/43

    The employee is set as

    The above listing would define an employee map with three entries apiece forfirstName, lastName, age, and salary, of types String, String, Integer,and Float, respectively.

    Using Reflection to extract bean properties as values

    Developers often use Java Reflection to improve custom tag code. On this section,we're going to rewrite MapEntryTag with Reflection so that it can use any beanproperty in any scope to define an entry into the map. For example, imagine that wehave a bean that looks like this:

    public class Test {

    String test="Jenny";

    public String getTest() {

    return test;

    }

    public void setTest(String string) {

    test = string;

    }

    }

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 21 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    22/43

    Our rewritten tag can use the bean property as an entry into the map, like this:

    Notice that the firstName entry is now defined with the bean's test property.

    To accomplish this, we need to add Reflection in our custom tag, like so (follow thecomments in the code to see how things were changed):

    public class MapEntryTag extends TagSupport {...

    /* All of these have corresponding getters and setter method */

    String type = "java.lang.String"; //Holder for the type attribute

    String id; //Holder for the id attribute

    String value; //Holder for value attribute

    String name; //Holder for name attribute

    String property; //Holder for property attribute

    String scope; //Holder for scope attribute

    public int doEndTag() throws JspException {

    MapDefineTag mapDef = (MapDefineTag) this.getParent();

    Object objectValue = null;

    /* Check to see if the value property is set,

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 22 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    23/43

    if it is then this is a simple entry */

    if (value !=null){

    if (type.equals("java.lang.String")) {

    objectValue = value;

    } else if (type.equals("java.lang.Integer")) {

    Integer intValue = Integer.valueOf(value);

    objectValue = intValue;

    } else if (type.equals("java.lang.Float")) {

    Float floatValue = Float.valueOf(value);

    objectValue = floatValue;

    }

    /* If it is not a simple entry,

    then use reflection to get the property from the bean */

    }else {

    Object bean =null;

    if (scope == null){

    bean = pageContext.findAttribute(name);

    }else if("page".equalsIgnoreCase(scope)){

    bean = pageContext.getAttribute(name);

    }else if("request".equalsIgnoreCase(scope)){

    bean = pageContext.getRequest().getAttribute(name);

    }else if("session".equalsIgnoreCase(scope)){

    bean = pageContext.getSession().getAttribute(name);

    }else if("application".equalsIgnoreCase(scope)){

    bean = pageContext.getServletContext().getAttribute(name);

    }

    /* If the property attribute is null,

    then just use the bean as the entry*/

    if (property==null){

    objectValue = bean;

    mapDef.getMap().put(id,bean);

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 23 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    24/43

    /* If the property attribute is set,

    then use reflection to read the property */

    }else {

    try{

    String propertyMethod = "get" +

    property.substring(0,1).toUpperCase() +

    property.substring(1, property.length());

    Method prop = bean.getClass()

    .getMethod(propertyMethod,new Class[]{});

    objectValue = prop.invoke(bean, new Object[]{});

    }catch(Exception e){

    throw new RuntimeException(e);

    }

    }

    }

    mapDef.getMap().put(id,objectValue);

    return EVAL_PAGE;

    }

    This seems like a lot of work just to achieve some functionality that a lot of tags needto do anyway. Fortunately for us, there is a library that makes this type ofdevelopment easier. See how this library -- Struts -- can help in the next section.

    Using Struts to simplify custom tag development

    An in-depth discussion of Struts is beyond the scope of this tutorial. (Check outResources for more information on this framework.) If you're already familiar with theframework, though, you can use your knowledge to aid your custom tagdevelopment.

    Instead of using Reflection to achieve the results we saw on the last section, you

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 24 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    25/43

    could use Struts's RequestUtils, as follows:

    public class MapEntryTag extends TagSupport {...

    private String type = "java.lang.String";

    ...

    public int doEndTag() throws JspException {

    MapDefineTag mapDef = (MapDefineTag) this.getParent();

    Object objectValue = null;

    if (value !=null){

    if (type.equals("java.lang.String")) {

    objectValue = value;

    } else if (type.equals("java.lang.Integer")) {

    Integer intValue = Integer.valueOf(value);

    objectValue = intValue;

    } else if (type.equals("java.lang.Float")) {

    Float floatValue = Float.valueOf(value);

    objectValue = floatValue;

    }

    }else {

    /** THIS USED TO BE 30 LINES OF CODE */

    objectValue = RequestUtils.lookup(pageContext, name, property, scope);

    }

    mapDef.getMap().put(id,objectValue);

    return EVAL_PAGE;

    }

    As you can see, the line objectValue =

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 25 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    26/43

    RequestUtils.lookup(pageContext, name, property, scope);

    replaces 30 lines of Reflection-based code! Struts ships with a lot of utilities thatmake custom tag development easier.

    Section 5. Body tags

    Introduction

    You can write tag handlers that manipulate their body content. Remember, a tag'sbody content is the data that appears in the JSP page between the opening andclosing tag of the custom tag. Tags that manipulate their bodies are called body

    tags. Body tag handlers are more complex to write than handlers for simple tags.

    Note: Remember, simple tags can have bodies too. The only difference is thatsimple tags can not read or manipulate their bodies.

    To write a body tag handler, you need to implement the BodyTag interface.BodyTag implements all the methods implemented by Tag (see Step 1: Create atag handler that implements the Tag interface for the details), along with two extramethods that deal with body content:

    Method Purpose

    void setBodyContent(BodyContent b) Setter method for the bodyContent property.

    void doInitBody() Prepares for evaluation of body. Called once pertag invocation, after a new BodyContent isobtained and set via setBodyContent(). Notinvoked if there is no body content requestedbecause doStartTag() has returnedEVAL_BODY_BUFFERED .

    Just as the Tag interface has the TagSupport class, the BodyTag interface has theBodyTagSupport class. Thus, your body tag handlers only need to override themethods that they will use. The BodyTagSupport class subclasses TagSupport

    and implements the BodyTag interface. This makes it easier to write body taghandlers. BodyTagSupport defines get/setBodyContent() and a protectedbodyContent instance variable.

    The BodyTagSupport class redefines the doStartTag() life cycle method toreturn EVAL_BODY_BUFFERED. By returning EVAL_BODY_BUFFERED,doStartTag() requests the creation of a new buffer -- that is, a BodyContent.

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 26 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    27/43

    BodyContent is a buffer that holds the runtime results of the evaluation of thebody. BodyContent subclasses JspWriter and acts as the implicit out for thebody of the tag. Thus, the JSP container creates an instance of BodyContent, andas it processes the body content of the tag, it writes to this instance instead to theroot JspWriter. Thus, when you use the implicit object out inside of a tag, you are

    really using a BodyContent object, not the JspWriter. (The JspWriter is theimplicit out for the page.)

    You can get the evaluated body as a String from BodyContent. BodyContentsare created at runtime by the container calling the pushBody() and popBody()methods of the pageContext for the page. (pushBody() is called only ifdoStartTag() returns EVAL_BODY_BUFFERED.) Thus, BodyContents are in anested structure of JspWriters and BodyContents. (The outer out can beanother BodyContent object, because a BodyContent is a JspWriter.) TheBodyContent is given to the body tag handler through the setBodyContent()method. The body tag handler is passed a BodyContent instance (via

    setBodyContent()) and can decide what to do with it. It may process it further,discard it, send it to the browser, etc.

    Enough background; let's look at the code! We'll look at a simple body tag examplein the next few sections.

    Example: The map tag

    The developer of a custom tag can decide what to do with the body of that tag. Forexample, you could write a tag that executes a SQL statement; the body of the tagwould be the SQL statement to be executed.

    Keeping with our hashmap theme, we will write a tag that parses a string that lookslike this:

    {

    firstName=Jennifer,

    lastName=Wirth,

    age=25

    }

    Essentially, our tag will read this kind of string and convert it to a Map(java.util.Map). We will call our new tag map. Here is an example of our new tagin action:

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 27 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    28/43

    Test Map JSP

    {

    firstName=Jennifer,

    lastName=Jones,

    age=25

    }


    The employee map is

    The code above creates a map called employee with three entries: firstName,lastName, and age.

    Implementing the tag handler

    MapParseTag is a tag handler for the map tag. It defines a map based on the stringpassed to the body. In the doAfterBody() method, MapParseTag grabs the bodycontent as a string using body.getString(). It then clears the body content usingbody.clearBody().

    public class MapParseTag extends BodyTagSupport {

    private String id;

    private Map map;

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 28 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    29/43

    public int doStartTag() throws JspException {

    map=new FastTreeMap();

    return EVAL_BODY_BUFFERED;

    }

    public int doAfterBody() throws JspException {

    /* Grab the body content */

    BodyContent body = this.getBodyContent();

    /* Get the body content as a String */

    String content = body.getString();

    /* Clear the body */

    body.clearBody();

    /* Parse the map */

    int start = content.indexOf("{");

    int end = content.lastIndexOf("}");

    content = content.substring(start+1, end);

    /* Parse the entries in the map */

    StringTokenizer token = new StringTokenizer(content,"=;, \t\r\n");

    while(token.hasMoreTokens()){

    String key = token.nextToken();

    String value = token.nextToken();

    map.put(key,value);

    }

    this.pageContext.setAttribute(id,map);

    return SKIP_BODY;

    }

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 29 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    30/43

    Simple enough! Now that we have covered tags that work on their bodies, let's covertags that implement execution flow in detail.

    Section 6. Control flow with custom tags

    Overview

    At times, you may want to conditionally invoke the body of a method based on someapplication-specific display logic. This can be done by returning a value fromdoStartTag(): SKIP_BODY to skip the body of the tag, or EVAL_BODY to evaluateit.

    Iteration tags need to implement the IterationTag interface. ThedoAfterBody() method is invoked by the container to determine whether toreevaluate the body or not. This method returns EVAL_BODY_AGAIN to signal thatthe container should keep evaluating the body. The doAfterBody() methodreturns SKIP_BODY to signify that the iteration action is over. Both the TagSupportclass and the BodyTagSupport class implement the IterationTag interface.

    Keeping with our map theme, in the next few sections we'll create a custom taghandler that iterates over a collection of maps and prints out their values.

    Control flow example

    Before we go into the implementation of the custom tag handler, let's take a look atour example tag in action. First, let's define two maps using the map tag from the lastexample:

    Test Map JSP

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 30 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    31/43

    {

    firstName=Jennifer,

    lastName=Wirth,

    age=33

    }

    {

    firstName=Kiley,

    lastName=McKeon,

    age=27

    }

    Next, let's create a collection called list and add the two maps (employee1 andemployee2) defined above to it.

    Now, here is how we would use a custom tag to iterate over our collection:

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 31 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    32/43

    First Name

    ${firstName}

    Last Name

    ${lastName}

    Age

    ${age}

    The map:printMaps tag iterates over the list collection. On each iteration, ituses its body, searching for keys into the map for the current iteration by searchingfor substrings that start with ${key}. It parses the key out of the ${} string and

    replaces it with the value of the that key from the map -- that is, withmap.get(key).

    Implementing the doStartTag() method

    The doStartTag() method grabs the collection out of scope, then grabs theiterator from the collection. If the iterator does not have any items in it(iter.hasNext()), the doStartTag() method returns SKIP_BODY, thusimplementing a logical if. In this case, that if boils down to, "If the collection isempty, skip the body evaluation." The iterator then grabs the first map out of the

    collection.

    public class MapPrintMapsTag extends BodyTagSupport {

    private String name;

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 32 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    33/43

    private Iterator iter;

    private Map map;

    private String scope;

    public int doStartTag() throws JspException {

    Collection collection = null;

    /* Grab the collection out of scope using the scope attribute. */

    if (scope == null){

    collection = (Collection) pageContext.findAttribute(name);

    }else if("page".equalsIgnoreCase(scope)){

    collection = (Collection) pageContext.getAttribute(name);

    }else if("request".equalsIgnoreCase(scope)){

    collection = (Collection) pageContext.getRequest().getAttribute(name);

    }else if("session".equalsIgnoreCase(scope)){

    collection = (Collection) pageContext.getSession().getAttribute(name);

    }else if("application".equalsIgnoreCase(scope)){

    collection = (Collection) pageContext.getServletContext().getAttribute(name);

    }

    /* Get the iterator from the collection. */

    iter = collection.iterator();

    /* If the collection is empty skip the body evaluation. */

    if (iter.hasNext()==false) return SKIP_BODY;

    /* Grab the first map out of the collection. */

    map = (Map)iter.next();

    return EVAL_BODY_BUFFERED;

    }

    Implementing the doAfterBody() method

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 33 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    34/43

    The doAfterBody() implements the iteration by returning SKIP_BODY if there areno items left to iterate. If there are items left, it will return EVAL_BODY_AGAIN. Aslong as doAfterBody() returns EVAL_BODY_AGAIN, the container will keepevaluating the body, as follows:

    public int doAfterBody() throws JspException {

    /** Process body */

    ...

    /** Write the processed buffer to the previous out */

    ...

    if (iter.hasNext() == false) {

    return SKIP_BODY;

    } else {

    map = (Map) iter.next();

    return EVAL_BODY_AGAIN;

    }

    }

    The doAfterBody() method grabs the body using getBodyContent(), thenuses the getString() method of the body content to get the string version of thecontent. It next clears the body content buffer, and uses a StringTokenizer tolook for strings that start with ${. It also creates a StringBuffer called buffer.As it iterates over the strings from the tokenizer, it appends them to the buffer.

    If the string from the tokenizer starts with ${, doAfterBody(), it then extracts the

    key from the string, and uses the key to look up the value in the map. It converts thevalue from the map into a string by calling the toString() method of the valueobject and appending the results to the buffer. The following listing illustrates howthis process works.

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 34 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    35/43

    /** Process body */

    /* Get and clear the body */

    BodyContent body = this.getBodyContent();

    String content = body.getString();

    body.clearBody();

    /* Process the body with a String tokenizer */

    StringTokenizer token = new StringTokenizer(content);

    /* Create an output buffer of the processed body */

    StringBuffer buffer = new StringBuffer(content.length() * 2);

    /* Iterate over the strings from the tokenizer

    and put them into the output buffer. */

    while (token.hasMoreTokens()) {

    String tok = token.nextToken();

    /* See if the String contains the special substring "${" */

    if (tok.startsWith("${")) {

    /* Parse the key out of the string */

    String key = tok.substring(2, tok.length() - 1);

    /* Use the key to look up the object in the map */

    Object value = (String) map.get(key);

    String svalue = tok;

    /* If the value is not null,

    get the value's string representation */

    if (value != null) {

    svalue = value.toString();

    }

    /* Add the string representation of the value

    to the output buffer */

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 35 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    36/43

    buffer.append(svalue + " ");

    } else {

    buffer.append(tok + " ");

    }

    }

    Once the doAfterBody() method constructs the output buffer, it outputs it to theprevious out, like so:

    try {

    this.getPreviousOut().print(buffer.toString());

    } catch (IOException e) {

    throw new JspException(e);

    }

    Thus, each iteration processes the body and outputs it to the previous out. If the

    previous out is the root JspWriter, then it will be written to the browser.

    Section 7. Wrap-up and resources

    Summary

    With the completion of this tutorial, you now have a deeper understanding of customtags. If you completed this tutorial, and you are new to custom tags, then you shouldbe ready to start using this powerful tool on your current project. You will no longeraccept mediocre Java scriptlets strewn about your JSP pages in an unmaintainableand unreusable manner. And even if you're not planning on creating your owncustom tags, this tutorial will help you understand custom tags that you mightencounter in code written by other developers.

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 36 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    37/43

    Section 8. Appendix

    Complete listing of tag handler class

    package trivera.tags.map;

    import java.util.HashMap;

    import java.util.Map;

    import java.util.TreeMap;

    import javax.servlet.jsp.JspException;

    import javax.servlet.jsp.tagext.TagSupport;

    import org.apache.commons.collections.FastHashMap;

    import org.apache.commons.collections.FastTreeMap;

    /**

    *

    *

    * Created to demonstrate the creation of custom tag handlers.

    * Created by Rick Hightower from Trivera Technologies.

    *

    * @jsp.tag name="mapDefine"

    * body-content="JSP"

    *

    * @jsp.variable name-from-attribute="id" class="java.util.Map"

    * scope="AT_BEGIN"

    */

    public class MapDefineTag extends TagSupport {

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 37 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    38/43

    public static final String FASTHASH = "FASTHASH";

    public static final String FASTTREE = "FASTTREE";

    public static final String HASH = "HASH";

    public static final String TREE = "TREE";

    private Map map = null;

    private String type = FASTTREE;

    private String id;

    private String scope;

    /* (non-Javadoc)

    * @see javax.servlet.jsp.tagext.Tag#doStartTag()

    */

    public int doStartTag() throws JspException {

    if (type.equalsIgnoreCase(FASTTREE)) {

    map = new FastTreeMap();

    } else if (type.equalsIgnoreCase(HASH)) {

    map = new HashMap();

    } else if (type.equalsIgnoreCase(TREE)) {

    map = new TreeMap();

    } else if (type.equalsIgnoreCase(FASTHASH)) {

    map = new FastHashMap();

    }

    if (scope == null){

    pageContext.setAttribute(id, map);

    }else if("page".equalsIgnoreCase(scope)){

    pageContext.setAttribute(id, map);

    }else if("request".equalsIgnoreCase(scope)){

    pageContext.getRequest().setAttribute(id, map);

    }else if("session".equalsIgnoreCase(scope)){

    pageContext.getSession().setAttribute(id, map);

    }else if("application".equalsIgnoreCase(scope)){

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 38 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    39/43

    pageContext.getServletContext().setAttribute(id, map);

    }

    return EVAL_BODY_INCLUDE;

    }

    /** Getter for property type.

    * @return Value of property type.

    * @jsp.attribute

    * required="false"

    * rtexprvalue="false"

    * description="Specifies the type of map

    * valid values are fasttree, fasthash, hash, tree"

    */

    public String getType() {

    return type;

    }

    /**

    * @param string

    */

    public void setType(String string) {

    type = string;

    }

    /** Getter for property id.

    * @return Value of property id.

    * @jsp.attribute required="true"

    * rtexprvalue="false"

    * description="The id attribute"

    */

    public String getId() {

    return id;

    }

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 39 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    40/43

    /**

    * @param string

    */

    public void setId(String string) {

    id = string;

    }

    public Map getMap(){

    return map;

    }

    public void release() {

    super.release();

    map = null;

    type = FASTTREE;

    }

    /** Getter for property scope.

    * @return Value of property scope.

    * @jsp.attribute required="false"

    * rtexprvalue="false"

    * description="The scope attribute"

    */

    public String getScope() {

    return scope;

    }

    /**

    * @param string

    */

    public void setScope(String string) {

    scope = string;

    }

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 40 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    41/43

    }

    ibm.com/developerWorks developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 41 of 43

    http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/
  • 8/7/2019 j Custom Tags PDF

    42/43

    Resources

    Learn

    Check out the J2EE API documentation for Tag and TagSupport.

    If you are looking for an application server to run these examples on, try IBMWebSphere Express.

    Need to get up to speed on JSP custom tags, servlets, filters and more? Try thisonline course from IBM: Servlet and JSP Development using WebSphereStudio V5.

    For more on this topic, read "Take control of your JSP pages with custom tags,"Jeff K. Wilson (developerWorks, January 2002).

    For more on taglibs, check out "JSP best practices: Intro to taglibs," BrettMcLaughlin (developerWorks, July 2003).

    For more on Struts, check out the Struts home page at the Apache Foundation.

    Get products and technologies

    You can find the Common Collection Library at the Commons Collections Webpage.

    Discuss

    Participate in the discussion forum for this content.

    About the author

    Rick Hightower

    Rick Hightower is a J2EE developer and consultant who enjoys workingwith J2EE, Ant, Hibernate, Struts, IBM's ETTK, and XDoclet. Rick is theformer CTO of Trivera Technologies, a global training, mentoring, andconsulting company focusing on enterprise development. He is aregular contributor to IBM developerWorks, and has written more than10 developerWorkstutorials on subjects ranging from EJB technologyto Web services to XDoclet. Rick just cofounded another company,

    called ArcMind, which specializes in agile methods, andStruts/JavaServer Faces development, consulting, and mentoring.While working at eBlox, Rick and the eBlox team used Struts longbefore the 1.0 release to build two frameworks and an ASP (applicationservice provider) for e-commerce sites. This framework currentlypowers more than 2,000 online storefronts. Rick recently finished abook called Professional Jakarta Struts. When not traveling around the

    developerWorks ibm.com/developerWorks

    Mastering custom JSP tags Trademarks Copyright IBM Corporation 2004. All rights reserved. Page 42 of 43

    http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/jsp/tagext/Tag.htmlhttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/jsp/tagext/TagSupport.htmlhttp://www-306.ibm.com/software/webservers/appserv/express/http://www-306.ibm.com/software/webservers/appserv/express/http://www-3.ibm.com/services/learning/MainServlet.wss?pageType=course_description&country=us&language=en&webLanguage=en&includeNotScheduled=y&courseCode=WF317http://www-3.ibm.com/services/learning/MainServlet.wss?pageType=course_description&country=us&language=en&webLanguage=en&includeNotScheduled=y&courseCode=WF317http://www.ibm.com/developerworks/java/library/j-taglib/http://www.ibm.com/developerworks/java/library/j-taglib/http://www.ibm.com/developerworks/java/library/j-jsp07233.htmlhttp://www.ibm.com/developerworks/java/library/j-jsp07233.htmlhttp://jakarta.apache.org/struts/http://jakarta.apache.org/commons/collections/http://jakarta.apache.org/commons/collections/http://www.ibm.com/developerworks/community/http://www.triveratech.com/http://www.arc-mind.com/http://www.ibm.com/developerworks/ibm/trademarks/http://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/legal/copytrade.shtmlhttp://www.ibm.com/developerworks/ibm/trademarks/http://www.arc-mind.com/http://www.triveratech.com/http://www.ibm.com/developerworks/community/http://jakarta.apache.org/commons/collections/http://jakarta.apache.org/commons/collections/http://jakarta.apache.org/struts/http://www.ibm.com/developerworks/java/library/j-jsp07233.htmlhttp://www.ibm.com/developerworks/java/library/j-taglib/http://www-3.ibm.com/services/learning/MainServlet.wss?pageType=course_description&country=us&language=en&webLanguage=en&includeNotScheduled=y&courseCode=WF317http://www-3.ibm.com/services/learning/MainServlet.wss?pageType=course_description&country=us&language=en&webLanguage=en&includeNotScheduled=y&courseCode=WF317http://www-306.ibm.com/software/webservers/appserv/express/http://www-306.ibm.com/software/webservers/appserv/express/http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/jsp/tagext/TagSupport.htmlhttp://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/jsp/tagext/Tag.html
  • 8/7/2019 j Custom Tags PDF

    43/43

    country consulting on J2EE and Struts projects or speaking atconferences about J2EE and extreme programming, Rick enjoysdrinking coffee at an all-night coffee shop, writing about Struts, J2EE,and other topics, and writing about himself in the third person.

    ibm.com/developerWorks developerWorks