I'm using a servlet and inside this i need to have an instance of object for each user, usually i would do it using a singleton but since (as far as I know) the servlet itself works as singleton i'm a bit confused:
how can I produce exactly one instance for each session/user?
how can I be sure it will be destroyed o session time-out?
what is the best approach, wait for some events of HttpServlet or act on requests accessing some property to understand what session is calling?
Edit:
The actual scenario is a web application that uses an external component for data access, isn't interesting what this object does for data retrieve, could be db accesses or web service calls i could ignore it.
What i have to create is an instance of this object for each Httpsession and ensure it will be destroyed after the session expire time.
Edit
Seems HttpSessionListener could be a solution: I could create my object associating it in a Map with the sessionid when the session is created and destroy on session expire. Anyone has experience on this?
For simple case you can use HttpSessionListener as follows:
#WebListener
public class MySessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
// new session created - add your singleton
Foo f = new Foo();
se.getSession().setAttribute("Foo", f);
// if you need id you can use - se.getSession().getId();
}
public void sessionDestroyed(HttpSessionEvent se) {
// session destroyed - do cleanup
Foo f = (Foo) se.getSession().getAttribute("Foo");
f.destroy(); // your object cleanup method
}
}
If you need to run it in the cluster with session replication, your class should be small and Serializable, otherwise you would need to implement your Map solution and HttpSessionActivationListener to restore its state on other JVM.
Not sure exactly what are you doing, but the simplest way would be to create a client cookie for each started session.
The cookie itself can have an expiration period and you keep on the server track of each session where the key is the generated cookie.
Once the client has a cookie he keeps it using on each request in order to stay in the same session.
Of course you need a way for each user to log in and get his cookie assigned and some server logic to delete not used session ... etc.
Simple solution:
In the description below, Blammy is the per session object name
During login or session creation, add a Blammy object to the session. HttpServletRequest.getSession(false) will return null if there is no session. This means you need to a) create a session and b) add Blammy to the new session.
Post login, check in the session for the Blammy object. If there is no Blammy, react appropriatedly
Use the Blammy object in the session as appropriate.
You can use HttpSessionEvent. On session create add a session attribute with a constant key and your objects instance as value.
Related
I would like to know how to crete a user session object that can be used across all user requests. The user can select profiles after login, so I need to update that session object with this profile data.
How is it done? How do I initialize a session scoped bean? How can I change objects in that SessionScoped bean later (it is necessary to remember some user actions in his session).
I would be very happy if you could help me in that matter :)
#SessionScoped #Named
public class UserSession implements Serializable {
private ExtendedUserPrincipal extendedUserPrincipal;
#PostConstruct
private void instantiateSession() {
extendedUserPrincipal = new ExtendedUserPrincipal();
}
public void setUserPrincipal(UserPrincipal userPrincipal) {
extendedUserPrincipal.setUserPrincipal(userPrincipal);
}
public void setUser(User user) {
extendedUserPrincipal.setUser(user);
}
public void setUserSecurityData(UserSecurityData userSecurityData) {
extendedUserPrincipal.setUserSecurityData(userSecurityData);
}
#Produces #AuthenticatedUser
private ExtendedUserPrincipal getPrincipal() {
return extendedUserPrincipal;
}
}
I invalidate the session by calling logout() and invalidate() on the session which I get from HttpServletRequest.
I'm injecting the user principal like this. The object should be the same for every user session
#Inject
#AuthenticatedUser
private ExtendedUserPrincipal extendedUserPrincipal;
I'm not sure what all the annotations mean, but you should just be able to put objects in the session manually with your HttpServletRequest object.
request.getSession().setAttribute("userbean", yourBean);
Then if you need to update it just get and set it like any other map
request.getSession().getAttribute("userbean");
The userbean will remain in the session until it is invalidated.
There are many different java libraries with different # annotations, but an annotation is usually just a shortcut for a more basic, manual operation.
I'm not familiar with the specific library/annotations you are using, but from the looks of it, #SessionScoped will just inject the bean into the user's session attributes 'automagically' for you.
A user's session is just a map that is active while a particular user is logged in. You could put any kind of java object in the session attributes map, it doesnt need to be a special kind of object or anything. A 'session scoped bean' is basically fancy words for 'a java object which has been added to the user's session attributes map.'
When the user's session ends, the request.getSession() object is destroyed, along with the objects in the attributes map (so long as they are not referenced anywhere else) thats why they are 'session scoped'.
Also, you might want to try and put #SessionScoped #Named on seperate lines, I'm not sure it will parse them on one line like that.
I use Spring 4.1.1. And I must make service of user session. What's the best way of storing session related data of a user? I read so many way's , but I don't understand which way is proper?
it's example that I need
#Controller
#SessionAttributes("user")
public class PagesController {
#RequestMapping(value="/sign_in", method = RequestMethod.POST)
public String getSignIn(#RequestParam(value="user")String user ,
#RequestParam(value="pass")String password,
Model model) {
UserDAO dao = new UserDao();
if(dao.isUserValid(user,password) && !model.containsAttribute("user")){
User user = new User();
model.addAttribute("user",user);
return USER_PAGE;
}
return LOGIN_PAGE;
}
}
First of all, Session Attribute is not a good option to store your user object. It is spring who decides when to clear a session attribute data. As per spring documentation, spring removes a session attribute when it understands that a 'conversation' is completed. You only use session attribute when you are in a controller scope and the data is temporarily needed to be stored in the session.
As far as user login object goes, the thing you need to do is to use http sesison. When you login/sign in to your application you actually post the login credential to your controller. Once validated, you put the user object (with your necessary info-as less as possible- in to an object and store in to your session). This object will remain as long as it doesn't expire or you clear it when the user trigger logout.
Moreover if you still want to use SessionAttribute to store your user Object. Then there can be further problem when you deploy your application to a clustered environment. Your session will have to be copied to each instance of your server unless you implement sticky session. Copying httpsession is the simplest of task whereas copying the same instance of a sessionAttribute is not.
#RequestMapping(value = "login.html", method = RequestMethod.POST)
public ModelAndView post(#ModelAttribute("login") LoginEntity login, HttpServletRequest req) {
... process the data ...
if passed put it into session:
HttpSession session = req.getSession(true);
UserObject userObject=new UserObject();
userObject.setName(login.getUserName());
...
session.setAttribute("user",userObject);
It is OK that you put your user object in session, and then use it in your project everywhere. However, if you get a lot of users, that means you have many user object in the memory of your server. The memory might run out.
Another way to do it is to put some user information in cookies with some encryption and validation, but just remember not to put too much info in cookies because cookies will be sent every time a request or a response is made. If there to much information to send, it will slow the response time.
And just a reminder, you should call status.setComplete() to clean the attributes inside a session when they are not needed.
Does SessionStatus object.setComplete() clears all the session attributes or just work for the controller in which it is used?
and if you don't know how to use it, you can see the article below
http://vard-lokkur.blogspot.tw/2011/01/spring-mvc-session-attributes-handling.html
I came across a code where the session object is obtained in two different ways (or rather wrote in two different ways).
using HttpServletRequest
someMethod(HttpServletRequest request){
HttpSession session = request.getSession();
//getAttribute from session
}
And using HttpSession
anotherMethod(HttpSession session){
//getAttribute from session
}
I went through this article and a question on SO. But i am still have some doubts.
Can someone help me understand what is the difference between these?
UPDATE
Both of these are methods in a spring controller and these are mapped to different ajax calls. I understand that there is a session associated with every request object but when you pass an HttpSession object where does it find the current session object(load all the attributes) or how is it obtained? When I call the method from javascript, I don't pass anything at all.
someMethod(HttpServletRequest request)
In this you are passing the current request object, from which you can obtain your current session and then you can get attributes from it.. You can get the current session object from your request object by using : -
request.getSession(false)
*NOTE: - We pass false as a parameter to getSession(false) to get any existing session.. If no session exist it will return null..
whereas, request.getSession() will always create a new session, so you won't get any prevoius attribute store in other session..
anotherMethod(HttpSession session)
Here you are passing the session object itself from somewhere.. Might be because, your session object contains many attributes, and you don't want to many parameters in the method..
But you should do all this session related task in your Servlet and pass the attribute to the methods of other class..
There is no huge difference between these two, the second method may be used if called multiple times to eliminate one extra method call request.getSession() by keeping session as somewhat like a local cache (with ignorable performance improvement unless called 100s of times).
eg,.
HttpSession session=request.getSession();
getFirstAttr(session);
getSecondAttr(session);
....
getHundredthAttr(session);
If you use the first method, then all the times that method is called one extra request.getSession() is called.
You don't need to float session objects if you have single attribute. Just simply access it using session object.
HttpSession session = request.getSession(true);
session.getAttribute(name);
Now only sensible case where you can float session objects is you have large number of attributes and you want each method to access its own set of attributes. In any case the method depends on session passed to it so it should not care how it was obtained.
Let's say I have a running Java-based web application with 0 or more valid HttpSession objects associated with it. I want a way to access the current list of valid HttpSession objects. I was thinking that I could implement an HttpSessionListener and use it to append to a list of session id values that are stored in an application-scoped attribute, but then I'm on the hook to update the list as sessions are invalidated and who knows what else.
Before I start baking my own solution I thought I should ask the question:
Does the servlet API provide some means of getting access to the complete list of non-invalidated session objects?
I am using Tomcat 6.x as my web application container, and the MyFaces 1.2.x (JSF) library.
SOLUTION
I followed an approach similar to what BalusC discussed in these existing questions:
How to easily implement "who is
online" in Grails or Java Application
?
JSF: How to invalidate an
user session when he logs twice with
the same credentials
I modified by SessionData class to implement HttpSessionBindingListener. When a binding event happens, the object will either add or remove itself from the set of all the SessionData objects.
#Override
public void valueBound(HttpSessionBindingEvent event) {
// Get my custom application-scoped attribute
ApplicationData applicationData = getApplicationData();
// Get the set of all SessionData objects and add myself to it
Set<SessionData> activeSessions = applicationData.getActiveSessions();
if (!activeSessions.contains(this)) {
activeSessions.add(this);
}
}
#Override
public void valueUnbound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
ApplicationData applicationData = getApplicationData();
Set<SessionData> activeSessions = applicationData.getActiveSessions();
if (activeSessions.contains(this)) {
activeSessions.remove(this);
}
}
The one thing that continues to irritate me is what happens when Tomcat is restarted. Unless Tomcat has been properly configured to NOT serialize sessions to disk, it will do so. When Tomcat starts up again, the HttpSession objects (and the SessionData objects along with them) are deserialized and the sessions are made valid again. However, the serialization/deserialization totally sidesteps the HttpSession listener events, so I do not have the opportunity to gracefully put the deserialized reference to the SessionData back in my managed Set of objects after the restart.
I don't have any control over the production configuration of Tomcat in my customer's organization, so I cannot assume that it will be done the way I expect it.
My workaround is to compare the HttpSession creation time with the application startup time when a request is received. If the session was created before the application startup time, then I call invalidate() and the user is sent to an error/warning page with an explanation of what happened.
I get the application startup time by implementing a ServletContextListener and storing the current time inside an application-scoped object from within the contextInitialized() method of my listener.
No, the Servlet API doesn't provide a way. You really have to get hold of them all with help of a HttpSessionListener. You can find several examples in the following answers:
How to find HttpSession by jsessionid?
How to find number of active sessions per IP?
How to check Who's Online?
How to invalidate another session when a user is logged in twice?
There is no straight forward way. It depends on deployment. Above will fail once you decide to introduce distributed deployment and load balancing.
Not really an answer, but in the good ol' days there was "javax.servlet.http.HttpSessionContext", but it was dropped as of version 2.1, explicitly with no replacement: https://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpSessionContext.html
I am developing a web app using servlets and jsps. I have a question about storing data I need to use across multiple servlets in a login session. When the user logs in, for example, I get the user object from the db and would like to store it somewhere and have the subsequent servlets and jsps use it without having to query the db again. I know that I have to store the object in a global array but am not able to figure out the best way to do this.
I am thinking of having a static hashmap or some other data structure created at webapp load time and I can use that to store the user object with the sessionID as the key for the hashmap.
Is there a better way? Any help is appreciated.
Thanks,
- Vas
You don't need to manage the sessions yourself. The servletcontainer will do it for you transparently in flavor of HttpSession. You normally use HttpSession#setAttribute() to store an object in the session scope and HttpSession#getAttribute() to get an object from the session scope. You can use HttpServletRequest#getSession() to get hold of a reference to the HttpSession.
E.g. in the login servlet:
User user = userDAO.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
} else {
// Show error?
}
You can get it back later in any servlet or filter in the same session by
User user = (User) request.getSession().getAttribute("user");
if (user != null) {
// User is logged in.
} else {
// User is not logged in!
}
You can even access it by EL in JSP:
<p>Welcome, ${user.username}!
(assuming that there's a Javabean getUsername() method)
There is a way to do this and it's defined in the servlet spec. You can get hold of the HttpSession object and add objects as "attributes".
Take a peek at the API here: http://java.sun.com/products/servlet/2.2/javadoc/javax/servlet/http/HttpSession.html
Depending on your needs and implementation, you can also consider following options:
making user object serializable and storing in session itself; in this case you must assure that subsequent changes to user object are propagated to the objected stored in session or DB (depending which will change)
storing only user ID in session and implement caching in your DAO/repository so no real DB query will be invoked if not necessary; if you are using Hibernate or some other ORM you might have this feature out of the box; this seems the least invasive as modifications on user object will be synchronized with application state and DB if properly handled by persistence layer
There are probably many more option out there.
We are constructing a social network like livemocha.com and we recommend you put the minimum possible in the session.
Storing only user ID in the session it's enough, and certainly, you don't need to assure that subsequent changes to the user object are propagated to the object stored in the session or DB (depending on which one will change). ;-)