HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 
Pluggable Session Java Servlet-Based, by Ruslan Belkin & Viswanath Ramachandran

Numerous books and publications are available on the various technologies that support e-commerce on the Internet. As Java Servlets and JavaServer Pages (JSPs) emerge as a popular technology, a lot of material is being written about them. Most of this material focuses on programming model features, ease-of-development issues, and integration with tools. However, Web site developers are increasingly concerned about developing sites that can scale to a large number of hits while keeping the complexity of the software at a reasonable level.

This article focuses on how Web developers can utilize advanced features of the next generation of Web server products to design their server-side applications for scalability and performance using Java, and specifically discusses the state and session management aspect of Web applications. It indicates how the pluggable session management service of iPlanet Web Server can be used to achieve high performance and scalability. This article assumes you're familiar with the Java Servlet API.

URL Encoding and Cookies
The HTTP that's used to access almost all the information on the Internet is stateless. This presented a problem, especially for transaction-based e-commerce sites, since they needed to identify a specific client across multiple requests. For example, when a client goes back to the server that's handling airline ticket reservations to confirm the selection, the server has to be able to identify the client and continue the transaction. One solution employed by early Web site developers was to encode relevant information directly into the response URL. This didn't require any additional capabilities from clients or servers, and it worked especially well on several prominent high-traffic sites. The method, known as URL encoding, is still widely used.

A later solution invented by Netscape for the state retention problem was the cookie mechanism. The server would send a cookie header to the client (browser), which would return that same cookie to the server on subsequent requests, thus allowing the server to uniquely identify the client. In addition, the cookie has a life span that allows it to expire. The cookie header, however, has a limitation on the length of the data it can transmit, and there's no mechanism enabling the server to ask for a specific cookie. Listing 1 provides the code for a Java Servlet that uses the cookie mechanism for maintaining the number of times a client has accessed the servlet.

Table 1 summarizes the features, advantages, and disadvantages of using cookies versus URL encoding.

Table 1

Server-Side Session Management
Due to size limitations of the URL encoding and cookie mechanisms, a need arose for more sophisticated session management techniques. Unfortunately, further revisions of the HTTP protocol elected not to address the issue of maintaining session data between the server and client, leading to the necessity of storing the session information associated with the client on the server side. Instead of transmitting the entire BLOB of data representing the session data (often not possible due to size limitations), the server would transmit a session cookie that contained only the session identifier (SID). In case the client didn't support cookies, the SID could be encoded in the URL instead. In the future, it would be used by the server to retrieve the session data stored somewhere on the server, typically in memory, on a disk, or in a database. The mechanism is generally referred to as server-side session management. The Java Servlet API provides programming model features that make the use of server-side session management extremely convenient and intuitive to the developer.

Table 2 summarizes the main features, and the advantages and disadvantages of the server-side maintenance of sessions versus the cookie-based mechanism.

Table 2

Listing 2 contains the code for a Servlet that maintains a client session using server-side sessions.

From the application developer's point of view, managing the session with the client is simple. The Servlet container takes care of all the specifics for generating the session ID, identifying the incoming request, storing objects associated with the session, and managing the session life cycle. Practically all the application developer needs to do is call the getSession () method on the HttpServletRequest object to obtain the reference to the session object.

Server-Side Session Properties
While the Servlet API offloads all the groundwork of managing the session with the client, making it easy to use, it doesn't specify anything about how session objects are created, where they're stored, what level of protection against failures is provided, and more. These issues are left for the Servlet container to define and implement. As we pointed out earlier, the session management could be inherently expensive and often dependent on the type and purpose of the Web application.

Depending on the type of application and specific customer requirements, you can examine the following considerations while evaluating the way the Servlet container manages sessions.

Life Span of the Session
Sessions can be short-lived (for a relatively short transaction, such as placing a stock trade). Usually these types of sessions are created and accessed often and you may want to make that process as lightweight as possible.

On the other hand, sessions can also be long-lived, for example, when the user logs into his or her brokerage account to perform various maintenance tasks and accesses pages at a relatively infrequent pace.

Persistence
The sessions may need to be made persistent - meaning the session data is stored in reliable storage and will persist there even across server restarts. By persisting your session you ensure a certain level of failover capabilities. Normally there'd be a price for that in terms of performance. The application developer must be aware that all objects placed into such a session must implement the java.io.Serializable interface.

