Programming
   Home >  Programming >  Java > 

Servlets


by Bill Venners


Agenda

  • HTML forms and CGI
  • Advantages of servlets over traditional CGI
  • Servlet lifecycle
  • HTTP request and form data
  • HTTP response
  • Persistant state

HTML Forms

<FORM method="POST" action="subscribe.cgi">
<INPUT type=hidden name="userrequest" value="subsingle">
<INPUT type=hidden name="outputfile" value="suboutput">
<INPUT type=hidden name="errorfile" value="suberror">
<TABLE cols="3">

<TR>
<TD align="right">
Your E-mail Address:
</TD>

<TD>
<INPUT type="text" name="email">
</TD>

<TD align="left">
<INPUT type="submit" value="Subscribe">
</TD>
</TR>
</TABLE>
</FORM>

GET and POST

  • Plain old GET:
    GET /jvm/index.html HTTP/1.0
    Referer: http://minovia/subscribe.html
    Connection: Keep-Alive
    User-Agent: Mozilla/4.7 [en] (Win98; I)
    Host: minovia
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    Accept-Encoding: gzip
    Accept-Language: en
    Accept-Charset: iso-8859-1,*,utf-8
    
  • Post:
    POST /subscribe.cgi HTTP/1.0
    Referer: http://minovia/subscribe.html
    Connection: Keep-Alive
    User-Agent: Mozilla/4.7 [en] (Win98; I)
    Host: minovia
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    Accept-Encoding: gzip
    Accept-Language: en
    Accept-Charset: iso-8859-1,*,utf-8
    Content-type: application/x-www-form-urlencoded
    Content-length: 85
    
    userrequest=subsingle&outputfile=suboutput&errorfile=suberror&email=bv%40artima.com
    
  • Get with data:
    GET /subscribe.cgi?userrequest=subsingle&outputfile=suboutput (cont...)
    &errorfile=suberror&email=bv%40artima.com HTTP/1.0
    Referer: http://minovia/subscribeNoPost.html
    Connection: Keep-Alive
    User-Agent: Mozilla/4.7 [en] (Win98; I)
    Host: minovia
    Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
    Accept-Encoding: gzip
    Accept-Language: en
    Accept-Charset: iso-8859-1,*,utf-8
    

CGI Programming

  • Web server fires off a new process (subscribe.cgi)
  • For POST, hands line of data as standard input
  • For GET, sets environment variable QUERY_STRING
  • HTTP response
  • CGI program parses input data, writes to standard output
  • Web server reads CGI program's output, and sends it back to client

A CGI Script

#!/usr/local/bin/perl

#
# Copyright (c) 1998 Bill Venners. All rights reserved.
#

$mailprogram = "/usr/lib/sendmail";

read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
        ($name, $value) = split(/=/, $pair);
        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
        $FORM{$name} = $value;
}
$outputtemplate = "$FORM{'outputfile'}.html";
$errortemplate = "$FORM{'errorfile'}.html";
$mailthis = "To: artima-request@lists.best.com\n";

# make sure the user entered a valid email address.
$temp = $FORM{'email'};
$temp =~ s/_/a/g;
$temp =~ s/-/a/g;
unless ($temp =~ /\w+@\w+\.\w\w+/) {
        &error($FORM{'email'});
        exit;
}

$mailthis .= "From: $FORM{'email'}\n";
$mailthis .= $FORM{'userrequest'};

open(MAIL,"|$mailprogram -t");
print MAIL "$mailthis\n";        
close(MAIL);

&write_output_html($FORM{'email'});
exit;

sub write_output_html {

   $email_address = $_[0];

   open(OUTPUTTEMPLATE,"$outputtemplate") || die $!;

   print "Content-type: text/html\n\n";

   while ($line = ) {

       $line =~ s/\?email_address\?/$email_address/g;
       print $line;
   }

   close(OUTPUTTEMPLATE);
}

sub error {

   $email_address = $_[0];

   open(ERRORTEMPLATE,"$errortemplate") || die $!;

   print "Content-type: text/html\n\n";

   while ($line = ) {

       $line =~ s/\?email_address\?/$email_address/g;
       print $line;
   }

   close(ERRORTEMPLATE);

   exit;
}

