3. Java Servlets

Introduction

Jakarta-Tomcat is the official reference implementation of the Java Servlet 2.2 and Java Server Pages technologies. Developed under the Apache license in an open and participatory environment, it is intended to be a collaboration of the best-of-breed developers from around the world.

Jakarta-Tomcat is a servlet container. Servlets are memory-resident Java programs, running inside a servlet container.

Installing Jakarta-Tomcat

Jakarta-Tomcat can be installed by downloading jakarta-tomcat-3.2.1.zip from the jakarta.apache.org site. This zip file is approximately 3 MB large. On unzipping this file, it will create a subdirectory called jakarta-tomcat-3.2.1, all the files will be installed in this subdirectory. On our machine, we have extracted this file to the root i.e. C:\. This assumes that you have downloaded version 3.2.1. By the time this you read this, version 4 will be out and all subdirectory names will change accordingly. However, all the programs should work in the same way.

Change to the bin directory in c:\jakarta-tomcat-3.2.1 and run the batch file 'startup'. This will open up a window and on your dos screen you will see the following statements:
C:\jakarta-tomcat-3.2.1\bin>startup
Starting tomcat in new window
Using classpath:
c:\jakarta-tomcat-3.2.1\classes;c:\jakarta-tomcat-3.2.1\lib\webserver.jar;c:\jakarta-tomcat\lib\jasper.jar;
c:\jakarta-tomcat-3.2.1\lib\xml.jar;c:\jakarta-tomcat-3.2.1\
lib\servlet.jar;c:\jdk1.2.2\lib\tools.jar;c:\jakarta-tomcat-3.2.1\lib\servlet.jar;c:\jswdk-1.0.1\lib\jspengine.jar;.;
C:\jakarta-tomcat-3.2.1\bin>

If you donot see the output as shown above, edit the startup.bat file and add these two lines at the beginning.
set JAVA_HOME=c:\jdk1.2.2
set TOMCAT_HOME=c:\jakarta-tomcat-3.2.1

In this chapter, we will build some simple servlets. This will help demonstrate the power and flexibility of the Java platform.

Servlets are at the frontline of Java web application development. They provide an easy way for server side code to communicate with web-based clients. In simple words, they are programs that run on a Web server and build Web pages.

startup is a batch file that will start the Java Web server. Minimize the screen and activate another DOS box. Change to the jakarta-tomcat-3.2.1 directory and then go to webapps. From this directory go to examples, then web-inf and then go to classes.

C:\jakarta-tomcat-3.2.1> cd webapps\examples\web-inf\classes

All the programs that you key in will be stored in this subdirectory.

C:\jakarta-tomcat-3.2.1\webapps\ examples\web-inf\classes >

In this subdirectory, create a file called zzz.java containing the following 3 lines.
zzz.java
public class zzz extends HttpServlet
{
}

On compiling, javac gives an error because the extended class is javax.servlet.http.HttpServlet and not HttpServlet.

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java

zzz.java:1: Superclass HttpServlet of class zzz not found.
public class zzz extends HttpServlet
^
1 error

Since we don't want the name to be lengthy, we will use the import statement. Doing so will get rid of the error.

If you do get an error, make sure the CLASSPATH variable has c:\jakarta-tomcat-3.2.1\lib\servlet.jar as one of the directory paths.

The code for applet.class is in some jar file and by default javac looks for it. Unfortunately, it could not find the code of javax.servlet.http.HtttpServlet and thus you got an error. The code for javax.servlet.http.HttpServlet is in servlet.jar which is in the lib subdirectory. A jar file is collection of .class files. Once you set the classpath correctly, javac looks at the jar file specified to see if it contains the required .class file. ClASSPATH is an environmental variable and it may have already been set to a certain path. To avoid overwritting the original information, we say %CLASSPATH%. Our modifications will now be added to the begin of the list.

We have given the CLASSPATH command as

C:\jakarta-tomcat-3.2.1\webapps\examples\WEB-INF\
classes>set CLASSPATH=c:\jakarta-tomcat-3.2.1\lib\servlet.jar;
%CLASSPATH%

zzz.java
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
}

Start any browser, it can be Internet Explorer or Netscape, and give the address as http://127.0.0.1:8080. First let's understand what this means. You are probably aware that every phone has a unique phone number. Similarly, every computer on the Net has a unique number. We can't just call it a number, so we call it an IP address. For example, the Microsoft site, like all other sites, has a unique IP address. If each computer on the Net were not identifiable by an IP address then we would not be able to connect to them. Each machine also has a common IP address 127.0.0.1 and can be represented as 'localhost'. You use this number to refer to your machine. Both 127.0.0.1 and localhost are the same. Since the address we're typing in is 127.0.0.1, it means that both the client and the server are running on the same machine.

Now, you may need to have ftp, email and http servers. That however, doesn't mean that you need a separate machine for each of them. Each packet on the internet has a number. For example, 25 is for email, 80 is for http. So, instead of separate machines, we have separate ports. These packets can be intercepted at the respective ports and passed on to the relevant server. Every server runs on a particular port. Just as the http server runs on port 80 and a smtp server runs on port 21, the Java Web server runs on port 8080. In case you want to change the port number or the original settings of the server, you can do so by giving various options to startup. Since we are not interested in doing this, we will simply use 8080.