Locality
When the server and the network setup can ensure that all requests from the same client will come back to the same server, there's no need to worry about the migration of sessions across server instances. However, a facility to access the session from the server instance that didn't create the original session may need to be provided. The simplest way to achieve this is to declare such sessions to be persistent and always store them in some central database.

More elaborate approaches can attempt to utilize the simple fact that the client wouldn't normally access two servers with the same session ID at the same time. This assumption allows the designer of the session manager to eliminate the potential need to lock (which will have to be a cross-instance lock) the session object.

Generation of Unique Session Identifiers
The session ID must be a unique identifier to unambiguously identify the session. Depending on the type of application, there could be different requirements for the session ID.

For a simple case of local nonpersistent sessions, this ID can be a number that is incremented every time the session is accessed, plus some time stamp to ensure the uniqueness across restarts. For multiple instances this ID must also include unique host information.

The above technique or a similar one, however, doesn't ensure the operation within an environment where security is a concern. The session ID, generated using one of the above simple approaches, could be easily guessed by a malicious client, thus allowing it to impersonate itself. The default session ID generator of iPlanet Web Server (iWS) produces cryptographically strong IDs. This, however, can bear some performance penalty, and in situations where security isn't an issue, the developer of the session manager can provide his or her own session ID generator.

Collaboration with Other Products
It's likely that the proposed Web application can be so complex that one specific set of features won't be able to satisfy all the requirements. For example, you may wish to have a lightweight, nonpersistent way of managing sessions for some part of your application, and a really elaborate, reliable session management facility for some other very critical, but not as frequently accessed, part of the application. It may be desirable to run some applications within a simple Servlet container that's built into the Web server to achieve high performance and low latencies. Some other pieces of the application may need to live within the Servlet container, which is part of the dedicated application server. It may be desirable to share the same session object with these different parts of the Web application.

Pluggable Session Management
In light of the previous discussion regarding the often contradictory needs of the server-side session container (Servlet container), it becomes apparent that there's no "one size fits all." It's essential to have some degree of pluggability in the Servlet container's session management.

During the design cycle of the iWS series, we came to the above conclusion that there could be different approaches and requirements in the way you handle session management, even within the same logical application. We thought it would be natural to make the session management facility pluggable so the developer could apply different session management techniques to various applications. iPlanet Web server goes even further by extending the granularity of pluggable session management to every Servlet context.

Implementing a pluggable session manager for iWS is very simple. The session manager implementer needs to extend the com.netscape.server.http.session.NSHttpSessionManager class. The session manager will be responsible for creating and managing session objects. Every session object the session manager creates needs to implement the standard HttpSession interface. Internally, however, it's up to the writer of the session manager to define the relationship between HttpSession objects and the session manager. Listing 3 contains the definition of the abstract class that every session manager in iWS is an instance of.

Registering your new session manager is easy - simply add a few lines to a configuration file called contexts.properties:

context.global.sessionmgr=com.Foo.Bar.mySessionManager
context.global.sessionmgr.initArgs=SomeInternalParameter=2000,
AnotherInternalParameter=1000

iWS4.1 can potentially instantiate multiple session managers within the same server process (one per each Servlet context). The developer of the session manager has to make sure that the code is thread-safe and allows for multiple instantiations.

What's Next?
We've all witnessed the remarkable growth of the World Wide Web from a publishing medium to a complex virtual world that mirrors virtually every activity in the real world. Upcoming major advancements in the bandwidth that's available to consumers and businesses are expected to bring many more exciting features to the Web and, in turn, dramatically increase the performance and scalability requirements for Web-based applications. Inefficiencies of today's Web that are already visible will become a major challenge for services and software businesses.

Let's illustrate this with the down-to-earth example of a grocery store operation. Normally a customer in a grocery store would pick up a shopping cart, roll it through the store getting desired items, then proceed to the counter. Now let's imagine that the grocery store assigns a representative to every shopping cart. This model won't scale at all, but that's the model currently employed by a majority of e-commerce sites. By maintaining state/session information, servers are effectively rolling the clients' shopping carts, thus causing major scalability bottlenecks. This problem can be solved on both ends of the link only by providing smarter clients that understand the boundaries of the Web application, providing facilities to serialize and retrieve arbitrary structured data to and from the client and the servers, and understanding how to talk to these next-generation clients as well as older browsers.