A Template File

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD>
<TITLE>Subscribe to the Artima Newsletter</TITLE>
<META NAME="description" content="The
Artima Newsletter is a monthly email publication announcing activities
at artima.com, a resource for Java and Jini developers.">
<META NAME="keywords" content="Java Newsletter, Mailing List">
<META NAME="author" content="Bill Venners">
</HEAD>
<!--BEGIN_ARTIMA_COLOR_SCHEME-->
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000CC" VLINK="#660099" ALINK="000066">
<!--END_ARTIMA_COLOR_SCHEME-->
<!--BEGIN_ARTIMA_LOGO-->
<CENTER>
<A href="index.html">
<IMG src="images/smartima.gif" alt="artima.com - a resource for Java and Jini developers"
border="0" width="421" height="22"></A><BR>
</CENTER>
<!--END_ARTIMA_LOGO-->
<!--BEGIN_LINKS-->
<CENTER>
<FONT size="-1" face="geneva, arial, sans-serif">
<A href="index.html">Artima</A> | 
<A href="search.html"><STRONG>Search</STRONG></A> | 
<A href="java/index.html">Java</A> | 
<A href="javadesign/index.html">Design</A> | 
<A href="jvm/index.html">JVM</A> | 
<A href="jini/index.html">Jini</A> | 
<A href="bookshop/index.html">Books</A> | 
<A href="javaseminars/index.html">Seminars</A> | 
<A href="subscribe.html"><STRONG>Subscribe</STRONG></A> 
</FONT>
</CENTER>
<BR>
<!--END_LINKS-->
<!--BEGIN_BURST:7:-->
<CENTER>
<A href="http://www.burstnet.com/ads/ad5150a-map.cgi/7"
target=_top><IMG src="//www.burstnet.com/cgi-bin/ads/ad5150a.cgi/7" 
width=468 height=60 border=0></A>
</CENTER>
<BR>
<!--END_BURST--> 
<!--BEGIN_TITLE_BLOCK-->
<font face="arial, helvetica" COLOR="#000066">
<font size=6>
<SPAN class=pagetitle1>Subscription Successful</SPAN>
</font>
</font>
<!--END_TITLE_BLOCK-->
<HR align="left" width="85%">
<TABLE CELLPADDING="3" CELLSPACING="0" BORDER="0" width="85%">
<TR>
<TD  width="100%" valign="top" rowspan="100">
<P>
You have been successfully added to the Artima Newsletter's mailing list at the
following e-mail address:
<BLOCKQUOTE>
<STRONG>?email_address?</STRONG>
</BLOCKQUOTE>

<P>You can expect a somewhat cryptic confirmation of your subscription via
e-mail. The message will be from artima-errors@lists.best.com and the
subject will be INFO RESPONSE.

<P>If you change your mind, you can
<A href="http://www.artima.com/unsubscribe.html">unsubscribe</A> at any time.

<P>
<HR align="left" width="100%">
Some entry points at <CODE>artima.com</CODE>:
<BLOCKQUOTE>
<UL>
<LI><A href="http://www.artima.com/index.html">Artima Software</A> - the
home page
<LI><A href="http://www.artima.com/javaseminars/index.html">Java Seminars</A>
- in-house and public classes taught by Biill Venners
<LI><A href="http://www.artima.com/javabooks.html">Java Books</A> - books
written or being written by Bill Venners
<LI><A href="http://www.artima.com/bv/index.html">Bill Venners</A> - personal
home page
</UL>
</BLOCKQUOTE>
</TD>
</TR>
</TABLE>
<HR width="100%">
<!--BEGIN_FOOTER-->
<TABLE width="100%">
<TR>
<TD align="left">
<FONT size="1" face="geneva, arial, sans-serif">
Last Updated: Wednesday, July 05, 2000
Copyright © 1996-2000 Bill Venners. All Rights Reserved. © 1996-2000 Bill Venners. All Rights Reserved. </FONT> </TD> <TD align="right"> <FONT size="1" face="geneva, arial, sans-serif"> URL: http://www.artima.com/javaseminars/modules/Servlets/index.html
Trouble with this page? Contact: <a href="mailto:webmaster@artima.com">webmaster@artima.com</a> </FONT> </TD> </TR> </TABLE> <!--END_FOOTER--> </BODY> </HTML>

