 |
Steve Eaton (steaton@us.ibm.com) IBM August 2001
This technical article was originally published a previous issue of the IBM DeveloperToolbox Technical Magazine. Subscribe to the IBM developerWorks journal for the latest technical articles on open standards-based technologies that are available to you offline in a printed publication.
A recent film concerns a hero who lost the ability to remember recent events. Every situation he finds himself in is brand new. He has no idea what happened to
get him where he is or what he should do next. To make his life manageable, he resorts to taking photos, writing little notes, and even scrawling important messages
on himself to remind him later of what has happened and what he needs to do.
Developers of Web applications face much the same problem. Servlets and Java Server Pages (JSP) pages are stateless; that is, they do not know what pages their
callers have visited previously or what information they have submitted with earlier requests. What appears to an end user to be a connected series of Web browser
pages, displayed while the user refines a search criterion or fills a shopping cart, in reality comprises a sequence of separate programs. Each Hypertext Transfer
Protocol (http) request is a new invocation of a servlet, Hypertext Markup Language (html) file, JSP, or other resource, that does not have access to the previous
request's data unless the developer provides a way of storing that data on the response to the client and retrieving it from the next request.
This differs from the traditional standalone program that may have displayed a number of windows or prompts while maintaining a single body of data within a single
process from start to finish. Moreover, each user who launched the application had a private process space and memory. The developer did not have to worry
about concurrent access from multiple users.
This article demonstrates how to manage session data using the Session Manager in the IBM WebSphere Application Server (WAS) Advanced Edition 3.5.3, but
the information presented applies to 3.0.x and 4.0 as well.
Techniques for maintaining session data
The HTTP protocol provides three ways of preserving a user's information across multiple requests (a session), regardless of what technology (Common Gateway
Interface (cgi) programming or servlets) is used to implement them:
-
Cookies
are name and value
pairs sent from a Web server to a browser and then returned by the browser
when there is a request back to the server. A server program creates a cookie
by writing text in the header section of the http response telling the browser
what to name the cookie and what value to give it. Browsers can retain cookies
across a Web browser session by storing them on the client.
-
Universal Resource Locator
(URL)
rewriting involves appending data to the end of a URL
containing name-value pairs. A server program can create dynamic HTML in which
the links the user selects from have data written into them already. This
allows session data to be carried along from request to request on the URL.
-
Hidden fields
are pre-filled HTML form values that the browser does not display but that are included, along with viewable fields, in the response sent back to the
server when the user submits a form request.
Each of these techniques suffer from four major disadvantages:
- They are designed to handle small amounts of data.
- They are designed to handle simple, character-string
data.
- They allow end users to view and potentially
manipulate session data before it is returned to a server (even hidden form
fields can be seen simply by browsing the HTML source).
- Perhaps worst of all, each of these is merely a mechanism for storing data on the client. All the logic needed to maintain a Web session, such as recognizing when a
new session should be started, correctly associating a request with an existing session, ensuring the uniqueness of a session (you don't want to share a user's
sensitive information with another), and knowing when and how to terminate a session, needs to be designed and implemented by you as the developer. In other
words, you have to take care of session management.
WebSphere's Session Manager component offers a better way.
httpSession interface
The Java servlet specification contains the interface javax.servlet.http.HttpSession that the WebSphere servlet engine supports. HttpSession provides Application
Program Interfaces (APIs) that handle many of the details of session access and management. Two important examples of these are:
-
putValue(String name,Object
value).
Stores an object in an HttpSession under the specified
name. Any object can be associated with a session.
-
getValue(String name).
Returns the object stored in the HttpSession under the specified name.
How does an HttpSession get created in the first place? By calling the javax.servlet.http.HttpServletRequest getSession() method on the servlet's request object. If a
session does not yet exist, this call creates one.
Some of these APIs have been deprecated with the Java Servlet Specification 2.2. The putValue() and getValue() methods, for example, have been replaced by
putAttribute() and getAttribute() respectively, although the Java Servlet Specification 2.1 methods are still supported. This article uses the 2.1 method names
because they are still used in WebSphere sample code. By using these three APIs in their servlets and JSPs, developers can keep track of session data. So where
are the details of session management?
WebSphere Session Manager
Servlet engines running under the WebSphere server contain an object called a Session Manager, as shown in Figure 1. In Version 4.0, the Session Manager interface is built into the properties pane of an application server, rather than being presented as a separate object. Also, you'll see a few more options, which allow you to more finely tune the Session Manager's runtime performance.
Figure 1. WebSphere topology with Session Manager
Let's take a look at some of the important settings you can make to a Session Manager. Most of them are on the Enable tab shown in Figure 2. When you create an
application server, you also create a servlet engine object. In turn, the engine automatically creates a Session Manager. The Session Manager allows the WebSphere
administrator to dynamically configure and tune the behavior of all HTTP sessions created by servlets within its application server.
Figure 2. Session Manager properties
From an application development perspective, servlet and JSP code do not interact directly with the Session Manager object. Rather, the Session Manager supports
the HTTPSession interface, which developers use for session functionality. All the servlet or JSP developer has to do is create the session and put and get data. This
allows the application developer to focus on business logic and ensures consistent behavior across all of the servlets called by its servlet engine.
-
Enable Sessions.
Selecting
yes causes the WebSphere server to keep track of sessions for you, and allows
you runtime use of the javax.servlet.http.HttpSession APIs. Selecting no
causes a java.lang.RuntimeException to be thrown whenever a servlet attempts
to create an HttpSession object. Enabling sessions requires some overhead; if
you have a Web application that does not create or gather any session data,
you may not want to enable sessions.
-
Enable Cookies.
If we are
using the HttpSession interface, what do we need cookies for? One key piece of
information still has to be stored on the client: an ID that uniquely
identifies each session. The Session Manager takes care of creating the
session ID, but it has to depend on the client browser to hold it and send it
back with subsequent requests. Therefore, for the ID itself, we're back to
cookies or URLs. By default, cookies are used. This is a big improvement.
Instead of having a note for every important message, our unfortunate hero now
only needs one to remind him where the filing cabinet is.
-
Enable URL Rewriting.
Instructs the Session Manager to use URL rewriting to store and retrieve the session ID. Unlike cookies, however, using URL rewriting requires additional coding as described in the WebSphere InfoCenter. Another problem with URL rewriting is that it doesn't work if there are any static HTML pages in your application's navigation path. The workaround is to convert any static pages to a jsp file or servlet.
What happens if you select both Enable Cookies and Enable URL Rewriting? The answer depends on whether a client browser accepts cookies and how a servlet is coded.
- If a servlet includes logic to encode the session ID as part of the URL, the WebSphere server maintains the session ID as part of the URL, whether or not Enable Cookies is selected and whether or not the requesting browser accepts cookies.
- If a browser accepts cookies and URL encoding is not used in the servlet, the Enable URL Rewriting setting is effectively ignored; the WebSphere server creates a cookie.
- If cookies are disabled on the browser, but the responding servlet does not encode the URL, Enable URL Rewriting is also ignored.
Before you decide to enable URLs, there's a significant disadvantage to consider. If there are any static HTML pages in the Web application's navigation path or servlets or JSPs that do not encode the URL, you will lose the session data.
-
Enable Persistent Sessions.
By default, session data is stored in the memory space of the servlet engine. If an application server dies, the data is lost. If this is a
concern, select yes to store session data in a database (a WebSphere DataSource you specify on the Persistence properties page) instead of in memory.
In a development environment, you can use the default DataSource (used by the WebSphere server to store its own information) as your session database. In a
production environment, however, work with your database administrator to create a separate database for session management, and create a DataSource to
represent the database in the WebSphere console.
Another reason to enable persistent sessions is if you are implementing a workload management scheme, under which multiple application servers (for example, Java
virtual machines with separate memory spaces) may serve the same Web application, each with its memory space. You may even have a Web application served by
multiple nodes (physical servers) under the same WebSphere domain. You don't want users who are filling a shopping cart to abruptly start over again because they
are bouncing between different clones of the same logical Web application. By enabling persistent sessions and specifying the same data source in each Session Manager, you allow a session to be shared across cloned application servers, possibly on different nodes .
Session affinity offers another way of dealing with the problem of sessions across multiple servers. Session affinity assures that within the scope of a session, all
requests go to the same server. WebSphere Application Server Advanced Edition 3.5.x uses persistent sessions and session affinity together to assure the integrity of
a session. It also provides automatic session caching to reduce the performance hit of accessing session data from storage. For detailed information on the WAS's
built-in session affinity, consult the WebSphere InfoCenter, section 4.4.1, "Tracking sessions."
Again, the WebSphere server takes care of the details for you; all you have to do is specify a data source. Keep in mind, however, that by using this feature, you
have all the concerns of any database application, such as performance considerations, available connections, and database backup and recovery.
Invalidate Time, located on the Intervals tab, specifies the maximum length of inactivity (no requests) beyond which the WebSphere server will logically kill a session
and treat requests as the start of a new session.
A classic example: HitCount
The WebSphere server comes with a simple, yet illustrative, example of using an HttpSession object, the HitCount servlet, as shown in Figure 3. HitCount
demonstrates several ways that a servlet can store and retrieve data, including HttpSession.
Figure 3. HitCount servlet output
Selecting the Session state (create if necessary) option, and clicking Increment causes the HitCount to rise. Listing 1 shows the source code from the HitCount
servlet.
Listing 1. HTTP session logic from HitCount
HttpSession session = req.getSession(true);
if ( session == null )
hwcount= "Hit count: Cannot create session as expected!";
else
{
integer value = (Integer)session.getValue("hwcount");
if ( value == null )
{value = new Integer(1);
hwcount = "Hit count: 1 (from new session)";
}
else
{value = new Integer(value.intValue() + 1);
hwcount = "Hit count: " + value +
" (from existing session)";
}
session.putValue("hwcount", value);
}
|
This code fragment calls a variation of the getSession() method, getSession(boolean). If passed true, it has the same effect as calling getSession(). If a session does
not yet exist, one is created.
The logic in HitCount is quite simple, but also quite useful in showing how your application will behave under various scenarios. To get a clear understanding of how
sessions work, try the following experiments, starting with the default Session Manager settings:
- Launch a browser, and request HitCount. Select Session state (create if necessary) option, and click Increment. Leave that browser up, and launch a new browser. Go to HitCount, and increment again in the new browser. Does it add to the existing count or start a new one? Close all browsers and start over again. Does the count continue, or does it start from zero?
- Try the same experiment as in the previous scenario, but use a different browser type. Does it act the same?
If you tried steps 1 and 2 with the Netscape and Microsoft Internet Explorer Web browsers, you probably noticed that Netscape shared its count across browsers, while Internet Explorer started a new count with each new browser. Remember, the session ID is stored in a cookie. The results demonstrate that Netscape shares its cookies across browser sessions, while Internet Explorer creates separate cookies for each browser.
This is an important lesson. Even with Session Manager, you are dependent to some extent on the client and how it stores and returns information.
- Disable cookies in your browser settings, and try the HitCount session increment option again. What happens now? Note that a new session, with a count of one, gets created each time we hit the servlet. The browser can't stop us from creating a new session and initializing its count to one, but because it won't store the information, it prevents us from retrieving it later. Our poor hero is writing his notes in disappearing ink.
- Try selecting Enable URL Rewriting in the Session Manager to address the problem of browsers not accepting cookies. When you test this, you'll see no change in behavior. Remember, URL rewriting requires extra steps in the server code that HitCount does not implement. Again, someone is sneaking up on our forgetful protagonist and snatching his notes while he's sleeping.
- Enable URL rewriting by updating HitCount.jsp (supplied with the WebSphere server) as follows by changing:
<FORM method=GET ACTION="HitCount">
|
to
<FORM method=GET ACTION=
<%=response.encodeURL("HitCount") %>>
|
Restart the example Web application to pick up the changed code, and try step 4 again. Now the count should increment regardless of whether the browser is accepting cookies. After selecting the Increment button and getting the response page, look at the URL in your browser. Now you can actually see your session ID.
- Start a HitCount session. Leaving the browser up, stop and start the application server, and try to increment the count again. It starts over; the old session ID, stored in memory, is gone.
- If you have an available data source (the default DataSource works fine for testing), select Enable Persistent Sessions in the Session Manager settings, stop and
restart the application server, and try the above exercises again, especially step 6. Now you should see the count preserved even when the application server is
restarted.
One more thing about HitCount: its interface presents the HttpSession as one more way to store data, along with persistent (data-based) Enterprise Java Beans
(EJBs) and Java DataBase Connectivity (JDBC) calls. Don't be misled by HitCount or the term persistent sessions into confusing session data with business data.
Even with persistence turned on, the data is lost when the session ends. Important information that the Web application captures, such as a purchase order or
updated user preferences, still needs to be written to a database or entered into a workflow process, as with a traditional application.
Through all these exercises, we have to guess at what is or is not going on with our HttpSession object. Wouldn't it be nice if there were an easy way to view session
data dynamically?
Snoop to the rescue
Fortunately, the Snoop servlet supplied with the WebSphere server and automatically deployed in the default configuration displays session data views. Most
WebSphere developers are familiar with Snoop; the ability to successfully request it from a browser is used as a basic indication that the WebSphere server is up
and running. Less well known is the fact that Snoop displays session information.
Use HitCount to start an HTTP session, and jump to the Snoop servlet by typing its URL in the browser. You should see a section in the Snoop output that looks
similar to Figure 4.
Figure 4. Snoop display of HitCount session data
Session ID is the unique key created by the Session Manager to store and retrieve session data. Session values is a list of the current session's data elements. In this
case, there is only one entry, hwcount, with a value of 1. Snoop displays your servlet's session data as well, as long as it is on the same application server.
The Snoop servlet uses several javax.servlet.http.HttpServletRequest and javax.servlet.http.HttpSession APIs to display this information:
- HttpServletRequest.getSession(false) returns a
session only if it already exists. This allows it to display the Session
section of the page without inadvertently creating a new session.
- HttpSession.getId() returns a String containing the
current session ID.
- HttpSession.getLastAccessedTime() and
getCreationTime() return the last time a page was requested in this session
and when the session was originally created, respectively (conveniently
represented as milliseconds since midnight January 1, 1970 GMT).
- HttpSession.getValueNames() returns an Enumeration of
Strings, allowing Snoop to loop through the session data to print the table of
session names and values, as shown in Figure 4.
- The HttpServletRequest. isRequestedSessionIdFromCookie() and isRequestedSessionIdFromURL() methods check whether the session ID came from a cookie
or rewritten URL and return a boolean value.
Now we can more easily make sense of the experiments we tried earlier. Try them again, and this time enter the URL for Snoop after each increment. You can see
when a new session (as indicated by a session ID) is created, when an old session is preserved, and when no session is created. Use the same technique to examine
your Web applications.
Conclusion
We have introduced the basic concept of managing Web sessions using the WebSphere Session Manager component and the HTTPSession interface. Now our
hero can sleep well at night, knowing his essential information is safe and secure.
References
- The WebSphere product provides the Snoop and
HitCount servlets and source code and automatically deploys the servlets as
part of the default configuration. You can find the source code files in your
WebSphere installation directories.
- Ayers, Danny, et al., Professional Java Server
Programming
- Wahli, Ueli, et al., Servlet and JSP Programming with IBM WebSphere and VisualAge for Java.
Resources
IBM DeveloperToolbox
Find the following article-related categories, products, or tools on your DeveloperToolbox CDs.
- Categories: Java tools, WebSphere
- IBM WebSphere Application Server Advanced Edition
About the author
Steve Eaton is a software engineer for the IBM WebSphere technical support team. He holds a Bachelor of Arts degree in English Language and Literature from the
University of Chicago and a Master of Science degree in Computer Science from the University of North Texas. You can contact him at steaton@us.ibm.com.
|

|
 |