Chapter 10 Custom Tag Development

(*) Tag File
Store the tag files in /WEB-INF/tags folder.
The name of the tag file will become the tag name. (Header.tag ==> Header will be the name of the tag in JSP)

JSP usage

<%@taglib prefix="mytags" tagdir="/WEB-INF/tags" %>
  • note that the tagdir attribute used instead of uri attribute
  • tagdir value is the folder where the tag files are located
<mytags:Header subtitle="Welcome" />
  • Header was the name of the file. (Header.tag)

Header.tag

<em><strong>${subtitle}</strong></em>

* The difference from <jsp:include> or <c:import> is that they use parameter to pass down the variables and they will exist in the JSP after include is comleted. But with Tag file, the attribute variable will not be available after the call.

* Tag files do not require to be defined in TLD file. Instead we use new directive in the tag file to define various information

<%@ attribute  name="subtitle" required="true" rtexprvalue="true" %>

Since subtitle is required, if the attribute subtitle is not used within the tag used in the JSP, you will get exception.

*If you want to use body with the Tag File,
JSP page

<mytags:Header>This is a body</mytags/Header>

Header.tag

<em><strong><jsp:doBody/></strong></em>

Additional tag for TAG files

<%@tag body-content="scriptless" %>

By default, the body-content is “scriptless” if tag directive not defined. In TAG FILE, scriplets are not allowed within BODY , so JSP for body-content not allowed.

Searching for the tag files (order)

  1. /WEB-INF/tags
  2. /WEB-INF/tags’ subfolder
  3. /META-INF/tags of Jar file in the /WEB-INF/lib
  4. /META-INF/tags’ subfolder of Jar file in the /WEB-INF/lib

* If tag file is deployed in a Jar, there must be TLD file for the tag files. See below example for such case.

<taglib>
	<tlib-version>1.0</tlib-version>
	<uri>myLib</uri>
	<tag-file>
		<name>Header</name>
		<path>/META-INF/tags/Header.tag</path>
	</tag-file>
</taglib>

* Scriptlet & EL implicit objects can be used in tag file except ServletContext. Instead JspContext is used.

(*) Tag Handlers

Simple (new) & Classic (old before 2.0)

Simple Tag Handler

  1. Write Class extends SimpleTagSupport
  2. override doTag() method
  3. create TLD file
    <tag>
    	<description>Testing simple tag</description>
    	<name>SimpleTest</name>
    	<tag-class>com.example.tag.TestSimpleTag</tag-class>
    	<body-content>empty</body-content>
    </tag>
  4. Deploy tag handlers TLD & class in /WEB-INF/file.tld
  5. Write JSP using the tag
    <%@ taglib prefix="mytag" uri="…" %>
    <mytag:SimpleTest />

* Processing Body example

Public void doTag() throws JspException, IOException {
	getJspBody().invoke(null) ; 
	// This will evaluate the body & print output to the response output. (when arg is null)
}

* Simple Tag handler Processing steps

  1. Load Class
  2. Instantiate class (no-arg constructor runs)
  3. Calls setJspContext(JspContext)
  4. If tag is nested, call the setParent(JspTag)
  5. If tag has attributes , call attributes bean setters.
  6. If Body exists & is not empty, setJspBody(JspFragment) is called
  7. Call the doTag()

Example
Jsp Tag invocation

<table>
	<myTags:simple movieList="${movieCollection}" >
		<tr><td>${movie.name}</td><td>${movie.genre}</td></tr>
	</myTags:simple>
</table>

The Tag handler class

Public class SimpleTagTest extends SimpleTagSupport {
	private List movieList;
	public void setMovieList(List movieList) {
		this.movieList = movieList;
	}
	Public void doTag() throws JspException, IOException {
		Iterator I = movieList.iterator();
		While(i.hasNext()){
			Movie movie = (Movie) i.next();
			getJspContext().setAttributes("movie", movie);
			getJspBody.invoke(null);
		}
	}
}

The TLD

<tag>
	<description>takes an attribute and iterates over body</description>
	<name>simple</name>
	<tag-class>com.example.tag.SimpleTagTest</tag-class>
	<body-content>scriptless</body-content>
	<attribute>
		<name>movieList</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
</tag>

JspFragment is an object represents JSP code (JspFragment jf = getJspBody(); )
Body of tag is encapsulated in JspFragment & then sent to the tag handler in the setJspBody(). No Scriptlets are allowed in body of tag for Simple Tag.

