Creating session explicitly in requestScoped bean in JSF 2
Asked Answered
W

3

7

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

Wahoo answered 8/3, 2013 at 17:38 Comment(7)
A webapp is multithreaded to handle requests concurrently. Requests can have the same session id. Have a look at Is HttpSession thread safe.Boil
@NicolasLabrot Yea, It can have same session id when requested from two different browsers in the same machine and hence it should be handled in a multi-threaded way. Apart from this case, if we talk about ideal case of request coming from different machines then multi-threaded doesn't come into picture right? The question is related to this case.Wahoo
@marceln Why this question has an ejb tag??Wahoo
Not only from different browser, but from different simultaneous request from the same browser : AJAX request, user who refresh n times... 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
@NicolasLabrot Ok about refreshing.. But, session variable will be cleared once the requestScoped bean is processed. I mean for the next request for that bean, that session variable will be refreshed as well. So I dont think the developer has to clear himself/herself. As to why its been done like this, Well thats my question here :) I am asking for a specific points myself :)Wahoo
They do not use the JSF way of session attribute with session bean. They go against the framework with a pattern which is not very readable (boiler plate), can be dangerous and do not promote good practice (duplication of code, business data stored as raw data...).Boil
@NicolasLabrot Hmm, yea, I know its not good practice. Can you elaborate on those bracketed reasons? If that causes a problem and how?Wahoo
P
7

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!

Premonish answered 12/3, 2013 at 18:27 Comment(7)
I understand that if we use session as I have mentioned in the question, we can avoid race condition by using synchronized block. But my original question is "what is the difference between using a single session scoped bean given by JSF than using session as in the requestScoped bean that I have mentioned here"? Any benefits in using sessionScoped bean than the way it is used here? Also,race condition might occur when we use sessionScoped as well right? how to avoid it?Wahoo
@hemanth Though my reply to your comment is a little late, you can see it in an edited answer.Premonish
Thanks for a detailed answer. "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.. " what you mean by that?Wahoo
My idea was that if you want to use a session for simple transfer of data between view (like database id, or previous choices in a wizard-like setup, or selected item, etc.) that will cause problems and should be solved by using other alternatives, that developer is most probably unaware of, because he abuses the session, when he first puts (unmanaged) data in session, later reads data from session and finally removes data from session.Premonish
ok.. that means we need to use other methods like <f:attribute>, <f:setPropertyActionListener>, <f:param> and the like in this cases right?Wahoo
Right, to transfer data in get requests, use the tags you mention. To pertain data acsoss redirects in post, make use of flash object. Session belongs to data inherent to the current user, and should not be used to solve other problems. This way you are dealing with scoping problems instead of concurrency problems.Premonish
What do you mean by scoping problems?Wahoo
F
4

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.

Fraser answered 13/3, 2013 at 20:21 Comment(8)
"what is the difference between using a single session scoped bean given by JSF than using session as in the requestScoped bean that I have mentioned here"? if not managed by JSF, then it won't be autocreated when you do #{sessionBeanName} in EL when it's not been created yet.Fraser
@Fraser Changing the scope from request to view would kill since we will not be able to get the session attribute set in the previous view? If am wrong then how does it kill the application?Wahoo
The referenced FacesContext instance is not valid anymore in next request.Fraser
@Fraser Can you elaborate? Do you mean the FacesContext instance will be refreshed on next request? On next request, a new instance will be created right, it will contain all the info again. how it would affect? Sorry for this, just want to make it clear.Wahoo
Your code has FacesContext assigned as property of a request scoped bean. If this bean is in a broader scope and any method tries to access the property during a subsequent request, then it would throw IllegalStateException.Fraser
@Fraser ok, cool I understood well by looking into one of your answers .. #10505988Wahoo
@Fraser But the application which I am looking at doesn't have a single viewScoped bean nor a sessionScoped bean. Thats why I asked this question cause it beat me to what limited knowledge of JSF I had :) Thanks a lot again for sharing this knowledge :)Wahoo
@Fraser ok.. It is working and in production with almost a million hits :) But the response is slow and the entire application is non-ajaxical :)Wahoo
F
3

I don't know what is happening with session in code after it is obtained and really everything depends on it.

With multithreading problem I must say that if you are just reading something from session there is no problem. When writing to session, there can appear huge problems. When multiple requests run for single session (AJAX requests, multiple tabs...) there will be a race condition so you can't be sure what is actually written in the session.

There is no JSF session and HTTP session, there is just one session and that is the HTTP session. JSF just provides a facade to that session, so from that point on there is no problem here how session is obtained. Adding some attributes to session is OK in some cases, but should be controlled and must be limited. For example you can generate some data in this backing bean and that data should be shown in another window (for example some report). You can add report data to session, and on another page when you obtain those data you remove them from session. This is limited as those pages will be in one flow, and there is nothing between them. But if that method is called for another purposes also that is a problem.

Fourposter answered 11/3, 2013 at 21:30 Comment(8)
So basically what you are summarizing is, we can get session like this and use it without following what JSF actually provides through SessionScoped bean. Also, are you saying about the multi-threading problem with session in general or when session is declared as instance variable?Wahoo
I just think that it is OK to use session to store some data which you will preserve in session or you just want to translate it through views for example (when you don't have conversation scope for example). In any case you should not use it to create some your "session scoped beans" as those beans will not be managed by JSF, and so they are not managed beans. For session scope this is general problem, see this link especially part "Threading considerations".Fourposter
For example, imagine you have some wizard which you want to implement which has multiple pages. You can store variables important for that wizard in session, and clear that data at the end of wizard. That is example. But those data are not managed beans, as they are managed by you not by JSF. Is it more clear now?Fourposter
Yea it is clear now. I know about it already. So, in a requestScope bean if we have an session instance variable then on ajax request there will be race condition, this is what you mean right?Wahoo
Yes. In case when you have two AJAX calls you will have two instances of request scoped bean racing with each other.Fourposter
So in case when you have no ajax calls then there will be no race condition. I mean when we call the requestScope bean only once then there wont be any race condition. Am I correct?Wahoo
It can be also situation when you open two tabs in browser. That is also same session, with possible to parallel requests.Fourposter
let us continue this discussion in chatWahoo

© 2022 - 2024 — McMap. All rights reserved.