After giving address:port, give /examples/servlet/ followed by the name of the class file, which is zzz. When you write /examples/servlet/, it is automatically converted to c:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes which is where Java will look for the zzz class file. This is known as url mapping. In effect, you are mapping from a logical url to a physical directory.
http://127.0.0.1:8080/examples/servlet/zzz

So when you say /examples/servlet/, the Java web server takes the /examples/servlet/ and maps it to a path on the hard disk. Then it picks up the file zzz.class from the directory. Unfortunately, you will see a screen with an error 'saying HTTP method GET is not supported by this URL.

If you look at the server DOS box, it displays a similar error. This obviously implies that we have done something wrong or a lot more must be added to get the servlet to work.

Add a function named doGet to zzz.java. This function receives two objects as parameters, req and res. req looks like HttpServerRequest and res looks like HttpServerResponse. They are to be found in HttpServlet.

zzz.java
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
}
}

Compile this program and you will get no error. By merely adding this one line, you will find that the error vanishes. Now we don't get an error because the server can now call the doGet function. The server looks for a doGet function in the class file and since there was no such function, we got the error. When zzz is loaded in the browser, it displays a blank screen (no error). In Internet Explorer, click on View and select Source, you will see html tags.

View - Source
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY><XMP></XMP></BODY></HTML>

We obviously didn't give these tags in our program. Hence it is assumed that the Java Web server created these tags and gave it to the browser.

A small piece of advice: Create a new servlet each time i.e. give a new file/class otherwise the browser takes it from the cache. Since the servlet is present in memory, even when you make changes in your program file there is no effect as the program output is picked up from the cache. Alternatively, you can use zzz for all your programs, but then after every change you will have to stop the server and then restart it. We will stick to zzz.

The Web Server is another name for the File Server. The web server is expected to send an html file over. Create an html file z.html in c:\jakarta-tomcat-3.2.1\webapps\root and type the following.

c:\jakarta-tomcat-3.2.1\webapps\root>edit z.html
z.html
Hi
Bye

Now view it in the browser by typing

http://127.0.0.1:8080/z.html

You will see Hi and Bye displayed in the browser window. So the web server sends z.html over to the browser. However, all of this is static. What we need are dynamic pages. We need someone who will dynamically generate the html files. To do so, the web server calls another program that processes the input and creates an html file. This is called CGI Programming. The web server simply sends the generated html file across to the browser.

Let's look at the next program and see what it displays.
zzz.java
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
System.out.println("<b>Bye");
}
}

In the earlier chapters, we learnt about System.out.println. Here we are giving <b>Bye as a parameter to this function. When you run the servlet,(remember to stop the server and then start it again) you will see a blank screen as before. View Source shows the same html file. But if you look at the server dos box it will show you <b>Bye.

System.out.println prints in the dos box. This proves that the function doGet is indeed being called by the web server.

We need to send an html file accross. Unfortunately, println displays its output in the dos box. So, let's see how the servlet gives the web server an html file so that it can send it to the browser.

zzz.java
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
PrintWriter out;
out = res.getWriter();
out.println("<b>Bye");
}
}

C:\jakarta-tomcat-3.2.1\webapps\ WEB-INF \examples\web-inf\classes>javac zzz.java
zzz.java:6: Class PrintWriter not found.
PrintWriter out = res.getWriter();
^
zzz.java:6: Exception java.io.IOException must be caught, or it must be declared
in the throws clause of this method.
PrintWriter out = res.getWriter();
^
2 errors

This program creates a variable 'out' which looks like PrintWriter. It also uses res, a parameter passed to doGet, which looks like HttpServletResponse. res has a member named getWriter which returns an object that looks like PrintWriter. PrintWriter has a member named println and hence the next line says out.println. This function is similar to System.out.println in terms of syntax. With System.out.println, 'out' was a member of System, but here out is a member of the PrintWriter class. The only problem here is that the name is not PrintWriter and hence we get all these errors.

Printwriter is not part of javax.servlet.http.HttpServlet but of java.io. Its full name is java.io.PrintWriter. So we add the import statement as shown below.
zzz.java
import java.io.*;
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
}
Here, getWriter throws an IOException. This exception is thrown when it cannot create an object like PrintWriter. The error is shown below. We won't talk about errors any more, instead we'll say that an exception occurred. To handle the exception, we have to catch it.

C:\jakarta-tomcat-3.2.1\ webapps \examples\web-inf\classes>javac zzz.java

zzz.java:7: Exception java.io.IOException must be caught, or it must be declared in the throws clause of this method.
PrintWriter out = res.getWriter();
^
1 error

We now have to use try and catch in order to handle the exception.

zzz.java
import java.io.*;
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
try
{
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
catch (Exception e){}
}
}

