Module 15: Servlets and Interactive Websites
Introduction
First, let's start by digesting some web-technology buzzwords:
Ajax, Angular, Apache, ASP, AWS, clientserver, Cookies, Certificates,
ColdFusion, CGI, CSS, Forms, Get, HTML, HTTP, Java, Javascript,
JQuery, JSon, JSP, NAB, Perl, Post, TCP/IP, SOAP, SSI, SSL, XML.
Exercise 1:
Which one of these is not a web technology buzzword?
Behind the scenes: HTML
What is HTML?
- HTML = HyperText Markup Language.
- Originates from SGML (which is more complex).
- It's a simple text markup/formatting language.
- Limited formatting control given to creator.
- Most formatting choices made by displayer.
- Simple input elements: form elements.
Learn more about HTML
Four ways of building an HTML website:
- Web design software
- Example: Adobe Dreamweaver.
- Build a media rich website, publish as HTML, and upload
to website.
- Use an online host:
- Examples: Squarespace, Wix, Weebly
- Quick drag-and-drop in browser, lots of templates.
- Host site manages your domain name.
- Use a content-system
- Examples: Drupal, Wordpress.
- Several templates, customizable.
- Easy to "edit in page".
Exercise 2:
- Create two simple HTML pages that link to each other.
- Create a form to read a name and password, where both
the text fields are aligned in a table.
Demonstrate both pages (but not the form action)
using these instructions.
How It Works: An Internet Crash-Course
- How stuff moves around the Internet: - in packets
- TCP/IP:
- IP: Internet Protocol (handles packets)
- TCP: Transmission Control Protocol (handles connections)
- Applications:
- HTTP: HyperText Transfer Protocol
- User clicks on link in browser.
- Browser examines URL and gets IP address of destination
(website).
- Browser sends HTTP request to website.
- Webserver is already listening at port.
- Webserver looks at request and extracts filename.
- Webserver sends entire file to browser.
- Browser decodes (parses) HTML and displays.
- Browser makes additional requests as needed (images etc).
- Sending Form data (parameters)
- User fills in Form (text, buttons etc).
- User clicks on submit.
- Browser collects Form data.
- Browser extracts URL buried in Form (not always visible to
user).
- Browser sends request and parameters to webserver.
- Webserver is listening on port.
- Webserver extracts Form data.
- Webserver fires up locally-residing program (CGI)
and hands over Form data (parameters).
- CGI program computes output and gives it to webserver.
- Webserver sends output back to Browser.
- Browser displays output.
CGI - Common Gateway Interface
What is CGI?
- A webserver feature that allows programs to run
alongside/inside the webserver.
- The programs can be written in any language.
- Sometimes the languages are interpreted (Perl, Java, Tcl, VB);
sometimes compiled (C, C++).
- The webserver passes Form data to these programs, and the
programs write output directly to the invoking Browser.
Exercise 3:
- Examine the search query at www.yahoo.com
or www.ask.com.
- Which of GET or POST is being used?
How does a webserver call a CGI program? Three possible ways:
- By forking a new process:
- Usually for C/C++ CGI programs.
- The webserver forks off a new (shell) process which starts
execution of the C program.
- The forking is performed for each HTTP request.
- Forking is expensive.
- Wasteful for CGI programs that run repeatedly.
- By pre-loading the program when the webserver is started:
- For commonly-used programs, the code can be rolled into the
webserver.
- Then, the CGI program is really part of the webserver.
- Extremely efficient since it is already loaded.
- Can crash the webserver if badly written.
- Changing the program requires re-starting the webserver.
- Dynamic one-time loading:
- The CGI program is loaded when first called.
- Subsequent requests simply multi-thread the already-loaded program.
- If the program is changed, it is re-loaded without bringing
the webserver down.
- Interpreted languages make this option very safe.
- This is the approach used by Java servlets.
Database Access
- What is a database system>
- Data (database).
- Programs that handle the data (database server).
- Programming language (SQL).
- How it's used by a webserver:
- CGI program realizes dbase needs to be accessed.
- It asks dbase server to get data (using SQL commands).
- Dbase server returns data.
- CGI program formats data in HTML and writes HTML to Browser.
- Several ways in which a CGI program can interface with a
Dbase server:
- Using a custom method used by that particular dbase server.
- Using a standard access method like ODBC/JDBC.
- Rolling the CGI program and dbase client into a single unit.
- Placing the entire webserver inside the dbase server/client.
(e.g., webserver is an Oracle OCI program).
Server Side Includes (SSI)
- What is an SSI?
- Code that's buried in a page (HTML) that never shows up at the
Browser.
- It gets executed at the server at the time the page is requested.
- Languages:
- Active Server Pages (ASP).
- Developed by Microsoft.
- Uses Visual Basic.
- Supported by some webservers (such as IIS).
- Java Server Pages (JSP).
- Uses Java as the "language".
- Supported by JSP package in webservers.
- The SSI "standard"
- Developed by Apache.
- A simple set of directives, like a macro language.
- Javascript:
- Some webservers now support a full Javascript engine.
- Example:
Here is a simple ASP page:
<html> <head> <title> Hello World </title> </head>
<body>
Hello World! (plain HTML text).
<%
Dim str
str = "Hello World (from Visual Basic string)"
Response.write (str)
%>
</body>
</html>
Before this is sent out by the webserver, the code is executed,
which writes "in place".
The HTML actually received by the requesting browser is:
<html> <head> <title> Hello World </title> </head>
<body>
Hello World! (plain HTML text).
Hello World (from Visual Basic string)
</body>
</html>
Client-Side Computing
- What is client-side computing?
- The page contains code that executes in the Browser.
- You can see this code on the client side (in the Browser).
- Languages:
Javascript, Visual Basic Script
- How it works: (Javascript example)
- Browser fetches page (as usual).
- Page contains Javascript.
- Browser brings up Javascript engine, which executes code.
- What can you do with Javascript?
- Bring up new windows.
- Flip-over images.
- Check input.
- Compute and write to page.
- Javascript is the most popular web front-end
language today.
- Popular Javascript libraries include:
- Angular.js (from Google)
- JQuery.js
- NOTE: Javascript has nothing to do with Java.
Exercise 4:
Find a webpage that uses Javascript or Visual Basic.
Java Servlets
- What are Java servlets?
- Java's solution to CGI programs.
- Wrong way to use Java as CGI:
- Write stand-alone Java program.
- Invoke it via new CGI shell process.
- The right way:
Use servlets and a servlet-compatible server.
- How it works:
- Browser makes a servlet request to webserver.
- Webserver recognizes the URL as a servlet URL.
(e.g., http://www.obvious.com/servlets/blah)
- Webserver loads servlet if not already loaded.
- Servlet executes and delivers output to webserver (HTML
output).
- Webserver delivers output to Browser.
- What you need to write servlets:
- JDK 1.2 or higher.
- A servlet-compatible webserver.
- Example: HelloWorld servlet
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class HelloWorld extends HttpServlet {
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// Set the content type of the response.
resp.setContentType ("text/html");
// Create a PrintWriter to write the response.
PrintWriter out = new PrintWriter (resp.getOutputStream());
// The first part of the response.
out.println ("<html>");
out.println ("<head><title> Test </title></head>");
out.println ("<body>");
// The greeting.
out.println ("Yo, Hello World!");
// Last part.
out.println ("</body>");
out.println ("</html>");
out.flush();
// Screen I/O
System.out.println ("Inside servlet ... servlet complete");
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
doGet (req, resp);
}
}
- So, what are GET and POST?
- When Form data is sent by the browser, it can be
sent in one of two ways: (1) using
the GET method and (2) using the POST method.
- In the GET method, the form data (parameters) is appended to the
URL, as in:
https://www.ask.com/web?q=house
Here, the text field contains house.
- In the POST method, the browser simply sends the form data
directly.
- When you create an HTML form, you decide whether you want to use
GET or POST.
- When you use GET, the doGet() method of your servlet is called,
otherwise the doPost() method is called.
- The standard practice is to use POST, unless you
need to use GET.
- You need to use GET when you want a link to invoke a CGI
program (servlet).
Your First Servlet - HelloWorld
Now let's write Java - a simple servlet that writes "Hello World!" to
the browser: (source file)
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class HelloWorld extends HttpServlet {
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// Set the content type of the response.
resp.setContentType ("text/html");
// Extract the PrintWriter to write the response.
PrintWriter out = resp.getWriter ();
// The first part of the response.
out.println ("<html>");
out.println ("<head><title> Test </title></head>");
out.println ("<body>");
// The greeting.
out.println ("Yo, Hello World!");
// Last part.
out.println ("</body>");
out.println ("</html>");
out.flush();
// Screen I/O
System.out.println ("Inside servlet ... servlet complete");
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// Default, for now.
doGet (req, resp);
}
}
Note:
- The servlet class libraries need to be imported,
along with PrintWriter.
- There are two methods, one for each type of request: GET or POST.
- You can decide not to "really" implement one method and instead
have it call the other.
- There are two object parameters to each method, the "request"
and the "respponse".
- The HttpServletResponse instance has an
OutputStream
that is used to write directly to the requesting browser.
- We set the content-type (as required by the HTTP protocol):
// Set the content type of the response.
resp.setContentType ("text/html");
- We write HTML to the output, e.g.,
out.println ("<html>");
out.println ("<head><title> Test </title></head>");
- Don't forget to flush the output stream:
out.flush();
- Optionally, for debugging, we can also write to the local
screen where the webserver is running:
System.out.println ("Inside servlet ... servlet complete");
Exercise 5:
Modify the HelloWorld example to print something else and test
it using these instructions.
Extracting Parameters in a Servlet
Next, let us create an HTML Form, and have a servlet pick up the
Form data entered by the user.
First, an HTML page with a form:
<html>
<head><title>Test Post</title>
<body>
<form action="http://unix.seas.gwu.edu:40013/servlets/TestForm" method="post">
Enter a string: <input type="text" name="param1">
And then press "Go": <input type="submit" value="Go">
</form>
</body>
</html>
Next, the TestForm.java servlet: (source)
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class TestForm extends HttpServlet {
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// Set the content type of the response.
resp.setContentType ("text/html");
// Extract the PrintWriter to write the response.
PrintWriter out = resp.getWriter ();
// The first part of the response.
out.println ("<html>");
out.println ("<head><title> Test </title></head>");
out.println ("<body>");
// Now get the parameters and output them back.
out.println ("Request parameters: ");
Enumeration e = req.getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String value = req.getParameter (name);
if (value != null)
out.println ("<li> name=[" + name + "] value=[" + value + "]");
else
out.println ("<li> name=[" + name + "] did not have a value");
}
// Last part.
out.println ("</body>");
out.println ("</html>");
out.flush ();
}
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
doPost (req, resp);
}
}
Note:
- We need to import java.util.Enumeration.
- Whatever parameters were provided are all in the
HttpServletRequest instance.
- We can list these parameters by getting an Enumeration
instance from the request by calling getParameterNames():
Enumeration e = req.getParameterNames();
- The "name" of a parameter is really the string in the
name attribute of the tag for the particular Form element.
- For example, the name string is param1 below.
Enter a string: <input type="text" name="param1">
- Now, if we want to retrieve the actual string typed in by the
user, we use that name in getParameter():
String whatTheUserTyped = req.getParameter ("param1");
Exercise 6:
Compile and test the above servlet using your assigned port number
with these instructions.
Exercise 7:
PART I: Change the HTML page by adding the following inside the "body"
<input type="hidden" name="hidden1" value="hiddenvalue1">
Use the same servlet as above (TestForm.java) as the form
action. You should see the hidden parameter.
PART II: log in to any web-based system where you have an
account, and examine the page sources to see whether there are hidden
parameters.
Hidden Parameters
Important observations about HTTP and webservers:
- HTTP is a "stateless" protocol. The webserver does not maintain
information across successive accesses.
- Thus, as a web programmer, your servlets cannot know "who" is
invoking the servlet.
Using hidden parameters to maintain user information in webpages:
- Initially, we'll ask for a "login" to know who our user is.
- Each successive page will be generated by the servlet.
- The generated pages will contain the user name buried in a hidden
parameter.
- Any request from a generated page can be personalized.
For example, suppose this is the login page:
After logging in, the user sees:
Upon clicking on "Fortune", say, the result is something like:
Note:
- The username appears on all screens.
- We will have our servlet track usernames by writing the username
to HTML as a hidden parameter, and by reading it each time.
Let us build this application step by step:
- First, we'll assume that that the servlet URL is
http://unix.seas.gwu.edu:40013/servlets/examples/TestLogin
- First, the HTML for the entry page
<html>
<head><title>Test Login</title>
<body>
<form action="http://unix.seas.gwu.edu:40013/servlets/examples/TestLogin" method="post">
Enter username: <input type="text" name="username">
<input type="submit" value="login">
<input type="hidden" name="page" value="loginpage">
</form>
</body>
</html>
- Next, the servlet:
(source file)
public class TestLogin extends HttpServlet {
static final boolean debug = false;
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// Set the content type of the response.
resp.setContentType ("text/html");
// Extract the PrintWriter to write the response.
PrintWriter out = resp.getWriter ();
// The first part of the response.
out.println ("<html>");
out.println ("<head><title> Test Login</title></head>");
out.println ("<body>");
// Write out the action, since that's common to all.
out.println ("<form action=\"http://unix.seas.gwu.edu:40013/servlets/examples/TestLogin\" method=\"post\">");
// Get the page info from hidden fields:
String whichPage = req.getParameter ("page");
String userName = req.getParameter ("username");
if (debug) {
// During debugging, it helps to print out the parameters in the response.
printParams (out, req);
}
// Determine action based on which page fired the request.
if (whichPage.equalsIgnoreCase ("loginpage")) {
handleLoginPage (out, userName);
}
else if (whichPage.equalsIgnoreCase ("menupage")) {
handleMenuPage (out, userName, req);
}
else {
handleError (out);
}
// End the form.
out.println ("</form>");
// Last part.
out.println ("</body>");
out.println ("</html>");
out.flush();
// Screen I/O
System.out.println ("Inside servlet ... servlet complete");
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// We need to implement POST because the forms are written as such.
doGet (req, resp);
}
void handleLoginPage (PrintWriter out, String userName)
{
out.println ("Hello " + userName + "! Choose from these options: ");
// The two buttons.
out.println ("<input type=\"submit\" name=\"Time\" value=\"Time\">");
out.println ("<input type=\"submit\" name=\"Fortune\" value=\"Fortune\">");
// Write out the extracted username:
out.println ("<input type=\"hidden\" name=\"username\" value=\"" + userName + "\">");
out.println ("<input type=\"hidden\" name=\"page\" value=\"menupage\">");
}
void handleMenuPage (PrintWriter out, String userName, HttpServletRequest req)
{
// Check which button was pressed:
String timeButtonPressed = req.getParameter ("Time");
out.println (userName + ", ");
if (timeButtonPressed != null) {
// Time event.
Date d = new Date ();
out.println ("the date/time is: " + d + ".");
}
else {
// Fortune event.
String fortune = "";
if ( (int)userName.charAt(0) % 2 == 0) {
fortune = "go out, meet people. Tomorrow is going to be great for you.";
}
else {
fortune = "stay at home. Tomorrow is going to be a lousy day for you.";
}
out.println (fortune);
}
}
void handleError (PrintWriter out)
{
out.println ("Enter username: <input type=\"text\" name=\"username\">");
out.println ("<input type=\"submit\" value=\"login\">");
out.println ("<input type=\"hidden\" name=\"page\" value=\"loginpage\">");
}
// For debugging:
void printParams (PrintWriter out, HttpServletRequest req)
{
out.println ("<p><hr><p> Request parameters: <ul>");
Enumeration e = req.getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
String value = req.getParameter (name);
if (value != null)
out.println ("<li> name=[" + name + "] value=[" + value + "]");
else
out.println ("<li> name=[" + name + "] did not have a value");
}
out.println ("</ul><hr>");
}
}
- For completeness, let's examine the HTML written out by the
servlet for the second screen shot:
<html>
<head><title> Test Login</title></head>
<body>
<form action="http://unix.seas.gwu.edu:40013/servlets/examples/TestLogin" method="post">
Hello Morpheus! Choose from these options:
<input type="submit" name="Time" value="Time">
<input type="submit" name="Fortune" value="Fortune">
<input type="hidden" name="username" value="Morpheus">
<input type="hidden" name="page" value="menupage">
</form>
</body>
</html>
Session tracking
We will use this example to illustrate session tracking:
Next, let's examine the code:
(source file)
public class PageCount extends HttpServlet {
static final boolean debug = false;
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...
// Extract page count:
String pageCountStr = req.getParameter ("pagecount");
int pageCount = -1;
try {
pageCount = Integer.parseInt (pageCountStr.trim());
}
catch (NumberFormatException e) {
// Handle exception ...
}
pageCount ++;
// Write out hidden field:
out.println ("<input type=\"hidden\" name=\"pagecount\" value=\"" + pageCount + "\">");
// Write out page count message:
out.println ("<br> <font color=\"#FF0000\">You have made " + pageCount + " page requests</font>");
// ...
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// We need to implement POST because the forms are written as such.
doGet (req, resp);
}
// ... (as before) ...
}
Note:
- We read the page count from the hidden field, increment and
write it back out.
- The initial page count is set to zero on the login page:
<html>
<head><title>Test Login</title>
<body>
<form action="http://unix.seas.gwu.edu:40013/servlets/examples/PageCount" method="post">
Enter username: <input type="text" name="username">
<input type="submit" value="login">
<input type="hidden" name="page" value="loginpage">
<input type="hidden" name="pagecount" value="0">
</form>
</body>
</html>
Exercise 8:
Run the above servlet. Make sure you use your assigned port number.
Use two browsers to simultaneously login with the same username.
Alternate between them. What do you notice?
About session tracking:
- Hidden parameters let you store the "state" of a user inside the
user's browser, which you can then access when the page's form fires
off the next request.
- However, two browsers accessing the same page will store
different information in the pages.
- In some applications, we would like to store the same information
for a user, no matter how many browsers are open.
- There are many reasons to maintain "server-side" session tracking:
- Information common to all user sessions needs to be in one place.
- Server-side information is secure.
- Server-side information can be accessed by a variety of
mechanisms, not just browsers.
- Server-side information can be bounded by "transactions".
- Server-side sessions can be kept "alive" even if the user
quits the browser (i.e., loses the page).
- Server-side sessions can be timed out.
Let's modify the servlet to handle "page counts" using server-side
session tracking:
- We will maintain a separate count for each user.
- To store a particular user's count, we'll use a hashtable.
Here's the program
(source file)
public class SessionPageCount extends HttpServlet {
// Store session info (page count) by username in hashtable.
Hashtable sessionTable = new Hashtable ();
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...
// Check if session exists:
Integer pageCount = (Integer) sessionTable.get (userName);
if (pageCount == null) {
// Create a new page count.
pageCount = new Integer (0);
}
pageCount = new Integer (1 + pageCount.intValue());
sessionTable.put (userName, pageCount);
out.println ("<br> <font color=\"#FF0000\">You have made " + pageCount + " page requests</font>");
// We don't really need this, but we'll use it for confirmation:
out.println ("<input type=\"hidden\" name=\"pagecount\" value=\"" + pageCount + "\">");
// ...
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// We need to implement POST because the forms are written as such.
doGet (req, resp);
}
// ...
}
Some improvements:
- Server-side session tracking allows "timing-out" a session if
it's been inactive for too long.
- Let's modify the above code to time-out a session if the user
has been inactive for more than one minute.
- We will also create a generic SessionInfo class in which
to place all user-related info.
(In this case, it's the page count, and the start-time of the session).
The program:
(source file)
// An instance of this for each user:
class SessionInfo {
int pageCount; // We'll now put the counter here.
long startTime; // For timeout's.
}
public class SessionPageCount2 extends HttpServlet {
// Store session info (page count) by username in hashtable.
Hashtable sessionTable = new Hashtable ();
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...
// Get the page info from hidden fields:
String whichPage = req.getParameter ("page");
String userName = req.getParameter ("username");
// First extract session info.
SessionInfo session = (SessionInfo) sessionTable.get (userName);
// Check if inactive session.
if (session != null) {
long minutesSince = (System.currentTimeMillis() - session.startTime) / (1000*60);
// See if user has been inactive for more than 1 minute.
if (minutesSince >= 1) {
out.println ("Session timed out. Please login again.");
out.println ("</form></body></html>");
out.flush ();
return;
}
}
else {
// Make session.
session = new SessionInfo ();
session.pageCount = 0;
session.startTime = System.currentTimeMillis ();
}
// Active session. Continue ...
// Determine action based on which page fired the request.
if (whichPage.equalsIgnoreCase ("loginpage")) {
handleLoginPage (out, userName);
}
else if (whichPage.equalsIgnoreCase ("menupage")) {
handleMenuPage (out, userName, req);
}
else if (whichPage.equalsIgnoreCase ("featurepage")) {
// Back button on Time or Fortune page
handleLoginPage (out, userName);
}
else {
handleError (out);
}
// Page count.
session.pageCount ++;
// Put updated page count back in table, and write out to page:
sessionTable.put (userName, session);
out.println ("<br> <font color=\"#FF0000\">You have made " + session.pageCount + " page requests</font>");
// We don't really need this, but we'll use it for confirmation:
out.println ("<input type=\"hidden\" name=\"pagecount\" value=\"" + session.pageCount + "\">");
// ...
}
public void doPost (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// We need to implement POST because the forms are written as such.
doGet (req, resp);
}
// ...
}
Server-side persistence
What is persistence?
- Suppose we wish to store information that remains even if the
server is re-booted.
- We need to use files or a database.
As an example, let us make the "page counts" persistent for users:
- We will use one file per user.
- The file will contain only one line: the number of page requests.
- For every request, the file will be updated.
Here's the program:
(source file)
// Use an instance of this class for each user.
class SessionInfo {
int pageCount; // Number of pages accessed.
long startTime; // Time at which session started in milliseconds.
}
public class SessionPageCount3 extends HttpServlet {
// Store session info (page count) by username in hashtable.
Hashtable sessionTable = new Hashtable ();
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ...
String userName = req.getParameter ("username");
// First extract session info.
SessionInfo session = (SessionInfo) sessionTable.get (userName);
// Check if inactive session.
if (session != null) {
long minutesSince = (System.currentTimeMillis() - session.startTime) / (1000*60);
if (minutesSince >= 1) {
out.println ("Session timed out. Please login again.");
out.println ("</form></body></html>");
out.flush ();
return;
}
}
else {
// Make session.
session = new SessionInfo ();
// Get current page count, if it exists, from file.
File f = new File (userName);
if (! f.exists()) {
// Create one and write zero.
f.createNewFile ();
PrintWriter pw = new PrintWriter (new FileWriter(f));
pw.println (0);
pw.close ();
}
// Read from file.
LineNumberReader lnr = new LineNumberReader (new FileReader (f));
String pageCountStr = lnr.readLine ();
try {
session.pageCount = Integer.parseInt (pageCountStr.trim());
}
catch (NumberFormatException e) {
session.pageCount = 0;
}
lnr.close ();
// Record the start of the session.
session.startTime = System.currentTimeMillis ();
}
// Active session. Continue ...
// ... (some code not shown) ...
// Page count stuff.
session.pageCount ++;
sessionTable.put (userName, session);
out.println ("<br> <font color=\"#FF0000\">You have made " + session.pageCount + " page requests</font> in your lifetime");
// Write current count to file:
File outFile = new File (userName);
outFile.delete ();
PrintWriter pw = new PrintWriter (new FileWriter (userName));
pw.println (session.pageCount);
pw.close ();
// ...
}
// ...
}
The topic of session tracking is complex:
- There are many session tracking "tools":
- Hidden parameters.
- Hidden parameters with server-side session objects.
- URL rewriting: parameters are written onto URL's.
- Using webserver-provided session-tracking API's.
- Cookies.
- Hidden parameters are not useful when URL's need to be
copied (as in email attachments).
- Users can turn off cookies.
- Webserver-provided API's may not be consistent.
- Summary: most websites use a combination of approaches.
Servlets and threads
Consider this example:
- We'll modify the simple PageCount servlet from before
to show the overall number of users who've logged in.
- We will deliberately introduce some delay in processing to
see what happens.
Here's the program:
public class VisitorCount extends HttpServlet {
// Count the total number of users:
int numLogins = 0;
public void doGet (HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
// ... as before ...
}
// ...
void handleLoginPage (PrintWriter out, String userName)
{
// Login count.
// Deliberately slow it down for users that start with "M".
if (userName.startsWith ("M")) {
try {
Thread.sleep (5000);
}
catch (InterruptedException e) {
// Handle exception ...
}
}
numLogins ++;
out.println ("Number of people who logged in before you: " + numLogins + "");
out.println ("Hello " + userName + "! Choose from these options: ");
// ...
}
}
Exercise 9:
Run the above servlet. Make sure you use your assigned port number.
Use two browsers to simultaneously login with two different
usernames, the first one should start with "M" and the second
one should NOT. Login first with the "M" name, and immediately
afterwards, login with the second.
Explain the result.
© 1998, Rahul Simha (revised 2017)