805 OCPJP 6 Questions 788 SCJP 5 questions 650 OCPJWCD 5 questions 600 OCAJP 7 questions 610 OCPJP 7 questions 510 Upgrade to OCPJP 7 questions 900 Java J2EE Qns

Tutorials

SCWCD : Building a Custom Tag Library

Describe the semantics of the "Classic" custom tag event model when each event method (doStartTag, doAfterBody, and doEndTag) is executed, and explain what the return value for each event method means; and write a tag handler class.

The classes and interfaces used to implement classic tag handlers are contained in the javax.servlet.jsp.tagext package. Classic tag handlers implement either the Tag, IterationTag, or BodyTag interface. Interfaces can be used to take an existing Java object and make it a tag handler. For newly created classic tag handlers, you can use the TagSupport and BodyTagSupport classes as base classes. These classes and interfaces are contained in the javax.servlet.jsp.tagext package.

Tag handler methods defined by the Tag and BodyTag interfaces are called by the JSP page's servlet at various points during the evaluation of the tag. When the start element of a custom tag is encountered, the JSP page's servlet calls methods to initialize the appropriate handler and then invokes the handler's doStartTag method. When the end element of a custom tag is encountered, the handler's doEndTag method is invoked for all but simple tags. Additional methods are invoked in between when a tag handler needs to manipulate the body of the tag.

Table 10.1. Tag Handler Methods

Tag TypeInterfaceMethods
BasicTagdoStartTag, doEndTag
AttributesTagdoStartTag, doEndTag, setAttribute1, ..., setAttributeN , release
BodyTagdoStartTag, doEndTag, release
Body, iterative evaluationIterationTagdoStartTag, doAfterBody, doEndTag, release
Body, manipulationBodyTagdoStartTag, doInitBody, doAfterBody, doEndTag, release

A tag handler has access to an API that allows it to communicate with the JSP page. The entry points to the API are two objects: the JSP context (javax.servlet.jsp.JspContext) for simple tag handlers and the page context (javax.servlet.jsp.PageContext) for classic tag handlers. JspContext provides access to implicit objects. PageContext extends JspContext with HTTP-specific behavior. A tag handler can retrieve all the other implicit objects (request, session, and application) accessible from a JSP page through these objects. In addition, implicit objects can have named attributes associated with them. Such attributes are accessed using [set|get]Attribute methods.

The Tag interface defines the basic protocol between a tag handler and a JSP page's servlet. It defines the life cycle and the methods to be invoked when the start and end tags are encountered.

The JSP page's servlet invokes the setPageContext, setParent, and attribute setting methods before calling doStartTag. The JSP page's servlet also guarantees that release will be invoked on the tag handler before the end of the page.

Here is a typical tag handler method invocation sequence:

ATag t = new ATag();
t.setPageContext(...);
t.setParent(...);
t.setAttribute1(value1);
t.setAttribute2(value2);
t.doStartTag();
t.doEndTag();
t.release(); 
					

The BodyTag interface extends IterationTag by defining additional methods that let a tag handler manipulate the content of evaluating its body:

  • setBodyContent - Creates body content and adds to the tag handler

  • doInitBody - Called before evaluation of the tag body. This method will not be invoked for empty tags or for non-empty tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE.

A typical invocation sequence is:

t.doStartTag();
out = pageContext.pushBody();
t.setBodyContent(out);
// perform any initialization needed after body content is set
t.doInitBody();
t.doAfterBody();
// while IterationTag.doAfterBody() returns EVAL_BODY_AGAIN we 
// iterate body evaluation
...
t.doAfterBody();
t.doEndTag();
out = pageContext.popBody();
t.release();

					

If the tag handler does not need to manipulate the body, the tag handler should implement the Tag interface. If the tag handler implements the Tag interface and the body of the tag needs to be evaluated, the doStartTag method needs to return Tag.EVAL_BODY_INCLUDE; otherwise it should return Tag.SKIP_BODY.

If a tag handler needs to iteratively evaluate the body, it should implement the IterationTag interface. The tag handler should return IterationTag.EVAL_BODY_AGAIN from IterationTag.doAfterBody method if it determines that the body needs to be evaluated again.

If the tag handler needs to manipulate the body, the tag handler must implement BodyTag (or be derived from BodyTagSupport).

When a tag handler implements the BodyTag interface, it must implement the doInitBody and the IterationTag.doAfterBody methods. These methods manipulate body content passed to the tag handler by the JSP page's servlet.

