Accessing a SessionScoped bean from another SessionScoped bean more than once in same session creates a new instance - session

I am experiencing a behavior in my application I do not understand. I have a servlet (Servlet1) that accepts a request, invalidates the current session, creates a new session, and then redirects on the request to a JSF page which references a #Named #SessionScoped bean (Bean1). Both the servlet and the bean #Inject another #SessionScoped bean (SharedBean). The first time I visit my servlet URL everything works correctly. However, the second time I visit the URL the #Named #SessionScoped bean is creating a new instance of sharedbean.
So what I would like to happen is this:
Servlet1 creates a new session
Servlet1 initializes SharedBean
Bean1 access SharedBean
This is happening correctly the first time I access my servlet URL but what is happening on the second invocation is this:
Servlet1 creates a new session
Servlet1 initializes SharedBean
Bean1 creates a new SharedBean
This doesn't seem like the correct behavior to me. I know I am missing something here and I would appreciate someone explaining it to me. Code is below:
Servlet1:
#WebServlet
public class Servlet1 extends HttpServlet
{
#Inject
private SharedBean sbean;
public doGet(HttpServeltRequest request, HttpServletResponse response)
{
HttpSession session = request.getSession();
session.invalidate();
session = request.getSession(true);
this.sbean.initialize();
response.sendRedirect(newURL);
}
}
Bean1:
#Named
#SessionScoped
public class Bean1 implements Serializable
{
#Inject
private SharedBean sbean;
public void actionMethod()
{
this.sbean.execute(); // New instance being created here on 2nd access!
}
}
SharedBean:
#SessionScoped
public class SharedBean implements Serializable
{
public void initialize() { /* do some work */ }
public void exeucte() { /* do some work */ }
}

Because each time the servlet is requested you invalidate the session. So the container creates a new bean or provides another instance. You have to invalidate the session after a certain period of time of inactivity of the user or some other endpoint.
SessionScoped means the bean instance is valid for multiple requests.
But you have to decide what a session means for your application.
In most cases a session is associated to the time a user logs in and logs out. So it is comprised of multiple requests.
So a session is valid for multiple requests and is the same for different servlets.
The session is managed by the servlet container (e.g Tomcat) and an instance of the session object is provided via a ServletContext instance.
You create a new session everytime your servlet is requested. That means the container just creates a ServletContext for this single request and always binds a new bean instance of your SharedBean to that context instance.
UPDATE due to comment.
In this case i would not suggest to let the container manage the bean injection.
Because you never know at what time the bean instance is created and associated with
a SharedBean instance. I think the reason is the issue that you create a new session within you servlet request method. The bean instances of the SharedBean can't be the same in this case, because the container creates an new instance of SharedBean and invalidates the shared bean instance bound to the servlet.
It would be better in this case to create the SharedBean
within the servlet, pass it to the session context as a parameter and use the
SessionContext within the bean to fetch the SharedBean instance.
UPDATE due to COMMENT
The injected beans are managed by the container. Means the container is responsible for creating and destroying the bean. If you create a new instance of the bean the reference (address) or bean instance is decoupled from the servlet container and not managed anymore by the container. So the shared bean reference is not available for your managed bean Bean1
UPDATE due to COMMENT
The answer to the problem is that the instance of the SharedBean which you create within the doGet method of the Servlet method is not communicated to the servlet container and therefor not available for the managed bean Bean1.

Related

Tomcat JSF Session BEan #Predestroy "Session already invalidated"

So I try to access an attribute of my HttpSession on my #PreDestroy method on a #SessionScoped JSF managed bean using
session.getAttribute("myAttribute");
But I get a
java.lang.IllegalStateException: getAttribute: Session has already been invalidated
Why?
I need to access the list of connections to external services opened by that session before one of my session beans is destroyed, and they are of course stored on a session attribute object.
How can I do that?
Explicitly accessing a session attribute in a session scoped managed bean doesn't make sense. Just make that attribute a property of the session scoped managed bean itself.
#SessionScoped
public class YourSessionScopedBean implements Serializable {
private Object yourAttribute; // It becomes a session attribute already.
#PreDestroy
public void destroy() {
// Just access yourAttribute directly, no need to do it the hard way.
}
}
The exception you faced occurred because the session was explicitly invalidated via a HttpSession#invalidate() call instead of "just" expired.

Using session-scoped object in singleton in Spring

