There are several reasons why programmers resort to CGI scripts
when designing web servers. The first is to provide dynamic
content--content that may be different each time a client browser
accesses a page. Examples include digital clocks that always display
the current time of day, or counters that display messages like "You
are visitor number 10,039 at this site."
Another reason for resorting to CGI scripts is to write special server
applications that give trusted users the ability to read and write
data to the server disk by issuing commands from a client application.
For example, the Java File Server (JFS) illustrates a classic remote
service allowing users to read and write to the server itself. JFS
provides print and files services to Java applets much like the UNIX
Network File Server, NFS. See
http://www.focus-asia.com/java/jfs
JavaServerTM technology is well suited to these kinds of
applications and generally simplifies the problem by letting you write
all server and client code in Java. Without a JavaServer, you have to
write CGI (Common Gateway Interface) programs--most commonly in Perl,
Shell scripts, or C--to allow client applications a way to work around
the built-in security features that protect both servers and clients
from unwanted modifications to local files and resources.
Servers and Servlets
Keep in mind the distinction between a JavaServer and a servlet.
As mentioned in the previous article, a servlet is the server-side
equivalent of an applet. Applets add dynamic behavior to client
browsers. Servlets add dynamic behavior to servers.
This article will only touch lightly on server administration
and will focus primarily on the advantages of extending server
functionality with servlets.
At the most basic level, a JavaServer lets you administer a
web site exactly as you would if you were using an Apache server,
an NCSA server, a CERN server, or any of the Netscape family of
servers (Netsite Communications Server and Netsite Commerce
Server). The JavaServer has the advantage of allowing the same
servlet extensions to run on a Windows platform as well as a UNIX
platform. A JavaServer can therefore be used in place of a Microsoft
Internet Information Server running on Windows NT.
For those familiar with CGI programming, servlets do for a JavaServer
what CGI scripts do for the above mentioned servers--or what
WinCGI (with Visual Basic, Delphi, or Visual C++) does in the case
of the Microsoft server on Windows NT.
Developing servlets is a three-step process:
- Write the servlet
- Install the servlet
- Run the servlet
Before digging into the the topic of developing servlets, you
should be familiar with the kinds of CGI scripts servlets are
intended to replace.
Extending a JavaServer with CGI Scripts
If you're already familiar with HTML forms processing with CGI scripts,
you can skip this section. But first, you may want to read the
HTML code used to generate the form shown in Figure 1. This form is
processed by the CGI Perl script,
jdc-example01.pl The next section will
show how the same form is handled using a servlet extension instead of
a CGI extension to the server. The main things you need to understand
before moving on to the next section include the difference between
CGI GET and POST methods for submitting forms, and the manner in which
form parameters or names are passed from the HTML form to a CGI script.
First consider how traditional CGI Perl scripts are handled by a
JavaServer. There won't be any surprises here for those accustomed to
extending server functionality by writing CGI scripts, whether in Perl,
UNIX shell script, AWK, C, or Visual Basic. However, it is important
to be clear about how name-value parameters are defined within
an HTML form, and how they are passed to CGI scripts by the server.
You'll see the same concepts applied to servlets when they
are introduced in a later section.
This section is written from the perspective of conventional CGI
programming. For those unfamiliar with CGI programming for extending
the services of a web server, this should acquaint you with the
basics. If you already build or maintain servers, the code here
should be easy to understand and will demonstrate that a JavaServer
provides the same services as Apache, NCSA, CERN, Netscape, Microsoft,
Internet Information Server, and other common web servers.
You must build two server-side pieces to solve the problem of form
submission requests and responses. Like many programming problems the
matter breaks down into input and output. In CGI terminology that's
the HTTP request and the HTTP response. The HTML
page containing the form makes up the input request to be submitted to
the server when the user presses the submit button appearing on the
form. The CGI script reads the input data as key-value pairs
or name-value pairs, processes the data, and generates an
output response that the server passes back to the client browser that
submitted the form.
Consider the form in Figure 1.
Figure 01.Full Size
The HTML code that generates this form is simple:
<html>
<head>
<title>JDC Registration Page</title>
</head>
<body>
<h1>JDC Registration Page</h1>
<form method="GET" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fdeveloper%2FtechnicalArticles%2FServlets%2FJavaServerTech2%2F%26quot%3Bcgi-bin%2Fjdc-example01.pl%26quot%3B%26gt%3B&y=1999
<pre>
First Name: <input type="text" name="firstname">
Last Name: <input type="text" name="lastname">
<input type="submit"> <input type="reset">
</pre>
</form>
</body>
</html>
File: server_root/public_html/jdc-example01.html
Source
Figure 2. Dynamic Page Generated by Perl Script.
Full Size
See Perl Script: server_root/cgi-bin/
jdc-example01-simplified.pl
Note: The HTML, Perl, and Java files used in this
article are not distributed with JavaServer. If you wish to use these
programs with a JavaServer, you must copy them to the appropriate
directory relative to the root directory where your JavaServer is
installed. For convenience partial pathnames, relative to
the server_root directory have been specified so
you will know where to put them. Copy HTML files to
server_root/public_html. Copy Perl CGI scripts
to server_root/cgi-bin. Copy Java source files to
server_root/servlets. Actually, this is not
strictly necessary in the case of Java files. Only the compiled
.class file needs to be copied to
server_root/servlets.
The above form specifies the GET method of passing data to the
CGI script.
<form method="GET" ...>
This means the name parameters will be
encoded and appended to the URL that invokes the CGI
script.
Two named input fields are specified in the form:
firstname and lastname.
First Name: <input type="text" name="firstname">
Last Name: <input type="text" name="lastname">
For the purposes of this article the JavaServer has been
installed in the directory /opt/JavaServer.
Throughout JavaServer
documentation you will see reference to the server
root directory, often indicated as server_root
when specified as code.
For the remainder of this article consider
server_root to and /opt/JavaServer
to be equivalent. If you have installed
the JavaServer in a different directory, be sure to
make the appropriate adjustments when instructed to
copy HTML, CGI, and servlet example programs to the
appropriate directories.
Two input buttons are specified. Note that these inputs
do not have names associated with them so their values
will not be passed on as part of the forms data.
<input type="submit"> <input type="reset">
These are standard HTML form inputs that have specific behaviors
associated with them. An input of type submit causes the
form to be submitted to the server when pressed. An input of type
reset causes all fields to be reset to their default
values without submitting the form.
If you get an error when you submit the form, be sure that you have
set the file mode of the Perl CGI script file to executable. If you
have not done this the JavaServer will indicate that the CGI program
has thrown an exception.
Assuming that this listing has been placed in
server_root/public_html, and the host name of
the machine on which the server is running is cool1, the
following URL will cause the above form to be displayed:
http://cool1:8080/jdc-example01.html
Note: Similar in notion to server_root, you will
see JavaServer documentation refer to a
Server_Host_Name. Assuming you have
accepted the default port address when you installed the server, the
generic address of the default server home page is specified as:
http://<EM><STRONG>Server_Host_Name
</STRONG></EM>:8080
By default, the standard location of html files
specified relative to the server_root
<EM>server_root</EM>/public_html
For this article, the standard html directory is:
/opt/JavaServer/public_html
and the JavaServer URL referring to the file,
jdc-example01.html, in this directory would be
http://cool1:8080/jdc-example01.html
Filling out the form with the First Name field set to "Greg" and the
Last Name field set to "Voss" will cause the following URL to be
invoked when the submit button is pressed:
http://cool1:8080/cgi-bin/jdc-example01.pl?
firstname=Greg&lastname=Voss
Note the key-value pairs of form data appended to the end of the URL
following the question mark. An ampersand (&) is used to separate
individual key-value parameters.
The Perl CGI script to be invoked was specified in the form tag of the
HTML file:
<form method="GET" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fdeveloper%2FtechnicalArticles%2FServlets%2FJavaServerTech2%2F%26quot%3Bcgi-bin%2Fjdc-example01.pl%26quot%3B%26gt%3B&y=1999
Unless a fully qualified URL is given, the location
of the script is relative to server_root,
in this case:
/opt/JavaServerBeta/cgi-bin/jdc-example01.pl
As a URL, this maps to:
http://cool1:8080/cgi-bin/jdc-example01.pl
This is the actual URL invoked by the server when the form is
submitted, minus the parameter data. The parameter data follows the
question mark and can be specially encoded so that it contains only
characters that are legally allowed in URLs.
?firstname=Greg&lastname=Voss
You see here the two key-value pairs or name-value pairs for the form
just submitted.
Here's the code for the Perl CGI script, which will now process the
client request:
#!/usr/local/bin/perl
##
## Print tags for beginng of HTML document to STDOUT
##
print <<EOM;
Content-type: text/html
<html>
<head><title>Welcome to the JDC</title></head>
<body>
<h1>Welcome to the JDC</h1>
<pre>
EOM
##
##Read the parameters passed by the HTML form
##from the QUERY_STRING environment variable.
##
$query_string = $ENV{'QUERY_STRING'};
##
##Decode the form data encoded in the URL.
##
$query_string =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack (
"C", hex ($1))/eg;
$query_string =~ s/\+/ /g;
##
##Break up the parameters passed in the URL
##into an array of key-value pairs.
##
@pairs = split (/&/, $query_string);
##
##Iterate over the array of key-value pairs,
##break up each pair into a key component and
##a value component. Build a hashtable, called
##form_data, allowing values to retrieved
##using a name key.
##
foreach $pair (@pairs) {
($key, $value) = split (/=/, $pair);
$form_data{$key} = $value;
}
##
## Now parameter values can be retrieved from
##the hashtable by supplying a name key.
##
$firstname = $form_data{"firstname"};
$lastname = $form_data{"lastname"};
##
## This is the dynamic content generated in
## response to the HTML form submission.
##
print "\n<h2>Greetings</h2>\n";
print "Hello $firstname $lastname.
Welcome to the JDC.\n\n";
##
##Print tags for end of HTML document
##to STDOUT
print <<EOM;
</pre>
</body>
</html>
EOM
close OUT;
File: server_root/cgi-bin/
jdc-example01-simplified.pl
I'll do a simple walkthrough for those whose Perl skills are as rusty
as mine.
The data that is printed to the standard output of the CGI script is
the dynamically generated page. At the beginning and end of the file
you'll see two short cuts, which are similar to 'here' files used in UNIX
shell scripts. Anything appearing after a sharp sign (#) on a line is
a comment.
You should recognize the first example as a standard
HTML header. Everything between
print <<EOM;
and
EOM
is printed to the standard output.
##
##Print tags for beginng of HTML document
##to STDOUT
print <<EOM;
Content-type: text/html
<html>
<head><title>Welcome to the JDC</title></head>
<body>
<h1>Welcome to the JDC</h1>
<PRE>
EOM
Similar code appears at the end of the CGI script to compose the end of
the HTML page.
##
##Print tags for end of HTML document to
##STDOUT
print <<EOM;
</PRE>
</body>
</html>
EOM
What you're really interested in, is the real dynamic content
generation that depends upon the CGI input parameters appearing in
between. The actual query string, the part of the URL following the
question mark, can be retrieved from the QUERY_STRING environment
variable:
$query_string = $ENV{'QUERY_STRING'};
However this string will be encoded to make it conform to the
requirements of URL specification. To see how such encoding works, try
submitting a name with spaces and other odd characters, for example,
try submitting a First Name of "Dr. J. 6/9/97" and a last name of
"Irving." You'll see an encoding that looks like this:
query_string: firstname=Dr.+J.+6%2F9%2F97&lastname=
Irving
The spaces have become plus signs (+) and the forward slashes (/) have
been hex encoded as %2F. The following Perl expression decodes any
hex encodings in the query:
$query_string =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack (
"C", hex ($1))/eg;
The next expression turns the plus signs back into spaces.
$query_string =~ s/\+/ /g;
This is a standard decoding idiom used in many Perl CGI scripts.
Next, the query string is split into an array of pairs using the
ampersand as a field separator.
@pairs = split (/&/, $query_string);
For the orginal submission, pairs would now be an array of two strings
with a base index of 0:
[0]"firstname=Greg"
[1]"lastname=Voss"
The script now iterates over this array, and splits each element into
key and value components using the equals sign in each string as a
field delimiter:
($key, $value) = split (/=/, $pair);
Once a parameter is broken up into a name and a value, the parameter
can be added to a hashtable called form_data:
$form_data{$key} = $value;
The values can later be retrieved from this hashtable by using the
name as a key:
$firstname = $form_data{"firstname"};
$lastname = $form_data{"lastname"};
At last you can print the dynamic content portion of the page being
generated. Such pages are sometimes called virtual pages because they
are created on the fly.
print"\n<h2>Greetings</h2>\n";
print "Hello $firstname $lastname.
Welcome to the JDC.\n\n";
The first statement generates a standard HTML level
2 heading. The second statment issues a greeting
substituting the firstname and lastname submitted
in the form.
Here's a slightly more elaborate version of the first example CGI
script. Some extra print stubs have been added for debugging and
tracing purposes. When the form is submitted and this CGI script is
invoked, you can follow the transformation of data from the hex
decoding of the passed parameters all the way to the construction of
the form_data hash table that allows the parameter values to be
retrieved by a name key.
#!/usr/local/bin/perl
##
##Print tags for beginng of HTML document to
##STDOUT
print <<EOM;
Content-type: text/html
<html>
<head><title>Welcome to the JDC</title></head>
<body>
<h1>Welcome to the JDC</h1>
<pre>
EOM
print "\n<h2>Debug Info</h2>\n";
$content_length = $ENV{'CONTENT_LENGTH'};
print "content_length: " , $content_length, "\n";
##
##Read the parameters passed by the HTML form
##from the QUERY_STRING environment variable.
##
$query_string = $ENV{'QUERY_STRING'};
print "query_string: ", $query_string, "\n";
$query_string =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack (
"C", hex ($1))/eg;
$query_string =~ s/\+/ /g;
print "query_string (decoded): ", $query_string, "\n";
print "\n";
##
##Break up the parameters passed in the URL
##into an array of key-value pairs.
##
@pairs = split (/&/, $query_string);
print "pairs :", @pairs, "\n";
print "pairs[0] :", $pairs[0], "\n";
print "pairs[1] :", $pairs[1], "\n";
##
## Iterate over the array of key-value pairs,
## break up each pair into key component and
## value component. Build hashtable, called
## form_data, allowing values to retrived
## using name key.
##
foreach $pair (@pairs) {
print "pair: ", $pair, "\n";
($key, $value) = split (/=/, $pair);
print "key: ", $key, " value: ", $value, "\n";
$form_data{$key} = $value;
}
print "\n%form_data: ", %form_data, "\n";
print "\nContents of %form_data hash table\n";
foreach $key (keys %form_data) {
print " $key: $form_data{$key}\n";
}
##
## Now parameter values can be retrieved from
##the hashtable by supplying a name key.
##
$firstname = $form_data{"firstname"};
$lastname = $form_data{"lastname"};
##
## This is the dynamic content generated in
## response to the HTML form submission.
##
print "\n<h2>Greetings</h2>\n";
print "Hello $firstname $lastname.
Welcome to the JDC.\n\n";
##
##Print tags for end of HTML document to
##STDOUT
print <<EOM;
</pre>
</body>
</html>
EOM
close OUT;
File: server_root/cgi-bin/
jdc-example01.pl
When this version of the CGI script is invoked,
you'll see something like Figure 3.
Figure 3. Full Size
Because this is a GET form, the arguments appear appended to the URL
in the browser's Location field:
http://cool1:8080/cgi-bin/jdc-example01.pl?firstname=
Greg&lastname=Voss
It may seem odd that two nearly identical HTML forms are
supplied:
jdc-example01.html
and
jdc-example01-simplified.html.
Each of these HTML files has a corresponding Perl CGI script
jdc-example01.pl
and
jdc-example01-simplified.pl.
The CGI script that prints more debug information does not have the
text -simplified inserted in the name. The reference
made to this CGI in the form tag must be changed as well. Only one
line is different in the HTML files. You can use one file if you want
to edit this line manually. The line
<form method="GET"
action="cgi-bin/jdc-example01-simplified.pl">
has been changed to
<form method="GET" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fdeveloper%2FtechnicalArticles%2FServlets%2FJavaServerTech2%2F%26quot%3Bcgi-bin%2Fjdc-example01.pl%26quot%3B%26gt%3B&y=1999
in the HTML form if you want debug information printed.
When the simplified form is submitted and processed by the CGI,
a dynamically generated web page is returned by the
browser by the server. The page should look like
Figure 4.
Figure 4. Full Size
The name-value parameters also appear in this URL, but the window
is too small to see them.
There are other CGI test scripts worth trying in the server_root/cgi-bin
directory. Standard CGI tests provided with Appache and and Netscape servers include
apache-test-cgi and
test-cgi.pl. These print arguments (not form parameters) and
environment variables so that you can check that the server is working as
expected.
-----------------------------------------------------
/opt/JavaServerBeta/cgi-bin:
total 32
-rwxr-xr-x 1 gvoss 721 Mar 20 16:19 apache-test-cgi
-r-xr-xr-x 1 gvoss 1665 Mar 4 12:46 nph-test-cgi.pl
-r-xr-xr-x 1 gvoss 899 Mar 4 12:46 redirect.pl
-r-xr-xr-x 1 gvoss 1221 Mar 4 12:46 test-cgi.pl
-r--r--r-- 1 gvoss 1527 May 15 23:04
jdc-example01-simplified.pl
-r--r--r-- 1 gvoss 2118 May 15 23:05 jdc-example01.pl
----------------------------------------------------
The HTML files that you need to copy to
server_root/public_html
are listed below for your convenience:
-----------------------------------------------------
/opt/JavaServerBeta/public_html:
-rw-rw-r-- 1 gvoss 683 May 15 23:20
jdc-example01-simplified.html
-rw-rw-r-- 1 gvoss 683 May 14 03:05
jdc-example01.html
-rw-rw-r-- 1 gvoss 739 May 15 16:59
jdc-example02-get.html
-rw-rw-r-- 1 gvoss 741 May 15 17:09
jdc-example02-post.html
-rw-rw-r-- 1 gvoss 801 May 14 06:06
jdc-example02.html
-----------------------------------------------------
Many other HMTL files designed to test the example servlets supplied with
JavaServer can be found in this directory as well.
Extending a JavaServer with Servlets
The usual way to extend web server functionality is to write CGI
scripts. Servlets eliminate the need to resort to CGI solutions.
However, CGI can still be used. If you have many existing CGI
programs for serving up dynamic content, you can still use them.
You'll probably want to convert at least those that are called
frequently, because the memory overhead of invoking a CGI program is
much greater than invoking a servlet service routine. Each time a CGI
script is called, an entire operating system process is created. In
contrast, servlet service routines are only light-weight threads. The
executable code for the servlet only needs to be loaded once--the
first time the service request associated with the service is invoked.
After the first invocation, the code is called directly by the server
with each request. In contrast, a CGI Perl script must be loaded into
memory each time a service request is made. This is expensive for
both processor and memory resources.
Step 1. Write the Servlet
Below, you'll see Java code for the servlet equivalent of the CGI
programs presented in the previous section. This source should be
compiled with JDK 1.1 or later, and the resulting class file should be
put in
<EM>server_root</EM>/sevlets
In my case, I put the Java source file in that directory and compile
there to create the class file:
/opt/JavaServerBeta/servlets/JdcExample02.java
/opt/JavaServerBeta/servlets/JdcExample02.class
Here's the servlet:
import java.io.*;
import java.servlet.*;
import java.servlet.http.*;
import sun.server.http.*;
import sun.misc.*;
import java.util.*;
public class JdcExample02 extends HttpServlet
{
//
//Initialize the servlet and set the html pages. Also
//@param stub Arguments passed by the servlet loader
//@return void
//
public void init (
ServletConfig config) throws ServletException
{
super.init(config);
}
//
// Write to servlet response file.
// @param request The servlet request.
// @param response The servlet response.
// @return void.
//
public void service (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
Enumeration names = request.getParameterNames();
PrintStream out = new PrintStream (
response.getOutputStream());
response.setContentType ("text/html");
out.println("<title>Welcome to the JDC (
Servlet Version)
</title>");
out.println("<h1>Welcome to the JDC (
Servlet Version)</h1>");
out.println("<h2>Debug Info</h2>");
//
// Iterate over all key-value pairs from form and print
//
while ( names.hasMoreElements() )
{
String key, value;
key = (String)names.nextElement();
value = request.getParameter (key);
out.println("key: " + key + " value: " + value);
out.println("<br>");
}
//
// Retrieve key-value pairs by key lookup
//
String firstname = request.getParameter (
"firstname");
String lastname = request.getParameter ("lastname");
out.println("<h2>Greetings</h2>");
out.println("<br>");
out.println("Hello " + firstname + " " + lastname + ".");
out.println("Welcome to the JDC.");
out.close();
}
}
File: server_root/servlets/
JdcExample02.java
Walking through this code, you'll notice it's quite a bit cleaner than
the CGI scripts. For a minimal servlet, recall that two methods must
be implemented to set up the basic service: init, and
service.
The init method is invoked when the servlet is first loaded.
This occurs on the first request for the service only; thereafter
the servlet remains in memory. In this example, the init
call is passed on to the superclass.
public void init (
ServletConfig config) throws ServletException
{
super.init(config);
}
If you boil the service method down to its essence, it's
really simple.
If you know the names of the form parameters you want to
print, you simply retrieve them and print them.
String firstname =
request.getParameter ("firstname");
String lastname =
request.getParameter ("lastname");
...
out.println("Hello " + firstname +
" " + lastname + ".");
This is the essence of the dynamic content generation. All the data
you need is contained in the request argument to service,
which is an instance of HttpServletRequest. Instead of
writing output to standard output, as in a CGI script, output is sent
back to the server, and then to the client browser by writing to an
output stream that can be retrieved from the second argument to
service. This argument is an instance of
HttpServletResponse and in this case is called
response.
PrintStream out =
new PrintStream (response.getOutputStream());
The first output you need to send to this stream is a header
line indicating the content type of the response. This
is done through the setContentType method
of HttpServletResponse.
response.setContentType ("text/html");
Note that this is not done through the output stream. That makes
sense because this information is always required in the response
header. Only the HTML codes and actual content are written directly
to the output stream.
out.println("<title>Welcome to the JDC (
Servlet Version) </title>");
out.println("<h1>Welcome to the JDC (
Servlet Version)</h1>");
...
out.println("<h2>Greetings</h2>");
out.println("<br>");
out.println("Hello " + firstname + " " + lastname + ".");
out.println("Welcome to the JDC.");
Be sure to close the output stream before exiting to make sure the
stream buffer is flushed:
out.close();
There's one more piece of code not yet explained. Strictly speaking
this code isn't necessary because you know all the names of the
parameters you are expecting to send. But in case you did not know
all the names in advance (or simply as a matter of convenience), you
can iterate over all the parameters with an Enumeration:
Enumeration names = request.getParameterNames();
You can now use the hasMoreElements method to test for the end of the
parameter list:
while ( names.hasMoreElements() )
{
...
}
You can retrieve the next parameter name or key from the nextElement
method of Enumeration:
String key, value;
key = (String)names.nextElement();
Given the key string, you can lookup the parameter value
from the response argument to the servlet with the
getParameter method defined in
HttpServletResponse
value = request.getParameter (key);
Now you can do whatever processing or output you like with
key and value:
out.println("key: " + key + " value: " + value);
out.println("<br>");
You'll frequently see loops of this structure in servlets:
while ( names.hasMoreElements() )
{
String key, value;
key = (String)names.nextElement();
value = request.getParameter (key);
out.println("key: " + key + " value: " + value);
out.println("<br>");
}
Figure 5 shows the virtual page generated by this
servlet when it receives firstname=Greg and lastname=Voss
as request parameters.
Figure 5.Full Size
Step 2. Install the Servlet
Once you've compiled this servlet, you've covered Step 1, Writing the
Servlet. In Step 2, you'll install it. Before you can get the
servlet to work, you'll need to install it in the JavaServer with the
JavaServer Administration Applet. This was covered in
JavaServer
Technologies, Part I . Recall, this is the second step of the
three-step process for extending a JavaServer with a servlet:
- Write the servlet
- Install the servlet
- Run the servlet
Step 3. Run the Servlet
As far as Step 3, you'll now need an HTML form to invoke the servlet.
This HTML form code will be nearly identical to the code used in the
CGI examples. The primary difference is in the action
argument to the form tag.
<form method="GET" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fservlet%2FJdcExample02%26gt&y=1999
Here, the GET method of parameter passing is used, but the POST method
could be used as well:
<form method="POST" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fservlet%2FJdcExample02%26gt&y=1999
No modification would be required to the servlet code to accommodate
the POST method.
The action statement indicates the alias name of the servlet as
specified when the servlet is installed with the JavaServer
Administration Applet. In this case the servlet name and the class
name are the same; they need not be. The first part of the pathname
in the action attribute tells the server that a servlet is being
invoked:
action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fservlet%2F&y=1999
The rest of the path names the actual servlet, in this case,
JdcExample02. In most cases you'll want to put the
servlet class in the default servlet directory:
server_root/servlets/JdcExample02.class
For this article, this translates to:
/opt/JavaServerBeta/servlets/JdcExample02.class
Here is the entire HTML form designed to invoke the
above servlet:
-----------------------------------------------------
File: /opt/JavaServerBeta/public_html/
jdc-example02-get.html
-----------------------------------------------------
<html>
<head>
<title>JDC Registration Page (Servlet GET")</title>
</head>
<body>
<h1>JDC Registration Page (Servlet Version)</h1>
<h2>method="GET"</h2>
<form method="GET" action=/old?u=http%3A%2F%2Fdeveloper.java.sun.com%2Fservlet%2FJdcExample02%26quot&y=1999
<PRE>
First Name: <input type="text" name="firstname">
Last Name: <input type="text" name="lastname">
<input type="submit"> <input type="reset">
</PRE>
</form>
</body>
</html>
File: server_root/public_html/
jdc-example02-get.html
Encoding and Decoding Form Parameters
Decoding form parameter data passed to the servlet is not
required with servlets as it is in CGI scripts. Basic functionality
inherited from HttpServlet handles the decoding automatically.
Instead you can directly access the key-value pairs created and encoded
by the client browser directly inside the servlets service method.
The decoded key-value pairs (sometimes called name parameters, derived
from the name attribute associated with HTML
input tags) can be retrieved directly from the first
argument of the HttpServlet::service method. By convention this name
is usually somthing like req or request to
highlight the fact that it carries data associated with an HTTP request
sent by the client browser.
Developing Servlets
As mentioned above, developing servlets is a three-step process,
reviewed here, one last time, at the risk of driving you crazy:
- Write the servlet
- Install the servlet
- Run the servlet
Tricks for Testing Servlets
If you don't want to write a full-blown web page to test your servlet,
you can write a canned request by appending form parameters to the URL
For example, to call the jdc-example01.pl Perl example script
listed above, without writing and HTML form, you could simply type a
URL that has the firstname and lastname
parameters directly embedded:
http://cool1:8080/cgi-bin/jdc-example01.pl?
firstname=Greg&lastname=Voss
Programming challenge: To help you understand Java
servlets, a good exercise would be to write a servlet called
EchoFormParameters.java, that simply echos the form
parameters that it receives. Such a program also provides a good test
harness when you want to verify that your form is, in fact, passing
the parameters you think it should.
Note, for a CGI script (Perl, shell-script, C, or other) the above
type of canned query only works with a GET method of parameter passing.
One of the subtle advantages of using servlets is that the servlet
doesn't care whether the form has used the GET or POST method to pass
arguments to the server.
This eliminates one of the primary disadvantages of using POST: you
can't set up a bunch of canned queries to verify the parameters.
Also, sometimes it makes sense to give the user a list of common
queries encoded directly as links from a primary page. With servlets
you can have the best of both GET and POST methods without maintaining
two sets of server-side request-handler code.
To GET or to POST?
That is the question CGI programmers face. There are advantages
and disadvanges to either method of posting.
Note that the same servlet can handle both GET and POST methods when
receiving form name parameters from a client browser request.
The beauty of this duality is that you can embed canned queries in
documents and pass them on to your server. Canned queries can be
composed in a single line (either as the action argument
of an HTML form statement, or by invoking the servlet
directly from the browser with a special form of URL).
This is how a form encodes parameter data when the GET method of a
document request is issued by the client browser. A question mark is
appended to end of the actual URL followed by name parameter data
pairs, with each pair being separated by an ampersand (&). Some
encoding of data is also performed. Special characters, which cannot
be part of a legal URL, are encoded as hexidecimal values preceded by
a percent sign (%). Spaces are encoded as plus signs (+). Composing
GET queries manually is handy for testing as you can compose dozens of
different test service requests to excercise different code in your
servlet's service routine without having to manually fill out a new
form each time you want to invoke the request.
If you wanted to handle both GET and POST methods of form submission
using normal CGI scripts, you would need two different scripts (or two
different code branches controlled by a conditional). Because
requests that pass a lot of data mostly use POST requests, it can be
difficult to automate testing; you cannot simply specify all
parameters in a single URL href tag as you could when using the GET
request method. With servlets, canned queries are always an option
because you can switch back and forth between GET and POST methods on
request pages without altering any code in the servlet that handles
and responds to the request.
Exploring JavaServer Directories
Here are some quick tips for familiarizing yourself with
the most important files in the JavaServer distribution.
Start by studying the example servlets. You'll want to look at the
form pages in the public_html directory as well as the corresponding
servlets that handle form requests. The servlets are found in the
servlets directory.
/opt/JavaServerBeta/public_html
/opt/JavaServerBeta/cgi-bin
/opt/JavaServerBeta/servlets
Thus, the critical directories, relative to
server_root are
public_html
cgi-bin
servlets
In addition, you may want to explore the documentation
directories:
/opt/JavaServerBeta/system/doc:
total 62
drwxrwxr-x 7 gvoss 512 Mar 4 15:56 .
drwxrwxr-x 6 gvoss 512 Mar 4 13:19 ..
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 administration
drwxrwxr-x 3 gvoss 6144 Mar 4 13:20 apidoc
-rw-r--r-- 1 gvoss 17844 Mar 4 13:20 faq.html
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 images
-rw-r--r-- 1 gvoss 3503 Mar 4 13:20 index.html
-rw-r--r-- 1 gvoss 12742 Mar 4 13:20 installation.html
-rw-r--r-- 1 gvoss 9744 Mar 4 13:20 knownbugs.html
-rw-r--r-- 1 gvoss 4736 Mar 4 13:20
release_notes.html
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 security
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 servlets
Example Servlets Distributed with JavaServer
JavaServer comes with a set of sample servlets that you can study and
use as a starting point for writing your own custom servlets. Use
the following URL to see a brief description of these servlets:
http://<EM><STRONG>(your.server)</STRONG>
</EM</system/doc/servlets/examples.html
For example, with a host name of cool1 and with JavaServer installed
to use the default port, use:
http://cool1:8080/system/doc/servlets/examples.html
This page contains links to run the example servlets, as well as links
to the source code for the example servlets. Note, that when you view
the examples.html file on the JavaServer site, rather
than a downloaded version on your local machine, you will not be able
to run the servlets directly. That's because the links assume that
the JavaServer is up and running on your local machine. To see what
these servlets do, download a copy of the Java server (with
documentation), run it, and bring up
http://<EM><STRONG>(your.server)</STRONG>
</EM>/system/doc/servlets/examples.html
Here's a list of the example servlets provided with JavaServer:
Simple
Snoop
Phone
Counter
Protected Servlet
Date
Hello World
Finger
Certificate Authority
(requires Navigator client)
Remember that these servlet names won't map directly to
Java class names. This is obvious from a quick look at
the contents of the servlet directory:
/opt/JavaServerBeta/servlets:
total 24
drwxrwxr-x 4 gvoss 2048 May 14 07:00 .
drwxrwxr-x 13 gvoss 512 Mar 4 14:03 ..
-rw-r--r-- 1 gvoss 2316 Mar 4 13:17
BBoardServlet.class
-rw-r--r-- 1 gvoss 2794 Mar 4 13:17
BBoardServlet.java
-rw-r--r-- 1 gvoss 7268 Mar 4 13:17 CA.class
-rw-r--r-- 1 gvoss 23720 Mar 4 13:17 CA.java
-rw-r--r-- 1 gvoss 513 Mar 4 13:17
ChatServlet$ClientInfo.class
-rw-r--r-- 1 gvoss 3619 Mar 4 13:17
ChatServlet.class
-rw-r--r-- 1 gvoss 4554 Mar 4 13:17
ChatServlet.java
-rw-r--r-- 1 gvoss 322 Mar 4 13:17
ClientInfo.class
-rw-r--r-- 1 gvoss 996 Mar 4 13:17
ClientInfo.java
-rw-r--r-- 1 gvoss 2545 Mar 4 13:16 Counter.class
-rw-r--r-- 1 gvoss 2424 Mar 4 13:16 Counter.java
-rw-r--r-- 1 gvoss 444 Mar 4 13:17
DBDataEncoder.class
-rw-r--r-- 1 gvoss 1328 Mar 4 13:17
DBDataEncoder.java
-rw-r--r-- 1 gvoss 760 Mar 4 13:17
DBDataSimpleEncoder.class
-rw-r--r-- 1 gvoss 1491 Mar 4 13:17
DBDataSimpleEncoder.java
-rw-r--r-- 1 gvoss 930 Mar 4 13:17
DateServlet.class
-rw-r--r-- 1 gvoss 1622 Mar 4 13:17
DateServlet.java
-rw-r--r-- 1 gvoss 2542 Mar 4 13:17
FingerServlet.class
-rw-r--r-- 1 gvoss 3655 Mar 4 13:17
FingerServlet.java
-rw-rw-r-- 1 gvoss 801 Mar 18 19:19
HelloServlet.class
-rw-r--r-- 1 gvoss 1042 Mar 4 13:17
HelloWorldServlet.class
-rw-r--r-- 1 gvoss 1823 Mar 4 13:17
HelloWorldServlet.java
-rw-r--r-- 1 gvoss 1664 Mar 4 13:17
InlineServlet.class
-rw-r--r-- 1 gvoss 2075 Mar 4 13:17
InlineServlet.java
-rw-r--r-- 1 gvoss 8858 Mar 4 13:17
LinkCheckerServlet.class
-rw-r--r-- 1 gvoss 16872 Mar 4 13:17
LinkCheckerServlet.java
-rw-r--r-- 1 gvoss 3012 Mar 4 13:16
MailServlet.class
-rw-r--r-- 1 gvoss 4676 Mar 4 13:16
MailServlet.java
-rw-r--r-- 1 gvoss 285 Mar 4 13:17
MovieFinderException.class
-rw-r--r-- 1 gvoss 7210 Mar 4 13:17
MovieFinderServlet.class
-rw-r--r-- 1 gvoss 11170 Mar 4 13:17
MovieFinderServlet.java
-rwxr----- 1 gvoss 2027 Apr 18 14:31
MovieFinderServlet.tag
-rw-r--r-- 1 gvoss 2543 Mar 4 13:16
PhoneServlet.class
-rw-r--r-- 1 gvoss 3090 Mar 4 13:16
PhoneServlet.java
-rw-r--r-- 1 gvoss 1062 Mar 4 13:16
ProtectedServlet.class
-rw-r--r-- 1 gvoss 1538 Mar 4 13:16
ProtectedServlet.java
-rw-r--r-- 1 gvoss 1772 Mar 4 13:17
RedirectServlet.class
-rw-r--r-- 1 gvoss 3433 Mar 4 13:17
RedirectServlet.java
-rw-r--r-- 1 gvoss 3200 Mar 4 13:17
ReleaseFormServlet.class
-rw-r--r-- 1 gvoss 3830 Mar 4 13:17
ReleaseFormServlet.java
-rw-r--r-- 1 gvoss 6183 Mar 4 13:17
RoomSchedServlet.class
-rw-r--r-- 1 gvoss 7037 Mar 4 13:17
RoomSchedServlet.java
-rw-r--r-- 1 gvoss 1605 Mar 4 13:17
SimpleFormServlet.class
-rw-r--r-- 1 gvoss 1913 Mar 4 13:16
SimpleFormServlet.java
-rw-r--r-- 1 gvoss 1047 Mar 4 13:16
SimpleServlet.class
-rw-r--r-- 1 gvoss 1523 Mar 4 13:16
SimpleServlet.java
-rw-r--r-- 1 gvoss 3337 Mar 4 13:16
SnoopServlet.class
-rw-r--r-- 1 gvoss 3533 Mar 4 13:16
SnoopServlet.java
-rw-r--r-- 1 gvoss 447 Mar 4 13:17 URLInfo.class
-rw-r--r-- 1 gvoss 123 Mar 4 12:46 phonelist
To see the actual Java source file name, you can either use the status
line of your web browser while reading the examples documentation
page, or you can run the JavaServer Administration Applet and press
the Servlets button to get a list of servlets with their corresponding
class names, default arguments, and load specifications.
Security and Access Control
This article deals with extending the server rather than administering
it. While you probably will want to become familiar with the server
administration applet and various ways of setting up log files and
security controls, initially you'll need to focus on ways to provide
dynamic content for users of your service. Eventually, however,
you'll want to use the JavaServer Administration Applet for managing
user access to HTML pages, as well as to files and directories on your
server.
Setting up password-controlled access to a given web page (or to a
domain) is easy. Use the JavaServer Administration Applet. When you
first invoke the applet, use admin for both login id and
password.
Use port 9090 to get to the main JavaServer Administration
page.
http://cool1:9090
From here you can launch the administation applet. Or you can specify
the applet directly.
http://cool1:9090/applet.html
Again, substitute your host name in the above URLs.
Once the administration applet is running, you'll see a list of
subcategories under the main entry titled "Java Webserver." With the
"Web Page Service" category selected, press the "Manage" button near
the bottom of the window.
A new applet page appears with buttons across the top. Press the
"Security" button. Select the "Resources" category appearing in the
tree at the left side of the new panel. A list of protected
resources, in this case HTML files, appears in the main applet window.
To added a new HTML file that requires password access, press the
"Add" button below panel listing the resources.
A dialog appears like that in Figure 6.
Figure 6. Full Size
Add the relative pathname for the file. For this exercise I made a
copy of the file protected.html in
server_root/public_html and called it
protected-gmv.html. Select the "Basic" scheme to get
simple password protection for the file. The Administration servlet
documentation covers the details of the "Basic" and "Digest" schemes.
These are common protection mechanisms supported by other servers as
well. Once you have added the file, it will appear in the list of
protected resources as shown in Figure 7.
Figure 7.Full Size
Now when you try to access the new file, you'll be asked to enter the
appropriate users id and password. Until you have set up your own
specific user account you can use "admin" for both as when you login
to the administration tool. Note that you only have to enter the
password once. Thereafter the password data is maintained so you can
travel about various protected pages and domains without having to
constantly reenter your password.
JavaServer Documentation
A good place to start is with the servlet tutorial. The URL for this
is
http://cool1:8080/system/doc/
servlets/servlet_tutorial.html
Or you can look directly at the file in
<EM>server_root</EM>/system/
doc/servlets/servlet_tutorial.html
For example:
/opt/JavaServerBeta/system/doc/
servlets/servlet_tutorial.html
The example servlets provided with JavaServer also come with
documentation. You can invoke the servlets from this documentation
page or look at the source code for the servlets.
http://cool1:8080/system/doc/servlets/examples.html
or, if you have access the server's file system, you can edit or view
the examples.html file directly:
<EM>server_root</EM>/system/
doc/servlets/examples.html
which for this article would appear as:
/opt/JavaServerBeta/system/doc/servlets/examples.html
For basic JavaServer information, you'll want to look at the HTML
files in
<EM>server_root</EM>/system/doc
/opt/JavaServerBeta/system/doc:
total 62
drwxrwxr-x 7 gvoss 512 Mar 4 15:56 .
drwxrwxr-x 6 gvoss 512 Mar 4 13:19 ..
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 administration
drwxrwxr-x 3 gvoss 6144 Mar 4 13:20 apidoc
-rw-r--r-- 1 gvoss 17844 Mar 4 13:20 faq.html
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 images
-rw-r--r-- 1 gvoss 3503 Mar 4 13:20 index.html
-rw-r--r-- 1 gvoss 12742 Mar 4 13:20 installation.html
-rw-r--r-- 1 gvoss 9744 Mar 4 13:20 knownbugs.html
-rw-r--r-- 1 gvoss 4736 Mar 4 13:20 release_notes.html
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 security
drwxrwxr-x 2 gvoss 512 Mar 4 13:20 servlets
The index.html file is the main entry to server
documentation and installation.html should guide you
through basic installation and configuration of your server. Assuming
a host hame of cool1. These files will have the
following URLs:
http://cool1:8080/system/doc/index.html
http://cool1:8080/system/doc/installation.html
You can either substitute your hostname in these URLs,
or use and absolute file name to read the documents.
Server Paradise
This article has touched only the most basic aspects of developing
servlets. There is an entire server and servlet programming API that
makes it convenient to write complex services for your clients without
having to focus on low-level details of HTTP protocols, request formats,
and headers.
In addition, you'll want to learn more about server administration,
including security and password management. You'll find you have full
control of various access and event logs to monitor users and
performance. You can mark specific servlets, files, and pages as
inaccessible, or as requiring various levels of password protection
using the JavaServer Administration Applet. Full documentation for
the applet, as well as tutorials for writing servlets and installing
the server and servlets, is distributed with JavaServer. You'll also
find extensive API documentation and example programs to study.
To give you a sense of how much we like and trust JavaServers, a
JavaServer is now hosting more than 10,000 members of the Java
Developer Connection Web Site. We're thrilled with the performance.
And now that we can write and maintain server extensions entirely in
Java, our site development team seems to think it's died and gone to
heaven. I hope you get as much out of JavaServers as we have.