SCOUG OS/2 For You - May 1998
Programming for the Net:
Serverside Java
Introduction
In previous articles we have looked at client-webserver interaction based on the CGI model. The client (usually a browser) transmits an HTTP request which optionally includes a set of parameters from the web page. The webserver starts a process, passes the parameters to the process and then
sends the output from the process back to the client.
The CGI program which processes the request can be developed using a number of different "languages" such as C, PERL or even REXX. While all of these work reasonably well, there are
several limitations:
- the overhead at the webserver in starting up a separate process for each request can be significant, especially when high-volume transaction loads exist.
- if the interaction requires multiple transactions, it can be problematic to retain persistent data (usually this is accomplished by passing "hidden" variables back and forth which not only increases the transmission volume but is also not secure).
- to a certain extent programs developed in these languages tend to be platform specific. This is especially true with C and less true with scripting languages such as PERL.
In this article, we will look at a new alternative to developing CGI programs (or webserver processes in general) using Java and see how this approach eliminates the limitations listed above.
Java Servlets - What Are They?
Java server request processing is supported by extension packages to the JDK. Currently they are available as separate classes but will be included in JDK 1.2 and beyond releases. The packages are:
- javax.servlet (generic transaction processing)
- javax.servlet.http (http transaction processing and subject of this article)
The http package is designed to encapsulate the properties and requirements of processing http requests. For example, the class supplies methods for getting request headers, creating response
headers and writing the response data.
In general, one servlet class will be written for each different process (as with CGI programs) and will be an extension of HttpServlet. The methods that commonly need to be coded are:
init(...) - performs onetime initialization
doGet(...) - if the GET request method is to be supported
doPost(...)- if the POST request method is to be supported
doPut(...) - if the PUT request method is to be supported
The parameters for each of the doXXX methods (details later on) are the same:
- HttpServletRequest object - for obtaining request information
- HttpServletResponse object - for building and transmitting the response
What makes this design powerful is how it is implemented. When a servlet class is first referenced in an http request (or if configured to be autostarted), the webserver creates an instance of the class and executes its init() method, passing any configuration parameters defined for the servlet. This allows the class to perform global initialization and create class variables that are available to all requests. The doXXX() method is then invoked to process the request, based on the request type.
After processing the first request, the class object remains active. As additional requests for the same servlet are received, a new request and response pair of objects is created and the appropriate doXXX() method of the existing class object is invoked (normally in a separate thread).
A summary of the benefits of this approach is:
- There is minimal startup overhead to process the request (after the first)
- Parallel request processing is automatically threaded
- Global (or persistent) data is easy to access/modify
- You get to write in Java
But How Do I Actually Write a Servlet?
Most of the work is done in the doXXX() method(s). As mentioned above, each receives a request and response object. The request object contains methods for obtaining the http headers, CGI parameters, and so forth; the response object provides for writing the output stream to the client. This work is essentially the same as is done in a traditional CGI program but is usually much easier to do using the Java framework.
For example, if a browser form (remember those from article 1?) sends fields for "firstname", "lastname" (using the POST method), the following simple servlet will send back a "welcome" response:
public class MyServlet extends HttpServlet {
...
// at startup, perform initialization for class
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
// process POST request
public void doPost(HttpServletRequest req,
HttpServlerResponse resp)
throws ServletException, IOException {
ServletOutputStream out = resp.getOutputStream(); //get outputstream
resp.setContentType("text/html"); //indicate output type
out.println("");
String firstName = req.getParameter("firstname"); //firstname
String lastName = req.getParameter("lastname"); //lastname
out.println("Welcome " + firstName + " " +
lastName + "");
out.println("");
out.close();
}
}
The next code, if inserted in the doXXXX method will print out the http headers and CGI parameters from the request:
Enumeration hdrs = req.getHeaderNames(); //gets all headers
while (hdrs.hasMoreElements()) {
String hdrname = hdrs.nextElement(); //next header name
out.println(" " + hdrname + ": " + req.getHeader(hdrname));
}
Enumeration parms = req.getParameterNames(); //get all param names
while (parms.hasMoreElements()) { //show each parm
String pname = parms.nextElement();
out.println(" " + pname + " = " + req.getParameter(pname));
}
Can I Have a Cookie Now?
A lot of existing webserver applications depend on passing Cookie information to/from client. If these types of applications are being replaced by servlets, it might still be necessary to preserve the
Cookie processing. The serlvet package contains a Cookie class for this purpose. A Cookie can be created using the constructor and set methods for defining its properties. For example:
Cookie myCookie = new Cookie("mine", "valueofmine");
myCookie.setPath("http://www.scoug.com");
would create a new Cookie for any requests going to scoug.com. This can be attached to the http response by:
resp.addCookie(myCookie);
The request object provides a method to obtain all the Cookies in the request. The following sample method would return a Cookie with a specified name:
public Cookie findCookie(String name, HttpServletRequest req) {
Cookie cookieArray[] = req.getCookies();
for (int i=0; i
I Want to Persist
It was mentioned above (more than once) that the servlet model provided a way of retaining a client's data between requests. This is implemented through a set of classes in the servlet package
which include HttpSession, HttpSessionContext, HttpSessionBindingEvent and HttpSessionBindingListener. Unfortunately, these classes are not yet supported in most of the webservers, although the Sun Java WebServer (written entirely in Java) does provide SessionID
parameter for each client.
A simple alternative is to use a Cookie to contain a "sessionid" value and to then use this value as a lookup in a hashtable (or some other collection class) to reference the client data. The hashtable would be defined at the class level and would be accessible by each request. The object in the table would normally be a custom class that defines properties and methods for the client.
For example:
//define a special class to handle the client data, EG
class clientData {
String id;
String firstname, lastname;
String address;
...
public ClientData(String s) {
id = s;
}
public String getId() {
return id;
}
public void setFirstname(String s) {
firstname = s;
}
public String getFirstname() {
return firstname;
}
...
}
//in the global area of servlet class definition:
Hashtable clients = new Hashtable(); //persistent data
// at the beginning of the doXXXX method, we would look for the
// sessionid Cookie and use its value as the lookup
ClientData cd;
Cookie sessCookie = findCookie("sessionid", req);
if (sessCookie == null) { //if not found
String newId = createUniqueId(); //method to get a new id
sessCookie = new Cookie("sessionid", newId);
resp.addCookie(sessCookie);
cd = new ClientData(newId);
clients.put(newId, cd); //add client to Vector
}
else {
cd = (ClientData) clients.get(sessCookie.getValue()); //if cookie, get the clientdata
}
// in the doXXX method, can then reference specific client data as needed
...
String name = cd.getFirstName() or cd.setFirstName(name);
This technique is quite powerful since the persistent data can be more than just data, such as actual class objects.
How To Use Servlets
To use them, a webserver must be enabled with appropriate Java runtime and servlet configuration capabilities. Most of the commercially available webserver products (eg Lotus Domino, Netscape, Apache, Sun Java Webserver) contain this support to some degree. There are also a number of standalone packages (servlet runners) which allow servlets to be tested without a webserver environment.
When a servlet class file has been created, it needs to be moved into the webserver's servlet directory (a special directory for servlets). For performance improvements, usually the servlet can also be configured to the webserver. This involves attaching a name to it, indicating that it is to be automatically started when the webserver starts (or not), and/or specifying parameters that are to be passed to it when it does start.
The servlet can be invoked from the client in one of several ways:
- Directly from the location (address) given to the browser, e.g.,
http://www.myWebServer.com/servlet/MyServlet
(this could also be specified in a FORM Action tag)
- Embedded in HTML - this is done using the <servlet>...</servlet> tags, similar to how an applet is invoked via <applet> tag. The differences for servlets are:
- the servlet executes on the webserver (so Java support does not need to be on the client)
- the HTML file in this case must actually be named as .shtml rather than .html
EG
<... request parameters ...>
The servlet's output will replace the tags in the transmitted response.
Summary
In this article, we have seen how to implement Java webserver processes using the javax.servlet.http extension package and reviewed some of the benefits which arise from using this approach. The primary advantage is that because the processes are coded in Java, you only need to learn the process environment itself (ie, http) to be able to create the servlet code.
The Southern California OS/2 User Group
P.O. Box 26904
Santa Ana, CA 92799-6904, USA
Copyright 1998 the Southern California OS/2 User Group. ALL RIGHTS
RESERVED.
SCOUG is a trademark of the Southern California OS/2 User Group.
OS/2, Workplace Shell, and IBM are registered trademarks of International
Business Machines Corporation.
All other trademarks remain the property of their respective owners.
|