CGI With Servlets

  • Web server fires off a Java application to host servlets
  • The first time a servlet is requested, host loads the servlet
  • From then on, host fires off a new thread to handle each request
  • If a servlet is updated, host replaces old servlet with new version

Servlet Advantages

  • Starting threads is cheaper than starting processes
  • For simultaneous clients, running multiple threads is cheaper than running multiple processes
  • CGI process disappears, but servlet stays around
  • Thus, servlets can maintain state, such as leaving a database connection open

Other Advantages

  • A cleaner API for CGI
  • Since they're written in Java, servlets are very portable
  • Traditional CGI programs vulnerable to many attacks that servlets aren't
  • Multiple servlets can share data, so can do database connection pooling

A Basic Servlet

 1 // In file Servlets/ex2/BasicServlet.java
 2
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class BasicServlet extends HttpServlet {
11 
12     public void doGet(HttpServletRequest request, HttpServletResponse response)
13         throws IOException, ServletException {
14
15         response.setContentType("text/html");
16
17         PrintWriter out = response.getWriter();
18         out.println("<HTML>");
19         out.println("<BODY>");
20         out.println("<HEAD>");
21         out.println("<TITLE>A Basic Servlet</TITLE>");
22         out.println("</HEAD>");
23         out.println("<BODY>");
24         out.println("<H1>A Basic Servlet</H1>");
25         out.println("<P>");
26         out.println("This page was produced by a servlet. Oh boy.");
27         out.println("</BODY>");
28         out.println("</HTML>");
29     }
30 }

Servlet Lifecycle

  • init() - called when servlet instantiated
  • service() - invoked with new thread for each client request
  • doXXX() - called by service() for GET, POST, HEAD, OPTIONS, TRACE, DELETE, PUT
  • SingleThreadModel - tag interface implemented by thread-unsafe servlets
  • destroy() - called before unloading a servlet

doGet() and doPost()

  • Most servlets just override doGet(), doPost(), or both
  • doGet() - called by service() for GET requests
  • doPost() - called by service() for POST requests
  • getLastModified() - used to set Last-Modified headers, respond properly to If-Modified-Since requests

Initialization Parameters

 1 // In file Servlets/ex2/ParamServlet.java
 2 
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.ServletConfig;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class ParamServlet extends HttpServlet {
12 
13     String DEFAULT_QUESTION = "(2 * b) || !(2 * b)";
14     String DEFAULT_ANSWER = "Get thee to a nunnery!";
15     String question;
16     String answer;
17 
18     public void init(ServletConfig config)
19         throws ServletException {
20 
21         super.init(config);
22 
23         question = config.getInitParameter("question");
24         if (question == null) {
25             question = DEFAULT_QUESTION;
26         }
27 
28         answer = config.getInitParameter("answer");
29         if (answer == null) {
30             answer = DEFAULT_ANSWER;
31         }
32     }
33 
34     public void doGet(HttpServletRequest request, HttpServletResponse response)
35         throws IOException, ServletException {
36 
37         response.setContentType("text/html");
38 
39         PrintWriter out = response.getWriter();
40         out.println("<HTML>");
41         out.println("<BODY>");
42         out.println("<HEAD>");
43         out.println("<TITLE>A Servlet that uses Parameters</TITLE>");
44         out.println("</HEAD>");
45         out.println("<BODY>");
46         out.println("<H1>Q & A</H1>");
47         out.println("<P>");
48         out.println("Question: " + question);
49         out.println("<P>");
50         out.println("Answer: " + answer);
51         out.println("</BODY>");
52         out.println("</HTML>");
53     }
54 }