Body content supports several methods to read and write its contents. A tag handler can use the body content's getString or getReader methods to extract information from the body, and the writeOut(out) method to write the body contents to an out stream. The writer supplied to the writeOut method is obtained using the tag handler's getPreviousOut method. This method is used to ensure that a tag handler's results are available to an enclosing tag handler.

If the body of the tag needs to be evaluated, the doStartTag method needs to return BodyTag.EVAL_BODY_BUFFERED; otherwise, it should return Tag.SKIP_BODY.

The doInitBody method is called after the body content is set but before it is evaluated. You generally use this method to perform any initialization that depends on the body content.

The IterationTag.doAfterBody method is called AFTER the body content is evaluated. IterationTag.doAfterBody must return an indication of whether to continue evaluating the body. Thus, if the body should be evaluated again, as would be the case if you were implementing an iteration tag, IterationTag.doAfterBody should return IterationTag.EVAL_BODY_AGAIN; otherwise, IterationTag.doAfterBody should return Tag.SKIP_BODY.

The following example reads the content of the body (which contains a SQL query) and passes it to an object that executes the query. Since the body does not need to be reevaluated, IterationTag.doAfterBody returns Tag.SKIP_BODY:

public class QueryTag extends BodyTagSupport {
	public int doAfterBody() throws JspTagException {
		BodyContent bc = getBodyContent();
		// get the bc as string
		String query = bc.getString();
		// clean up
		bc.clearBody();
		try {
			Statement stmt = connection.createStatement();
			result = stmt.executeQuery(query);
		} catch (SQLException e) {
			throw new JspTagException("QueryTag: " +
				e.getMessage());
		}
		return SKIP_BODY;
	}
} 
					

When you extend TagSupport, the doStartTag and doEndTag methods use the following return values (defined as constants):

  • doStartTag returns one of the following values:

    • Tag.EVAL_BODY_INCLUDE - Allow body text (including JSP code) between the start and end tags. Note, however, that body text is not available to the doEndTag method.

    • Tag.SKIP_BODY - Ignore body text. Any text between the start and end tags is not evaluated or displayed.

  • doEndTag returns one of the following values:

    • Tag.EVAL_PAGE - Continue evaluating the page.

    • Tag.SKIP_PAGE - Ignore the remainder of the page.

The following tag handler outputs messages from the doStartTag and doEndTag methods. These messages form the contents of the tag in the JSP page:

import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.io.IOException;

public class SimpleTag extends TagSupport {

	/**
	* Executes when the tag is started.
	*/
	public int doStartTag() throws JspException {
		try {
			pageContext.getOut().print("Hello from doStartTag()");
			// Allow text in the body of the tag.
			return EVAL_BODY_INCLUDE;
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		}
	}

	/**
	* Executes with the end tag.
	*/
	public int doEndTag() throws JspException {
		try {
			pageContext.getOut().print("Hello from doEndTag()");
			// Continue evaluating the page.
			return EVAL_PAGE;
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		}
	}
}
					

If your custom tag must modify body content, extend the BodyTagSupport class. It implements BodyTag. Provides the doInitBody and IterationTag.doAfterBody methods. Extend this class when your tag handler must modify body content. The doStartTag method can return BodyTag.EVAL_BODY_BUFFERED in addition to Tag.EVAL_BODY_INCLUDE and Tag.SKIP_BODY.

The BodyContent object is a subclass of JspWriter. JspWriter is the writer used internally for the JSP out variable. The BodyContent object is available to doInitBody, IterationTag.doAfterBody, and doEndTag through the bodyContent variable. You can integrate this object's contents with the original JspWriter in the doEndTag method. The BodyContent object contains methods that you use to write output as well as methods to read, clear, and retrieve its contents. For example, you can use bodyContent.getString() to retrieve the writer's contents, optionally modifying the contents before integrating them with the original JspWriter.

The servlet container invokes the doInitBody method if the doStartTag method returns BodyTag.EVAL_BODY_BUFFERED. Use this method to initialize the body content, if necessary. Then the tag handler processes the body, and invokes the IterationTag.doAfterBody method.

The IterationTag.doAfterBody method returns Tag.SKIP_BODY or IterationTag.EVAL_BODY_AGAIN. If it returns IterationTag.EVAL_BODY_AGAIN, the servlet container loops back and re-executes the body. This lets you loop over repetitive data, such as enumerations and database result sets.

The following example shows using the doInitBody and IterationTag.doAfterBody methods. It also shows how to integrate bodyContent output with the output stream:

public class TestBody extends BodyTagSupport {
	public int doStartTag() throws JspException {
		try {
			pageContext.getOut().print("doStartTag()");
			return EVAL_BODY_BUFFERED;
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		}
	}

