Home | Download | PDF | API | FAQ | Search | Feedback | History

> ## Programming Simple Tag Handlers

> The classes and interfaces used to implement simple tag handlers are contained in the `javax.servlet.jsp.tagext` package. Simple tag handlers implement the `SimpleTag` interface. Interfaces can be used to take an existing Java object and make it a tag handler. For most newly created handlers, you would use the `SimpleTagSupport` classes as a base class.

> The heart of a simple tag handler is a single method--`doTag`--which gets invoked when the end element of the tag is encountered. Note that the default implementation of the `doTag` method of `SimpleTagSupport` does nothing.

> A tag handler has access to an API that allows it to communicate with the JSP page. The entry point to the API is the JSP context object (`javax.servlet.jsp.JspContext)`. The `JspContext` object provides access to implicit objects. `PageContext` extends `JspContext` with servlet-specific behavior. Through these objects, a tag handler can retrieve all the other implicit objects (request, session, and application) that are accessible from a JSP page. If the tag is nested, a tag handler also has access to the handler (called the parent) that is associated with the enclosing tag.

> ### Including Tag Handlers in Web Applications

> Tag handlers can be made available to a web application in two basic ways. The classes implementing the tag handlers can be stored in an unpacked form in the `WEB-INF/classes/` subdirectory of the web application. Alternatively, if the library is distributed as a JAR, it is stored in the `WEB-INF/lib/` directory of the web application.

> ### How Is a Simple Tag Handler Invoked?

> The `SimpleTag` interface defines the basic protocol between a simple tag handler and a JSP page's servlet. The JSP page's servlet invokes the `setJspContext`, `setParent`, and attribute setting methods before calling `doStartTag`.

>     ATag t = new ATag();
>     t.setJSPContext(...);
>     t.setParent(...);
>     t.setAttribute1(value1);
>     t.setAttribute2(value2);
>     ...
>     t.setJspBody(new JspFragment(...))
>     t.doTag();

> The following sections describe the methods that you need to develop for each type of tag introduced in Types of Tags.

> ### Tag Handlers for Basic Tags

> The handler for a basic tag without a body must implement the `doTag` method of the `SimpleTag` interface. The `doTag` method is invoked when the end element of the tag is encountered.

> The basic tag discussed in the first section, `<tt:basic />`, would be implemented by the following tag handler:

>     public HelloWorldSimpleTag extends SimpleTagSupport {
>       public void doTag() throws JspException, IOException {
>         getJspContext().getOut().write("Hello, world.");
>       }
>     }

> ### Tag Handlers for Tags with Attributes

> #### Defining Attributes in a Tag Handler

> For each tag attribute, you must define a set method in the tag handler that conforms to the JavaBeans architecture conventions. For example, consider the tag handler for the JSTL `c:if` tag:

>     <c:if test="${Clear}">

> This tag handler contains the following method:

>     public void setTest(boolean test) {
>       this.test = test;
>     }

> As shown by the preceding example, the name of the attribute must match the name of the set method.

> #### Attribute Validation

> The documentation for a tag library should describe valid values for tag attributes. When a JSP page is translated, a web container will enforce any constraints contained in the TLD element for each attribute.

> The attributes passed to a tag can also be validated at translation time using the `validate` method of a class derived from `TagExtraInfo`. This class is also used to provide information about variables defined by the tag (see TagExtraInfo Class).

> The `validate` method is passed the attribute information in a `TagData` object, which contains attribute-value tuples for each of the tag's attributes. Because the validation occurs at translation time, the value of an attribute that is computed at request time will be set to `TagData.REQUEST_TIME_VALUE`.

> The tag `<tt:twa` `attr1="value1"/>` has the following TLD `attribute` element:

>     <attribute>
>       <name>attr1</name>
>       <required>true</required>
>       <rtexprvalue>true</rtexprvalue>
>     </attribute>

> This declaration indicates that the value of `attr1` can be determined at runtime.

> The following `validate` method checks whether the value of `attr1` is a valid Boolean value. Note that because the value of `attr1` can be computed at runtime, `validate` must check whether the tag user has chosen to provide a runtime value.

>     public class TwaTEI extends TagExtraInfo {
>       public ValidationMessage[] validate(TagData data) {
>         Object o = data.getAttribute("attr1");
>         if (o != null && o != TagData.REQUEST_TIME_VALUE) {
>           if (((String)o).toLowerCase().equals("true") ||
>             ((String)o).toLowerCase().equals("false") )
>             return null;
>           else
>             return new ValidationMessage(data.getId(),
>               "Invalid boolean value.");
>         }
>         else
>           return null;
>       }
>     }

> #### Setting Dynamic Attributes

> Simple tag handlers that support dynamic attributes must declare that they do so in the `tag` element of the TLD (see Declaring Tag Handlers). In addition, your tag handler must implement the `setDynamicAttribute` method of the `DynamicAttributes` interface. For each attribute specified in the tag invocation that does not have a corresponding `attribute` element in the TLD, the web container calls `setDynamicAttribute`, passing in the namespace of the attribute (or `null` if in the default namespace), the name of the attribute, and the value of the attribute. You must implement the `setDynamicAttribute` method to remember the names and values of the dynamic attributes so that they can be used later when `doTag` is executed. If the `setDynamicAttribute` method throws an exception, the `doTag` method is not invoked for the tag, and the exception must be treated in the same manner as if it came from an attribute setter method.

> The following implementation of `setDynamicAttribute` saves the attribute names and values in lists. Then, in the `doTag` method, the names and values are echoed to the response in an HTML list.

>     private ArrayList keys = new ArrayList();
>     private ArrayList values = new ArrayList();

>     public void setDynamicAttribute(String uri,
>       String localName, Object value ) throws JspException {
>       keys.add( localName );
>       values.add( value );
>     }

>     public void doTag() throws JspException, IOException {
>       JspWriter out = getJspContext().getOut();
>       for( int i = 0; i < keys.size(); i++ ) {
>           String key = (String)keys.get( i );
>           Object value = values.get( i );
>           out.println( "<li>" + key + " = " + value + "</li>" );
>       }
>     }

> #### Setting Deferred Value Attributes and Deferred Method Attributes

> For each tag attribute that accepts a deferred value expression or a deferred method expression, the tag handler must have a method to access the value of the attribute.

> The methods that access the value of a deferred value attribute method must accept a `ValueExpression` object. The methods that access the value of a deferred method attribute must accept a `MethodExpression` object. These methods take the form setX, where X is the name of the attribute.

> The following example shows a method that can be used to access the value of a deferred value attribute called `attributeName`:

>     private javax.el.ValueExpression attributeName = null;

>     public void setAttributeName(
>       javax.el.ValueExpression attributeName)
>     {
>       this.immediate = immediate;
>     }

> Deferred value attributes and deferred method attributes are primarily used by JavaServer Faces technology. See Getting the Attribute Values (page 441)for an example of creating a tag handler that processes these attributes for a JavaServer Faces application.

> If you have an attribute that is both dynamic and deferred (meaning that the tag attribute definition accepts a deferred expression and has `rtexprvalue` set to true) then the `setX` method that accesses this value must accept an `Object` instance and test if the `Object` instance is a deferred value expression, as shown in this pseudocode:

>     public void setAttr(Object obj) {
>       if (obj instance of ValueExpression) {
>         // this is a deferred expression
>       else {
>         // this is an rtexpression
>       }
>     }

> ### Tag Handlers for Tags with Bodies

> A simple tag handler for a tag with a body is implemented differently depending on whether or not the tag handler needs to manipulate the body. A tag handler manipulates the body when it reads or modifies the contents of the body.

> ##### Tag Handler Does Not Manipulate the Body

> If a tag handler needs simply to evaluate the body, it gets the body using the `getJspBody` method of `SimpleTag` and then evaluates the body using the `invoke` method.

> The following tag handler accepts a `test` parameter and evaluates the body of the tag if the test evaluates to `true`. The body of the tag is encapsulated in a JSP fragment. If the test is `true`, the handler retrieves the fragment using the `getJspBody` method. The `invoke` method directs all output to a supplied writer or, if the writer is `null`, to the `JspWriter` returned by the `getOut` method of the `JspContext` associated with the tag handler.

>     public class IfSimpleTag extends SimpleTagSupport {
>       private boolean test;
>       public void setTest(boolean test) {
>         this.test = test;
>       }
>       public void doTag() throws JspException, IOException {
>         if(test){
>           getJspBody().invoke(null);
>         }
>       }
>     }

> ##### Tag Handler Manipulates the Body

> If the tag handler needs to manipulate the body, the tag handler must capture the body in a `StringWriter`. The `invoke` method directs all output to a supplied writer. Then the modified body is written to the `JspWriter` returned by the `getOut` method of the `JspContext`. Thus, a tag that converts its body to uppercase could be written as follows:

>     public class SimpleWriter extends SimpleTagSupport {
>       public void doTag() throws JspException, IOException {
>         StringWriter sw = new StringWriter();
>         jspBody.invoke(sw);
>         jspContext().
>           getOut().println(sw.toString().toUpperCase());
>       }
>     }

> ### Tag Handlers for Tags That Define Variables

> Similar communication mechanisms exist for communication between JSP page and tag handlers as for JSP pages and tag files.

> To emulate `IN` parameters, use tag attributes. A tag attribute is communicated between the calling page and the tag handler when the tag is invoked. No further communication occurs between the calling page and the tag handler.

> To emulate `OUT` or nested parameters, use variables with availability `AT_BEGIN`, `AT_END`, or `NESTED`. The variable is not initialized by the calling page but instead is set by the tag handler.

> For `AT_BEGIN` availability, the variable is available in the calling page from the start tag until the scope of any enclosing tag. If there's no enclosing tag, then the variable is available to the end of the page. For `AT_END` availability, the variable is available in the calling page after the end tag until the scope of any enclosing tag. If there's no enclosing tag, then the variable is available to the end of the page. For nested parameters, the variable is available in the calling page between the start tag and the end tag.

> When you develop a tag handler you are responsible for creating and setting the object referenced by the variable into a context that is accessible from the page. You do this by using the JspContext().setAttribute(name, value) or `JspContext.setAttribute(name,` `value,` `scope)` method. You retrieve the page context using the `getJspContext` method of `SimpleTag`.

> Typically, an attribute passed to the custom tag specifies the name of the variable and the value of the variable is dependent on another attribute. For example, the `iterator` tag introduced in Chapter 4 retrieves the name of the variable from the `var` attribute and determines the value of the variable from a computation performed on the `group` attribute.

>     public void doTag() throws JspException, IOException {
>       if (iterator == null)
>         return;
>       while (iterator.hasNext()) {
>         getJspContext().setAttribute(var, iterator.next());
>         getJspBody().invoke(null);
>       }
>     }
>     public void setVar(String var) {
>       this.var = var;
>     }
>     public void setGroup(Collection group) {
>       this.group = group;
>       if(group.size() > 0)
>         iterator = group.iterator();
>     }

> The scope that a variable can have is summarized in Table 7-13. The scope constrains the accessibility and lifetime of the object.

> Table 7-13 Scope of Objects
> Name | Accessible From | Lifetime
> --- | --- | ---
> `page` | Current page | Until the response has been sent back to the user or the request is passed to a new page
> `request` | Current page and any included or forwarded pages | Until the response has been sent back to the user
> `session` | Current request and any subsequent request from the same browser (subject to session lifetime) | The life of the user's session
> `application` | Current and any future request in the same web application | The life of the application

> ##### TagExtraInfo Class

> In Declaring Tag Variables for Tag Handlers we discussed how to provide information about tag variables in the tag library descriptor. Here we describe another approach: defining a tag extra info class. You define a tag extra info class by extending the class `javax.servlet.jsp.tagext.TagExtraInfo`. A `TagExtraInfo` must implement the `getVariableInfo` method to return an array of `VariableInfo` objects containing the following information:

> - Variable name
> - Variable class
> - Whether the variable refers to a new object
> - The availability of the variable

> The web container passes a parameter of type `javax.servlet.jsp.tagext.TagData` to the `getVariableInfo` method, which contains attribute-value tuples for each of the tag's attributes. These attributes can be used to provide the `VariableInfo` object with an EL variable's name and class.

> The following example demonstrates how to provide information about the variable created by the `iterator` tag in a tag extra info class. Because the name (`var`) and class (`type`) of the variable are passed in as tag attributes, they can be retrieved using the `data.getAttributeString` method and can be used to fill in the `VariableInfo` constructor. To allow the variable `var` to be used only within the tag body, you set the scope of the object to `NESTED`.

>     package iterator;
>     public class IteratorTEI extends TagExtraInfo {
>       public VariableInfo[] getVariableInfo(TagData data) {
>         String type = data.getAttributeString("type");
>         if (type == null)
>           type = "java.lang.Object";
>         return new VariableInfo[] {
>           new VariableInfo(data.getAttributeString("var"),
>           type,
>           true,
>           VariableInfo.NESTED)
>         };
>       }
>     }

> The fully qualified name of the tag extra info class defined for an EL variable must be declared in the TLD in the `tei-class` subelement of the `tag` element. Thus, the `tei-class` element for `IteratorTei` would be as follows:

>     <tei-class>
>       iterator.IteratorTEI
>     </tei-class>

> ### Cooperating Tags

> Tags cooperate by sharing objects. JSP technology supports two styles of object sharing.

> The first style requires that a shared object be named and stored in the page context (one of the implicit objects accessible to JSP pages as well as tag handlers). To access objects created and named by another tag, a tag handler uses the `pageContext.getAttribute(name,` `scope)` method.

> In the second style of object sharing, an object created by the enclosing tag handler of a group of nested tags is available to all inner tag handlers. This form of object sharing has the advantage that it uses a private namespace for the objects, thus reducing the potential for naming conflicts.

> To access an object created by an enclosing tag, a tag handler must first obtain its enclosing tag by using the static method `SimpleTagSupport.findAncestorWithClass(from,` `class)` or the `SimpleTagSupport.getParent` method. The former method should be used when a specific nesting of tag handlers cannot be guaranteed. After the ancestor has been retrieved, a tag handler can access any statically or dynamically created objects. Statically created objects are members of the parent. Private objects can also be created dynamically. Such privately named objects would have to be managed by the tag handler; one approach would be to use a `Map` to store name-object pairs.

> The following example illustrates a tag handler that supports both the named approach and the private object approach to sharing objects. In the example, the handler for a query tag checks whether an attribute named `connectionId` has been set. If the `connectionId` attribute has been set, the handler retrieves the connection object from the page context. Otherwise, the tag handler first retrieves the tag handler for the enclosing tag and then retrieves the connection object from that handler.

>     public class QueryTag extends SimpleTagSupport {
>       public int doTag() throws JspException {
>         String cid = getConnectionId();
>         Connection connection;
>         if (cid != null) {
>         // there is a connection id, use it
>           connection =(Connection)pageContext.
>             getAttribute(cid);
>         } else {
>           ConnectionTag ancestorTag =
>             (ConnectionTag)findAncestorWithClass(this,
>               ConnectionTag.class);
>           if (ancestorTag == null) {
>             throw new JspTagException("A query without
>               a connection attribute must be nested
>               within a connection tag.");
>           }
>           connection = ancestorTag.getConnection();
>           ...
>         }
>       }
>     }

> The query tag implemented by this tag handler can be used in either of the following ways:

>     <tt:connection cid="con01" ... >
>       ...
>     </tt:connection>
>     <tt:query id="balances" connectionId="con01">
>       SELECT account, balance FROM acct_table
>         where customer_number = ?
>       <tt:param value="${requestScope.custNumber}" />
>     </tt:query>

>     <tt:connection ... >
>       <tt:query cid="balances">
>         SELECT account, balance FROM acct_table
>         where customer_number = ?
>         <tt:param value="${requestScope.custNumber}" />
>       </tt:query>
>     </tt:connection>

> The TLD for the tag handler uses the following declaration to indicate that the `connectionId` attribute is optional:

>     <tag>
>       ...
>       <attribute>
>         <name>connectionId</name>
>         <required>false</required>
>       </attribute>
>     </tag>

> ### Examples

> The simple tags described in this section demonstrate solutions to two recurring problems in developing JSP applications: minimizing the amount of Java programming in JSP pages and ensuring a common look and feel across applications. In doing so, they illustrate many of the styles of tags discussed in the first part of the chapter.

> #### An Iteration Tag

> Constructing page content that is dependent on dynamically generated data often requires the use of flow control scripting statements. By moving the flow control logic to tag handlers, flow control tags reduce the amount of scripting needed in JSP pages. Iteration is a very common flow control function and is easily handled by a custom tag.

> The discussion on using tag libraries in Chapter 4 introduced a tag library containing an `iterator` tag. The tag retrieves objects from a collection stored in a JavaBeans component and assigns them to an EL variable. The body of the tag retrieves information from the variable. As long as elements remain in the collection, the `iterator` tag causes the body to be reevaluated. The tag in this example is simplified to make it easy to demonstrate how to program a custom tag. web applications requiring such functionality should use the JSTL `forEach` tag, which is discussed in Iterator Tags (page 176).

> ##### JSP Page

> The `index.jsp` page invokes the `iterator` tag to iterate through a collection of department names. Each item in the collection is assigned to the `departmentName` variable.

>     <%@ taglib uri="/tlt" prefix="tlt" %>
>     <html>
>       <head>
>       <title>Departments</title>
>       </head>
>       <body bgcolor="white">
>       <jsp:useBean id="myorg" class="myorg.Organization"/>
>       <table border=2 cellspacing=3 cellpadding=3>
>         <tr>
>           <td><b>Departments</b></td>
>         </tr>
>       <tlt:iterator var="departmentName" type="java.lang.String"
>           group="${myorg.departmentNames}">
>         <tr>
>           <td><a href="list.jsp?deptName=${departmentName}">
>             ${departmentName}</a></td>
>         </tr>
>       </tlt:iterator>
>       </table>
>       </body>
>     </html>

> ##### Tag Handler

> The collection is set in the tag handler via the `group` attribute. The tag handler retrieves an element from the group and passes the element back to the page in the EL variable whose name is determined by the `var` attribute. The variable is accessed in the calling page using the JSP expression language. After the variable is set, the tag body is evaluated with the `invoke` method.

>     public void doTag() throws JspException, IOException {
>       if (iterator == null)
>         return;
>       while (iterator.hasNext()) {
>         getJspContext().setAttribute(var, iterator.next());
>         getJspBody().invoke(null);
>       }
>     }
>     public void setVar(String var) {
>       this.var = var;
>     }
>     public void setGroup(Collection group) {
>       this.group = group;
>       if(group.size() > 0)
>         iterator = group.iterator();
>     }

> #### A Template Tag Library

> A template provides a way to separate the common elements that are part of each screen from the elements that change with each screen of an application. Putting all the common elements together into one file makes it easier to maintain and enforce a consistent look and feel in all the screens. It also makes development of individual screens easier because the designer can focus on portions of a screen that are specific to that screen while the template takes care of the common portions.

> The template is a JSP page that has placeholders for the parts that need to change with each screen. Each of these placeholders is referred to as a parameter of the template. For example, a simple template might include a title parameter for the top of the generated screen and a body parameter to refer to a JSP page for the custom content of the screen.

> The template uses a set of nested tags--`definition`, `screen`, and `parameter`--to define a table of screen definitions and uses an `insert` tag to insert parameters from a screen definition into a specific application screen.

> ##### JSP Pages

> The template for the Duke's Bookstore example, `template.jsp`, is shown next. This page includes a JSP page that creates the screen definition and then uses the `insert` tag to insert parameters from the definition into the application screen.

>     <%@ taglib uri="/tutorial-template" prefix="tt" %>
>     <%@ page errorPage="/template/errorinclude.jsp" %>
>     <%@ include file="/template/screendefinitions.jsp" %>
>     <html>
>     <head>
>     <title>
>     <tt:insert definition="bookstore" parameter="title"/>
>     </title>
>     </head>
>     <body  bgcolor="#FFFFFF">
>       <tt:insert definition="bookstore" parameter="banner"/>
>     <tt:insert definition="bookstore" parameter="body"/>
>     <center><em>Copyright &copy; 2004 Sun Microsystems, Inc. </em></center>
>     </body>
>     </html>

> The `screendefinitions.jsp` page creates a definition for the screen specified by the request attribute javax.servlet.forward.servlet_path:

>     <tt:definition name="bookstore"
>     screen="${requestScope
>       ['javax.servlet.forward.servlet_path']}">
>       <tt:screen id="/bookstore">
>       <tt:parameter name="title" value="Duke's Bookstore"
>         direct="true"/>
>       <tt:parameter name="banner" value="/template/banner.jsp"
>         direct="false"/>
>       <tt:parameter name="body" value="/bookstore.jsp"
>         direct="false"/>
>       </tt:screen>
>       <tt:screen id="/bookcatalog">
>       <tt:parameter name="title" direct="true">
>           <jsp:attribute name="value" >
>             <fmt:message key="TitleBookCatalog"/>
>           </jsp:attribute>
>         </tt:parameter>
>         <tt:parameter name="banner" value="/template/banner.jsp"
>         direct="false"/>
>         <tt:parameter name="body" value="/bookcatalog.jsp"
>         direct="false"/>
>       </tt:screen>
>       ...
>     </tt:definition>

> The template is instantiated by the `Dispatcher` servlet. `Dispatcher` first gets the requested screen. `Dispatcher` performs business logic and updates model objects based on the requested screen. For example, if the requested screen is
> `/bookcatalog`, `Dispatcher` determines whether a book is being added to the cart based on the value of the Add request parameter. It sets the price of the book if it's on sale, and then adds the book to the cart. Finally, the servlet dispatches the request to `template.jsp`:

>     public class Dispatcher extends HttpServlet {
>       @Resource
>       UserTransaction utx;

>       public void doGet(HttpServletRequest request,
>         HttpServletResponse response) {
>         String bookId = null;
>         Book book = null;
>         String clear = null;
>         BookDBAO bookDBAO =
>           (BookDBAO)getServletContext().
>             getAttribute("bookDBAO");
>         HttpSession session = request.getSession();
>         String selectedScreen = request.getServletPath();
>         ShoppingCart cart = (ShoppingCart)session.
>           getAttribute("cart");
>         if (cart == null) {
>           cart = new ShoppingCart();
>           session.setAttribute("cart", cart);
>         }
>         if (selectedScreen.equals("/bookcatalog")) {
>           bookId = request.getParameter("Add");
>           if (!bookId.equals("")) {
>             try {
>               book = bookDBAO.getBook(bookId);
>               if ( book.getOnSale() ) {
>                 double sale = book.getPrice() * .85;
>                 Float salePrice = new Float(sale);
>                 book.setPrice(salePrice.floatValue());
>               }
>               cart.add(bookId, book);
>             } catch (BookNotFoundException ex) {
>               // not possible
>             }
>           }
>         } else if (selectedScreen.equals("/bookshowcart")) {
>           bookId =request.getParameter("Remove");
>           if (bookId != null) {
>             cart.remove(bookId);
>           }
>           clear = request.getParameter("Clear");
>           if (clear != null && clear.equals("clear")) {
>             cart.clear();
>           }
>         } else if (selectedScreen.equals("/bookreceipt")) {
>         // Update the inventory
>           try {
>             utx.begin();
>             bookDBAO.buyBooks(cart);
>             utx.commit();
>           } catch (Exception ex) {
>             try {
>               utx.rollback();
>               request.getRequestDispatcher(
>                 "/bookordererror.jsp").
>                 forward(request, response);
>             } catch(Exception e) {
>                 System.out.println(
>                   "Rollback failed: "+e.getMessage());
>                 e.printStackTrace();
>             }
>           }
>         }
>         try {
>           request.
>             getRequestDispatcher(
>             "/template/template.jsp").
>             forward(request, response);
>         } catch(Exception ex) {
>           ex.printStackTrace();
>         }
>       }

>       public void doPost(HttpServletRequest request,
>         HttpServletResponse response) {
>         request.setAttribute("selectedScreen",
>           request.getServletPath());
>         try {
>           request.
>             getRequestDispatcher(
>             "/template/template.jsp").
>             forward(request, response);
>         } catch(Exception ex) {
>           ex.printStackTrace();
>         }
>       }
>     }

> ##### Tag Handlers

> The template tag library contains four tag handlers--`DefinitionTag`, `ScreenTag`, `ParameterTag`, and `InsertTag`--that demonstrate the use of cooperating tags. `DefinitionTag`, `ScreenTag`, and `ParameterTag` constitute a set of nested tag handlers that share private objects. `DefinitionTag` creates a public object named `bookstore` that is used by `InsertTag`.

> In `doTag`, `DefinitionTag` creates a private object named `screens` that contains a hash table of screen definitions. A screen definition consists of a screen identifier and a set of parameters associated with the screen. These parameters are loaded when the body of the definition tag, which contains nested `screen` and `parameter` tags, is invoked. `DefinitionTag` creates a public object of class `Definition`, selects a screen definition from the `screens` object based on the URL passed in the request, and uses this screen definition to initialize a public `Definition` object.

>     public int doTag() {
>       try {
>         screens = new HashMap();
>         getJspBody().invoke(null);
>         Definition definition = new Definition();
>         PageContext context = (PageContext)getJspContext();
>         ArrayList params = (ArrayList) screens.get(screenId);
>         Iterator ir = null;
>         if (params != null) {
>           ir = params.iterator();
>           while (ir.hasNext())
>             definition.setParam((Parameter)ir.next());
>         // put the definition in the page context
>         context.setAttribute(definitionName, definition,
>           context.APPLICATION_SCOPE);
>         }
>       }

> The table of screen definitions is filled in by `ScreenTag` and `ParameterTag` from text provided as attributes to these tags. Table 7-14 shows the contents of the screen definitions hash table for the Duke's Bookstore application

> Table 7-14 Screen Definitions
> Screen ID | Title | Banner | Body
> --- | --- | --- | ---
> `/bookstore` | `Duke's Bookstore` | `/banner.jsp` | `/bookstore.jsp`
> `/bookcatalog` | `Book Catalog` | `/banner.jsp` | `/bookcatalog.jsp`
> `/bookdetails` | `Book Description` | `/banner.jsp` | `/bookdetails.jsp`
> `/bookshowcart` | `Shopping Cart` | `/banner.jsp` | `/bookshowcart.jsp`
> `/bookcashier` | `Cashier` | `/banner.jsp` | `/bookcashier.jsp`
> `/bookreceipt` | `Receipt` | `/banner.jsp` | `/bookreceipt.jsp`

> .

> If the URL passed in the request is /`bookstore`, the `Definition` object contains the items from the first row of Table 7-14 (see Table 7-15).

> Table 7-15 Definition Object Contents for URL /bookstore
> Title | Banner | Body
> --- | --- | ---
> `Duke's Bookstore` | `/banner.jsp` | `/bookstore.jsp`

> The parameters for the URL `/bookstore` are shown in Table 7-16. The parameters specify that the value of the `title` parameter, `Duke's Bookstore`, should be inserted directly into the output stream, but the values of `banner` and `body` should be included dynamically.

> Table 7-16 Parameters for the URL /bookstore
> Parameter Name | Parameter Value | isDirect
> --- | --- | ---
> `title` | `Duke's Bookstore` | `true`
> `banner` | `/banner.jsp` | `false`
> `body` | `/bookstore.jsp` | `false`

> `InsertTag` inserts parameters of the screen definition into the response. The `doTag` method retrieves the definition object from the page context and then inserts the parameter value. If the parameter is direct, it is directly inserted into the response; otherwise, the request is sent to the parameter, and the response is dynamically included into the overall response.

>     public void doTag() throws JspTagException {
>       Definition definition = null;
>       Parameter parameter = null;
>       boolean directInclude = false;
>       PageContext context = (PageContext)getJspContext();

>         // get the definition from the page context
>       definition = (Definition)context.getAttribute(
>         definitionName, context.APPLICATION_SCOPE);
>         // get the parameter
>       if (parameterName != null && definition != null)
>         parameter = (Parameter)
>           definition.getParam(parameterName);

>       if (parameter != null)
>         directInclude = parameter.isDirect();

>       try {
>         // if parameter is direct, print to out
>         if (directInclude && parameter  != null)
>           context.getOut().print(parameter.getValue());
>         // if parameter is indirect,
>             include results of dispatching to page
>         else {
>           if ((parameter != null) &&
>             (parameter.getValue() !=  null))
>           context.include(parameter.getValue());
>         }
>       } catch (Exception ex) {
>           throw new JspTagException(ex.getMessage());
>       }
>     }