Last Modified Date

 1 // In file Servlets/ex3/ModificationTimeServlet.java
 2 
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.ServletConfig;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class ModificationTimeServlet extends HttpServlet {
12 
13     String DEFAULT_QUESTION = "(2 * b) || !(2 * b)";
14     String DEFAULT_ANSWER = "Get thee to a nunnery!";
15     String question;
16     String answer;
17     private long modificationTime; // in millisecs
18 
19     public void init(ServletConfig config)
20         throws ServletException {
21 
22         super.init(config);
23 
24         question = config.getInitParameter("question");
25         if (question == null) {
26             question = DEFAULT_QUESTION;
27         }
28 
29         answer = config.getInitParameter("answer");
30         if (answer == null) {
31             answer = DEFAULT_ANSWER;
32         }
33 
34         // Round to nearest second
35         modificationTime = (System.currentTimeMillis() / 1000) * 1000;
36     }
37 
38     public long getLastModified(HttpServletRequest request) {
39 
40         return modificationTime;
41     }
42 
43     public void doGet(HttpServletRequest request, HttpServletResponse response)
44         throws IOException, ServletException {
45 
46         response.setContentType("text/html");
47 
48         PrintWriter out = response.getWriter();
49         out.println("<HTML>");
50         out.println("<BODY>");
51         out.println("<HEAD>");
52         out.println("<TITLE>A Servlet that uses Parameters</TITLE>");
53         out.println("</HEAD>");
54         out.println("<BODY>");
55         out.println("<H1>Q & A</H1>");
56         out.println("<P>");
57         out.println("Question: " + question);
58         out.println("<P>");
59         out.println("Answer: " + answer);
60         out.println("</BODY>");
61         out.println("</HTML>");
62     }
63 }

Form Data

  • Name-value pairs passed from client in GET or POST via methods of HttpServletRequest
  • getParameter(String) returns:
    • String value from form
    • "" if param exists but no value
    • null if param doesn't exist
  • getParameterValues(String) returns:
    • array of values for one param name
    • null if param doesn't exist
  • Parameter names are case sensitive
  • getParameterNames() returns unordered Enumeration of names

Using Form Parameters

 1 // In file Servlets/ex4/FormServlet.java
 2 
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import javax.servlet.ServletException;
 6 import javax.servlet.ServletConfig;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10  
11 public class FormServlet extends HttpServlet {
12 
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14         throws IOException, ServletException {
15 
16         response.setContentType("text/html");
17 
18         PrintWriter out = response.getWriter();
19         out.println("<HTML>");
20         out.println("<BODY>");
21         out.println("<HEAD>");
22         out.println("<TITLE>A Form Servlet</TITLE>");
23         out.println("</HEAD>");
24         out.println("<BODY>");
25         out.println("<H1>A Servlet in Top Form</H1>");
26         out.println("<P>");
27         out.println("Name: " + request.getParameter("name"));
28         out.println("<P>");
29         out.println("Rank: " + request.getParameter("rank"));
30         out.println("<P>");
31         out.println("Serial Number: " + request.getParameter("serial"));
32         out.println("</BODY>");
33         out.println("</HTML>");
34     }
35
36     public void doPost(HttpServletRequest request, HttpServletResponse response)
37         throws IOException, ServletException {
38 
39         doGet(request, response);
40     }
41 }
 1 <HTML>
 2 <HEAD>
 3 <TITLE>A Form for a Servlet</TITLE>
 4 </HEAD>
 5 <BODY>
 6 <CENTER>
 7 <H1>We Have Ways To Make You Talk</H1>
 8 <FORM action="/examples/servlet/FormServlet">
 9 <TABLE>
10 <TR>
11 <TD>
12 <STRONG>Name:</STRONG>
13 </TD>
14 <TD>
15 <INPUT type="text" name="name">
16 </TD>
17 </TR>
18 <TR>
19 <TD>
20 <STRONG>Rank:</STRONG>
21 </TD>
22 <TD>
23 <INPUT type="text" name="rank">
24 </TD>
25 </TR>
26 <TR>
27 <TD>
28 <STRONG>Serial Number:</STRONG>
29 </TD>
30 <TD>
31 <INPUT type="text" name="serial">
32 </TD>
33 </TR>
34 <TR>
35 <TD colspan="2" align="center">
36 <INPUT type="submit" value="Submit">
37 </TD>
38 </TR>
39 </TABLE>
40 </FORM>
41 </CENTER>
42 </BODY>
43 </HTML>

Reading All Parameters

 1 // In file Servlets/ex5/AllParamsServlet.java
 2 
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import java.util.Enumeration;
 6 import javax.servlet.ServletException;
 7 import javax.servlet.ServletConfig;
 8 import javax.servlet.http.HttpServlet;
 9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 