	public void doInitBody() throws JspException {
		try {  
			// Note, that this is a different writer than the one
			// you have in doStartTag and doEndTag.
			bodyContent.print("doInitBody()");
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		} 
	}

	public int doAfterBody() throws JspException {
		try {
			// Note, that this is a different writer than the one
			// you have in doStartTag and doEndTag.
			bodyContent.print("doAfterBody()");
			// return IterationTag.EVAL_BODY_AGAIN;  
			// Use this to loop
			return SKIP_BODY;
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		} 
	}

	public int doEndTag() throws JspException {
		try {  
			// Write from bodyContent writer to original writer.
			pageContext.getOut().print(bodyContent.getString());
			// Now we're back to the original writer.
			pageContext.getOut().print("doEndTag()");
			return EVAL_PAGE;
		} catch(IOException ioe) {
			throw new JspException(ioe.getMessage());
		} 
	}
}
					

Using the PageContext API, write tag handler code to access the JSP implicit variables and access web application attributes.

A PageContext is an object that provides a context to store references to objects used by the page, encapsulates implementation-dependent features, and provides convenience methods. A JSP page implementation class can use a PageContext to run unmodified in any compliant JSP container while taking advantage of implementation-specific improvements like high performance JspWriters.

The PageContext provides a number of facilities to the page/component author and page implementor, including:

  • a single API to manage the various scoped namespaces

  • a number of convenience API's to access various public objects

  • a mechanism to obtain the JspWriter for output

  • a mechanism to manage session usage by the page

  • a mechanism to expose page directive attributes to the scripting environment

  • mechanisms to forward or include the current request to other active components in the application

  • a mechanism to handle errorpage exception processing

public abstract class JspContext {

	public abstract void setAttribute(String name, Object value);
	public abstract void setAttribute(String name, Object value, int scope);
	public abstract Object getAttribute(String name);
	public abstract Object getAttribute(String name, int scope);
	public abstract Object findAttribute(String name);
	public abstract void removeAttribute(String name);
	public abstract void removeAttribute(String name, int scope);
	public abstract int getAttributesScope(String name);
	public abstract Enumeration getAttributeNamesInScope(int scope);
	public abstract JspWriter getOut();

}
					
public abstract class PageContext extends JspContext {

	public abstract javax.servlet.http.HttpSession getSession();
	public abstract java.lang.Object getPage(); 
	public abstract javax.servlet.ServletRequest getRequest();
	public abstract javax.servlet.ServletResponse getResponse();
	public abstract java.lang.Exception getException();
	public abstract javax.servlet.ServletConfig getServletConfig();
	public abstract javax.servlet.ServletContext getServletContext();

	public abstract void forward(java.lang.String relativeUrlPath)
		throws javax.servlet.ServletException, java.io.IOException;
	public abstract void include(java.lang.String relativeUrlPath)
		throws javax.servlet.ServletException, java.io.IOException;
	public abstract void handlePageException(java.lang.Exception e)
		throws javax.servlet.ServletException, java.io.IOException;

}
					

Given a scenario, write tag handler code to access the parent tag and an arbitrary tag ancestor.

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 with the static method TagSupport.findAncestorWithClass(from, class) or the TagSupport.getParent() method. The former method should be used when a specific nesting of tag handlers cannot be guaranteed. Once 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 objects can be stored in a tag handler with the setValue method and retrieved with the getValue method.

