7.5 The Session Tracking API

Java Servlet Programming, 2nd Edition > 7. Session Tracking > 7.5 The Session Tracking API

 
< BACKCONTINUE >

7.5 The Session Tracking API

Fortunately for us servlet developers, it's not always necessary for a servlet to manage its own sessions using the techniques we have just discussed. The Servlet API provides several methods and classes specifically designed to handle short-term session tracking on behalf of servlets. In other words, servlets have built-in session tracking.[4]

[4] Yes, we do feel a little like the third grade teacher who taught you all the steps of long division, only to reveal later how you could use a calculator to do the same thing. But we believe, as your teacher probably did, that you better understand the concepts after first learning the traditional approach.

The Session Tracking API, as we call the portion of the Servlet API devoted to session tracking, should be supported in any web server that supports servlets. The level of support, however, depends on the server. Most servers support session tracking through the use of persistent cookies, with the ability to revert to using URL rewriting when cookies fail. Some servers allow session objects to be written to the server's disk or to a database as memory fills up or when the server shuts down. (The items you place in the session need to implement the Serializable interface to take advantage of this option.) See your server's documentation for details pertaining to your server. The rest of this section describes the lowest-common-denominator functionality required by Servlet API 2.2 for a nondistributed server. Remember, Chapter 12 discusses distributed session tracking.

7.5.1 Session-Tracking Basics

Session tracking is wonderfully elegant. Every user of a site is associated with a javax.servlet.http.HttpSession object that servlets can use to store or retrieve information about that user. You can save any set of arbitrary Java objects in a session object. For example, a user's session object provides a convenient location for a servlet to store the user's shopping cart contents or, as you'll see in Chapter 9, the user's database connection.

To allow web applications to operate independently, sessions are scoped at the web application level. This means each ServletContext maintains its own pool of HttpSession instances, and a servlet running inside one context cannot access session information saved by a servlet in another context.

A servlet uses its request object's getSession( ) method to retrieve the current HttpSession object:

public HttpSession HttpServletRequest.getSession(boolean create)

This method returns the current session associated with the user making the request. If the user has no current valid session, this method creates one if create is true or returns null if create is false. The standard use of the method is getSession(true), so for simplicity Servlet API 2.1 introduced a no-argument version that assumes a create flag of true:

public HttpSession HttpServletRequest.getSession()

To ensure the session is properly maintained, the getSession( ) method must be called at least once before committing the response.

You can add data to an HttpSession object with the setAttribute( ) method:

public void HttpSession.setAttribute(String name, Object value)

This method binds the specified object value under the specified name. Any existing binding with the same name is replaced. To retrieve an object from a session, use getAttribute( ):

public Object HttpSession.getAttribute(String name)

This methods returns the object bound under the specified name or null if there is no binding. You can also get the names of all of the objects bound to a session with getAttributeNames( ):

public Enumeration HttpSession.getAttributeNames()

returns an Enumeration containing the names of all objects bound to this session as String objects or an empty Enumeration if there are no bindings. Finally, you can remove an object from a session with removeAttribute( ) :

public void HttpSession.removeAttribute(String name)