Note that we have given "<b>Bye" to out.println. This is because <b> in html means bold. We want Bye to be displayed in bold letters and the <b> tag will allows us to do that.

We are not catching the IOException exception thrown by getWriter but instead are catching Exception. We are using Exception because it catches all the exceptions that can ever occur. There is a possibility that getWriter may throw two different exceptions; in that case you will have to catch both of them with separate try-catchs. The right way to catch exceptions is to have a separate try and catch for every function that throws an exception. We are however, using a single try block for all the statements so that we don't have to worry about the exceptions that occur.

Now, run the program from the browser. Great! Finally, you get to see Bye on the screen! Click on View source and it will give you <b> and Bye.

View Source
<b>Bye

Let's say we have a file a.html. When the web server sends a file over, it actually first sends some data and then the html file. This initial data is called a header. The first line of the header in most cases is

HTTP/1.0 200 OK.

HTTP stands for the hyper text transfer protocol. A protocol is a set of rules. The http protocol specifies how a browser communicates with a web server. It decides on issues like port nos to be used for communication, the error codes and what they mean and so forth. All web servers follow the http protocol.

zzz.java
import java.io.*;
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
try
{
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
catch (Exception e){}
}
}

View Source
<b>Bye

A header is always sent along with an html file. The browser knows about the type of the document being received by looking at the header. Thus, if the browser finds that the header says text/plain then it will display the text as it is. If it sees that the header has text/html then it will display the text in the html format. Since we did not set the header for Content-Type earlier, it was assumed to be text/html.

In this program, we have res and req. To receive something from the client we use req and to send something to the browser we use res.

res has functions that lets you send something to the web server. That content then has to be passed to the browser. res, that looks like HttpServletResponse, has a function named ContentType which by default is set to text/html. Here we change it to text/plain. So we have added res.SetContentType("text/plain") in the above program. The actual header that is generated looks like this.

Content-Type: text/plain

A header is sent before the actual data and it consists of words which end in a colon. These words describe the rest of the html file being sent across. Text/plain is called a mime type. Content-Type is a header which tells the browser the nature of the file being sent across. If it said image/gif, then the browser would know that it is receiving a picture file which has a gif file format.
Even though, in the program, we did not specify any headers, the java web server sends a large number of them over. We have the option of changing the values of these headers and to also send our own.

Once the browser knows that the text coming in is an html file, it interprets <b> and displays the remaining text in bold. It works perfectly and as advertised, hence the Bye becomes bold.

You can change it back to text/html if you like. But it is not necessary as the default is text/html.

zzz.java
import java.io.*;
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
try
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
catch (Exception e){}
}
}

These programs that we have been writing so far are called Servlets. Why so? Well because they are derived from HttpServlet. A servlet is a class which is derived from HttpServlet.

In chapter 2, we covered exception handling and learnt new words like try and catch. Most of you may not like using try and catch, so Java gives us an option to use the 'throws' clause instead. There are a number of ways of doing the same thing. Here, we have used throws as part of the function syntax because you may see it in other books and it may confuse you. It is just an alternative to try and catch.

To use the throws clause, use the word throws followed by the exception. The function doGet, in the following example, says throws IOexception. Hence, you don't have to put a 'try-catch' within the code for the functions throwing exceptions.

zzz.java
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML> <b>hi </HTML>");
out.close();
}
}

Here, in out.println we have included the <HTML> </HTML> tag. Normally, html code is written within the html tag. Since html is forgiving, it doesn't matter if you choose not to include these tags. That's the reason we got away with it in our earlier program.

It is good programming practice to close a file and if you don't, it is closed by default. out.close closes the newly generated file. If you run this from the browser, it will dispaly 'hi' in the browser window.

View Source
<HTML> <b>hi </HTML>

When we want to dynamically generate html files, we use programs written in C, Perl, Java etc. Perl is an interpreted language and so it is very slow. Java servlets stay in memory and are thus quite fast. Perl as a program is called each time the program needs to be run. Perl runs, generates a file and then quits. If a Perl program is required to connect to a database, maybe to retrieve data and then disconnect, imagine the amount of time involved to complete the transaction!. This CGI program is great if it is for a few connections but not for a million connections.

Servlets are not removed from memory. To prove this, all that we do in the next program is, display the value of i, which is a variable created outside a function.

zzz.java
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
int i = 0;
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
i++;
out.println("<HTML> hi " + i + " </HTML>");
out.close();
}
}

Here we are incrementing i by 1 in the function doGet. The first time that doGet gets called, i will be incremented by 1, and then each time you click on Refresh, it will keep incrementing by 1. This proves that the code is memory-resident. This is one of the reasons why you need to stop your server and then restart it if you want to use the same servlet. Also try using a fresh copy of IE or Netscape and you'll notice that the value of i is retained across browsers. Hence if it is 3 in the first copy, clicking on Refresh in the second will make it 4 and then clicking on Refresh in the first copy makes it 5. Thus, we can see that servlets never get removed from memory.
The web server sent Content-Type as one of the headers to the web browser. Similarly, there are headers that are sent by the web browser to the web server. To figure out what these headers are, HttpServletRequest is given as a parameter to doGet.

