Are JSF 2.x @ViewScoped managed beans thread safe?
Asked Answered
T

2

20

I've been googling for a couple hours on this issue to no eval.

WELD docs and the CDI spec are pretty clear regarding thread safety of the scopes provided.

For example:

  • Application Scope - not safe

  • Session Scope - not safe

  • Request Scope - safe, always bound to a single thread

  • Conversation Scope - safe (due to the WELD proxy serializing access from multiple request threads)

I can't find anything on the View Scope defined by JSF 2.x.

It is in roughly the same bucket as the Conversation Scope in that it is very possible for multiple requests to hit the scope concurrently despite it being bound to a single view / user. What I don't know is if the JSF implementation serializes access to the bean from multiple requests.

Anyone have knowledge of the spec or of the Morraja/MyFaces implementations that could clear this up?

Tertullian answered 14/9, 2011 at 2:44 Comment(0)
B
20

The view scope is with normal usage thread safe. It can be used by only one browser window/tab. Namely, it's keyed by an unique hidden input field which is set on the initial GET request. Every postback on the same view will use the one and same view scoped bean. The browser itself already "synchronizes" postback requests in the same window/tab. A new browser window/tab is effectively a new GET request and will therefore create a new and completely independent view.

As to ajax postbacks, they are by specification queued. This is mentioned in chapter 13.3.2 of the JSF 2 specification:

13.3.2 Ajax Request Queueing

All Ajax requests must be put into a client side request queue before they are sent to the server to ensure Ajax requests are processed in the order they are sent. The request that has been waiting in the queue the longest is the next request to be sent. After a request is sent, the Ajax request callback function must remove the request from the queue (also known as dequeuing). If the request completed successfully, it must be removed from the queue. If there was an error, the client must be notified, but the request must still be removed from the queue so the next request can be sent. The next request (the oldest request in the queue) must be sent. Refer to the jsf.ajax.request JavaScript documentation for more specifics about the Ajax request queue.

Only when using PrimeFaces, queueing can be disabled with <p:ajax async="true">. When using this in combination with view scoped beans, threadsafety must be reconsidered the same way as for session scoped beans.

See also:

Beata answered 14/9, 2011 at 3:21 Comment(6)
I understand that, however just as with the conversation scope, its possible for there to be multiple ajax requests in flight at any given time, each one results in a request thread which can access the view the scope. Think of someone spam clicking an ajax button that results in data modification in the bean, if the access of those requests isn't synchronized or serialized by a proxy then there can be issues.Tertullian
Oh, this way. Yes, the ajax requests from the same view are queued in client side as stated in JSF 2 spec. I'll update the answer with an extract of the spec. Synchronous requests are not queued by JSF, but it's the browser which does that anyway.Beata
thank you for the update, if i could trouble you for 1 additional question: Its clear that the quoted spec covers ajax calls, however, if you had a link to a jsf view which was backed by a viewscoped bean, and that view had a method to call in the backing bean via a f:event, say a preRenderView event or something. If the source link were spam clicked, i would expect multiple calls to that method (i think, i'm not 100% clear on when exactly the view scope would begin), any idea if those calls would be queued in the way that ajax calls are?Tertullian
Maybe what i'm asking would fall into the bucket of synchronous requests? I'm not sure that the browser really queues them however, i've done some testing on the case i just described with sessionscoped beans to see what would happen and i definitely get concurrent method execution.Tertullian
Links are GET requests and every GET request will recreate the bean, also when it's in the same window. A non-null/void navigation outcome will also recreate the bean.Beata
@Beata I'm a little late on this, but lets say I have a viewscoped bean and on the page I trigger an ajax request to a external service (using only javascript) and when that call returns, I call a p:remoteCommand from javascript that uses a method of the bean to update the user view. Is it possible that this creates a problem with concurrency? If the user keeps using the bean while the remoteCommand actionListner is being executed.Metamerism
M
4

ViewScoped beans are stored in a "view" Map that is created for every UIViewRoot. When two concurrent requests are processed by a JSF runtime, usually, it is unlikely that the same UIViewRoot instance is created/restored for these requests, as the javax.faces.ViewState form parameter in the HTTP request is used to determine whether an existing UIViewRoot instance should be restored or not (on postback). As BalusC has indicated, two different browser windows will result in two different view scoped beans being created, as the underlying ViewStates parameters are different for both the browser tabs (if you are issuing two different HTTP requests and the browser is using the response of each to display the individual tabs, instead of using a cached copy).

The part about thread-safety however goes beyond browser tabs/windows. There is no inherent mechanism within the JSF runtime (atleast within Mojarra) that will synchronize access to the UIViewRoot and the view map, if two HTTP requests (and hence, two threads) present the same javax.faces.ViewState value in the request to be processed by the container. Hence, view scoped beans are not threadsafe by nature, and neither are they accessed in a thread safe manner. You could confirm this by replaying requests with the same javax.faces.ViewState values and observe the behavior of the container/JVM when multiple such requests are received by the container in a short duration (resulting in the possibility of concurrent access to the same UIViewRoot instance by multiple threads).

Marismarisa answered 14/9, 2011 at 4:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.