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?

Learn more about HTML

Four ways of building an HTML website:

 

Exercise 2:

  1. Create two simple HTML pages that link to each other.
  2. 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

 

 


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:

  1. Examine the search query at www.yahoo.com or www.ask.com.
  2. Which of GET or POST is being used?
 

How does a webserver call a CGI program? Three possible ways:

  1. 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.

  2. 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.

  3. 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:
    1. Using a custom method used by that particular dbase server.
    2. Using a standard access method like ODBC/JDBC.
    3. Rolling the CGI program and dbase client into a single unit.
    4. 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:

  • For each user, we will display the number of page requests made.
  • The login screen will look the same as before:

  • After login, the number of page requests is "1"

  • After clicking on one of the options, the number of page requests increases:

    Note that we've added a "back" button to go back to the menu page.

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)