zzz.java
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML>");
out.println( "Request method : " + req.getMethod()+"<p>");
out.println( "Request URI : "+ req.getRequestURI()+"<p>");
out.println( "Request protocol : "+ req.getProtocol()+"<p>");
out.println( "Servlet path : " + req.getServletPath()+"<p>");
out.println( "Path info : " + req.getPathInfo()+"<p>");
out.println( "Path translated : " + req.getPathTranslated()+"<p>");
out.println( "Query string : " + req.getQueryString()+"<p>");
out.println( "Content length : " + req.getContentLength()+"<p>");
out.println( "Content type : " + req.getContentType()+"<p>");
out.println( "Server name : " + req.getServerName()+"<p>");
out.println( "Server port : " + req.getServerPort()+"<p>");
out.println( "Remote user : " + req.getRemoteUser()+"<p>");
out.println( "Remote address : " + req.getRemoteAddr()+"<p>");
out.println( "Remote host : "+ req.getRemoteHost()+"<p>");
out.println( "Authorization scheme : " + req.getAuthType()+"<p>");
out.println("getCharacterEncoding:" + req.getCharacterEncoding()+"<p>");
out.println("getScheme: " + req.getScheme());
out.println("</HTML>");
out.close();
}
}

In Internet Explorer, the functions returned the following values:
Request method : GET
Request URI : /examples/servlet/zzz
Request protocol : HTTP/1.1
Servlet path : /servlet/zzz
Path info : null
Path translated : null
Query string : null
Content length : -1
Content type : null
Server name : 127.0.0.1
Server port : 8080
Remote user : null
Remote address : 127.0.0.1
Remote host : 127.0.0.1
Authorization scheme : null
getCharacterEncoding:null
getScheme: http

To understand all these headers, you have to go to the relevant RFC (Request For Comments). RFC's are internet standards. The RFC will tell you what each one of the headers is all about. There are thousands of RFCs on the net so you will have to find and read the RFC about the HTTP protocol.

Thus, the servlet knows about the server and user's data from the headers sent in by the server.

Type in the next program as given and in the browser address bar type the url as:

http://127.0.0.1:8080/examples/servlet/zzz?pqr=abcd

zzz.java
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
String aa;
aa = req.getParameter("pqr");
out.println("<HTML>");
out.println( "pqr is " + aa);
out.println("</HTML>");
out.close();
}
}

getParameter is a function in HttpServletRequest. To this function, a parameter pqr is given. req.getParameter removes the = sign and assigns the value of pqr ie abcd to aa. In the url, we've given pqr=abcd, so the string aa becomes abcd.
pqr is abcd

This is how the servlet can figure out what the user has typed. If instead of abcd you had initialized pqr to abcd xyz then aa would return abcd xyz.

Once you press enter, the screen will show pqr as abcd, but if you look at the address bar, it will display %20 in the place of a space. At times instead of a '%' sign it may also show a '+' sign. All the reserved characters get converted to ascii but in hexadecimal. The RFC forbids you to use certain characters like spaces so they are encoded as '+' or '%'. Since we can't use reserved characters in a url, they have to be replaced with their hexadecimal equivalent. To sum up , if you use the reserved characters in a URL, then as specified in the RFC, they are converted to hexadecimal characters.

Now, if you want to search for some word in a search engine, you will type that word in the text box provided and press enter. The search engine will search its database for that word and provide a list of all the sites that are related to it. This list will then be passed on to a program which will generate an html file.

Let's create an html file where you can enter some text in a text box. Remember webapps\root is where you create the file.

>edit a.html

a.html
<form action="http://127.0.0.1:8080/aa.html">
<input type=text name=pqr>
<input type=submit value=search>
</form>

Form is the tag used for creating a form in html. input type=text specifies that we want to create a text box and the name of that text box is pqr. So, this will dispaly a simple text box.

Type the following in the address bar

http://127.0.0.1:8080/a.html

Now type 'abcd' in the text box and press enter or click on search. Take note of the url in the address bar. It says

http://127.0.0.1:8080/aa.html?pqr=abcd

Earlier, we typed a similar url ourselves in the address bar. Now we are generating it through the html file. Ignore the error that you see in the browser window.

Now edit your a.html file to match the following

a.html
<form action="http://127.0.0.1:8080/aa.html">
<input type=text name=pqr>
<input type=text name=aa>
<input type=submit value=search>
</form>

Here, we have an additional text box called aa and a button called submit.
Excecute it from the browser. Type abcd in the first text box and efgh in the second. Now click on the submit button. It will display for you the following url

http://127.0.0.1:8080/aa.html?pqr=abcd&aa=efgh

Thus you can have many name value pairs in the url, each seperated by &, after the '?'.

In all these programs, we have been seeing the parameters in the url. We now have a servlet which takes these values and displays them in the browser. So, lets rewrite the servlet and compile it and then create a small html file that does this for us.