I have a problem with one of my beans. I have a bean, which has a singleton scope and second bean which has session scope.
I'm using java based config in my spring app, I added proxy mode to my session scope bean, but it throws exception when I'm tryign to use that (session scoped) bean:
Method threw 'org.springframework.beans.factory.BeanCreationException' exception. Cannot evaluate my-bean-full-name$$EnhanceBySpringCGLIB#ID.toString()
From what I have read here http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-other-injection-proxies
I thought that only thing which I have to do is to add
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
to my bean class (which also has #Component annotation and it is scanned by Spring)
The thing which I was missing was this line in my web app initializer:
servletContext.addListener(new RequestContextListener());
After that, bean has been injected

How does #SessionScoped work with EJB? Is CDI only for web-tier?

How is the session defined in #SessionScoped CDI bean?
Is this annotation valid only when called from Servlet container, where the session is well defined in form of HttpSession?
If not, than how an EJB with #Inject #SessionScoped MyBean myBean can know what the session really is? I mean, methods of this EJB could have been invoked by a standalone client, RESTful WS or by some other view.
What should happen in such case? Should the annotation have no meaning, should it inject fresh MyBean instance for each request or maybe it should retain the same instance across all requests?
Taken from the #SessionScoped specification
The session scope is active:
during the service() method of any servlet in the web application,
during the doFilter() method of any servlet filter and when the
container calls any HttpSessionListener, AsyncListener or
ServletRequestListener.
So in short, yes. It is bound to the HttpSession. Also:
The session context is shared between all servlet requests that occur
in the same HTTP session. The session context is destroyed when the
HTTPSession times out, after all HttpSessionListeners have been
called, and at the very end of any request in which invalidate() was
called, after all filters and ServletRequestListeners have been
called.

Listening to when the user session is ended in a JSF managed bean

Is it possible to do something like this: When a user session starts I read a certain integral attribute from the database. As the user performs certain activities in this session, I update that variable(stored in session) & when the session ends, then I finally store that value to the DB.
My question is how do I identify using the JSF framework if the user session has ended & I should then store the value back to DB?
Apart from the HttpSessionListener, you can use a session scoped managed bean for this. You use #PostConstruct (or just the bean's constructor) and #PreDestroy annotations to hook on session creation and destroy
#ManagedBean
#SessionScoped
public class SessionManager {
#PostConstruct
public void sessionInitialized() {
// ...
}
#PreDestroy
public void sessionDestroyed() {
// ...
}
}
The only requirement is that this bean is referenced in a JSF page or as #ManagedProperty of any request scoped bean. Otherwise it won't get created. But in your case this should be no problem as you're apparently already using a session scoped managed bean, just adding a #PreDestroy method ought to be sufficient.
My question is how do I identify using
the JSF framework if the user session
has ended & I should then store the
value back to DB?
The JSF framework does not have a separate concept of a session; it uses the underlying session management features of the Servlet specification.
You would have to create a HttpSessionListener that provides hooks for you to capture the session creation and destruction events, where you can read the value and store it back into the DB.
HttpSessionListener, or if you need Dependency Injection for that save, you might use #PostConstruct & #PreDestroy. Remember that the session is destroyed when you call invalidate() or after session timeout, not when the user closes the browser. Why do you use Session Scope anyway, Conversation Scope might fit you better.

Spring bean initialized on web app starts up

This is probably due to my ignorance of the Spring framewok but i am building a JSF+Facelets+Spring web app, i have a bean that whose init method i want to get called at the time the application is started. My problem is getting the bean initialized. I can reference the bean on a page, and when I go to the page, the bean is initialized, and works as directed; what I would like instead is for the bean to be initialized when the application is started
What is the way to get a Spring bean initialized on web app starts up
Your question is more Spring-targeted than JSF-targeted. I know the solution for JSF, but I don't think that this suits a Spring bean. I googled a second and found this topic at the Spring forum which may be of use for you. It describes/links several different approaches: http://forum.springsource.org/archive/index.php/t-21982.html
All the code that you want to handle immediately after an webapp is initialized can be done in a class that implements ServletContextListener as
#WebListener
public class ApplicationListener implements ServletContextListener {...}
and you can create spring application context like
ApplicationContext context = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
// of course, an ApplicationContext is just a BeanFactory
BeanFactory factory = context;
and get the bean you are interested in and go on.

Resources