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.


Contents | Foreword | About the Authors | Introduction |
Appendix |Chapter 1 |Chapter 2 |Chapter 3 |Chapter 4 |Chapter 5 |Chapter 6 |
Chapter 7 |Chapter 8 |Chapter 9 |Chapter 10 |Chapter 11