zzz.java
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
String aa,bb;
aa = req.getParameter("pqr");
bb = req.getParameter("xyz");
out.println("<HTML>");
out.println( "pqr is " + aa + " xyz " + bb);
out.println("</HTML>");
out.close();
}
}

If you are using many values in the address line, use getParameter as before. As long as you know the name of the textbox, you can get the related value without a problem.

b.html
<html>
<b>Test</b>
<form action="http://127.0.0.1:8080/examples/servlet/zzz" method="get">
<input type=text name="pqr">
<input type=text name="xyz">
<input type=submit value="Click...">
</form>
</html>

Save the html file in c:\jakarta-tomcat-3.2.1\webapps\root. In the browser enter the url as
http://127.0.0.1:8080/b.html

In the text boxes, type in 'hi' in the first one and 'bye' in the second. When we click on the button labeled Click, a new screen similar to the one seen before emerges in the window. Our program, zzz, gets called. This is because we specified it in action. Also, we have specified method=get. When we use get, whatever you type in the text box, along with its name, becomes a part of the url. Give the method as post and you will see that the fields are not sent as a part of the url. They are sent separately. We will explain get and post later.
Note the url in the address bar

http://127.0.0.1:8080/examples/servlet/zzz?pqr=hi&xyz=bye

zzz generates an html file depending on what we type in the text boxes. req.getParameter picks up the values for the names specified.

pqr is hi xyz bye

What we have been trying to explain is called CGI Programming. CGI stands for Common Gateway Interface. It specifies how data is transferred from the browser to the web server and vice-versa. When we visit a site, it may ask us to fill up a form. The data we key in is sent to the server as name value pairs. The name is the name of the text box and the value is what we key in the text boxes.

The next program is a little lengthier.

zzz.java
import java.io.*;
import javax.servlet.http.*;
import java.util.Properties;
import java.util.Enumeration;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
Properties props;
props= System.getProperties();
PrintWriter out=res.getWriter();
Enumeration enprop= props.propertyNames();
String key="";
while (enprop.hasMoreElements())
{
key=(String)enprop.nextElement();
out.println("<p>");
out.println(key+"="+props.getProperty(key));
out.println("<p>");
}
out.println("<p>----------<p>");
props.list(out);
}
}

This program uses a function named System.getProperties. System is a class and it is something that Java gives us for free. In our earlier programs, we worked with an object named out. Here, we have getProperties which returns an object that looks like Properties. It is similar to the 'out' object. This value is stored in a variable called props that looks like Properties. The Java Web Server has a large number of properties. We intend to list all of them.

A property is a name and an associated value.When you say aa=bb, aa is the name of the property, bb its value.You can have hundreds of such properties. As the name of the property changes, the value changes too. What you need to do for one, you need to do for all. Since we want to access all properties and are not aware of the number, we use an Enumeration.

An Enumeration represents an array, enumeration means more than one of the same thing. Ten people become an enumeration. What can be done with one can be repeated for all ten. So, an enumeration is like a for statement where you simply repeat.

We need an object that looks like an Enumeration, props.propertyNames() returns a similar object. This object is stored in a variable called enprop. enprop denotes all the property names. Many functions return an Enumeration. Any Enumeration has a member function named hasMoreElements.

Assuming there are ten property names, the while loop will go on ten times. The function will return true when there are more elements, otherwise it will return false. nextElement will give the next element. The variable named key, which looks like a string, will be equal to the return value of enprop.nextElement. Note that nextElement may return a string or a number but key is a string. We have given (String) so that no matter what nextElement returns it is cast to a String and given to key. Remove (String) and you will get an error saying you need to cast it to a String. But what does enprop.nextElement return? It returns the property name. We can retrieve the property name only if the property exists. Hence the presence of the property is checked first.

If the first property is named aaa, which has the value 'vijaymukhi', then enprops.nextElement will return aaa which will be stored in key and getproperty("aaa") will be its value which is vijaymukhi. So the Enumeration will give all the names and getProperty will get its value.

You may not want to get into all these details. Alternatively, props has a member called 'list' to which you can give the variable 'out'. This will give you a similar listing. Thus in Java, whenever there is a name=value pair and there are a number of such pairs, this method can be used to access all of them.

Enter the url as http://127.0.0.1:8080/servlet/zzz and it will display an output which is too large to be dispalyed.

In the following program we have used a function called getParameterNames which gives us the names of the parameters.
Giving the url as http://127.0.0.1:8080/examples/servlet/zzz?aa=bb&cc=dd indicates that the parameter names are aa and cc and the values are bb and cc respectively. It is similar to the earlier examples. getParameterNames also returns an Enumeration. In our earlier program, we used getProps. If you have ten words like aa=bb,cc=dd etc. you will have that many name and value pairs. The while loop here remains the same.

zzz.java
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("Parameters:<p>");
Enumeration pNames = req.getParameterNames();
while (pNames.hasMoreElements()) {
String name = (String) pNames.nextElement();
String[] val = req.getParameterValues(name);
out.println(" " + name + ":");
for (int i = 0; i < val.length; i++) {
out.println(" " + val[i] + "<p>");
}
}
}
}

