Announcement Announcement Module
Collapse
No announcement yet.
Using session scoped b. in HttpSessionListener when invoked on session timeout Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using session scoped b. in HttpSessionListener when invoked on session timeout

    I'm using session scoped beans in HttpSessionListener to do some cleanup on user logout, which is done by session.invalidate(). It's working fine when listener is fired by user action, but when it's fired by session timeout (or redeploy) i get this error:
    Code:
    Cause: com.ibatis.common.beans.ProbeException: Could not get property 'username' from cz.profinit.mobilegha.model.util.SessionData$$EnhancerByCGLIB$$9f6db13a.  Cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.sessionData': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
    	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    	at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
    	at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
    	at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:411)
    	at cz.profinit.mobilegha.dao.LoginDaoIBatis.traceLogout(LoginDaoIBatis.java:48)
    	at cz.profinit.mobilegha.services.LoginServiceImpl.traceLogout(LoginServiceImpl.java:152)
    	at cz.profinit.mobilegha.util.SessionListener.sessionDestroyed(SessionListener.java:44)
    	at org.apache.catalina.session.StandardSession.expire(StandardSession.java:777)
    	at org.apache.catalina.session.StandardSession.expire(StandardSession.java:735)
    	at org.apache.catalina.session.StandardSession.expire(StandardSession.java:723)
    	at org.apache.catalina.session.StandardManager.stop(StandardManager.java:806)
    	at org.apache.catalina.core.StandardContext.stop(StandardContext.java:5325)
    	at com.sun.enterprise.web.WebModule.stop(WebModule.java:357)
    	at org.apache.catalina.core.ContainerBase.removeChild(ContainerBase.java:1102)
    	at com.sun.enterprise.web.WebContainer.unloadWebModule(WebContainer.java:2207)
    	at com.sun.enterprise.web.WebContainer.unloadWebModule(WebContainer.java:2137)
    	at com.sun.enterprise.server.WebModuleDeployEventListener.moduleUndeployed(WebModuleDeployEventListener.java:226)
    	at com.sun.enterprise.server.WebModuleDeployEventListener.moduleUndeployed(WebModuleDeployEventListener.java:313)
    	at com.sun.enterprise.admin.event.AdminEventMulticaster.invokeModuleDeployEventListener(AdminEventMulticaster.java:976)
    	at com.sun.enterprise.admin.event.AdminEventMulticaster.handleModuleDeployEvent(AdminEventMulticaster.java:961)
    	at com.sun.enterprise.admin.event.AdminEventMulticaster.processEvent(AdminEventMulticaster.java:464)
    	at com.sun.enterprise.admin.event.AdminEventMulticaster.multicastEvent(AdminEventMulticaster.java:176)
    	at com.sun.enterprise.admin.server.core.DeploymentNotificationHelper.multicastEvent(DeploymentNotificationHelper.java:308)
    	at com.sun.enterprise.deployment.phasing.DeploymentServiceUtils.multicastEvent(DeploymentServiceUtils.java:226)
    	at com.sun.enterprise.deployment.phasing.ServerDeploymentTarget.sendStopEvent(ServerDeploymentTarget.java:332)
    	at com.sun.enterprise.deployment.phasing.ApplicationStopPhase.runPhase(ApplicationStopPhase.java:136)
    	at com.sun.enterprise.deployment.phasing.DeploymentPhase.executePhase(DeploymentPhase.java:108)
    	at com.sun.enterprise.deployment.phasing.PEDeploymentService.executePhases(PEDeploymentService.java:919)
    	at com.sun.enterprise.deployment.phasing.PEDeploymentService.undeploy(PEDeploymentService.java:329)
    	at com.sun.enterprise.deployment.phasing.PEDeploymentService.undeploy(PEDeploymentService.java:304)
    	at com.sun.enterprise.admin.mbeans.ApplicationsConfigMBean.undeploy(ApplicationsConfigMBean.java:638)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at com.sun.enterprise.admin.MBeanHelper.invokeOperationInBean(MBeanHelper.java:375)
    	at com.sun.enterprise.admin.MBeanHelper.invokeOperationInBean(MBeanHelper.java:358)
    	at com.sun.enterprise.admin.config.BaseConfigMBean.invoke(BaseConfigMBean.java:464)
    	at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836)
    	at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
    	at sun.reflect.GeneratedMethodAccessor13.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at com.sun.enterprise.admin.util.proxy.ProxyClass.invoke(ProxyClass.java:90)
    	at $Proxy1.invoke(Unknown Source)
    	at com.sun.enterprise.admin.server.core.jmx.SunoneInterceptor.invoke(SunoneInterceptor.java:304)
    	at com.sun.enterprise.interceptor.DynamicInterceptor.invoke(DynamicInterceptor.java:174)
    	at com.sun.enterprise.deployment.autodeploy.AutoDeployer.invokeUndeploymentService(AutoDeployer.java:884)
    	at com.sun.enterprise.deployment.autodeploy.AutoDeployer.undeployJavaEEArchive(AutoDeployer.java:396)
    	at com.sun.enterprise.deployment.autodeploy.AutoDeployer.undeployApplication(AutoDeployer.java:378)
    	at com.sun.enterprise.deployment.autodeploy.AutoDeployer.deployJavaEEArchive(AutoDeployer.java:532)
    	at com.sun.enterprise.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:492)
    	at com.sun.enterprise.deployment.autodeploy.AutoDirReDeployer.redeploy(AutoDirReDeployer.java:78)
    	at com.sun.enterprise.server.StandaloneWebModulesManager.reload(StandaloneWebModulesManager.java:189)
    	at com.sun.enterprise.server.ReloadMonitor.run(ReloadMonitor.java:168)
    	at java.util.TimerThread.mainLoop(Timer.java:512)
    	at java.util.TimerThread.run(Timer.java:462)
    I suppose that when glassfish fires session listener on session timeout, the executing thread is not bound to any request so it's not possible to use session scoped beans. Is there any workaround for this? It seems to me that it's very common scenario, but i can't find any solution. I can get the session object in session listener, but how do I tell spring that current thread is bound to this particular session? The code of session listener follows:

    Code:
    public class SessionListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent arg0) {
    
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent arg0) {
            ILoginService loginService = null;
            WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(arg0.getSession().getServletContext());
    
            if (ctx.containsBean("loginService")) {
                loginService = (ILoginService) ctx.getBean("loginService");
            } else {
                throw new RuntimeException("No bean loginService.");
            }
            loginService.traceLogout();
        }
    }
    Code:
    ...
    <bean id="sessionData" class="cz.profinit.mobilegha.model.util.SessionData" scope="session">
        <aop:scoped-proxy/>
      </bean>
    <bean id="loginService" class="cz.profinit.mobilegha.services.LoginServiceImpl">
        <property name="loginDao" ref="loginDao"></property>
        <property name="sessionData" ref="sessionData"></property>
      </bean>
    ...
    Last edited by calavera.info; Jan 16th, 2009, 03:44 AM.

  • #2
    No solution

    Although I think this is the case of virtualy every application that needs session based cleanup, it seems there is no solution for this. I had to solve it by putting a non-proxied copy of my session scoped bean into session manually in my service on login (it wasn't easy to find out how to do that either):
    Code:
    ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest().getSession().setAttribute(SessionListener.sessionDataKey, backupSessionData);
    and overload a logout method so that it accepts custom sessionData object (which is obtained directly from session in SessionListener). I have to say that this issue is making session scope practicaly useless for us:-(.

    Comment


    • #3
      Another approach

      Another way to deal with this problem is to guess the key of the stored bean in session. By examining the session content I found out that Spring is constructing the key as "scopedTarget.<bean id>". Although this is not clean solution (there is no guarantee that key will always look like this), we are using it since the previous solution could not be used outside the web container and therefore it was impossible to do automatic testing without a lot of workarounds.

      Comment


      • #4
        Some progress

        I got some advice in another thread - http://forum.springframework.org/showthread.php?t=28389. Using destroy-method attribute is much cleaner solution than using session directly, but after I tried it I got the exact same exception when it was destroyed on session timeout.

        As our projects grows, more and more tasks has to be done on session invalidation. We have to duplicate every service method we call with SessionData as a parameter. Like there is no session scope bean at all! If we didn't used session scope, it would be much easier now!. Am I really the only one who can see this major drawback of session scoped beans?

        This is what my server logs on redeploy:
        Code:
        support.DisposableBeanAdapter Invocation of destroy method 'destroy' failed on bean with name 'scopedTarget.sessionData': org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.sessionData': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
        Last edited by calavera.info; Feb 10th, 2009, 09:10 AM. Reason: Supplying additional info

        Comment


        • #5
          Your are not alone (misery loves company)!

          No you are not alone. We also are having the same issues and would love to have an elegant generic solution...

          Comment


          • #6
            Best solution so far?

            I got an idea this morning. It's so simple (although I didn't tested it yet). Instead of hacking Spring core to (for example) add possibility to set session bounded to current thread from session listener, let's do it in our custom proxy class. It should be easy to create such generic proxy with aspects, but for sake of simplicity, I will show straightforward example (in pseudocode):

            Code:
            class SessionScopeProxy implements SessionData {
            	@Required
            	private SessionData realSessionBean;
            	public String getUsername() {
            		try {
            			return realSessionBean.getUsername();
            		} catch ("No thread bound request found") {
            			return BoundedSessionHolder.getSessionData().getUsername();
            		}
            	}
            }
            And in SessionListener add this line:
            Code:
            BoundedSessionHolder.bindSessionForCurrentThread(session);
            Why didn't I think of this earlier?
            Last edited by calavera.info; Mar 20th, 2009, 05:01 AM. Reason: Typo mistakes

            Comment


            • #7
              A possible solution

              Hi, I had the same problem a few days ago and found a very nice solution:

              You have to add the following line to your web.xml:

              Code:
              <listener>
                <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
              </listener>
              This listener assures that the HttpServleRequest and HttpServletResponse-Object is bound to each thread within a http request.

              Hope I could help.

              Comment


              • #8
                Slightly different problem

                Hi, thank you for your answer, bud sadly the problem you solved is much easier than what is described here. I have RequestContextListener in my application (otherwise it wouldn't work at all), but the point is, that this listener doesn't help you when something is happening outside of the context of HttpRequest, eg when the action is fired by HttpSessionListener.

                Comment


                • #9
                  Ah, OK

                  Fu**, your right.

                  Now I got the same problem. Mh really frustrating that spring isn't able to serve a solution for this very common problem

                  Comment


                  • #10
                    Hi, friend.

                    I'm facing exactly the same problem as you. How did you work it out? Is there any solution for now?

                    Everything goes fine if I manually invalidate the session on a Servlet, but if it times out, then I got the "Scope 'session' is not active for the current thread;".

                    I know the problem is that the thread that times out session is a internal one, not attached to a request, but I still need to do the cleanup when the session times out.

                    Thanks.

                    Comment

                    Working...
                    X