HttpSession
interface, as defined in Java EE 6, provides for a way of user actions grouping, identification of continuous actions performed by a user and storing information about that user across more than one page request.
General overview
Since the session is obviously shared among many requests, it gives rise to the problems of thread safety and their implications. In the Servlet 3.0 specification, chapter 7 on Sessions, one may find support for importance of dealing with such problems:
Multiple servlets executing request threads may have active access to the same session object at the same time. The container must ensure that manipulation of internal data structures representing the session attributes is performed in a thread safe manner. The Developer has the responsibility for thread safe access to the attribute objects themselves. This will protect the attribute collection inside the HttpSession object from concurrent access, eliminating the opportunity for an application to cause that collection to become corrupted.
Servlet 3.0 Specification (JSR-315), ch. 7.7.1, emphasis mine.
But where does all this mess stem from? In the times of pre-AJAX web applications developers didn't bother too much about synchronization because the probability that the same user accessed the session cuncurrently had little probability. But with the rising tendency towards building AJAX-enabled web applications, it is quite likely that two requests from the same user could come concurrently and therefore access the session concurrently as well.
As a side note, it is worth noting that the threading problem can be slightly lowered by using SingleThreadModel
interface of the servlet, but necessity of its application is disputed (Servlet 3.0 Specification (JSR-315), ch. 2.2.1). Besides, it is deprecated since Servlet 3.0 and "objects that are accessible to more than one servlet instance at a time, such as instances of HttpSession, may be available at any particular time to multiple servlets, including those that implement SingleThreadModel".
Problems with synchronization
Java EE 6 tutorial explicitly states that "Concurrent access can arise ... when multiple web components access objects stored in a session" (The Java EE 6 Tutorial, ch. II-15). Moreover, if we take a closer look on HttpSession
interface, we will find some methods that allow binding objects to sessions, essentially providing for the possibility to store user information across multiple user connections, thus overcoming the statelessness of the HTTP protocol. These methods are:
getAttribute(String name)
(and the now-deprecated getValue(String name)
);
setAttribute(String name, Object value)
(and the now-deprecated putValue(String name, Object value)
;
removeAttribute(String name)
(and the now-deprecated removeValue(String name)
);
invalidate()
and
- other methods of the interface.
The last method invalidates this session and unbinds any objects, holding user information, bound to it, so it is not what we're afraid of. The most important methods are the ones that read, write and remove Object
s from/to the session, because these methods will be call to deal with / access data at the same time by different threads.
The obvious problems of concurrent access are, as Brian Goetz mentions in Java theory and practice: Are all stateful Web applications broken?:
- atomicity failure, where one thread is updating multiple data and another thread reads the data while they are in an inconsistent state and
- visibility failure between a reading thread and a writing thread, where one thread modifies the data but the other sees a stale data or data in inconsistent state.
Simple solution to the problem
He later propeses 5 techniques of reducing concurrency problems within web applications and finally states that "Serializing requests on an HttpSession makes many concurrency hazards go away". Marty Hall proposes the following about the synchronization in his online tutorial on Session tracking: "use the session or perhaps the value from the session as the label of the synchronized block". So, the basic setup is:
HttpSession session = request.getSession();
synchronized(session) {
SomeClass value = (SomeClass)session.getAttribute("someID");
if (value == null) {
value = new SomeClass(...);
}
doSomethingWith(value);
session.setAttribute("someID", value);
}
With this setup, overlapping requests to access the session will be synchronized.
Example of not thread safe usage
HttpSession session = request.getSession();
MyClass myClass = (MyClass)session.getAttribute("myClass");
if(myClass != null) {
myClass.performOperation();
session.setAttribute("myClass", myClass);
}
The need for explicit operation with session in JSF
It is clearly understood that manipulation of data in session object may lead to concurrency issues. Moreover, its applicability is dubious when you choose to develop within a JSF framework that will manage the session objects implicitly for you.
In the end, you are supposed to put objects in session when they inherently belong there. Developers sometimes tend to put objects in session as a means of solving the problem their way, but usually there is a better way. Some mistakes are covered in the article JSF Best Practices: Scope management for clean sessions by Thomas Asel.
Some ways of threading problems alleviation
Most of the threading problems arise when the HttpSession
is used the wrong way. In this light the threading problems are the consequence of scoping problems.
If, for example, you put a value in a session that is supposed to belong to a narrower scope, that is, request scope, or view scope, your code becomes vulnerable to cuncurrency problems with tangible probability. Instead, if all your session data belongs to the right scope, the probability that users ever face concurrency issues is extremely low.
@SessionScoped
beans thread safety must be ensured by the developer, as soon as JSF stores ultimately those beans as an attribute of HttpSession
with managed bean's name as the key. The access to the managed bean by name is a convenience in JSF and as far as I know, is under the covers done by session.getAttribute("managedBeanName")
.
In this context, if a user placed correct data in a session and managed it correctly (I mean didn't solve problems that should be solved without session disturbance), then the only disadvantage I see is mentioned in BalusC's answer, which is to quote "tight coupling and bad design". Otherwise (if we omit that JSF manages lifecycle of the bean under the covers correctly and bad design problems), the usage is analogous.
Some examples of scoping problems that cause concurrency problems that come to mind:
- Storage of anything but related to user information in session (user authentication details, his preferences, locale choice in internationalized web applications;
- Sharing information between views should not be done by using session: retrieval of data should be done by
GET
requests, manipulation of data should be done by POST
requests; passing data during page forwarding can be done by, for example, using <f:setPropertyActionListener>
, passing data during page redirection can be done, for example, using #{flash}
attributes;
- Passing information in repeated components setup should be done without disturbing the session, via
<f:attribute>
, <f:setPropertyActionListener>
, <f:param>
, and retrieval of information - via action(listener) methods, <f:viewParam>
, etc.
To sum it up, you will of course some day see misplaced output if you don't follow closely to the abovementioned list, but will hardly ever see any issues if you choose the right data to belong to the session scope. Typically this choice of data can be made while answering is the information required during the entire user session question.
Having said that, a common mistake is to put information in session to have it available in subsequent views, retrieve that information and then remove it from session, which is obviously wrong. I strongly believe that this approach was taken by your interlocutor.
In the end, JSF is evolving to facilitate developmental tasks, so why not use its helpful features!
Anyway the session variable will be cleared once the request is processed
if the developeur do it explicitly at the end of the request, otherwise the session attributes remains the time of the session. But why storing in session map, attribute with request scope? – Boil