12 public class AllParamsServlet extends HttpServlet {
13 
14     public void doGet(HttpServletRequest request, HttpServletResponse response)
15         throws IOException, ServletException {
16 
17         response.setContentType("text/html");
18 
19         PrintWriter out = response.getWriter();
20         out.println("<HTML>");
21         out.println("<BODY>");
22         out.println("<HEAD>");
23         out.println("<TITLE>A Servlet that Reports all Parameters</TITLE>");
24         out.println("</HEAD>");
25         out.println("<BODY>");
26         out.println("<H1>The Parameters and Their Values:</H1>");
27 
28         Enumeration names = request.getParameterNames();
29         while (names.hasMoreElements()) {
30             out.println("<P>");
31             String name = (String) names.nextElement();
32             String value = request.getParameter(name);
33             out.println("Parameter Name: " + name + "<BR>");
34             out.println("Parameter Value: " + value);
35         }
36 
37         out.println("</BODY>");
38         out.println("</HTML>");
39     }
40 
41     public void doPost(HttpServletRequest request, HttpServletResponse response)
42         throws IOException, ServletException {
43 
44         doGet(request, response);
45     }
46 }

Request Headers

  • getHeader(String headerName) returns String value or null
  • Header name is not case sensitive
  • getHeaders(String headerName) returns Enumeration of values of all occurances
  • getHeaderNames() returns Enumeration of all header names in request

