You can also maintain state in hidden form fields. But storing session state in the client using HTTP cookies or hidden form fields has significant security risks as it exposes a part of your application internals to the untrusted client layer. Also, a cookie-based approach won't work at all if the user has disabled the use of cookies in the browser.
An alternative to cookies is URL rewriting, which means appending the session ID to all the URLs (including all the hyperlinks and action attributes of the forms) in the HTML page which is being sent as a response to the client. However, although this a robust way to support sessions, it comes at a cost: its costs developer effort and it costs time and machine resources. (Bear in mind that even static HTML pages must be run through a
servlet in order to rewrite the URLs.)
As mentioned, you can store session state in stateful session beans or in the database. However, SFSBs do not scale as well as stateless session beans, and use of the DB can slow performance significantly. For a web client, it is probably best to store the session state in an HttpSession in the Web tier. If the business objects are stateless, then the application can often be scaled by simply adding more Web servers, rather than more Web servers and more
EJB servers. Another advantage of using the HttpSession to store conversational state is that the Servlet API offers an easy way to be notified when a session expires.
And although the Servlet spec does not require it, most servlet containers also provide some form of proprietary HttpSession replication which gives you load balancing, scalability, fault tolerance, and high availability.