Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating session explicitly in requestScoped bean in JSF 2

I have a doubt here about creating session in requestScoped bean in JSF 2.x. I understand that we need not create session in JSF 2.x since we can directly use a sessionScoped bean to put the user required data. But I recently was introduced to a JSF code where the developer had created instance variable of session and get session from facescontext, like below

 @ManagedBean
 @RequestScoped
 Public class someClass(){

 FacesContext facesContext = FacesContext.getCurrentInstance();
 HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);

 public void someFunction(){

 //Some code here..

 session.setAttribute("key","value");

 //Some code here..

 }

  //rest of the code here...
 }

Well, I told them that one should not have "session" as a instance variable and also there is no need to get a session explicitly in JSF 2 and rather use a sessionScoped bean.

For the first I gave a reason as "keeping session as instance variable is not thread safe" and for the second statement I gave as "you are doing a workaround for JSF session which is already provided".

The counter-argument what I got was, For first reason "Ours is web application so there is no question of multi-threading". For second I got "Anyway the session variable will be cleared once the request is processed, so there is nothing wrong here.

I had a no other strong points to rectify it.So my question is, 1) were they correct? 2) is there any other specific reason why we should be doing in a way it ought to be done? 3) And finally, anything which might have prompted them to use that way?

can anybody please elaborate? Please correct me. Thanks

like image 695
h-kach Avatar asked Mar 08 '13 17:03

h-kach


2 Answers

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 Objects 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!

like image 93
skuntsel Avatar answered Sep 30 '22 11:09

skuntsel


Whilst this would theoretically work, this is simply tight coupling and bad design. A very small change from @RequestScoped to @ViewScoped would kill the entire web application altogether. This is definitely not right. A backing bean class should be designed in such way that it's technically not sensitive to the scope it is been declared in.

You should never assign the FacesContext or any of its artifacts as a property of a backing bean, but always access it in the thread local scope, no excuses.

like image 29
BalusC Avatar answered Sep 30 '22 12:09

BalusC