|
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."
Servers and ServletsKeep 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:
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 ScriptsIf 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:
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="cgi-bin/jdc-example01.pl">
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:
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.
Similar code appears at the end of the CGI script to compose the end of the HTML page.
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.
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="cgi-bin/jdc-example01.pl">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.
The HTML files that you need to copy to server_root/public_html
are listed below for your convenience:
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 ServletsThe 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:
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.
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.
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.
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:
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:
action
argument to the form tag.
<form method="GET" action=/servlet/JdcExample02> Here, the GET method of parameter passing is used, but the POST method could be used as well: <form method="POST" action=/servlet/JdcExample02> 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=/servlet/
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.classFor this article, this translates to: /opt/JavaServerBeta/servlets/JdcExample02.class Here is the entire HTML form designed to invoke the above servlet:
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 ServletsAs mentioned above, developing servlets is a three-step process, reviewed here, one last time, at the risk of driving you crazy:
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 DirectoriesHere 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/servletsThus, the critical directories, relative to server_root are
public_html
cgi-bin
servlets
In addition, you may want to explore the documentation
directories:
Example Servlets Distributed with JavaServerJavaServer 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.htmlFor example, with a host name of cool1 and with JavaServer installed to use the default port, use: http://cool1:8080/system/doc/servlets/examples.htmlThis 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:
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:
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 ControlThis 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 DocumentationA 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
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 ParadiseThis 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. | |||||||||||||||||||||||||
|
| ||||||||||||