Request Convenience Methods

  • getCookies(): Cookie header as Cookie[]
  • getContentLength(): Content-Length header (num bytes sent by POST)
  • getAuthType() and getRemoteUser(): parsed Authorization header
  • getContentType(): Content-Type header (for data attached via POST or PUT
  • getMethod(): GET, POST, HEAD, etc.
  • getRequestURI(): URL between port and ?
  • getProtocol(): HTTP/1.0, HTTP/1.1, etc.

HTTP Request Headers

  • Accept: MIME types client can accept
  • Accept-Charset: Character set client can handle: ISO-8859-1, etc.
  • Connection: whether to keep socket open: keep-alive or close
  • From: email address of requestor (used by spiders)
  • Host: host and port in original URL
  • If-Modified-Since: send only if newer
  • Pragma: value no-cache tells proxies to always forward request
  • Referer: URL of referring web page
  • User-Agent: browser or client

Compressing Pages

 1 // In file Servlets/ex6/CompressServlet.java
 2 
 3 import java.io.PrintWriter;
 4 import java.io.IOException;
 5 import java.io.OutputStream;
 6 import javax.servlet.ServletException;
 7 import javax.servlet.ServletConfig;
 8 import javax.servlet.http.HttpServlet;
 9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 import java.util.zip.GZIPOutputStream;
12 
13 public class CompressServlet extends HttpServlet {
14 
15     public void doGet(HttpServletRequest request, HttpServletResponse response)
16         throws IOException, ServletException {
17 
18         response.setContentType("text/html");
19 
20         PrintWriter out;
21         String zipped = " (Compressed Document)";
22 
23         String acceptedEncodings = request.getHeader("Accept-Encoding");
24         if ((acceptedEncodings != null)
25             && (acceptedEncodings.indexOf("gzip") != -1)) {
26 
27             // GZIP is accepted, so send a compressed document
28             OutputStream gzipper = new GZIPOutputStream(response.getOutputStream());
29             out = new PrintWriter(gzipper);
31             response.setHeader("Content-Encoding", "gzip");
32         }
33         else {
34             out = response.getWriter();
35             zipped = " (Uncompressed Document)";
36         }
37 
38         out.println("<HTML>");
39         out.println("<BODY>");
40         out.println("<HEAD>");
41         out.println("<TITLE>A Romantic Servlet" + zipped + "</TITLE>");
42         out.println("</HEAD>");
43         out.println("<BODY>");
44         out.println("<H1>How do I love thee? Let me count the ways.</H1>");
45 
46         out.println("<P>");
47 
48         for (int i = 1; i < Integer.MAX_VALUE; ++i) {
49             out.print(Integer.toString(i) + ", ");
50             if ((i % 100) == 0) {
51                 out.println("");
52                 out.println("<P>");
53             }
54         }
55 
56         out.println(Integer.toString(Integer.MAX_VALUE));
57 
58         out.println("</BODY>");
59         out.println("</HTML>");
60     }
61 
62     public void doPost(HttpServletRequest request, HttpServletResponse response)
63         throws IOException, ServletException {
64 
65         doGet(request, response);
66     }
67 }

HTTP Response

  • Response consists of:
    1. status line
    2. response headers
    3. blank line
    4. data
    HTTP/1.1 200 OK
    Content-Type: text/plain
    
    Think Objects!
    
  • Must set status line and response headers before starting to send data
  • In 2.1, PrintWriter isn't buffered
  • In 2.2, can use get/setBufferSize() and isCommited()

Status Codes

  • setStatus(int): standard way
    (can use constants: SC_NOT_FOUND, etc.)
  • sendError(int code, String msg): sends status code plus HTML formatted msg
  • sendRedirect(String url): generates 302 response and Location header with value url

Response Headers

  • Response Headers
  • Send cookies
  • Specify page modification date (for client caching)
  • Tell client to reload after designated interval
  • Specify content length (for persistent socket connections)
  • Specify MIME type

Setting Headers

  • setHeader(String hdr, String val): sets header to value
  • setDateHeader(String hdr, long ms): sets header to millisecs since epoch converted to date
  • setIntHeader(String hdr, int val): sets header to val converted to string
  • setContentType(): sets Content-Type
  • setContentLength(): sets Content-Length (for persistent connections)
  • addCookie(): inserts a cookie into Set-Cookie
  • sendRedirect(String url): sets Location to url plus status code to 302

HTTP Response Headers

  • Use getRequestProtocol() before using 1.1-only headers
  • Content-Encoding: compression technique
  • Content-Language: language of the data string
  • Content-Length: bytes of data being sent
  • Content-Type: MIME type
  • Last-Modified: when data was last changed
  • Pragma: no-cache for 1.0 clients
  • Set-Cookie: set a cookie

Cache-Control Header

  • New in HTTP 1.1
  • public: cacheable
  • private: for single user, cache only in private store
  • no-cache: never cache (same as Pragma: no-cache)
  • no-store: don't cache or even make a temp file
  • must-revalidate: always go back to source
  • proxy-revalidate: shared caches must always go back to source
  • max-age=xxx: consider stale after xxx seconds
  • s-max-age=xxx: shared caches should consider data stale after xxx seconds

Refresh Header

  • Not in HTTP 1.1, but supported by Netscape and IE
  • How many seconds to wait before automatically requesting the page again
    setIntHeader("Refresh", 60);
    
    or
    setHeader("Refresh",
        "5; http://www.artima.com/realindex.html");
    

Session Tracking API

  • HttpSession uses cookies, if supported, else URL-rewriting
  • Must look up current session object, or create a new one
  • Retrieve and store data in the session object
  • Discard completed/abandoned sessions
  • Encode session info in URLs

Using HttpSession

  • HttpSession session = request.getSession(true);
  • getAttribute(String name) - get a previously stored Object value
  • setAttribute(String name, Object value) - associate a value with a name
  • If implements HttpSessionBindingListener, valueBound() or valueUnbound() called
  • removeAttribute(String name) - removes any value associated with name
  • getAttributeNames() - get names of all attributes for a session
  • getID() - returns unique String key for session
  • isNew() - true if just created
  • getCreationTime() - true if just created
  • getLastAccessTime() - returns time when client last sent a request associated with the session
  • get/setMaxInactiveInterval() - get or set the number of seconds after which a session should be automatically inactivated
  • invalidate() - true if just created

Exercises

Problem 1.

Download and install tomcat, perhaps into the C:\jakarta-tomcat directory. For a users guide to tomcat, visit C:\jakarta-tomcat\doc\uguide\tomcat_ug.html.

To configure the tomcat servlet container server, set the environment variable TOMCAT_HOME to the installation directory, as in:

set TOMCAT_HOME=c:\jakarta-tomcat

To start tomcat, just run the startup batch file in the bin subdirectory of the installation directory, as in:

c:
cd \jakarta-tomcat
startup

Once you've started the server, open a web browser and try connecting to your own port 8080, where tomcat will be running, by typing a URL into to browser's address field such as:

http://127.0.0.1:8080/

Click on Servlet Examples, then try to run the various example servlets on the Servlet Examples page.

Problem 2.

Create a servlet, FirstServlet.java that just generates a web page with the greeting, "My first servlet works like a charm!".

Compile your servlet, then move the FirstServlet.class file to the webapps\examples\WEB-INF\classes subdirectory of the tomcat installation directory.

Test your servlet by typing in its name into the browser's address field, using a URL such as:

http://taiping:8080/examples/servlet/FirstServlet

Problem 3.

Create a new directory named MyPages in the webapps\examples directory of your tomcat installation directory. In your MyPages directory, create a web page named subscribe.html that allows a user to subscribe to your mailing list. Place a form on the page that contains one text input field, labeled "Your email address:". The

Create a servlet named SubscribeServlet.java, that just generates a web page that prints out the value of the email address typed into the form. Make sure your servlet will respond to both GET and POST methods.

To run the servlet, once again just move the SubscribeServlet.class file to the webapps\examples\WEB-INF\classes subdirectory of the tomcat installation directory, and type the appropriate URL into the browser's address field, as in:

http://taiping:8080/examples/servlet/SubscribeServlet

Problem 4.

Change the SubscribeServlet from Problem 3 so that it verifies that a valid email address was typed in. An email address is valid if it has one or more characters, a dot ('.'), one more characters, the at sign ('@'), and one or more characters.

If the user types in a valid email address, just generate a web page that says the user has successfully subscribed to your mailing list. If the user does not provide a valid email address, generate an error page that indicates they didn't type in a valid email address. On the error page, include the an input field and submit button in which they can try again. When they type in an email address on this error page and press submit, they'll run your SubscribeServlet again.

Install and test your servlet, trying various valid and invalid email addresses.

Problem 5.

Unless you used template files in Problems 3 and 4, make a new version of your SubscribeServlet called SubscribeServlet2 that, instead of printing out hard coded HTML tags from println() statements, reads in template files that define the base HTML output for the success and error pages. The servlet should search through the template file for a special trigger character sequence, such as ?email_address?, and replace that trigger with the actual email address typed into the form.

Install and test your servlet with various valid and invalid email addresses.

Problem 6.

Create a servlet called CounterServlet that just returns a web page that indicates how many times someone has accessed that servlet. To do this, you'll need to create an instance variable in the servlet that keeps track of how many accesses have already occurred. Because incrementing an int or long is not an atomic operation for a thread, you'll have to synchronize access to that int or long counter variable.

Install and test your servlet. Each time you hit it, it should increment the number displayed back to the browser.

Problem 7.

Create an ecommerce web application that allows a user to purchase "Whiz-bang Widgets." Create one web page (titled "Buy a Whiz-Bang Widgit!") that allows the user to specify his or her name and the number of Whiz-bang Widgets desired. Make sure you say how much each widget will cost. When the user submits this page, a servlet (named WhizbangServlet.java) will verify that all fields have been filled with valid responses. If not, the servlet should give an error page that includes the same form (use a template file). If the user has typed in valid data, the servlet should create a session object. The servlet should store the user's name and desired widget count into the session object, and return a page that has the title "Credit Card Information," that lists the total amount of widgets ordered, and the total price.

Install and test this form and servlet.

Problem 8.

Enhance the Credit Card Information page from Problem 7, such that it contains a form that allows the user to type in his or her credit card information -- at a minimum: the credit card type (Visa, Mastercard, American Express, etc.), the credit card number, the name on the card, and the expiration date. To be nice, fill in the name on card field with the name the user typed into the name field of the previous (Buy a Whiz-Bang Widgit!) web page.

Create a new servlet, named CreditCardServlet.java, that verifies that the form data typed into this page is valid. If not, show an error page that includes the form so they can try again. If the user was successful, add the credit card information to the session object and print out a final verification page that contains all the information the user has typed in. Ask the user if all this information is OK, and whether or not he or she really wants all those Whizbang Widgets.

Problem 9.

Create one final servlet, named SoldServlet.java, that responds to the user pressing OK on the verification page returned by the CreditCardServlet. This servlet should grab the session object for the user and just print out a page that says, "Sold!", and lists once again the user's name, the number of widgets, and the total cost.