30 Custom Tags
Pravin Jain
Introduction
Welcome to this module on developing custom tags. In the last module we had looked at the standard tags which are available for use in a JSP. Those standard tags, we had used was something like jsp: there were bean tags, we had tags for including an applet. there are these readymade standard tags which are available for use in any JSP. to include any of those standard tags, we simply say,
<jsp:tagname attributes>.
That way we could be using any of those standard tags. we have various categories of those standard tags.
Other than these standard tags,there is also a possibility of a java programmer creating certain more tags of his own and using them within a jsp page. It is not that in a jsp page you will be able to use those standard tags only. you can inlcude other created tags as well.For eg. we have programmers whose job is to only create good tags which are more general purpose tags, creating them in the form of a library and distributing it for others to use. we have got something called tag library.someone could create a full library of tags and then this library could be included in any JSP.
Using the taglib directive
so what all things can be used in a JSP? we can use html, expressions, scriptlets, directives.one of the directives was the taglib directive…we could say @taglib, We can say <%@ taglib…there are two attributes there. one attribute is URI=”you give some URI”..what’s that URI for? that URI is for a tld file.what is TLD? its tag library descriptor. and then the other attribute which says prefix=”some kind of a prefix”. Here, there is some restriction on the prefix. the prefix can’t be saying jsp.Because when we use std tags that prefix is jsp. There are certain things which are reserved and cannot be used as prefix in our taglib directive. the prefix value can’t be jsp,jspx,java, javax. You can have any other things. the idea here is when I am saying @taglib, I am saying, in this particular JSP, I would like to be using all those tags which are available ot declared in this particular tld file.
The tld file
A TLD file is an XML file. In this XML file, we got <taglib></taglib> and within that we have got the tags. we give our name to the tag and associate this name with a particular class. we have a class corresponding to each tag which has been developed. A tag developer defines certain classes and also creates a TLD file which gives a name to the tag that is defined using a java class. This module concentrates on how do we define this kind of tag classes and a little bit about how to create a TLD file. we will also have a demonstration later which shows how to create a TLD file and how to create custom tag which can then be used in a JSP file. so we used the taglib directive in a JSP and specify the TLD file .that TLD file says there is a name there. It assocites a name with our tag.whenever we want to use any tag which is available in that TLD, we will be using that prefix:the name which appears in the TLD.
What are tags
All these are valid XML tags and they have to follow the hierarchical structure of XML. we have a parent tag, there is a child tag. Any tag may have a parent tag..and tags also have attributes. attribute will have a name. whenever we use a tag, we say prefix:tagname then we might be using attribute, whatever attibute is allowed for this tag.
eg. attribute= value for the attribute which may be in ‘ ‘ or ” “.
<prefix:tagname attrib1=’value1’ attrib2=”value2” ..> body of the tag </prefix:tagname>
we may have the body for the tag and after the body you may have the end of the tag. you may have tags which do not allow a body. we are looking at this from the point of view of a tag developer.
The three kinds of tags
What does a tag developer have to do here? If someone wants to develop tags, he will have to define certain classes. there is one more API which is related to JSP. The JSP API has a package called javax.servlet.jsp.tagext (tag extention). and this tag extention has got certain interfaces.There are three interfaces for creating defferent kinds of tags. we have one kind of a tag which is a simple tag, we normally use it for tags which do not have a body. it may have have attributes. we have another kind of a tag which is known as IterationTag which extends from a Tag. it has a few more things.
You may use an IterationTag where we have some kind of a body. you may like to repeat a body in the output again and again till a certain condition is met which may be decided by the tag itself.so we have tag called IterationTag.
Then we have a BodyTag which is an extension of IterationTag. It has an ability of looping over a body content but the idea here is, in the body tag,the content within the start and end of a tag, that body content is made available to the tag and it is the tag which decides how to use it. the buffer created through which the body content would be made available to the tag is directly accessible to the tag. The IterationTag does not process a body.the iIterationTag only says I want the body to be processed by the JSP. the iteration tag does not get hold of the content. This is the difference there.
So we thave these 3 kinds of tags. Lets look at each of these tags here.
Developing a simple tag
When you make a tag entry within a JSP, there is a life-cycle for this tag object within the JSP page itself. lets start by looking at the life-cycle of a simple JSP tag. so if you define a class by implementing from Tag interface. If you have an empty tag, you may be implementing the Tag interface.
So, lets look at what methods are there and how they get invoked.
As soon as the JSP page is going to be loaded it would be invoking a method which is embeded here, it would invoke the method called setPageContext(). PageContext is the object which contains all other implicit objects of the JSP. The idea here is to make all the implicit objects available to the tag object. The tag developer now gets hold of the current implicit objects. eg.From the cutom tag object, the developer wants to put some output, he has the ‘out’ object available to him. If he wants to read some parameters from the request, he has the ‘request’ object available from the pageContext. So the idea is to push the pageContext object into the Tag component.(its the tag component which the tag developer is creating) So the first lifecycle method is the setPageContext().
The next thing, the tag has is a method callled setParent(). If there is a parent tag, this method would be invoked and the parent tag object would be made available to this tag.
There is an addtional method in the interface called getParent().The implementation of setParent() should store this parent in some instance variable. you must keep an instance variable to store your parent tag object and your getParent() method must be implemented that way.
The next thing, in this tag you have got your attributes. you have att_name1=att_value/s att_name2=att_value/s. the developer would have used some attributes for the tag when he is using a particular tag. So the values for these attributes have to be given to this tag components and for that the tag developer has to have the setter methods coressponding to the attributes. for eg. you may have a tag to put the current date and time. you call that tag as now, you create a class called NowTag which implements the Tag interface. You would like to have the date time formating to be specified as an attribute not compulsory. if you have an attribute called format, your class must have a method called
void setFormat(String format).
what is allowed here is there is an implicit conversion from String to the primitive types available to us. the idea is to have the setter method for all the attributes.
When you are designing your tag, you have already decided on attribute_name, So whatever attribute_names you have, for each attribute you must have a setter method,
void setAttributename(primitive type or string).
From life cyle point of view first invokation of setPageContext(), next was setParent(), next is the invocation of setter method for the attributes. Once the invocation of setter methods for the attributes is over, so the tag component has been told that these are the attributes which the webpage designer has set for you,
Next the engine invokes the method int doStartTag().
the return value here is going to decide whether the body content is going to be processed or not, it has to be evaluated or not by the page engine. Should the JSP engine be evaluating the body content or not, that will be decided depending on the return value of the doStartTag().for the return value we have static constants in the tag interface We have a constant called SKIP_BODY or EVAL_BODY_INCLUDE, in the Tag interface.. So you may be returning one of those two values here. Normally if its an empty tag,which doesnt have a body then it should be returning SKIP_BODY. If it has a body and the tag decides that the body needs to be evaluated, it should return EVAL_BODY_INCLUDE. If SKIP_BODY is returned it will straight away jump to invoking the next method which is
void doEndTag().
If it had returned EVAL_BODY_INCLUDE, it would evaluate the body content and then it will be invoking the doEndTag().
For this doEndTag(), the tag is given another control whether the rest of the page needs to be skipped or I need to proceed further. So you return any of the two constants called SKIP_PAGE or you might be returning EVAL_PAGE. These are static variables in the Tag interface. Normally you may be saying EVAL_PAGE, so it will process further and within the page it will be processing rest of the things. Once the page is over, there is another lifecycle method which is at the end. The method is
void release().
That way the Tag interface has all these methods. void setPageContext(PageContext ctx)
void setParent(Tag parent) attribute methods
Tag getParent() int doStartTag()
int doEndTag() void release()
Iteration tag
You might be interested in using the next type of tag which is the iteration tag. The lifecycle of IterationTag is very similar to the Tag interface. But there is a little change here.
In case of an IterationTag,the evaluation is same, the lifecycle is similar, We have setPageContext(), we have setParent() getting invoked and then we also have the invocation for the setter methods for attributes.
But then we have one additional method. When we return EVAL_BODY_INCLUDE from doStartTag. it will evaluate the body content but after the body content has been evaluated, it invokes an additional method which we have in the IterationTag. That method is
public int doAfterBody()
In lifecycle it is after the doStartTag(). If doStartTag() returns SKIP_BODY, then this method wont be called. It will straightaway go for doEndTag(). But if it is returning EVAL_BODY_INCLUDE, after the evaluation of body is over, it will invoke the method doAfterBody(). This method in order to repeat the evaluation of body content, it can return a value called EVAL_BODY_AGAIN, a constant in the IterationTag. the integer value returned by doAfterBody(), it can be EVAL_BODY_AGAIN.
if it retuns EVAL_BODY_AGAIN it just keeps on repeating the evaluation of body and invokes this method again, unless it says SKIP_BODY. Once it says SKIP_BODY it will be going to the regular life-cycle methods…namely the doEndTag().. At the end of the page it has to call the release method.
Body tag
We have the third type of tag called the BodyTag.
BodyTag interface extends from the IterationTag.here also the evaluation of body is done but in a different manner from the way it is done in iteration tag.
In the IterationTag,the body content goes into the output but in this case of a body tag, We have an option whereby we can prevent the content being directly evaluated by the JSP engine, instead we can ask the JSP engine to put it in a buffer and make it available to this body tag object.
So the kind of methods which we have here, when we look at the lifecycle for a body tag again are on a line similar to earlier one but lets just go where the differences are?
First step was setPageContext(), then setParent(), then setter methods for the attributes, and then we have the doStartTag() which can return SKIP_BODY or EVAL_BODY_INCLUDE. other than this EVAL_BODY_INCLUDE, if the doStartTag() returns EVAL_BODY_BUFFERED, a constant in the BodyTag, in that case a BodyContent object is created.It is a class which extends from JSPWriter which is a buffer. This buffer content is accessible. We have a method to get it as a string. So we have this BodyContent object being created by the engine,
After the doStartTag() retuns a EVAL_BODY_BUFFERED, it would invoke the method called
public void setBodyContent(BodyContent content),
the empty buffer is made available to our tag object and after the invocation of setBodyContent() it is again asking the tag that if you want you can do some initialization on this buffer. So it is calling a method called
public void doInitBody().
So these two additional methods have come in here. So for a BodyTag we have two additional methods public void setBodyContent(BodyContent content)
public void doInitBody()
This would be used for initialization purpose and then the evalution of body content would take place. Then similar to the iteration tag, it would be invoking the method for doAfterBody(). What is this evaluation of the iteration tag? Its not going to evaluate the JSP body content in the output Because it is saying buffered its not going in the output, it is instead put into the buffer which was given to us, which is given to the tag in the setBodyContent() method. the BodyContent object given to us in the setBodyContent() method is then updated. for a body content, this body content is being appended into the buffer.then there is an invocation of doAfterBody(). You can then decide what you like to do with the content which is available to you. The content is now with the tag in case of a BodyTag. The content was never with the tag in the IterationTag. the body tag can then decide how to use the content.
Like IterationTag it can also decide whether it would like to have this appended another time again in the body content If it wants to repeatedly have it appended that could also be done, the doAfterBody() can just keep on repeating EVAL_BODY_AGAIN, if its saying EVAL_BODY_AGAIN, the body doesnt go to the output, the body gets appended to the bodyContent object.We have this happening unless it says SKIP_BODY. Only when it says SKIP_BODY, it goes to the invocation of doEndTag(). In the doEndTag() you have the buffer ready with all the things and you can decide how to use the entire buffer. there are easier ways to push into the output whatever has been accomodated or you can work on the entire buffer in the bodyContent, get it as a String and manipulate it and give it in the output. so you get control over content in case of BodyTag. Thats what we have in the BodyTag.
In the end it would again have a invocation of release method.that way we have got these three different types of tag and then we have the TLD file which has to be written.
The TLD file
The TLD file is an XML file, it associates the name with the tag, it also mentions about what kind of content this tag will have, whether the tag has empty body content or it has got some body content which is used as a JSP or in case of BodyTag it will say the bodycontent is tag dependent. In case of IterationTag, it says the bodycontent is a JSP. This is something which is mentioned in a tld file. The TLD file how it is to created, what it should contain, that we will be covering in our next module.
The next module will be about a demonstration on how write these three kinds of tags, and how to create a tld file.
So we have seen, how a custom can be created and these tags can then be used by a web page developer in a JSP. This way we have interfacing between, web page designer and a Java programmer. As far as managing these tags is concerned. These tag classes will have to be managed for a web application, by having them in the classes folder under WEB-INF of the application, or may be we can have the jar file and keep it in the lib folder. The tld file is advised to be kept in somewhere within the WEB-INF. Normally, we create a folder called tld and put our tld file over there. So, when we use the taglib directive we specify uri=’/WEB-INF/tld/tldfilename’ So, as a tag library developer, you can create any of the three kind of tags. Thatw what we have in this module. In the next module we will be having a demonstration.
you can view video on Custom Tags |
Suggested Reading:
- Core Servlets and Java Server Pages Volume 2 by Marty Hall & Larry Brown, Second Edition, Pearson Education.
- Core JSP by Damon Haugland and Aaron Tavistock, Pearson Education
- Java Server Programming for Professionals by Ivan Bayross, Sh aranam Shah, Cynhthia Bayross and Vaishali Shah Shroff Publishers and Distributros.
- http://docs.oracle.com/javaee/5/tutorial/doc/bnagx.html