*JspFragment.invoid(java.io.writer) : use null as arg to send output to response otherwise create a write object & pass it. Work with write to access the body.

If doTag() throws SkipPageException, all the contents will be shown right before Exception. But the rest of the page will not be shown. (Stop processing) If JspException occurs , error page will be shown.


(*) Classic Handler

Create a classic handler by extending TagSupport or BodyTagSupport.

The order that BodyTag is extended / implemented parents classes.
JspTag interface <== Tag interface <== IterationTag interface (doAfterBody() belongs here ) <== BodyTag interface (doInitBody(), setBodyContent(BodyContent) belong this interface)

TagSupport implement IterationTag interface.
BodyTagSupport implement BodyTag interface.

public int doStartTag() throws JspException (Note that no IOException)

  • Return SKIP_BODY ==> No Body Process
  • Return EVAL_BODY_INCLUDE ==> Body process ==> call doAfterBody()

public int doEndTag() throws JspException

  • Return EVAL_PAGE ==> cdontinue with the rest of page
  • Return SKIP_PAGE ==> same as SkipPageException.

LifeCycle

  1. Load class
  2. Instantiate class (call no-arg constructor)
  3. Call setPageContext(Pagecontext)
  4. If tag nested, call setParent(Tag)
  5. If tag has attributes, call attributes setters
  6. Call doStartTag()
  7. If doStartTag returns EVAL_BODY_INCLUDE , the body is evaluated.
  8. doAfterBody() is called after body is evaluated
  9. doEndTag()

public int doAfterBody() throws JspException

  • Return SKIP_BODY ==> goto doEndTag()
  • Return EVAL_BODY_AGAIN ==> eval body again ==> doAfterBody called again

Default Return Values of the methods if not overridden:

  • doStartTag ==> SKIP_BODY
  • doAfterBody ==> SKIP_BODY
  • doEndTag ==> EVAL_PAGE

Classic handler object is reused unlike simple handler.

* Dynamic Attribute Interface
To pass down bunch of attributes to that are not actually used in the TAG class. Just like HTML default attributes.

Implement DynamicAttributes interface

public void setDynamicAttribute(String uri,String name, Object value) {
	hashmap.put_(name, value);
}

TLD for Dynamic Attribute

<tag>
	<name></name><tag-class></tag-class><body-content>empty</body-content>
	<attribute> 
<name></name><type></type>
<required></required><rtexprvalue></rtexprvalue>
</attribute>
	<dynamic-attributes>true</dynamic-attributes>
</tab>

In case of TAG FILES

<%@ tag body-content="empty" dynamic-attributes="tagAttrs" %>

BodyTagSupport Class : This is just to work with the actual body content.
There is one more return value for the doStartTag() : EVAL_BODY_BUFFERED (default return for the BodyTagSupport class).
When EVAL_BODY_BUFFERED is returned, setBodyContent() & doInitBody() called before evaluate the body.

Nesting Tags : How to access parent tag? ==> using getParent()

//Getting top most tag handler
Tag parent = getParent();
While (parent != null) {
	parent = parent.getParent();
	nestLevel++;
}

Using getParent(), a classic can access only classic tag parents, and a simple tag can access either a classic or simple parent.

If you want to access child from the parent: there is no predefined method. You will need to create custom method for the parent Tag class & call it from the child Tag class by getting getParent and call the method. Store child data to parent class using the method.

findAncestorWithClass(Tag,class of ancestor Tag you want to search)
This searches Tag parent until the class matches. This function does not belong to interface but to final classes (SimpleTagSupport, TagSupport, BodyTagSupport)

<%@ attribute name="extra" fragment="true" %>
<jsp:invoke fragment='extra'>

<jsp:invoke > ==> just like processing tag body but attribute fragment ?? Need to check further.

Also SimpleTagSupport & TAG FILE do not support ‘JSP’ type for <body-content>. But with classic handler TagSupport & BodyTagSupport, ‘JSP’ can be used for <body-content>

(*) Next: [SCWCD] Cram Sheet 8 - Web Deployment and Security



One Response to “[SCWCD] Cram Sheet 7 - Custom Tag Development”

  1.   Remember the code? » Blog Archive » [SCWCD] Cram Sheet 6 - using JSTL Says:

    [...] Next: [SCWCD] Cram Sheet 7 - using JSTL Posted by HanaDaddy Filed in java Tags: java, SCWCD [...]

Leave a Reply