10.
The Jakarta-Tomcat Project
Create a simple JSP
file in any subdirectory. We have created a new directory ‘myprg’ in
c:\jakarta-tomcat-3.2.1\webapps\examples\jsp and written our programs there.
d1.jsp
<html>
<body>
<pp:log1>
Vijay Mukhi
</pp:log1>
</body>
</html>
Output in Browser
Vijay Mukhi
View Source
<html>
<body>
<pp:log1>
Vijay Mukhi
</pp:log1>
</body>
</html>
This program
introduces the tag <pp:log1>. This tag is similar to the jsp:tag which
you are already familiar with. pp is not a predefined tag, it is our own custom
tag. A custom tag allows you to extend a tag rather than use an existing tag.
For those who need to
have their memory refreshed, type in the following in the IE address bar.
http://127.0.0.1:8080/examples/jsp/myprg/d1.jsp
You will observe that
the tag is ignored, since neither the browser nor the server understands
<pp:log1>. All that we see in IE or any browser is Vijay Mukhi and in
View Source, we see the jsp file unchanged. The Java Web Server ignored the
tag. The Java Web Server takes a long time to send back any output but the
important thing to note is that the web server and the browser, both, ignored the tag as they don’t understand it.
There is no output in tha Java Server window and it is the servlet generated
which send the jsp file over unchanged.
Our next program
includes minor changes.
d2.jsp
<html>
<body>
<%@ taglib uri=”http://java.apache.org/tomcat/examples-taglib” prefix=”pp” %>
<pp:log1>
Vijay Mukhi
</pp:log1>
</body>
</html>
Output in Browser
org.apache.jasper.JasperException: No such tag log1 in the tag library imported with prefix pp
It shows an error in
the browser. The first statement within the body tag is a directive named
taglib, followed by uri, an attribute, which stands for ‘universal
resource identifier’. The uri attribute is given a specific url. Another
attribute required named prefix is initialized to pp, which is the name of our
tag. When you try to load this JSP file, the browser shows you an error. The
error says that it is an internal server error which means that we’ve upset the
Java Web Server. The error clearly
indicates that there is no tag log1 with the pp prefix. It does not recognize
pp as a valid tag.
In order to validate
it, go to the following subdirectory- C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF.
Here, you will find a file by the name of web.xml. The file web.xml and the
WEB-INF subdirectory have now been standardized by the java servlet
specification. In the earlier days, you could put whatever you wanted in
whichever file and that could be located in any subdirectory. A major part of
the Java servlet specification deals with the directories, their names and the
files they should contain.
web.xml talks about
the web server. We have reproduced a part of the file that is relevant to our
discussion.
web.xml
<taglib>
<taglib-uri>
http://java.apache.org/tomcat/examples-taglib
</taglib-uri>
<taglib-location>
/WEB-INF/jsp/example-taglib.tld
</taglib-location>
</taglib>
It starts with <taglib>
within which is <taglib-uri>,this is the same url or name that we have
given in the JSP file. The location it points to is /WEB-INF/jsp/example-taglib.tld.
The uri is mapped to
the location. The file example-taglib.tld contains the taglib description. Open
this file by giving the path as follows:
>edit C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\jsp\example-taglib.tld.
example-taglib.tld
<?xml version=”1.0" encoding=”ISO-8859-1" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<!— a tag library descriptor —>
<taglib>
<!— after this the default space is
“http://java.sun.com/j2ee/dtds/jsptaglibrary_1_2.dtd”
—>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>simple</shortname>
<uri></uri>
<info>
A simple tab library for the examples
</info>
<tag>
<name>ShowSource</name>
<tagclass>examples.ShowSource</tagclass>
<info> Display JSP sources </info>
<attribute>
<name>jspFile</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
Since this file does
not contain pp , we see an error. Now, we will add our own uri ‘vijay’ to the
xml file and the tag pp in a tld file.
d3.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1>
Vijay Mukhi
</pp:log1>
</body>
</html>
web.xml
..
..
<taglib>
< taglib-uri >
vijay
</taglib-uri>
< taglib-location >
/WEB-INF/jsp/ea.tld
</taglib-location>
</taglib>
Add the following
lines in web.xml somewhere at the bottom. Now you must restart the web server
because web.xml is only read at startup time.
Truncated Output in Browser
org.apache.jasper.compiler.CompileException: C:\jakarta-tomcat-3.2.1\webapps\examples\jsp\myprg\d3.jsp(2,0) Unable to open taglibrary vijay : C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\jsp\ea.tld (The system cannot find the file specified)
The web server starts fine
but when we load d3.jsp in the browser we get the error as shown above. When
the Java Web Server starts, it reads web.xml. There it meets a tag named
taglib. Within that it finds a tag taglib-uri which encloses a name, vijay.
Then it looks at another tag taglib-location, which holds the name of the file
/WEB-INF/jsp/ea.tld. It looks for ea.tld as the details of vijay are stored in
it.
When the server encounters a jsp tag starting with pp, it
looks at one of the earlier lines to check for a uri associated with this tag.
This is done by using the taglib directive where we have given the uri as vijay
and the prefix as pp.
Vijay in web.xml
points to a file named ea.tld. The file ea.tld is not present in the directory
because we didn’t create it. Hence the error.
Create this file in
the location specified in the web.xml file but leave it empty.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\jsp>copy con ea.tld
.............................................leave a blankline press {Enter}
^Z
1 file(s) copied
Shutdown and restart
the Java Web Server. Once again, we get errors again.
Let’s go back and load
d3.jsp
Output in Browser
org.apache.jasper.compiler.CompileException: C:\jakarta-tomcat-3.2.1\webapps\examples\jsp\myprg\d3.jsp(2,0) Unable to open taglibrary vijay : Parse Error in the tag library descriptor: Document root element is missing.
You get the error
since the file ea.tld is empty, although the error does say this. The tld
extension is a short form for tag library description. It is an xml file and
every xml file must begin with xml version=1.0. As of now the only version that
xml understands is version 1.0 . Key in
the following few lines in the tld file to have this error disappear. What we
are now learning are the rules of xml.
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib
PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag
Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
The second line that
contains DOCTYPE taglib.... The word following DOCTYPE - taglib, is the
starting tag or the first tag or the document root. It indicates the beginning and an end of the
xml document. In other words it is the first tag we will encounter. PUBLIC is
some sort of an identifier and the rules of this document are stored in
web-jsptaglibrary_1_1.dtd. These rules decide on the other tags to be allowed
in the document, their order and how many times they can appear. It is like a
syntax check which HTML desn’t have. This also means that we can’t write just
anything in a tld file, it has to follow the rules which are specified in the
dtd. XML is called the eXtensible
Markup Language because it is used to write other markup languages.
These rule are specified through the dtd which is also an xml file
Truncated Output in Browser
org.apache.jasper.compiler.CompileException: C:\jakarta-tomcat-3.2.1\webapps\examples\jsp\myprg\d3.jsp(2,0) Unable to open taglibrary vijay : Parse Error in the tag library descriptor: Element taglib requires additional elements
The error is now
different from the earlier one where
there was no mention of a tag taglib in the file. The document type is
taglib, but it needs more elements and one of them is a tag named pp.
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
</tag>
</taglib>
Truncated Output in Browser
javax.servlet.ServletException: examples/xxx
Root Cause
java.lang.NoClassDefFoundError: examples/xxx
The error tells us
that we need a class named examples.xxx.
The taglibrary is pp
and has the version 1.0 which can be any number that we like. This library has
a tag named log1. The tagclass associated with this name will be loaded or
called when some action has to be taken on the tag. Since we do not have this
class, we get the error.
tagclass refers to the
Java file that contains the code. Since everything is bundled in a package,
xxx.java is included in the package ‘examples; and hence the first line is
package examples;
The directory where
xxx.class would be searched for by default is C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes
and because of the package statement, we have to move down into the examples
sub-directory.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes >cd examples
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>edit xxx.java
xxx.java
package examples;
public class xxx
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
}
The first line is
package examples. This directory will be searched for from the classpath. The
servlet specification says that all your
class files should be in web-inf\classes and all jar files in web-inf\jar.
Hence examples is created in web-inf\classes. Compile the java file and reload
the jsp file in yur browswe. The java file will give you an error.
Truncated Output in Browser
javax.servlet.ServletException: (class: jsp/myprg/_0002fjsp_0002fmyprg_0002fd_00033_0002ejspd3_jsp_0, method: _jspService signature: (Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V) Incompatible object argument for function call
In english, this error
means that we have to derive xxx from some class as there are some functions
which are being called by the Java Web
Server and they do not seem to exist in our
servlet.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>javac xxx.java
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
}
We get 2 errors. The
first one is at the import statement. Whenever we get an error at an import it
means that we have not specified a jar file in our classpath.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>set CLASSPATH=c:\jakarta-tomcat.3.2.1\lib\servlet.jar;%CLASSPATH%
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>javac xxx.java
Now the earlier import
error disappears and we get another one stating that ExampleTagBase cannot be
found. Once again we have to set classpath to the sub directory before
examples, i.e. upto classes.
Set classpath=C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes;%CLASSPATH%
Now javac does not
give us any errors.
If our Java file or
class file has to represent a tag, then it should extend a class that contains
all the code to represent a tag. Hence we have extended xxx from
ExampleTagBase. This class is in the same subdirectory but it in turn refers to
other classes.
In case you don’t see
the same results as we do, then shutdown the server and restart it. Load d3.jsp
in your browser and the Java Web Server dos box will show ‘In Constructor xxx’.
This means that the JSP engine on seeing pp:log1, instantiated xxx. Hence the
constructor is called.
In addition, the View
Source now shows us the following. This proves that the Java Web Server has now
changed the file and then sent it across.
View Source
<html>
<body>
</body>
</html>
A look at the next
program
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return SKIP_BODY;
}
}
This program
implements a function named doStartTag.
The return value is SKIP_BODY. This is a number which we will concern ourselves
with it a little later. In the web server console we will now see two lines of
output which tell us that the function doStartTag is called.
Let’s add one more
function named doEndTag.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return SKIP_BODY;
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
}
The output in the dos
box clearly tells us that at first the JSP engine calls doStartTag and then
doEndTag. This implies that the tags used in the JSP file are calling Java code
in xxx. doStartTag returns SKIP_BODY whereas doEndTag returns EVAL_PAGE. These return
values are numbers or ints. We still do not see any output in the IE window.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
}
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>javac xxx.java
xxx.java:11: Undefined variable: EVAL_BODY_TAG
return EVAL_BODY_TAG;
^
1 error
On compiling, we get
an error. This is because we have used EVAL_BODY_TAG, a variable that the
compiler does not understand. We thought it would exist in ExampleTagBase but
it is a member of BodyTag. To get rid of this error we have to implement an
interface named BodyTag. This is demonstrated in the next example.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
}
When you implement
from an interface, the interface either contains variables that have been given
values or it can contain function prototypes. Since the interface BodyTag also
contains variables, the error disappears. In IE, we see no errors provided we
shutdown the server, move one directory up, deltree work, md work, go back to
bin and then run startup again.
In the next program,
we have added a function named doAfterBody.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx
extends ExampleTagBase
implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
System.out.println(“doAfterBody1 “ );
return SKIP_BODY;
}
}
At first doStartTag is
called and because this function returns EVAL_BODY_TAG, the JSP engine will now
call doAfterBody. But if you replace
EVAL_BODY_TAG with SKIP_BODY, the function
doAfterBody will not be called.
Thus the JSP
engine/Java web server will first call doStartTag and depending on what it
returns it will or will not call doAfterBody.
Tags in html can
either have some content or they can be empty. In our case we have vijay mukhi,
which is our body. This can be retrieved in doAfterBody. Let’s understand how
this is done.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
return SKIP_BODY;
}
}
In order to do this,
use bodyOut.getString in doAfterBody. bodyOut is an object in ExampleTagBase
and getString is a function in bodyOut which returns the string of the body,
which in our case is Vijay Mukhi.
A quick look at d3.jsp
in case you have forgotten
d3.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1>
Vijay Mukhi
</pp:log1>
</body>
</html>
BodyOut is an object
which is an instance of BodyContent. This string will only be dispalyed in the
web server console window. To see it in
the browser, we have to use some more functions like writeOut and getEnclosingWriter()
in bodyOut. These functions throw an exception. Merely saying ‘doAfterBody
throws IOException’ will not work because the signature changes. So, we must
put the code of doAfterBody in a try and catch.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements BodyTag {
public xxx() {
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
try {
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return SKIP_BODY;
}
}
Output in Browser
<html>
<body>
Vijay Mukhi
</body>
</html>
The function
bodyOut.getEnclosingWriter returns an object that looks like java.io.Writer and
bodyOut.writeOut requires a java.io.Writer. writeOut will write the entire body
as an html page. In doAfterBody, you can actually write into your html page
which will then be sent over. Thus, writeOut will actually send the contents
between our tag log1 in our jsp file, which was Vijay Mukhi, over to the web
server.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements BodyTag {
public xxx() {
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
System.out.println(“doAfterBody1 “ );
return SKIP_BODY;
}
public void doInitBody() {
System.out.println(“doInitBody “ );
}
}
As you can see in your
dos box, doStartTag is called first, then doInitBody is called and finally
doAfterBody. This happens because we return EVAL_BODY_TAG in doStartTag.
Since doAfterBody
returns SKIP_BODY, the process terminates. If it were to return EVAL_BODY_TAG
then you would keep seeing Vijay Mukhi indefinitely.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx
extends ExampleTagBase
implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody () {
try
{
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return EVAL_BODY_TAG;
}
public void doInitBody()
{
System.out.println(“doInitBody “ );
}
}
This means doAfterBody
is invoked after each body evaluation. On returning EVAL_BODY_TAG, a new
evaluation of the body will start and it will follow the same procedure i.e.
calling doAfterBody. The entire roller coaster stops it sees get SKIP_BODY.
The JSP engine calls
these function for us to execute certain tasks in them. doInitBody is called
only once and if we have any one time tasks to perform, we place them in
doInitBody. In doAfterBody we receive the content the tag encloses and can
create an html file which will be sent across to the browser.
We have now learnt that
when there is a tag in a JSP file, certain code in the class file gets called.
Note that these tags can also have attributes. The next example deals with an
attribute in the tag.
C:\jakarta-tomcat-3.2.1\webapps\examples\jsp\myprg>edit d4.jsp
d4.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1 aa=”hell”>
Vijay Mukhi
</pp:log1>
</body>
</html>
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements
BodyTag {
public xxx() {
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
try {
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return SKIP_BODY;
}
public void doInitBody() {
System.out.println(“doInitBody “ );
}
public void setAa(String v) {
System.out.println(“setaa “ + v);
}
}
Here, we have an
attribute named aa which is initialized to hell. If we stop here, we will not
get an error even though in ea.tld we have not specified the attributes that
are allowed with our tag log1, and a prefix of pp. In the browser run d4.jsp
and not d3.jsp.
If we remove the
function named setaa from xxx then we will get the following error in our
browser.
Truncated Output in Browser
javax.servlet.ServletException: examples.xxx: method setAa(Ljava/lang/String;)V not found
So in ea.tld, we have
to say attribute /attribute within the tag and within it we specify the name of
our attribute i.e. aa.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\jsp>edit ea.tld
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
<attribute>
<name>aa</name>
</attribute>
</tag>
</taglib>
aa now becomes an
attribute. For it to be an attribute, you need a function named setaa in
xxx.java. This function takes one string as a parameter, named v in this case.
The value of v is hell.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>edit xxx.java
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx extends ExampleTagBase implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
try
{
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return SKIP_BODY;
}
public void doInitBody()
{
System.out.println(“doInitBody “ );
}
public void setaa(String v) {
System.out.println(“setaa “ + v);
}
}
When you see the dos
screen, you will realize that the attributes are called after the constructor.
The value of v is hell, the same value that the attribute had. There is no
getaa in the class file. In a way, this class file resembles a Java Bean that
has a set and a get for the attributes.
A tag can have a subtag named required. When you say that the tag required encloses a value true, then you have to have to have that attribute as part of the tag. It is mandatory and not having it present will get us an error.
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
<attribute>
<name>aa</name>
<required>true</required>
</attribute>
</tag>
</taglib>
d5.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1 >
Vijay Mukhi
</pp:log1>
</body>
</html>
We do not have an
attribute named aa which is mandatory in the ea.tld file.
The error is as
follows
Truncated Output in Browser
org.apache.jasper.compiler.CompileException: C:\jakarta-tomcat-3.2.1\webapps\examples\jsp\myprg\d4.jsp(3,0) According to the TLD attribute aa is mandatory for tag log1
Now that we have
learnt how we can have tags and how a class file is loaded to work with tags,
let’s go back to the basics again.
The class Tag is a
base class. All the other tags are derived from Tag. The class BodyTag adds two
more methods. If you want support tags then you will have to implement Tag.
Let’s start with the smallest one. Here we say public class xxx implements tag.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx implements Tag
{
}
>javac zzz.java
xxx.java:3: class examples.xxx must be declared
abstract. It does not define void release() from interface
javax.servlet.jsp.tagext.Tag.
public class xxx implements Tag
^
xxx.java:3: class examples.xxx must be declared
abstract. It does not define int doEndTag() from interface
javax.servlet.jsp.tagext.Tag.
public class xxx implements Tag
^
xxx.java:3: class examples.xxx must be declared
abstract. It does not define void setPageContext(javax.servlet.jsp.PageContext) from
interface javax.servlet.jsp
.tagext.Tag.
public class xxx implements Tag
^
xxx.java:3: class examples.xxx must be declared
abstract. It does not define javax.servlet.jsp.tagext.Tag getParent() from interface javax.servlet.jsp.tagext.Tag.
public class xxx implements Tag
^
xxx.java:3: class examples.xxx must be declared abstract. It does not define void setParent(javax.servlet.jsp.tagext.Tag) from interface javax.servlet.jsp.tagext.Tag.
public class xxx implements Tag
^
6 errors
On compiling, you will
get 6 errors. You can get rid of the errors by including the word abstract.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public abstract class xxx implements Tag
{
}
But if someone derives
from xxx, he will get errors. Basically, there are 6 functions in tag that have
to be implemented. So, we remove abstract and place these 6 functions one by
one. The 6 functions are: release,
doEndTag, setParent ,getParent, setPageContext
and doStartTag.
d6.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1 >
Vijay Mukhi
</pp:log1>
</body>
</html>
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
</tag>
</taglib>
xxx.java
package examples;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class xxx implements Tag
{
protected Tag parent;
public void release() {
System.out.println(“release”);
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
public void setParent(Tag parent) {
System.out.println(“setParent”);
this.parent = parent;
}
public Tag getParent() {
System.out.println(“getParent”);
return this.parent;
}
public void setPageContext(PageContext pageContext) {
System.out.println(“setPageContext”);
}
public int doStartTag() {
System.out.println(“doStartTag”);
return SKIP_BODY;
}
}
When you open d6.jsp
in the browser you will get the following error
Truncated Output in Browser
javax.servlet.ServletException: examples/xxx
The reason we get the
error is because the jsp engine expects the class to implement from both Tag
and BodyTag.
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>edit xxx.java
xxx.java
package examples;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class xxx implements Tag,BodyTag
{
protected Tag parent;
public void release() {
System.out.println(“release”);
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
public void setParent(Tag parent) {
System.out.println(“setParent”);
this.parent = parent;
}
public Tag getParent() {
System.out.println(“getParent”);
return this.parent;
}
public void setPageContext(PageContext
pageContext) {
System.out.println(“setPageContext”);
}
public int doStartTag() {
System.out.println(“doStartTag”);
return SKIP_BODY;
}
}
C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\classes\examples>javac xxx.java
xxx.java:5: class examples.xxx must be declared
abstract. It does not define void setBodyContent(javax.servlet.jsp.tagext.BodyContent)
from interface javax.servlet.jsp.tagext.BodyTag.
public class xxx implements Tag,BodyTag
^
xxx.java:5: class examples.xxx must be declared
abstract. It does not define void doInitBody() from interface
javax.servlet.jsp.tagext.BodyTag.
public class xxx implements Tag,BodyTag
^
xxx.java:5: class examples.xxx must be declared abstract. It does not define int
doAfterBody() from interface javax.servlet.jsp.tagext.BodyTag.
public class xxx implements Tag,BodyTag
^
3 errors
Once again the error
appears because of the interface.
xxx.java
package examples;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class xxx implements Tag,BodyTag
{
protected Tag parent;
protected BodyContent bodyOut;
protected PageContext pageContext;
public void release() {
System.out.println(“release”);
}
public int doEndTag() {
System.out.println(“doEndTag”);
return EVAL_PAGE;
}
public void setParent(Tag parent) {
System.out.println(“setParent”);
this.parent = parent;
}
public Tag getParent() {
System.out.println(“getParent”);
return this.parent;
}
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
System.out.println(“setPageContext”);
}
public int doStartTag() {
System.out.println(“doStartTag”);
return EVAL_BODY_TAG;
}
public void doInitBody() throws JspException {
System.out.println(“doInitBody”);
}
public int doAfterBody() throws JspException {
System.out.println(“doAfterBody”);
return SKIP_BODY;
}
public void setBodyContent(BodyContent bodyOut) {
System.out.println(“setBodyContent”);
this.bodyOut = bodyOut;
}
}
Output in Server window
setPageContext
setParent
doStartTag
setBodyContent
doInitBody
doAfterBody
doEndTag
release
8 functions are called
in all. The first function that is called is setPageContext. This function
receives a parameter named pageContext. It takes this object that looks like
PageContext and stores it in a public variable of the same name i.e.
pageContext. If we use this.pageContext we are referring to the public
variable. Without this, pageContext refers to
the parameter passed to the function. This is how we initialize the
first of the three public variables in our class. Recall how we used bodyOut
earlier.
The next function to
be called is setParent, which as the name suggests, refers to the parent Tag
which it is passes as a parameter and initializes the public variable parent.
Thereafter, doStartTag
and doEndTag are called and then finally, release is called. getParent doesn’t
ever get called. This is the only function that isn’t called and the order in
which they are called remains constant. In addition, three more functions which
refer to the body are also called. They are doInitBody, doAfterBody and
setBodyContent.
The function
setBodyContent is the one that initializes bodyOut, which we use to reference
our tag. First doStartTag is called and if we returns EVAL_BODY_TAG in this
function, then SetBodyContent, doInitBody and doAfterTag are called.
The exampleTagClass,
which we derived from in the earlier examples has two to three variables -
Parent, bodyOut, pageContext. These were initialized in the functions and were
mandatory in the required classes.
That means if you want
to create your own class then you can name it anything you like. So you don’t
have to use ExampleTagClass. All that you have to do is derive from Tag and
BodyTag and make sure that the functions do what we have done. ExampleTagClass
is useful because we do not want to implement so many functions and we can call
it a helper class.
In doStartTag, if you
return SKIP_BODY, then setBodyContent isn’t called. so you don’t require an
object that looks like BodyContent.
BodyContent is a
subclass of jspwriter. If doStartTag returns SKIP_BODY then none of the tags
from BodyTag will ever be called. It is only if doStartTag returns
EVAL_BODY_TAG that the rest of them are called.
Let’s consider another
set of examples.
We will keep reminding
you that attributes and methods are called before any other function.
Here, we have the same
old tag pp:log1. A JSP tag starts with <% and here we use the same = with a
name memb.
d6.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1 >
Vijay <%= memb %>
</pp:log1>
</body>
</html>
On doing so, you will
get the following error.
Output in Browser
org.apache.jasper.JasperException: Unable to compile
class for JSPC:\jakarta-tomcat-3.2.1\work\localhost_8080%2Fexamples\_0002fjsp_0002fmyprg_0002fd_00036_0002ejspd6_jsp_1.java:79:
Undefined variable: memb out.print( memb );
This is an error
because the jsp engine cannot find a variable named memb.
In our next program,
we have the same doStartTag, doAfterBody, doInitBody and are doing exactly the
same thing as earlier. But we have made an addition; we have added one more
line where we are calling a function pageContext.setAttribute(). So in other
words, we are creating a variable named memb and initializing it to Sonal.
xxx.java
package examples;
import javax.servlet.jsp.tagext.*;
public class xxx
extends ExampleTagBase
implements BodyTag
{
public xxx()
{
System.out.println(“In Constructor xxx”);
}
public int doStartTag() {
System.out.println(“doStartTag1 “ );
return EVAL_BODY_TAG;
}
public int doAfterBody() {
try
{
System.out.println(“doAfterBody1 “ );
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return SKIP_BODY;
}
public void doInitBody()
{
System.out.println(“doInitBody “ );
pageContext.setAttribute(“memb”, “Sonal”);
}
}
You see the same error
as before.
This means that we now
have to go back to our ea.tld file, and introduce a new tag named a
teiclass.
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
<teiclass>examples.yyy</teiclass>
</tag>
</taglib>
yyy.java
package examples;
import javax.servlet.jsp.tagext.*;
public class yyy extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[]
{
new
VariableInfo(“memb”,”String”,true,VariableInfo.NESTED)
};
}
}
>javac yyy.java
In the yyy class,
which is derived from the TagExtraInfo tag, we once again start with the
package examples. Class yyy extends TagExtraInfo. getVariableInfo is a member
of this class, which returns an array of VariableInfo. Here, we’re returning an
object that looks like an array of VariableInfo. Instead of giving a semicolon
to end the statement, we are giving an open curly bracket. At this point, we
are creating the array VariableInfo and initializing it at the same time. The
syntax is important. Since it is an array, you can say new as many times as you
want, one below the other for each member of the array. Here, we are creating
memb, a variable of type string, and VariableInfo.NESTED indicates that it is
nested one within the other. It will display Vijay Sonal in the browser and in
the Java Web Server, and of course no errors!
What if, in
doStartTag, we give pageContext.setAttribute(“memb”, Sonal2") and in
doAfterBody we give pageContext.setAttribute(“memb”, Sonal3"), as shown
below.
public int doStartTag() {
System.out.println(“doStartTag2 “ );
pageContext.setAttribute(“memb”, “Sonal2”);
return EVAL_BODY_TAG;
}
public int doAfterBody() {
try
{
System.out.println(“doAfterBody1 “ );
pageContext.setAttribute(“memb”, “Sonal3”);
String s = bodyOut.getString();
System.out.println(s);
bodyOut.writeOut(bodyOut.getEnclosingWriter());
}
catch (Exception e) {}
return SKIP_BODY;
}
We have initialized
memb in three differnet places. Yet we see Sonal. The doStartTag function is
called right at the beginning. Here, memb should have been initialized to
Sonal2, but it is in doAfterBody that we say bodyout.write. doAfterBody has a
setattribute too. In such a case, doAfterBody has no effect. Therefore, as the
setattribute in doafterbody is ignored, Sonal will be displayed. Hence you
should not use setAttribute everywhere as it will be ignored.
NESTED is the scope
for the variable. If you say nested then the variable is available between the
start and the end tag. If you change nested to AT_BEGIN, then it is available
from that tag to the end of the page. But if you use AT_END, then it is
available from the end of the tag to the end of the page.
In the following
example, we have used memb twice.
d8.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<pp:log1>
Vijay <%= memb %>
</pp:log1>
<p> Vijay1 <%=memb %>
</body>
</html>
xxx.java remains the
same as before
yyy.java
package examples;
import javax.servlet.jsp.tagext.*;
public class yyy extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[]
{
new
VariableInfo(“memb”,”String”,true,VariableInfo.NESTED)
};
}
}
Truncated Output in Browser
org.apache.jasper.JasperException: Unable to compile
class for
JSPc:\jakarta-tomcat-3.2.1\work\localhost_8080%2Fexamples\_0002fjsp_0002fmyprg_0002fd_00036_0002ejspd6_jsp_1.java:109:
Undefined variable: memb out.print( memb );
If you use NESTED,
then you will get an error as shown above.
yyy.java
package examples;
import javax.servlet.jsp.tagext.*;
public class yyy extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[]
{
new
VariableInfo(“memb”,”String”,true,VariableInfo.AT_BEGIN)
};
}
}
Output in Browser
Vijay Mukhi Sonal
Vijay1 Sonal3
In the Server Window
Vijay Mukhi Sonal
AT_BEGIN means that
they are now 2 different values to the same variable memb.
yyy.java
package examples;
import javax.servlet.jsp.tagext.*;
public class yyy extends TagExtraInfo
{
public VariableInfo[] getVariableInfo(TagData data)
{
return new VariableInfo[] {
new VariableInfo(“memb”,”String”,true,VariableInfo.AT_END)
};
}
}
When we use AT_END we
will get the same error as before
The scope of a
variable decides where the variable will be created and where it will be
allowed.
Our next few examples
will further expand on this concept.
d9.jsp
<html>
<body>
<%@ taglib uri=”vijay” prefix=”pp” %>
<ul>
<pp:log1 att1=”98.5" att2=”92.3" att3=”107.7">
<li><%= memb %></li>
</pp:log1>
</ul>
</body>
</html>
ea.tld
<?xml version=”1.0" ?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN” “http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>pp</shortname>
<tag>
<name>log1</name>
<tagclass>examples.xxx</tagclass>
<teiclass>examples.yyy</teiclass>
<bodycontent>JSP</bodycontent>
<attribute>
<name>att1</name>
<required>true</required>
</attribute>
<attribute>
<name>att2</name>
<required>true</required>
</attribute>
<attribute>
<name>att3</name>
<required>true</required>
</attribute>
</tag>
</taglib>
xxx.java
package examples;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import java.util.Hashtable;
import java.io.Writer;
import java.io.IOException;
public class xxx extends ExampleTagBase implements
BodyTag
{
private String atts[] = new String[3];
int i = 0;
public void setAtt1(String value) {
System.out.println(“setAtt1 “ + value);
atts[0] = value;
}
public void setAtt2(String value) {
System.out.println(“setAtt2 “ + value);
atts[1] = value;
}
public void setAtt3(String value) {
System.out.println(“setAtt3 “ + value);
atts[2] = value;
}
public int doStartTag() throws JspException {
System.out.println(“doStartTag “);
return EVAL_BODY_TAG;
}
public void doInitBody() throws JspException {
System.out.println(“doInitBody “);
pageContext.setAttribute(“memb”, atts[i]);
i++;
}
public int doAfterBody() throws JspException {
System.out.println(“doAfterBody “ + i);
try {
if (i == 3) {
bodyOut.writeOut(bodyOut.getEnclosingWriter());
return SKIP_BODY;
} else
pageContext.setAttribute(“memb”, atts[i]);
i++;
return EVAL_BODY_TAG;
} catch (IOException ex) {
throw new JspTagException(ex.toString());
}
}
}
yyy.java
package examples;
import javax.servlet.jsp.tagext.*;
public class yyy extends TagExtraInfo {
public VariableInfo[] getVariableInfo(TagData data) {
return new VariableInfo[] {
new VariableInfo(“memb”,”String”,true,VariableInfo.AT_BEGIN)
};
}
}
Output in Browser Window
* 98.5
* 92.3
* 107.7
Lets sum up everything
now. Nearly everything remains the same. At first, let’s take a look at the jsp
file. As usual we have tags like html and then body. Here log1 has a prefix pp
and it has three attributes; att1, att2 and att3 with values 98.5, 92.3 and
107.7 respectively. The <ul> tag is to display an unordered list and it
needs <li> which stands for the start of the list and </li> means
the end of the list. These tags i.e. ul and li are only meant for ornamental
purposes. Memb is a variable which is enclosed in % and angle brackets i.e. it
is a jsp tag.
As we have memb and 3
attributes, we should change the tld file to include these attributes. The
attributes and methods have the first preference. Hence the setAtt1, setAtt2
and setAtt3 functions will be called first. These three functions accept only
one string parameter. We have created an array atts of type String. In these
functions, we are initializing the array atts to the values passed on to the
Java program by jsp. Since this is done
first, before any other function is called, you will see setAtt1, setAtt2 and
setAtt3 with their values displayed using System.out.println in you server dos
screen.
Once this is done, the
next function to be called is doStartTag. This function displays ‘doStartTag’
and then we return EVAL_BODY_TAG. It is because of this return value that the
JSP Engine now calls doInitBody.
In this function, the
value of i is 0 and we then call pageContext.setAttribute. This creates memb as
a variable and initializes it to the value stored in atts[0]. The value of i is
incremented by 1 and the next function to be called is doAfterBody. Here, we
check whether the value of i equals 3. As this condition evaluates to false,
the else is called. Now pageContext.setAttribute will initialize memb to the
value in atts[1]. Again the value of i is incremented but now we return
EVAL_BODY_TAG. This will call doAfterBody once again and since the if condition
is false again, it will initialize memb to the value in atts[2]. On adding 1 to
i, ii now becomes 3. EVAL_BODY_TAG will call doAfterBody once again. Now the
value of i is 3, so the function bodyOut.writeOut(bodyOut.getEnclosingWriter())
will write these values of memb on the browser screen and return SKIP_BODY.
Thus it will now skip the body functions.
In this example,
comment out the i++ and then see the results. Remove the comments and you will
understand the flow of doAfterBody.