The biggest challenge for the Web development community will be to agree on an acceptable set of standards that are going to be implemented by leading Web clients. We're hopeful and optimistic that the Mozilla open-source browser project supported by Netscape (a subsidiary of America Online) will play an important role in advancing these kinds of new technologies.

Author Bios
Ruslan Belkin, lead engineer and architect of Java Servlet and JSP support in iPlanet Web Server 4.0/4.1 (formerly known as Netscape Enterprise Server), has over 10 years of experience in the industry and is a member of the Servlet API expert group. Ruslan has worked on Java, CORBA, distributed objects, component models, and scripting languages, with special focus on high performance implementations of standards. [email protected]

Viswanath Ramachandran is a researcher working on JSP and JavaScript support in the iPlanet Web server group. A member of the JSP expert group, he has a PhD in computer science from Brown University in the field of programming languages. [email protected]

	



Listing 1: State maintenance using a simple cookie

public class CookieServlet extends HttpServlet
{
public void doGet (HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException

	{
		Integer nof = new Integer(0);
		Cookie cookies[] = req.getCookies();

		for (int i = 0; i < cookies.length; i++)
			if (cookies[i].getName().equals("CounterCookie"))
			{
				String nofS = cookies[i].getValue();
				try {
					nof = Integer.valueOf (nofS);
				}
				catch (Exception nfe) {}
				break;
			}
		nof = new Integer (nof.intValue()+1);
		Cookie c = new Cookie ("CounterCookie", nof.toString());
		res.addCookie(c);
		// ...
		out.println("You have visited this page" + nof + " times");
		// ...
 	}
}



Listing 2: State maintenance using a servlet server-side session

public class SessionServlet extends HttpServlet
{
public void doGet (HttpServletRequest req,
HttpServletResponse res)
throws ServletException, IOException
	{
// this will create the session if it doesn't exist
		HttpSession session = req.getSession (true);
		
		PrintWriter out = res.getWriter();

out.println("<HEAD><TITLE> " + "SessionServlet Output " + 
"</TITLE></HEAD><BODY>");
		out.println("<h1> SessionServlet Output </h1>");

		Integer ival =
(Integer) session.getValue("sessiontest.counter");
		if (ival==null) 
			ival = new Integer(1);
		else 
			ival = new Integer(ival.intValue() + 1);

		session.putValue("sessiontest.counter", ival);		
	    	out.println("You have hit this page <b>" +
ival + "</b> times.<p>");
		// Session ID encoded in the response URL
		out.println("<a href=\"" + res.encodeUrl (myUrl) +
"\">Click here </a> if your browser doesn't support cookies");

		out.println("</BODY>");
	}
}



Listing 3: Base Class for all pluggable session managers

/*
 * Every session manager supported by iWS must extend this class
 */

package com.netscape.server.http.session;

...

public abstract class NSHttpSessionManager {
    
	/**
	 * Initializes session manager. This method will only be called once
	 * 
	 * @param props	A collection of init parameters passed by webserver
	 */
    	public abstract void init (Properties props);

	/**
	 * Creates a session with the specified session id
	 * 
	 * @param id	session ID
	 * @return	newly created session
	 */
    	public abstract HttpSession createSession(String id);
	
	/**
	 * Delete a specified session
	 * 
	 * @param session
	 */
    	public abstract void deleteSession(HttpSession session);

	/**
	 * Request an existing session with the specified session id
	 * 
	 * @param id	session ID
	 */
    	public abstract HttpSession getSession(String id);
	
	/**
	 * Get default session expiration timeout in seconds
	 */
public abstract int getDefaultTimeOut();
    
	/**
	 * a method which will be called periodically to let the 
       * session manager expire old sessions
	 */
    	public abstract void reaper ();

	/**
	 * Update method will be called by the server at the end 
       * of every request to give
	 * the session manager an opportunity to store the session 
       * into reliable storage if needed
	 * 
	 * @param session	The session object
	 */
	public void update (HttpSession session);	// does nothing by default
	
	/**
	 * Generate random session ID
	 * 
	 * @return	random unique string which represents random ID
	 */
	public String generateSID ();			
	// generates cryptographically-strong ID by default
	
public int getMaxSession();			// returns 0 by default
public int getSessionCount();			// returns 0 by default
}

  
 
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.