The following example illustrates a tag handler that supports both the named and private object approaches to sharing objects. In the example, the handler for a query tag checks whether an attribute named connectionId has been set. If the connection 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 BodyTagSupport {
	public int doStartTag() 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 could 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 indicates that the connectionId attribute is optional with the following declaration:

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

					

Describe the semantics of the "Simple" custom tag event model when the event method (doTag) is executed; write a tag handler class; and explain the constraints on the JSP content within the tag.

JSP 2.0 introduces a new type of tag extension called a Simple Tag Extension. Simple Tag Extensions can be written in one of two ways:

  • In Java, by defining a class that implements the javax.servlet.jsp.tagext.SimpleTag interface. This class is intended for use by advanced page authors and tag library developers who need the flexibility of the Java language in order to write their tag handlers. The javax.servlet.jsp.tagext.SimpleTagSupport class provides a default implementation for all methods in SimpleTag.

  • In JSP, using tag files. This method can be used by page authors who do not know Java. It can also be used by advanced page authors or tag library developers who know Java but are producing tag libraries that are presentation-centric or can take advantage of existing tag libraries.

In addition to being simpler to work with, Simple Tag Extensions do not directly rely on any servlet APIs, which allows for potential future integration with other technologies. This is facilitated by the JspContext class, which PageContext now extends. JspContext provides generic services such as storing the JspWriter and keeping track of scoped attributes, whereas PageContext has functionality specific to serving JSPs in the context of servlets. Whereas the Tag interface relies on PageContext, SimpleTag only relies on JspContext. Unlike classic tag handlers, SimpleTag does not extend Tag.

package javax.servlet.jsp.tagext;
					
public interface SimpleTag extends JspTag {
	public void doTag()throws JspException, java.io.IOException;
	public void setParent(JspTag parent);
	public JspTag getParent();
	public void setJspContext(JspContext pc);
	public void setJspBody(JspFragment jspBody);
}
					

Most SimpleTag handlers should extend javax.servlet.jsp.tagext.SimpleTagSupport. This is the convenience class, similar to TagSupport or BodyTagSupport. There are also some helpful methods included in this class that include:

  • public JspFragment getJspBody() - returns the body passed in by the container via setJspBody. The JspFragment encapsulates the body of the tag. If the JspFragment is null, it indicates that tag has a body content type of empty.

  • public static final JspTag findAncestorWithClass(JspTag from, java.lang.Class klass) - finds the instance of a given class type that is closest to a given instance. This method uses the getParent() method from the Tag and/or SimpleTag interfaces. This method is used for coordination among cooperating tags. While traversing the ancestors, for every instance of TagAdapter (used to allow collaboration between classic Tag handlers and SimpleTag handlers) encountered, the tag handler returned by TagAdapter.getAdaptee() is compared to klass. In a case where the tag handler matches this class, and not its TagAdapter, is returned.

The body of a Simple Tag, if present, is translated into a JSP Fragment and passed to the setJspBody method. The tag can then execute the fragment as many times as needed. Because JSP fragments do not support scriptlets, the <body-content> of a SimpleTag cannot be "JSP". A TLD is invalid if it specifies "JSP" as the value for <body-content> for a tag whose handler implements the SimpleTag interface. JSP containers are recommended to but not required to produce an error if "JSP" is specified in this case.

During the translation phase, various pieces of the page are translated into implementations of the javax.servlet.jsp.tagext.JspFragment abstract class, before being passed to a tag handler.

JSP fragments are pieces of JSP code. Written using standard JSP syntax, a fragment is translated into an implementation of the interface JspFragment for use by tag handlers. A JSP fragment is used to represent the body of a tag for use with a SimpleTag handler. The JspFragment interface declares only two methods: invoke and getJspContext.

package javax.servlet.jsp.tagext;

public abstract class JspFragment {
	public abstract void invoke(java.io.Writer out)
		throws JspException, java.io.IOException;
	public abstract JspContext getJspContext();
}
					
invoke causes the fragment to be executed, writing the output produced to the Writer passed to it. You can invoke a fragment as many times as needed. invoke can throw a SkipPageException, which signals that the fragment has determined that the remainder of the page doesn't need to be evaluated.

The following example shows the simple custom tag:

public class MySimpleTag extends SimpleTagSupport {
	public void doTag()	throws JspException, IOException {
		getJspContext().getOut().write("Hello, World !");
	}
}					
					

The lifecycle of a Simple Tag Handler is straightforward and is not complicated by caching semantics. Once a Simple Tag Handler is instantiated by the Container, it is executed and then discarded. The same instance must not be cached and reused.

The following lifecycle events take place for the simple tag handler (in the same order):

  1. A new tag handler instance is created each time the tag is encountered by the container. This is done by calling the zero argument constructor on the corresponding implementation class. It is important to note that a new instance must be created for each tag invocation.

  2. The setJspContext() and setParent() methods are invoked on the tag handler. If the value being passed is 'null', then the setParent() method need not be called. In the case of tag files, a JspContext wrapper is created so that the tag file can appear to have its own page scope. Calling getJspContext() must return the wrapped JspContext.

  3. The container calls the setters for each attribute defined for this tag in the order in which they appear in the JSP page or Tag File. If the attribute value is an expression language expression or a runtime expression, it gets evaluated first and is then passed on to the setter. On the other hand if the attribute is a dynamic-attribute then setDynamicAttribute() is called.

  4. The setJspBody() method is called by the container to set the body of this tag, as a JspFragment. A value of null is passed to setJspBody() if the tag is declared to have a <body-content> of empty.

  5. The doTag() method is called by the container. All tag logic, iteration and body evaluations occur in this method.

  6. All variables are synchronized after the doTag() method returns.

The following example simply writes the body to the output stream. When the Writer given to invoke is null, the output from invoke goes to the JspWriter associated with the JspContext of the tag handler:

					
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class MySimpleTag extends SimpleTagSupport {
	public void doTag() throws JspException, IOException {
		getJspBody().invoke(null);
	}
}
					
The invoke method directs all output to a supplied writer or to the JspWriter returned by the getOut method of the JspContext associated with the tag handler if the writer is null.

<%@ taglib uri="/mytag" prefix="mytag" %>
<html>
	<body>
		<mytag:MySimpleTag>
			Hello, World !
		</mytag:MySimpleTag>
	</body>
</html>
					
					

SimpleTagSupport provides the convenience method getJspBody() to return the JspFragment generated for the body content. The following example demonstrates that a SimpleTag can obtain a copy of the body so that it can use or MANIPULATE it:

public class MySimpleTag extends SimpleTagSupport {
	public void doTag() throws JspException, IOException  {
		StringWriter sw = new StringWriter();
		getJspBody().invoke(sw);
		getJspContex().getOut().write(sw.toString());
	}
}					
					
is equivalent to:
public class MySimpleTag extends SimpleTagSupport {
	public void doTag() throws JspException, IOException  {
		StringWriter sw = new StringWriter();
		jspBody().invoke(sw);
		getJspContex().getOut().write(sw.toString());
	}
}					
					

Describe the semantics of the Tag File model; describe the web application structure for tag files; write a tag file; and explain the constraints on the JSP content in the body of the tag.

Writing a traditional custom tag requires two steps:

  • Writing and compiling a tag handler.

  • Defining the tag that is associated with the tag handler.

Tag files simplify the process. First, tag files don't need to be compiled. They are compiled as they are invoked. Also, tag files allow tag extensions to be written using only JSP syntax. This means someone who does not know Java can also write tag extensions. Secondly, a tag element in a tag library descriptor describes the name to be used in a JSP page to reference the custom action. Using tag files, the name of a custom action is the same as the tag file representing the action. Therefore, you don't need a tag library descriptor at all. A tag file looks like a JSP page. It can have directives, scripts, EL expressions, and standard and custom tags. A tag file has the .tag or .tagx extension and can also include other files that contain a common resource. An include file for a tag file has a .tagf extension.

To work, tag files must be placed in the WEB-INF/tags directory under your application directory OR a subdirectory under it. The container converts each tag file found in (or uder) WEB-INF/tags into a tag handler.

A number of implicit objects are available from inside of a tag file. You can access these objects from a script or an EL expression:

Table 10.2. The Tag Files implicit objects

ObjectType
requestjavax.servlet.http.HttpServletRequest
responsejavax.servlet.http.HttpServletResponse
outjavax.servlet.jsp.JspWriter
sessionjavax.servlet.http.HttpSession
application javax.servlet.ServletContext
configjavax.servlet.ServletConfig
jspContextjavax.servlet.jsp.JspContext

This is the example of a tag library in which the tag file simply writes a String to the implicit out object:


<%—  WEB-INF/tags/myExample.tld —%>

<%
	out.println("Hello, World !");
%>
					
					
In JSP you need the taglib directive as usual, with the prefix attribute to identify your tag library throughout the page. NOTE, instead of a uri attribute, you have a tagdir attribute. The tagdir attribute refers to the WEB-INF/tags directory OR ANY subdirectory below WEB-INF/tags:
					
<%@ taglib prefix="simpleTag" tagdir="/WEB-INF/tags" %>

<simpleTag:myExample />
					
					

Combined with the expression language (EL), you can really build a scriptless JSP page very rapidly. The following example accepts an attribute from a calling JSP page and converts it to the upper case:

					
<%— WEB-INF/tags/myExample2.tld —%>

<%@ attribute name="someAttribute" %>
<%
	someAttribute = someAttribute.toUpperCase();
	out.println(someAttribute);
%>
					
					
The following JSP page that uses the tag file:

<%@ taglib prefix="simpleTag" tagdir="/WEB-INF/tags" %>

<simpleTag:myExample2 someAttribute="hello" />
					
					

example, which is Java-code-free:


<%— WEB-INF/tags/myExample3.tag —%>
<%@ variable name-given="myVar" scope="AT_BEGIN" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:set var="myVar" value="3"/>

After: ${myVar}

<jsp:doBody/>
					
					
To use the tag file, use the following JSP page:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="sampleTag" tagdir="/WEB-INF/tags" %>

<c:set var="myVar" value="1"/> 

Before: ${myVar} <br>

<simpleTag:myExample3/>
					
					

scjp 1.5 | scjp 1.6 | scwcd 1.5
Java Certifications
www.javacertifications.net