23

I am new to the world of J(2)EE and web app development but am quickly navigating my way around it and learning a lot. Every day is a fantastic voyage of new discovery for me.

I am currently working on a project in which I am using Visual JSF Woodstock on Glassfish v2. I am pretty new to JSF also.

There are times when I need to save some objects (say MyObject for instance) between requests. And from what I have read and understood so far, I need to be using sessions to save these objects between different requests. So far so good.

Exactly how to do this is where my concern lies. I know that in JSP you can use the session.setAttribute("myObj", myObject) which would save the object at client side using cookies or url rewrites or hidden form variables.

On the other hand, in JSF I use Session scoped beans, say SessionBean1 for e.g., and save objects as SessionBean1 properties (e.g. SessionBean1.setSomeOjb(myObj)). Is this the right way to go about with this?

I am guessing that doing it this way will result in increased memory utilization at the server end since each request will create a new instance of the session scoped bean, SessionBean1 plus the memory utilized by the saved myObject instances in SessionBean1.

I have read that you can use FacesContext.getExternalContext().getSession/getSessionMap() which would save session variables at client side.

So which method would you suggest that I use - the session scoped bean or the sessionmap to save objects for access between requests for a session?

Thanks.

Francois Bourgeois
  • 3,650
  • 5
  • 30
  • 41
SibzTer
  • 1,737
  • 4
  • 14
  • 18

3 Answers3

24

In general Java EE Web Apps tend not to expect to save session data client side. You're right to be concerned about session bloat on the server side, a common problem seen is to have huge session footprints which can cause significant resource and performance issues, and can be especially in clustered environments.

I'd like to know where you see

I have read that you can use FacesContext.getExternalContext().getSession/getSessionMap() which would save session variables at client side.

I believe (correct me on this point) that this simply gives access to the HttpSession object, on which you can then use the same

 session.setAttribute("myObj", myObject)

this does not in itself send the object back to the client, it's held in the server and keyed by some session identifier, usually passed in a cookie.

Now there are two other techniques: you could explicitly choose to put data into a cookie of your own manufacture - the servlet APIs that you can access from JSF or JSP would let you do that, or you can use hidden fields on your forms, and hence pass aorund session data.

But consider this. A rule of thumb on the App Server I use is that HttpSession of the order of 1k-4k tend not to be a problem. Larger than that (and I have seen sessions of measured in megabytes) do stress the infrastructure. If you were concerned about sessions of that size would you expect to send megabytes of data in a cookie or hidden field back to the browser on every request? Even 1k-2k is probably a bit big.

So recommendations:

  1. Keep it simple. Use the Session API, or its JSF manifestation.

  2. Keep the amount of data in the session under control.

Added in response to question about clustering:

Typically, in a clustered environment we have session affinity, so that requests are sent back to the same cluster member. However we still need to consider the case (perhaps if a cluster members fails) when the request goes to a different server.

Some App Server vendors offer session replication, either via direct inter-server communication or by persisting the session to a database - obviously there are overheads here, so sometimes, for low value sessions we just accept the loss of session in event of failure.

There is an argument that if the session data has high value then it should be persisted by the application, it's actually business data and should be treated as such. Increasingly, NOSQL databases such as Cloudant or MongoDb are used for this. In this case we may think of the HTTP session as a cache, in the knowledge that the session data can be retrieved in the event of error.

So I'd argue that a Shopping Cart may well have considerable value to the business; it represent the customers thoughtful accumulation of things they want to spend money on. So it should be persisted, rather then just kept in the session. Once we decide to persist it, then we find that it leads to other interesting scenarios such as a consolidated experience across many client devices. The customer starts shopping at home on a desktop PC, but completes the purchase online.

So a further principle:

3). Don't over-use the HTTP session just because it's there. Consider the business value of the data and whether it should be persisted.

djna
  • 54,992
  • 14
  • 74
  • 117
  • You are right. I had mistakenly understood that the whole session objects are being saved in the session map and the session map is then being sent to the client where it is stored in the form of cookies or hidden field. Instead it is the session id which is being sent to the client. If I understand correctly, this session id can be used to retrieve the instance of the HttpSession that is storing all the attributes for that particular web session, right? Thank you for pointing out my misunderstanding. – SibzTer Aug 15 '09 at 21:35
  • Hi, I know that has a long time that you answer the question but you said something interesting about clustered environment. How can I keep the session in this type of architecture if the session is saved in the server that answer the request? – kavain Aug 11 '15 at 19:33
  • 1
    @Kavain: Good Java-EE servers provide the option to optimize session replication in clusters for failover. They allow servers to be configured in groups, so not all servers get all session info. Only the ones that are in the same group. Better for performance in the replication itself and in memory usage. So e.g. having 1.000.000 users with a session size of 100k on 100 servers will not mean that each server will require 100GB of memory. Distrubuted in groups of 3, will require each server to just have 3 GB. And a session size of 100k is large... – Kukeltje Aug 12 '15 at 08:03
  • @djna: really good explanation. My understanding of how Session works it was a bit wrong. I read some articles a time ago (One of the articles: http://brockallen.com/2012/04/07/think-twice-about-using-session-state/) that why we should think before using Sessions, probably I misunderstood, but now I believe I get it. Thanks. – kavain Aug 12 '15 at 15:04
15

I'm working on a project of the university with my colleagues, is a web like GoogleImage Labeler. Well, so we have an UserController, with its methods login, logout, etc... and we scope the session like this:

@ManagedBean(name = "userController")
@SessionScoped

Ok, this is what the wizard of NetBeans creates for you.

Our way of creating and managing the session is:

At the register method (in which we use the attributes of the form in the XHTML...) we persist the user in the DB and then we add the values in the session:

FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("user", current);

Where "current" is an User (The logged user, of course). We have the same at the login method.

At the logout method we have:

FacesContext.getCurrentInstance().getExternalContext().invalidateSession();

I hope this helps you.

Carlos Vega
  • 1,341
  • 2
  • 13
  • 35
  • 2
    This is clumsy. Just assign the `current` as property of `UserController` (as it's *already* in the session scope!) and set it to `null` on logout (or better, do `ExternalContext#invalidateSession()`. See also http://stackoverflow.com/questions/3841361/jsf-http-session-login/3842060#3842060 – BalusC Nov 17 '11 at 13:56
  • I have edited the post to replace my code with the one @BalusC said. I've changed `FacesContext context = FacesContext.getCurrentInstance(); context.getExternalContext().getSessionMap().remove("user");` for `FacesContext.getCurrentInstance().getExternalContext().invalidateSession();` – Carlos Vega Nov 17 '11 at 14:47
2

So which method would you suggest that I use - the session scoped bean or the sessionmap to save objects for access between requests for a session?

These two things store data in exactly the same place.

<managed-bean>
  <managed-bean-class>foo.Bar</managed-bean-class>
  <managed-bean-name>bar</managed-bean-name>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Once referenced in an expression, you can lookup "bar" programmatically via the external context.

FYI: in JSF2, the declaration can be removed and replaced with annotations:

@ManagedBean(name="bar") @SessionScoped
public class Bar {
...
McDowell
  • 107,573
  • 31
  • 204
  • 267
  • Must admit it's about 3 years since I touched JSF. Back then I would just use a session scoped managed bean, pretty much as you show. I didn't consider any alternaticve at the time. I guess one issue might be how to make sure we keep this tidy, don't want to gradually acuumulate lots of session-scoped managed beans. This may be down to carefully chosen bean names. – djna Aug 15 '09 at 20:36