This method removes the object bound to the specified name or does nothing if there is no binding. Each of these methods can throw a java.lang.IllegalStateException if the session being accessed is invalid (we'll discuss invalid sessions in an upcoming section).

Note that Servlet API 2.2 changed these method names from setValue( ), getValue( ), getValueNames( ), and removeValue( ) to the more standard names setAttribute( ), getAttribute( ), getAttributeNames( ), and removeAttribute( ). The Value methods still work but are deprecated.

7.5.2 A Hit Count Using Session Tracking

Example 7-4 shows a simple servlet that uses session tracking to count the number of times a client has accessed it, as shown in Figure 7-2. The servlet also displays all the bindings for the current session, just because it can.

Example 7-4. Session Tracking a Hit Count
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SessionTracker extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary     HttpSession session = req.getSession();     // Increment the hit count for this page. The value is saved     // in this client's session under the name "tracker.count".     Integer count = (Integer)session.getAttribute("tracker.count");     if (count == null)       count = new Integer(1);     else       count = new Integer(count.intValue() + 1);     session.setAttribute("tracker.count", count);     out.println("<HTML><HEAD><TITLE>SessionTracker</TITLE></HEAD>");     out.println("<BODY><H1>Session Tracking Demo</H1>");     // Display the hit count for this page     out.println("You've visited this page " + count +       ((count.intValue() == 1) ? " time." : " times."));     out.println("<P>");     out.println("<H2>Here is your session data:</H2>");     Enumeration enum = session.getAttributeNames();     while (enum.hasMoreElements()) {       String name = (String) enum.nextElement();       out.println(name + ": " + session.getAttribute(name) + "<BR>");     }     out.println("</BODY></HTML>");   } }
Figure 7-2. Counting client visits

This servlet first gets the HttpSession object associated with the current client. By using the no-argument version of getSession( ), it asks for a session to be created if necessary. The servlet then gets the Integer object bound to the name tracker.count. If there is no such object, the servlet starts a new count. Otherwise, it replaces the Integer with a new Integer whose value has been incremented by one. Finally, the servlet displays the current count and all the current name/value pairs in the session.

7.5.3 The Session Lifecycle

Sessions do not last forever. A session either expires automatically, after a set time of inactivity (for the Tomcat Server the default is 30 minutes), or manually, when it is explicitly invalidated by a servlet. A server shutdown may or may not invalidate a session, depending on the capabilities of the server. When a session expires (or is invalidated), the HttpSession object and the data values it contains are removed from the system.

Beware that any information saved in a user's session object is lost when the session is invalidated. If you need to retain information beyond that time, you should keep it in an external location (such as a database) and provide your own mechanism for associating the user with his database entries. Common approaches are to require some form of login, set a long-term cookie that can be read for years, and/or provide the user with a rewritten URL to bookmark.

A real-life example is My Yahoo! where users login using an HTML form, have their login session tracked using an expire-at-browser-shutdown cookie, and (if they check the Remember My ID & Password box) have a persistent cookie set to record their identity until they explicitly log out. It's especially interesting that even though Yahoo may know the user's identity because of the persistent cookie, Yahoo still requires the user to enter her password before accessing email and other sensitive information.

The built-in session-tracking capability can still be used in conjunction with long-term sessions to manage the login session, store a handle to the external data, and/or hold a cached copy of the information in the database for quick retrieval.

7.5.4 Setting the Session Timeout

Ideally, a session would be invalidated as soon as the user closed his browser, browsed to a different site, or stepped away from his desk. Unfortunately, there's no way for a server to detect any of these events. Consequently, sessions live throughout some period of inactivity after which the server assumes the user must have left and it's not worth holding session state for him any more.

The default session timeout can be specified using the web.xml deployment descriptor; it applies to all sessions created in the given web application. See Example 7-5.

Example 7-5. Setting the Default Timeout to One Hour
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"     "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd"> <web-app>     <!-- ..... -->     <session-config>         <session-timeout>             60 <!-- minutes -->         </session-timeout>     </session-config> </web-app>

The <session-timeout> tag holds a timeout value given in minutes. For this example, we specified that should 60 minutes pass without the user making any request to this web application, the server can invalidate the user's session and unbind the objects stored within. The servlet specification requires the timeout value be a "whole number," which precludes negative values, but some servers use a negative value to indicate sessions should never time out.

Timeout values can also be configured individually for a session. The HttpSession object has a setMaxInactiveInterval( ) method to support this fine-grained control:

public void HttpSession.setMaxInactiveInterval(int secs)

This method specifies the timeout value for this session, as given in seconds. A negative value for the interval indicates the session should never time out. Yes, the units don't match those of <session-timeout>, for no good reason except accident. To help you remember which units to use, think to yourself: "For fine-grained control I have fine-grained units."

The current timeout value can be retrieved using getMaxInactiveInterval( ):

public int HttpSession.getMaxInactiveInterval()

This method returns the timeout value for this session, in seconds. If you don't specify a <session-timeout> you can call this method on a new session to determine the default timeout of your server.

Example 7-6 demonstrates these methods with a servlet that displays the current timeout value, then sets the new timeout value to two hours. On first execution, the current timeout displays the application-wide setting. On second execution, the current timeout displays two hours because that's the timeout set during the first execution.

Example 7-6. Toying with the Timeout
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SessionTimer extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary     HttpSession session = req.getSession();     out.println("<HTML><HEAD><TITLE>SessionTimer</TITLE></HEAD>");     out.println("<BODY><H1>Session Timer</H1>");     // Display the previous timeout     out.println("The previous timeout was " +                 session.getMaxInactiveInterval());     out.println("<BR>");     // Set the new timeout     session.setMaxInactiveInterval(2*60*60);  // two hours     // Display the new timeout     out.println("The newly assigned timeout is " +                 session.getMaxInactiveInterval());     out.println("</BODY></HTML>");   } }
7.5.4.1 Choosing the right timeout

So we're armed with several ways to control session timeouts, but what timeout value is best to use? The answer, of course, is that it depends.

The first thing to remember is that the session timeout value does not determine how long a session lasts. It determines only how long the server will wait between requests before invalidating the session. A session with a half-hour timeout could easily last for hours.

Determining the proper period of inactivity requires a compromise between user convenience, user security, and server scalability. Longer timeouts provide the user more convenience because she can pause longer between requests, perhaps taking a phone call or checking her email, without losing her state. Shorter timeouts increase user security because it limits the time of vulnerability should a user forget to log out, and it increases server scalability because it lets the server free the objects in the session that much sooner.

For a starting point, ask yourself what is the maximum interval you would expect your users to pause between requests? A typical answer is a half-hour.

Now take your answer to that question and apply some rules of thumb:

  • Secure web applications, such as online banking, should have shorter than usual timeouts to reduce the opportunity for an imposter to exploit an abandoned browser.

  • Sessions that store "expensive" items (like database connections) should also have shorter than usual timeouts to allow the server to reclaim or release the items as quickly as possible.

  • Sessions that store no "expensive" items can have longer than usual timeouts.

  • Sessions that store shopping cart contents (expensive or not!) should have longer timeouts because users may not remember all of their cart contents, meaning an early invalidation will cost you money!

  • Sessions that cache database information should have shorter timeouts if the cache is large, but longer timeouts if the database lookup is particularly slow.

  • If you train your users to log out when they are finished, the default timeout can be set longer.

Finally, remember the timeout does not have to be the same for every user. You can use setMaxInactiveInterval( ) to set a custom timeout based on user preferences or even change the timeout during the session's lifetime perhaps to make the timeout shorter after storing an "expensive" item.

7.5.5 Lifecycle Methods

There are several additional methods involved in managing the session lifecycle:

public boolean HttpSession.isNew()

This method returns whether the session is new. A session is considered new if it has been created by the server but the client has not yet acknowledged joining the session.

public void HttpSession.invalidate()

This method causes the session to be immediately invalidated. All objects stored in the session are unbound. Call this method to implement a "logout."

public long HttpSession.getCreationTime()

This method returns the time at which the session was created, as a long value that represents the number of milliseconds since the epoch (midnight, January 1, 1970, GMT).

public long HttpSession.getLastAccessedTime()

This method returns the time at which the client last sent a request associated with this session, as a long value that represents the number of milliseconds since the epoch. The current request does not count as the last request.

Each of these methods can throw a java.lang.IllegalStateException if the session being accessed is invalid.

7.5.6 Manually Invalidating a Stale Session

To demonstrate these methods, Example 7-7 shows a servlet that manually invalidates a session if it is more than a day old or has been inactive for more than an hour.

Example 7-7. Invalidating a Stale Session
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class ManualInvalidate extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary     HttpSession session = req.getSession();     // Invalidate the session if it's more than a day old or has been     // inactive for more than an hour.     if (!session.isNew()) {  // skip new sessions       Date dayAgo = new Date(System.currentTimeMillis() - 24*60*60*1000);       Date hourAgo = new Date(System.currentTimeMillis() - 60*60*1000);       Date created = new Date(session.getCreationTime());       Date accessed = new Date(session.getLastAccessedTime());       if (created.before(dayAgo) || accessed.before(hourAgo)) {         session.invalidate();         session = req.getSession();  // get a new session       }     }     // Continue processing...   } }

7.5.7 How Sessions Really Work

So, how does a web server implement session tracking? When a user first accesses a web application, that user is assigned a new HttpSession object and a unique session ID. The session ID identifies the user and is used to match the user with the HttpSession object in subsequent requests. Some servers use a single session ID for the entire server with each web application mapping that ID to a different HttpSession instance. Other servers assign a session ID per web application, as an extra precaution against a malicious web application helping an intruder impersonate you.

Behind the scenes, the session ID is usually saved on the client in a cookie called JSESSIONID. For clients that don't support cookies, the session ID can be sent as part of a rewritten URL, encoded using a jsessionid path parameter, e.g., http://www.servlets.com/catalog/servlet/ItemDisplay;jsessionid=123?item=156592391X. Other implementations, like using SSL (Secure Sockets Layer) sessions, are also possible.

A servlet can discover a session's ID with the getId( ) method:

public String HttpSession.getId()

This method returns the unique String identifier assigned to this session. For example, a Tomcat Server ID might be something like awj4qyhsn2. The method throws an IllegalStateException if the session is invalid.

Remember, the session ID should be treated as a server secret. Be careful what you do with this value.

The Deprecation of HttpSessionContext

In Servlet API 2.0, there existed an HttpSessionContext object that could be used for perusing the current sessions (and corresponding session IDs) managed by the server. Almost always the class was used for debugging, checking what sessions existed. The class still exists for binary compatibility, but beginning with Servlet API 2.1 it has been deprecated and defined to be empty. The reason is that session IDs must be carefully guarded, so they shouldn't be stored in an easily accessible single location, especially when the existence of that location doesn't provide any significant benefit beyond debugging.

7.5.8 Applet-Based Session Tracking

Almost every server that supports servlets implements cookie-based session tracking, where the session ID is saved on the client in a persistent cookie. The server reads the session ID from the JSESSIONID cookie and determines which session object to make available during each request.

For applet clients this can present a problem. Most applet environments implement HttpURLConnection in such a way that when an applet makes an HTTP connection, the environment automatically adds the containing browser's cookies to the request. This allows the applet to participate in the same session as other requests from the browser. The problem is that other applet environments, such as older versions of the Java Plug-In environment, do not have that integration with the browser and thus applet requests appear separate from the browser's normal session. The solution for the situation when applets need to run in such environments is to send the session ID to the applet and let the applet pass that ID back to the server as an artificially created JSESSIONID cookie. Chapter 10 includes an HttpMessage class to help with this. The applet can receive the session ID as a normal applet parameter (dynamically added to the HTML page containing the applet).

7.5.9 Noncookie Fallbacks

The servlet specification mandates web servers must also support session tracking for browsers that don't accept cookies, so many use URL rewriting as a fallback. This requires additional help from servlets that generate pages containing URLs. For a servlet to support session tracking via URL rewriting, it has to rewrite every local URL before sending it to the client. The Servlet API provides two methods encodeURL( ) and encodeRedirectURL() to perform this encoding:

public String HttpServletResponse.encodeURL(String url)

This method encodes (rewrites) the specified URL to include the session ID and returns the new URL, or, if encoding is not needed or not supported, it leaves the URL unchanged. The rules used to decide when and how to encode a URL are server-specific. All URLs emitted by a servlet should be run through this method. Note that this encodeURL( ) method could more properly have been named rewriteURL( ) so as not to be confused with the URL encoding process that encodes special characters in URL strings.

public String HttpServletResponse.encodeRedirectURL(String url)

This method encodes (rewrites) the specified URL to include the session ID and returns the new URL, or, if encoding is not needed or not supported, it leaves the URL unchanged. The rules used to decide when and how to encode a URL are server-specific. This method may use different rules than encodeURL( ). All URLs passed to the sendRedirect( ) method of HttpServletResponse should be run through this method.

The following code snippet shows a servlet writing a link to itself that is encoded to contain the current session ID:

out.println("Click <A HREF=\"" +             res.encodeURL(req.getRequestURI()) + "\">here</A>"); out.println("to reload this page.");

On servers that don't support URL rewriting or have URL rewriting turned off, the resulting URL remains unchanged. Now here's a code snippet that shows a servlet redirecting the user to a URL encoded to contain the session ID:

res.sendRedirect(res.encodeRedirectURL("/servlet/NewServlet"));

A servlet can detect whether the session ID used to identify the current HttpSession object came from a cookie or from an encoded URL using the isRequestedSessionIdFromCookie( ) and isRequestedSessionIdFromURL( ) methods:

public boolean HttpServletRequest.isRequestedSessionIdFromCookie() public boolean HttpServletRequest.isRequestedSessionIdFromURL()

Determining if the session ID came from another source, such as an SSL session, is not currently possible.

A requested session ID may not match the ID of the session returned by the getSession( ) method, such as when the session ID is invalid. A servlet, though, can determine whether a requested session ID is valid using isRequestedSessionIdValid( ) :

public boolean HttpServletRequest.isRequestedSessionIdValid()

Finally, be aware when using session tracking based on URL rewriting that multiple browser windows can belong to different sessions or the same session, depending on how the windows were created and whether the link creating the windows was URL rewritten.

7.5.10 SessionSnoop

The SessionSnoop servlet shown in Example 7-8 uses most of the methods discussed thus far in the chapter to snoop information about the current session. Figure 7-3 shows a sample of its output.

Example 7-8. Snooping Session Information
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SessionSnoop extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary     HttpSession session = req.getSession();     // Increment the hit count for this page. The value is saved     // in this client's session under the name "snoop.count".     Integer count = (Integer)session.getAttribute("snoop.count");     if (count == null)       count = new Integer(1);     else       count = new Integer(count.intValue() + 1);     session.setAttribute("snoop.count", count);     out.println("<HTML><HEAD><TITLE>SessionSnoop</TITLE></HEAD>");     out.println("<BODY><H1>Session Snoop</H1>");     // Display the hit count for this page     out.println("You've visited this page " + count +       ((count.intValue() == 1) ? " time." : " times."));     out.println("<P>");     out.println("<H3>Here is your saved session data:</H3>");     Enumeration enum = session.getAttributeNames();     while (enum.hasMoreElements()) {       String name = (String) enum.nextElement();       out.println(name + ": " + session.getAttribute(name) + "<BR>");     }     out.println("<H3>Here are some vital stats on your session:</H3>");     out.println("Session id: " + session.getId() +                 " <I>(keep it secret)</I><BR>");     out.println("New session: " + session.isNew() + "<BR>");     out.println("Timeout: " + session.getMaxInactiveInterval());     out.println("<I>(" + session.getMaxInactiveInterval() / 60 +                 " minutes)</I><BR>");     out.println("Creation time: " + session.getCreationTime());     out.println("<I>(" + new Date(session.getCreationTime()) + ")</I><BR>");     out.println("Last access time: " + session.getLastAccessedTime());     out.println("<I>(" + new Date(session.getLastAccessedTime()) +                 ")</I><BR>");     out.println("Requested session ID from cookie: " +                 req.isRequestedSessionIdFromCookie() + "<BR>");     out.println("Requested session ID from URL: " +                 req.isRequestedSessionIdFromURL() + "<BR>");     out.println("Requested session ID valid: " +                  req.isRequestedSessionIdValid() + "<BR>");     out.println("<H3>Test URL Rewriting</H3>");     out.println("Click <A HREF=\"" +                 res.encodeURL(req.getRequestURI()) + "\">here</A>");     out.println("to test that session tracking works via URL");     out.println("rewriting even when cookies aren't supported.");     out.println("</BODY></HTML>");   } }
Figure 7-3. Example output from SessionSnoop

This servlet begins with the same code as the SessionTracker servlet shown in Example 7-4. Then it continues on to display the current session's ID, whether it is a new session, the session's timeout value, the session's creation time, and the session's last access time. Next the servlet displays whether the requested session ID (if there is one) came from a cookie or a URL and whether the requested ID is valid. Finally, the servlet prints an encoded URL that can be used to reload this page to test that URL rewriting works even when cookies aren't supported.

7.5.11 Session Binding Events

Some objects may wish to perform an action when they are bound to or unbound from a session. For example, a database connection may begin a transaction when bound to a session and end the transaction when unbound. Any object that implements the javax.servlet.http.HttpSessionBindingListener interface is notified when it is bound to or unbound from a session. The interface declares two methods, valueBound( ) and valueUnbound( ), that must be implemented:

public void HttpSessionBindingListener.valueBound(             HttpSessionBindingEvent event) public void HttpSessionBindingListener.valueUnbound(             HttpSessionBindingEvent event)

The valueBound( ) method is called when the listener is bound into a session, and valueUnbound( ) is called when the listener is unbound from a session by being removed or replaced or having the session become invalid.

The javax.servlet.http.HttpSessionBindingEvent argument provides access to the name under which the object is being bound (or unbound) with the getName( ) method:

public String HttpSessionBindingEvent.getName()

The HttpSessionBindingEvent object also provides access to the HttpSession object to which the listener is being bound (or unbound) with getSession( ):

public HttpSession HttpSessionBindingEvent.getSession()

Example 7-9 demonstrates the use of HttpSessionBindingListener and HttpSessionBindingEvent with a listener that logs when it is bound to and unbound from a session.

Example 7-9. Tracking Session Binding Events
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SessionBindings extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/plain");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary     HttpSession session = req.getSession();     // Add a CustomBindingListener     session.setAttribute("bindings.listener",                          new CustomBindingListener(getServletContext()));     out.println("This page intentionally left blank");   } } class CustomBindingListener implements HttpSessionBindingListener {   // Save a ServletContext to be used for its log() method   ServletContext context;   public CustomBindingListener(ServletContext context) {     this.context = context;   }   public void valueBound(HttpSessionBindingEvent event) {     context.log("[" + new Date() + "] BOUND as " + event.getName() +                 " to " + event.getSession().getId());   }   public void valueUnbound(HttpSessionBindingEvent event) {     context.log("[" + new Date() + "] UNBOUND as " + event.getName() +                 " from " + event.getSession().getId());   } }

Each time a CustomBindingListener object is bound to a session, its valueBound( ) method is called and the event is logged. Each time it is unbound from a session, its valueUnbound( ) method is called so that event too is logged. We can observe the sequence of events by looking at the server's event log.

Let's assume that this servlet is called once, reloaded 30 seconds later, and not called again for at least a half-hour. The event log would look something like this:

[Tue Sep 27 22:46:48 PST 2000]   BOUND as bindings.listener to awj4qyhsn2 [Tue Sep 27 22:47:18 PST 2000]   UNBOUND as bindings.listener from awj4qyhsn2 [Tue Sep 27 22:47:18 PST 2000]   BOUND as bindings.listener to awj4qyhsn2 [Tue Sep 27 23:17:18 PST 2000]   UNBOUND as bindings.listener from awj4qyhsn2

The first entry occurs during the first page request, when the listener is bound to the new session. The second and third entries occur during the reload, as the listener is unbound and rebound during the same setAttribute( ) call. The fourth entry occurs a half-hour later, when the session expires and is invalidated.

7.5.12 Shopping Using Session Tracking

Let's end this chapter with a look at how remarkably simple our shopping cart viewer servlet becomes when we use session tracking. Example 7-10 shows the viewer saving each of the cart's items in the user's session under the name cart.items. Notice the URLs in the page are rewritten to support clients that have cookies disabled.

Example 7-10. Using the Session Tracking API
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class ShoppingCartViewerSession extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     // Get the current session object, create one if necessary.     HttpSession session = req.getSession();     // Cart items are maintained in the session object.     String[] items = (String[])session.getAttribute("cart.items");     out.println("<HTML><HEAD><TITLE>SessionTracker</TITLE></HEAD>");     out.println("<BODY><H1>Session Tracking Demo</H1>");     // Print the current cart items.     out.println("You currently have the following items in your cart:<BR>");     if (items == null) {       out.println("<B>None</B>");     }     else {       out.println("<UL>");       for (int i = 0; i < items.length; i++) {         out.println("<LI>" + items[i]);       }       out.println("</UL>");     }     // Ask if they want to add more items or check out.     out.println("<FORM ACTION=\"" +                 res.encodeURL("/servlet/ShoppingCart") + "\" METHOD=POST>");     out.println("Would you like to<BR>");     out.println("<INPUT TYPE=SUBMIT VALUE=\" Add More Items \">");     out.println("<INPUT TYPE=SUBMIT VALUE=\" Check Out \">");     out.println("</FORM>");     // Offer a help page. Encode it as necessary.     out.println("For help, click <A HREF=\"" +                 res.encodeURL("/servlet/Help?topic=ShoppingCartViewer") +                 "\">here</A>");     out.println("</BODY></HTML>");   } } 
 


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net