Chapter 3. Servlet Best Practices Jason Hunter
3.1 Working Effectively with Servlets
3.1.4 Think of Sessions as a Local Cache
Servlet sessions as implemented by HttpSession provide a simple and convenient mechanism to store information about a user. While sessions are a useful tool, it's important to know their limitations. They are not a good choice for acting as the back-end storage in real-world applications, no matter how tempting it might be to try it. Rather, sessions are best thought of as a handy local cache—a place to store information which, if lost, can be recovered or safely ignored.
To understand why this is, we should quickly review how sessions work. Sessions generally use cookies to identify users. During a client's first request to a server, the server sets a special cookie on the client that holds a server-generated unique ID. On a later request the server can use the cookie to recognize the request as coming from the same client. The server holds a server-side hashtable that associates the cookie ID keys with HttpSession object values. When a servlet calls request.getSession( ) , the server gets the cookie ID, looks up the appropriate HttpSession, and returns it. To keep memory in check, after some period of inactivity (typically 30 minutes) or on programmer request, the session expires and the stored data is garbage-collected.
Session data is inherently transient and fragile. Session data will be lost when a session expires, when a client shuts down the browser,[2] when a client changes browsers, when a client changes machines, or when a servlet invalidates the session to log out the user. Consequently, sessions are best used for storing temporary information that can be forgotten—because either it's nonpermanent or is backed by a real store.
[2] The session data isn't lost immediately when a browser is shut down, of course, because no notification is
sent to the server. However, the session data will be lost because the browser will lose its session cookies, and after a timeout the server will garbage-collect the abandoned session data.
When information needs to be persistent, I recommend using a database, an EJB backed by a database, or another formal back-end data store. These are much safer, portable, and reliable, and they work better for backups. If the data must have a long-term association with a user, even when he moves between machines, use a true login mechanism that allows the user to relogin and reassociate. Servlet sessions can help in each case, but their role should be limited to a local cache, as we'll see in the next section.
3.1.4.1 Architecture of a shopping cart
Let's look at how you can architect session tracking for a shopping-cart application (think Amazon.com). Here are some requirements for your shopping cart:
O’Reilly – Java Enterprise Best Practices 64
• Logged-in users get a customized experience. • Logins last between browser shutdowns. • Users can log out and not lose cart contents. • Items added to a cart persist for one month.
• Guests are allowed to place items in the cart (although contents are not necessarily available to the guest for the long term or from a different browser).
• Purchasing items in the cart requires a password for safety.
Servlet sessions alone don't adequately satisfy these requirements. With the right server you might be able to get sessions to persist for a month, but you lose the information when a user changes machines. Trying to use sessions as storage, you also need to take pains to expire individual items (but not the whole session) after a month, while at the same time making sure to put nothing into the session that shouldn't be kept indefinitely, and you need a way to log out a user without invalidating his cart contents. There's no way to do this in API 2.3!
Here's one possible architecture for this application that takes advantage of sessions as a local cache: if the user has not logged in, he is a guest, and the session stores his cart contents. The items persist there as long as the session lasts, which you have deemed sufficient for a guest. However, if the user has logged in, the cart contents are more safely recorded and pushed through to a back-end database for semi-permanent storage. The database will be regularly swept to remove any items added more than a month earlier. For performance, the user's session should be used to store cart contents even if the user is logged in, but the session should act as a local cache of the database—allowing later requests to display cart information without going across the wire to the database on each request.
The user logins can be tracked with a manually set cookie with a long expiration time. After a form-based login, the cookie stores a hash of the user's ID; the hash corresponds to the database records. On later visits, the user can be automatically recognized and his cart contents loaded into the session. For safety, on checkout the server logic asks for password verification before proceeding. Even though the server knows the client's identity, because the login is automatic the billing activity should be protected. The marker stating that the password was verified would, of course, be stored in the session, with a 30-minute timeout being fairly appropriate! A user-request logout would require only the removal of the cookie. The full architecture is shown in Figure 3-3.
O’Reilly – Java Enterprise Best Practices 65
Figure 3-3. Shopping-cart architecture
In this example you proposed custom login management. The default servlet form-based login could be used—however, it's designed for single-session login to restrict access to secure content. It is not designed for multisession login to identify users for shopping-cart applications.
3.1.4.2 When to use sessions
As shown in the shopping-cart example, sessions are useful but aren't a panacea. Sessions make the best sense in the following situations:
Storing login status
The timeout is useful, and changes between browsers or machines should naturally require a new login.
Storing user data pulled from a database
The local cache avoids an across-the-wire database request.
Storing user data that's temporary
Temporary data includes search results, form state, or a guest's shopping-cart contents that don't need to be preserved over the long term.
O’Reilly – Java Enterprise Best Practices 66