The req.getParameterNames returns a string. The value is not a single value but an array of strings. Hence we have used val.length to find the number of members in the array. The for loop allows us to display them.


Whenever we have more than one name/value pair, the function returns an enumeration which then uses the same while loop to display all the multiple values. Enumeration makes the programmers life easier.

In the same way, we can get the header names and cookies. Thus, even though you don't know about cookies as yet you are able to do this.Cookies have been dealt with in one of our chapters further on.

zzz.java
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("Request headers:");
Enumeration hNames = req.getHeaderNames();
while (hNames.hasMoreElements()) {
String name = (String) hNames.nextElement();
String value = req.getHeader(name);
out.println(" " + name + " : " + value);
out.println("<br>");
}
out.println();
out.println("Cookies:");
Cookie[] cookies = req.getCookies();
for (int i = 0; i < cookies.length; i++) {
String name = cookies[i].getName();
String value = cookies[i].getValue();
out.println(" " + name + " : " + value);
}
}
}

Output
Request headers: Accept-Language : en-us
Connection : Keep-Alive
User-Agent : Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; COM+ 1.0.2204)
Host : 127.0.0.1:8080
Accept-Encoding : gzip, deflate
Accept : */*
Cookies:

Since we don't have any cookies at present, we don't see anything. If you have understood the earlier example then this one will be a cake walk. It is basically for accessing multiple things that are similar.

We also see the list of headers we are being sent by the browser.

In servlets, you can do anything you want. You can pick up an html file from your hard disk and send it over or go to another site on the net, pick up an html file from there and send it across. Let's see how the second method works.

zzz.java
import javax.servlet.http.*;
import java.io.*;
import java.net.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException
{
URL u;URLConnection c;InputStream n;DataInputStream d;String s;
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<HTML>");
out.println("<head><title>Hello World</title></head>");
out.println("<body>");
out.println("<h1>Hello World</h1>");
try {
u=new URL("http://www.vijaymukhi.com");
c = u.openConnection();
n = c.getInputStream();
d=new DataInputStream(n);
while ((s=d.readLine()) != null )
out.println(s);
n.close();
}
catch(Exception x){}
out.println("</body></html>");
out.close();
}
}

This program retrieves a page from the net and sends it to the browser. Let's understand the mechanics of it.

A url identifies a resource. So 'new URL' takes a string, a site address or a url and returns an object that looks like URL. Here we have given our site address, so make sure that you are connected to the Internet.

The object that looks like URL has a function named openConnection. 'u' is just the form of the url. It is broken up into protocol, portno, address parameter and other things like that. It actually uses the TCP protocol to physically connect to the webserver and returns an object that stands for the connection. That is why c is not a URL, but an object that looks like a URLConnection.

Now we need to read and write to this connection. The getInputStream function of URLConnection returns an object that looks like InputStream from where you can read stuff. The only problem is that the InputStream is too low level. To read data from this stream, an object that looks like DataInputStream is created. The developers of Java could have stopped at InputStream but they want us to use DataInputStream. You must be asking yourself useless questions like 'Why'? Don't torture yourself with the unnecessary!

DataInputStream has functions like readLine, which returns data one line at a time. When there are no more lines to return, it returns a null. Once some data is received, out.println is used to display it in the browser and the stream is then closed. One of the functions throws an exception and we catch the exception so that the program ends normally.

An applet is a Java program that runs within your browser. The browser has an applet engine which executes the code coming in from across the net. A servlet is also a Java program but it executes on the server. Unlike the browser, the server doesn't execute a servlet but instead calls a program named the Servlet Engine. This program executes the Java code. Just as an applet must be derived from Applet, a servlet must be derived from Servlet.

The whole idea behind servlets is that the Servlet Engine executes Java code, which creates the html file and gives it to the web server. The web server then sends it across to the browser.

zzz.java
public class zzz extends Servlet
{
}

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java

zzz.java:1: Superclass Servlet of class zzz not found.
public class zzz extends Servlet
^
1 error

In this program, zzz extends Servlet. HttpServlet, which we used earlier, too is derived from Servlet. Had we derived from Servlet in the earlier programs, then our programming would have been more tedious. So, to demonstrate and appreciate how HttpServlet makes life easier for us, we will extend Servlet. We know that HttpServlet is derived from Servlet because we looked at the source code. If you have downloaded Jakarta-Tomcat with the source code option then you can edit the file HttpServlet.java and see for yourself.

Coming back to our program, let's compile it.

The compiler comes back with an error saying Servlet not found. We got an error because we have not specified the full name. To remove the error, give an import statement because the full name is javax.servlet.Servlet. We know that this is the full form becuase we looked at an existing example. Also be sure to set the classpath as before.

zzz.java
import javax.servlet.*;
public class zzz extends Servlet
{
}

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java

zzz.java:2: Can't subclass interfaces: interface javax.servlet.Servlet
public class zzz extends Servlet
^
1 error

Giving the full name does not seem enough! Javac comes back with an error because it knows javax.servlet.Servlet to be an interface. An interface and a class look the same. The help files will tell you that Servlet is an interface. You cannot distinguish between a interface and a class using just the name.

zzz.java
import javax.servlet.*;
public class zzz implements Servlet
{
}

To use an interface, we write 'implements Servlet'. We've explained earlier that an interface is a collection of function prototypes. Unfortunately, when we say implements Servlet, we get 5 errors. Runnable had only one function called run, this one has 5 functions. When you say implements Servlet, it guarantees that it looks like a Servlet and that it defines all the five functions. Because the Java Web server expects a class derived from Servlet, it expects your program to have those same five functions.
C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java

zzz.java:2: class zzz must be declared abstract. It does not define void destroy() from interface javax.servlet.Servlet.
public class zzz implements Servlet
^
zzz.java:2: class zzz must be declared abstract. It does not define void service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) from interface javax.servlet.Servlet.
public class zzz implements Servlet
^
zzz.java:2: class zzz must be declared abstract. It does not define void init(javax.servlet.ServletConfig) from interface javax.servlet.Servlet.
public class zzz implements Servlet
^
zzz.java:2: class zzz must be declared abstract. It does not define java.lang.String getServletInfo() from interface javax.servlet.Servlet.
public class zzz implements Servlet
^
zzz.java:2: class zzz must be declared abstract. It does not define javax.servlet.ServletConfig getServletConfig() from interface javax.servlet.Servlet.
public class zzz implements Servlet
^
5 errors

We now need to create these five functions in zzz and the only statement included in these functions is System.out.println. This is what the next program shows.

zzz.java
import javax.servlet.*;
public class zzz implements Servlet
{
ServletConfig a;
public void destroy()
{
System.out.println("destroy");
}
public String getServletInfo()
{
System.out.println("getServletInfo");
return "";
}
public void service(ServletRequest req,ServletResponse res)
{
System.out.println("service");
}
public void init(ServletConfig a)
{
System.out.println("init");
}
public ServletConfig getServletConfig()
{
System.out.println("getServletConfig");
return (ServletConfig) a;
}
}

When a function returns void it means you don't need to give a return value. But if it returns a String, then either you must return a meaningful string or an empty string (which is two double quotes). When the function returns a ServletConfig then we must return a ServletConfig. Let's check that out! say return 0 like we have done in the following program.

zzz.java
import javax.servlet.*;
public class zzz implements Servlet
{
ServletConfig a;
public void destroy()
{
System.out.println("destroy");
}
public String getServletInfo()
{
System.out.println("getServletInfo");
return "";
}
public void service(ServletRequest req,ServletResponse res)
{
System.out.println("service");
}
public void init(ServletConfig a)
{
System.out.println("init");
}
public ServletConfig getServletConfig()
{
System.out.println("getServletConfig");
return 0;
}
}

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java
zzz.java:29: Incompatible type for return. Can't convert int to javax.servlet.ServletConfig
return 0;
^
1 error

So, we must return a ServletConfig. In order to do that 'a' is made a public variable, which looks like ServletConfig and is returned from getServletConfig. Now you're probably wondering why we've made it public and haven't put it in the function itself. Well, in that case you will have to use new. Let's see what happens. Make the changes in the program as shown below.
zzz.java
import javax.servlet.*;
public class zzz implements Servlet
{
public void destroy()
{
System.out.println("destroy");
}
public String getServletInfo()
{
System.out.println("getServletInfo");
return "";
}
public void service(ServletRequest req,ServletResponse res)
{
System.out.println("service");
}
public void init(ServletConfig a)
{
System.out.println("init");
}
public ServletConfig getServletConfig()
{
ServletConfig a;
a=new ServletConfig();
System.out.println("getServletConfig");
return (ServletConfig)a;
}
}

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java
zzz.java:27: interface javax.servlet.ServletConfig is an interface. It can't be instantiated.
a=new ServletConfig();
^ 1 error

You will now get an error saying you can't instantiate from an interface. There is no other way out. We have to make it public. So zip back to the original program, the one where 'a' is public, and run it. Javac will not complain. Move to the browser and check if the servlet works over there.

Well, it does work! It shows a valid blank screen. But to actually confirm that the servlet has worked, switch to the server dos box. Out of the 5 functions, only two of them get called, init and service. init gets called once and service gets called each time refresh is clicked. So, click on refresh and check the dos box.

Now let's do something smart. It may be too much to ask but we believe in making the impossible possible! Put all the code that was in doGet into service within the try and the catch. Everything works as advertised.
zzz.java
import java.io.*;
import javax.servlet.*;
public class zzz implements Servlet
{
ServletConfig a;
public void destroy()
{
System.out.println("destroy");
}
public String getServletInfo()
{
System.out.println("getServletInfo");
return "";
}
public void service(ServletRequest req,ServletResponse res)
{
try
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
catch (Exception e){}
System.out.println("service");
}
public void init(ServletConfig a)
{
System.out.println("init");
}
public ServletConfig getServletConfig()
{
System.out.println("getServletConfig");
return (ServletConfig) a;
}
}

As before, init and service are called. Service takes the same parameters as doGet. So we follow the same logic, that is, create a PrintWriter and write to the PrintWriter.

Earlier, we derived from HttpServlet. HttpServlet has the same five functions that we have in zzz, so it's possible to replace HttpServlet with zzz. In either case, the Java Web server calls init only once. If you have an init in your program then that's the one that's called, else, the init in HttpServlet is called. Both init's don't do anything right now and it is upto you to decide if you want init to do something. You can put code that is to be executed once in init.

The Java Web server calls service. Service has the getparameter function to figure out whether the http method was 'post' or 'get'. It is called with the same parameters and it puts these on the stack. It in turn calls doGet or doPost. The destroy gets called only at the end. Remember, with get, the parameters are sent with the url as one packet, but with post, a seperate packet is sent.

We implement from Servlet because the Java Web server insists that we do so. If you remove implements Servlet from zzz it will give you tons of errors. This shows that HttpServlet does implement servlet. You must have the five functions, but the order of functions is not important.

The Java developers realized that programmers would not like the idea of writing these functions each time, so they created a class called GenericServlet containing these functions.

In the next program, zzz extends GenericServlet. On saying javac, it gives an error on service.

zzz.java
import javax.servlet.*;
public class zzz extends GenericServlet
{
}

C:\jakarta-tomcat-3.2.1\webapps\examples\web-inf\classes>javac zzz.java

zzz.java:3: class zzz must be declared abstract. It does not define void service(javax.servlet.ServletRequest, javax.servlet.ServletResponse) from class javax.servlet.GenericServlet.
public class zzz extends GenericServlet
^
1 error

To understand this error let's look at a part of the GenericServlet file. We have printed a part of this file relevant to our discussion.

GenericServlet.java
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable

You can search for this file with an extension of .java or .html in the jakart-tomcat subdirectory

It contains the service function, but we will have to write our own service function because the class GenericServlet is abstract. We will explain what we mean by that with the help of an example.

yyy.java
public abstract class yyy implements xxx
{
public void aaa()
{
}
public abstract void bbb();
}

xxx.java
interface xxx
{
public void aaa();
public void bbb();
}

Now let's create ppp.java and extend from yyy.

ppp.java
import java.io.*;
public class ppp extends yyy
{
}

Run this and you get an error similair to the one we got when we tried to extend from GenericServlet. That means when a function is declared as abstract in the class we are extending from, we cannot directly use it. Instead we have to write our own function i.e we have to override it. So make the following changes in ppp.java

The class yyy implements an interface xxx. xxx has 2 function prototypes. yyy decides to have the code for only one function aaa and not bbb. Now if we compile yyy we will get an error. Thus the only way to remove the errors is by making bbb abstract and also the class abstract. Now if anybody wants to extend from the class yyy, he has to write the code of bbb.

ppp.java
import java.io.*;
public class ppp extends yyy
{
public void bbb()
{
System.out.println("hi");
}
}

Since bbb is abstract, you cannot call it directly. We are overriding bbb by giving our own function. Now compile it and you will not get any errors.

Similarly, for our previous program we have to override service. So in the next program we have added service and init.

zzz.java
import java.io.*;
import javax.servlet.*;
public class zzz extends GenericServlet
{
public void service(ServletRequest req,ServletResponse res)
{
try
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<b>Bye");
}
catch (Exception e){}
System.out.println("service");
}
public void init(ServletConfig a)
{
System.out.println("init");
}
}

Any servlet can be extended from GenericServlet. Even HttpServlet is derived from GenericServlet. The service function in HttpServlet checks for the method and accordingly calls doGet and DoPost. It also contains init. GenericServlet makes writing servlets much easier.
The following html file will create a simple form where the method used is 'post'. So within the servlet, function doPost will be called.

a.htm
<html>
<form action=/servlet/zzz method=post>
<input type=submit value="Click...">
</form>
</html>

zzz.java
import java.io.*;
import javax.servlet.http.*;
public class zzz extends HttpServlet
{
public void doGet(HttpServletRequest req,HttpServletResponse res)
{
try
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<b>Get");
}
catch (Exception e){}
}
public void doPost(HttpServletRequest req,HttpServletResponse res)
{
try
{
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("<b>Post");
}
catch (Exception e){}
}
}
When you change the method to 'get', doGet will be called, which will print get in the window.

Remember, the html file must be in c:\jakarta-tomcat-3.2.1\webapps\root. The only difference between 'get' and 'post' is that in get, the query string is passed as a header value. So a header called Query_String is created which contains all that we have keyed in. If you say method=post then the data is sent separately. It is not a part of the header.

There is a finite amount of data that can be given to the environmental variable, so if you're not going to be exceeding that, use 'get'. When you want to send a large chunk of data, then use 'post'. Other methods are available too, but they are not used as frequently.

Conclusion

You have seen how the Java servlet is both simple and powerful. It allows us to extend the functionality of any web server with just a few lines of code.


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