We are building a java application which is currently using servlets that use a DAO like manager layer to access the database. We are wanting to be able to scale the application to run on multiple web servers in the future. The main sys admins come from a ms/asp background. They got burned by storing data in the asp session in the past so they went to a model where they stored all session data in the db and pulled it out for each http request.
I would like to introduce an ejb model as an alternative for scaling the app. My basic idea is to use a stateful session bean (ssb) to store the session info. If we put the ssb id into the users browser via a cookie then we could pull it out at the beginning of every http request/response loop. This way the servlets could be load balanced and we wouldn't have to make them sticky.
Can any body share some thoughts about this approach?
This approach may be workable, and in many respects is prefferable to writing all the session information in a database.
However, you should remember that session beans are designed to serve one client only. If for some reason two of your web servers access the same session bean at the same time, results can be unexpected (either one will block the other or an exception will be thrown to one). This kind of thing could happen is the user opens two browser windows, or hits refresh rapidly. So make sure you handle these cases.
ah good point.
I think its a problem even in the straight servlet scenario but it wouldn't neccessarily throw an exception...
How would you suggest handling it? For the most part the http session is used to store a User object and an Organization object. Both of those are exposed as entity beans and also have stateless session bean facades in front of them. I could store the userId (ie the entity pk) in the browser cookie and then use that to access either the session facade or straight into the entity bean.
We also use the http session to pass data around between servlets. Although I dont' think we do that too much and could probably convert those cases to pass it via a get parameter or a hidden form field.
Do you think this is a better approach?
You suggest using the userid as a 'key' to the stateful bean, holding this in a cookie. This implies to me that you are using some login process to identify users, so you might want to consider using the principle from the security context instead. This is equivalent, but doesn't need to be passed back in a cookie to the browser, which improves the security of the solution (anyone could make guesses of the userid in your scenario thus accessing that persons state data).
Also, regardless of solution chosen, Gal's point about simultaneous access still holds true: using a userid, however garnered, won't prevent this.
The idea you are proposing is one I have mooted over myself as a way of managing state independently of any particular channel solving the problem just once.
Andrew, could you please eloborate about security context and Principle? As far as I understood, you're proposing declarative security. It's okay, but how will you manage to register new users without server's administrator's participance? (if I still have some white gaps in my J2EE knowledge - most of them should be in the field of declarative security - it sounds conservative, but I never used it).
Relating to the problem discussed above - yes, database is a good solution, but too slow. I solved this problem for myself in that way: I reference statefuls with HTTPSession IDs (that are pretty hard to guess), I have StatefulStorageFactory that handles all stateful accesses. Factory stores session bean handles in JNDI for clustering issues, knows how to cache handles and remote interfaces, knows how to prevent the simultaneous access (it becomes pretty easy if you have the same access point - when stateful is accessed - it sets up the corresponding flag in JNDI, so the factory knows when particular bean is accessed and provides "simultaneous access" situation handling. By the way, factory is singleton). Anyway, JNDI is pretty much faster than database and I have less performance overheads plus full clustering support.
Alex, not sure I completely understand your question but I'll try to explain a bit further anyway! If there is a requirement to identify users, then there needs to be a login process of some sort. My suggestion implies configuring the app server to handle this (which is no bad thing in my opinion). Taking WAS as an example, this can be configured to use either OS user ids, LDAP, or home-grown. Either way, the result of logging on is the establishment of a security context for the user's session, under the covers, by the app server. From this context (which is 'attached' to each incoming request by the app server), it is possible to obtain the principal, i.e. user id, for any request. This can then be used to lookup in the DB, JNDI etc the state for that user. Because the security context itself doesn't travel to the browser, just a session id, it is more secure than actually using the user id itself.
I don't believe all situations would involve sys admin type activities (i.e. setting up new users). Some applications, e.g. home banking, may require intervention for LDAP or RACF additions, but more open applications could use a home-grown security authentication mechanism with store/retrieval direct to a DB.
I would suggest that even with hard-to-guess lookup keys, one should try and be as secure as possible (risk management)to prevent session takeover.
Note that if the app server is not configured to turn on security this solution won't work and one might need to think along the lines that you have of establishing a unique lookup id.
Does this clarify?
I think the main question here was about using session beans to hold the state *instead* of the DB. Your suggestion is indeed usefull if a DB is used. However, when using session beans, it's impossible to "look the session bean up" according to some ID. The only way to get access to it is by serializing the remote reference or the handle.
Gray, did I read your question correctly? Did you mean to use a strategy similar to what I described above?
My question was if you think using an entity bean as the main entry point would be better then using a stateless session bean. Your mentioning that a stateless session bean would throw exceptions made me think that an entity bean would synchronize access to the user object so you wouldn't have problems if the user double clicked or refreshed.
Your point made me realize that you can't use a stateless session bean unless you can guarantee that the user will be accessing the app in a serial manner, which you can't do with servlets (unless you account for that within your code like the JNDI scenario mentioned above). Since an entity automatically serializes requests you wouldn't have to worry about it on the servlet side.
So we could store the user pk within the browser's session cookie. And then at the beginning of each http request use the pk to find the User entity bean. In this scenario we could allow the servlets to be a part of a farm and not have to worry about sending the user to the same machine each time. We wouldn't be able to use the session to store transient data that gets passed between servlets.
Thanks for clarification - it's a declarative security approach. May be I am too dumb, but I still can't figure out how WAS knows about its home-grown accounts to keep associating principles with them - can you, please, give a few links to sample implementations of that approach, I would be very grateful.
I'm currently playing around with a prototype that I wrote that uses a stateful EJB for holding all the session data.
I essentially had to implement some solution that managed a session in such a way as to create dynamic session spaces that are unique to particular screens and operations, as well as common spaces that are shared by the whole session or by all screens in an operation.This is to preserve session data integrity that is unique to a particular context(operation,screen or common).This paradigm arose because users can open new windows in the browser, so you can be at the same screen or executing the same operation in the the same session. I didn't explain that very well..but hopefully some of you get the point..anyway, for each web session, I create a stateful session EJB and set this as an atribute in the web session.Then all the setting and getting of session data is done with the EJB reference that is held in the web session.The EJB actually abstracts quite a bit of session management complexity, to implement the above requirements.I guess I could of done this at the web layer, but I thought of the following justifications for moving session management the a stateful ejb :
2)thread synchronization ie:prevent race-condition stuff
3)takes load off web server
4)can apply transactional control to session management
Did you have to deal with the fact that StatefulSessionBeans throw exceptions if they are accessed by two threads at a time?
Ie did you have to somehow serialize access to the session bean within the web layer?
Thats the part that I don't want to have to do and so was thinking that using an entity bean would be better
Yes I did....the stateful ejb isn't actualy called directly, rather it is encapsulated in another class that wraps syncronized methods around the ejb method calls.
Don't know what you mean by 'home-grown accounts'. Within WAS users must be registered in some way before they can establish a signed-on session (deliberately avoiding the term secure session). To do this you can configure WAS to use the OS userids (those set up by SYSADMIN for each user), use an LDAP service (again setup appropriately) or a WAS deployer supplied mechanism (e.g. a DB lookup bean that takes a given userid/password combination and returns whether the combination is valid). If WAS is configured to have security turned on, each request to an EJB is checked to verify that the user generating the request is authenticated and authorised to use the bean/bean method. The actual mechanics are WAS specific but one can get hold of the security context. WAS must associate a session id of some sort to each signed-on user in order to reestablish this context for each request. Unfortunately I have no pointers to sample implementations beyond that supplied in the WAS documentation. You could try looking up the info on IBM's WAS developer web site.
the original question suggested using Entity beans which does imply a DB or persistent storage mechanism. The point about serialising the handle is correct but not always necessary depending upon design. The state bean should have a generic interface (e.g. Object getAttribute(String name), void setAttribute(String name, Object object) - please rationalise for appropriate syntax!) and the state itself should be held within some serialisable container, e.g. Hashtable. This means only the state and not the bean needs to serialised - the stateful bean can be reestablished when needed, with a completely new handle, and loaded with the appropriate state from the serialised persistent version - again there are appropriate algorithms for doing this in a performant manner. Only EJBs (stateless session beans, not entity beans) have access to the stateful bean, the handle is not required by the servlet.
I believe that this offers the best solution in terms of security - no clear data going to the browser, only the WAS supplied session id - and problem solving - works for web and non-web clients (channel independent, state management solved once). Agree? Disagree? These are the really useful types of discussion!
Bringing to the top.