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.