ICEfaces
  1. ICEfaces
  2. ICE-5997

Improve handling of session invalidation.

    Details

    • Affects:
      Compatibility/Configuration

      Description

      When programmatically ending a session by calling HttpSession.invalidate(), we need to support the same behaviour as stock JSF if possible. Currently, calling invalidate() on the session is resulting in the following NullPointerException (very similar to the issue experienced by the customer in the related case):

      java.lang.NullPointerException
      at org.icefaces.event.WindowAndViewIDSetup$1.encode(WindowAndViewIDSetup.java:66)
      at org.icefaces.event.UIOutputWriter.encodeBegin(UIOutputWriter.java:32)
      at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1641)
      at javax.faces.render.Renderer.encodeChildren(Renderer.java:164)
      at org.icefaces.render.RendererWrapper.encodeChildren(RendererWrapper.java:54)
      at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:849)
      at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1643)
      at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646)
      at org.icefaces.context.DOMPartialViewContext.processPartial(DOMPartialViewContext.java:151)
      at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:968)
      at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1643)
      at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:378)
      at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:127)
      at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:117)
      at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
      at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:135)
      at javax.faces.webapp.FacesServlet.service(FacesServlet.java:309)
      at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
      at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
      at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
      at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
      at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:332)
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:233)
      at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
      at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
      at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
      at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
      at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
      at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
      at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
      at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
      at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
      at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
      at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
      at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
      at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
      at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
      at java.lang.Thread.run(Thread.java:637)

        Activity

        Hide
        Deryk Sinotte added a comment -

        In building and testing an application that invalidates the session through various means, there were some relevant observations:

        Stock JSF

        When invalidating the session programmatically with stock JSF (no ICEfaces or Ajax), processing continues and new sessions are created as required. For example, if we dump a portion of the stack from an HttpSessionListener.sessionCreated method, we can see that JSF will create new sessions for things that it needs to do.

        [#|2010-08-16T16:54:44.312-0700|SEVERE|glassfishv3.0|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=26;_ThreadName=Thread-1;|java.lang.Exception: Stack trace
        at java.lang.Thread.dumpStack(Thread.java:1230)
        at org.icefaces.test.invalidate.SessionUtil.sessionCreated(SessionUtil.java:36)
        at org.apache.catalina.session.StandardSession.tellNew(StandardSession.java:411)
        at org.apache.catalina.session.StandardSession.setId(StandardSession.java:391)
        at org.apache.catalina.session.ManagerBase.createSession(ManagerBase.java:889)
        at org.apache.catalina.session.StandardManager.createSession(StandardManager.java:326)
        at org.apache.catalina.connector.Request.doGetSession(Request.java:2804)
        at org.apache.catalina.connector.Request.getSession(Request.java:2528)
        at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:919)
        at com.sun.faces.context.SessionMap.getSession(SessionMap.java:225)
        at com.sun.faces.context.SessionMap.put(SessionMap.java:122)
        at com.sun.faces.context.SessionMap.put(SessionMap.java:57)
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.getResponseEncoding(FaceletViewHandlingStrategy.java:951)
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.createResponseWriter(FaceletViewHandlingStrategy.java:860)
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:364)
        at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:127)
        at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:117)

        Even invalidating the session in the post RenderReponse phase (via a PhaseListener) will cause JSF to create a new session to write the state into. Since the new session is not aligned with the clients session id, the next interaction with the page will throw a ViewExpiredException, which can be configured in the web.xml to redirect to a new page.

        Show
        Deryk Sinotte added a comment - In building and testing an application that invalidates the session through various means, there were some relevant observations: Stock JSF When invalidating the session programmatically with stock JSF (no ICEfaces or Ajax), processing continues and new sessions are created as required. For example, if we dump a portion of the stack from an HttpSessionListener.sessionCreated method, we can see that JSF will create new sessions for things that it needs to do. [#|2010-08-16T16:54:44.312-0700|SEVERE|glassfishv3.0|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=26;_ThreadName=Thread-1;|java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1230) at org.icefaces.test.invalidate.SessionUtil.sessionCreated(SessionUtil.java:36) at org.apache.catalina.session.StandardSession.tellNew(StandardSession.java:411) at org.apache.catalina.session.StandardSession.setId(StandardSession.java:391) at org.apache.catalina.session.ManagerBase.createSession(ManagerBase.java:889) at org.apache.catalina.session.StandardManager.createSession(StandardManager.java:326) at org.apache.catalina.connector.Request.doGetSession(Request.java:2804) at org.apache.catalina.connector.Request.getSession(Request.java:2528) at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:919) at com.sun.faces.context.SessionMap.getSession(SessionMap.java:225) at com.sun.faces.context.SessionMap.put(SessionMap.java:122) at com.sun.faces.context.SessionMap.put(SessionMap.java:57) at com.sun.faces.application.view.FaceletViewHandlingStrategy.getResponseEncoding(FaceletViewHandlingStrategy.java:951) at com.sun.faces.application.view.FaceletViewHandlingStrategy.createResponseWriter(FaceletViewHandlingStrategy.java:860) at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:364) at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:127) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:117) Even invalidating the session in the post RenderReponse phase (via a PhaseListener) will cause JSF to create a new session to write the state into. Since the new session is not aligned with the clients session id, the next interaction with the page will throw a ViewExpiredException, which can be configured in the web.xml to redirect to a new page.
        Hide
        Deryk Sinotte added a comment -

        I should note that with stock JSF, you can also use the strategy of redirecting to a JSP page and calling <%session.invalidate%> from there. After that, if you use the back button and then try and interact with the original page, the ViewExpiredException is thrown and can be handled via the error-page configured in the web.xml. I've added this scenario to the test case:

        <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/faces/viewExpired.xhtml</location>
        </error-page>

        Show
        Deryk Sinotte added a comment - I should note that with stock JSF, you can also use the strategy of redirecting to a JSP page and calling <%session.invalidate%> from there. After that, if you use the back button and then try and interact with the original page, the ViewExpiredException is thrown and can be handled via the error-page configured in the web.xml. I've added this scenario to the test case: <error-page> <exception-type>javax.faces.application.ViewExpiredException</exception-type> <location>/faces/viewExpired.xhtml</location> </error-page>
        Hide
        Deryk Sinotte added a comment -

        I've checked in my invalidation test case under icefaces/samples/test/invalidate. I'm also attaching an HTML page that summarizes the current state of affairs and what might need to be done to fix the various issues.

        Show
        Deryk Sinotte added a comment - I've checked in my invalidation test case under icefaces/samples/test/invalidate. I'm also attaching an HTML page that summarizes the current state of affairs and what might need to be done to fix the various issues.
        Hide
        Deryk Sinotte added a comment -

        I've made more improvements to the test case as well as checked in some change to help with some of the inconsistencies. There is now a SessionExpiredListener that listens for sessionDestroyed() events and, if they were caused programmatically via session.invalidate() will push a SessionExpiredException onto the queue which is in turn delivered to the client in our standard popup. This is more accurate than the ViewExpiredException and occurs before the WindowScope has a chance to complain which makes it fail faster (a good thing).

        When a session times out, the next interaction with the application will throw the ViewExpiredException. This is because there is no FacesContext available when this occurs (it's doesn't happen during a request) and the ViewExpiredException occurs when the view is being restored and still under JSF control.

        I've also changed how the compat versions of the "Server Internal Error" popups are being restrained. It's now wired to a NOOP rather than disabling them altogether which would have interfered with the status component.

        Show
        Deryk Sinotte added a comment - I've made more improvements to the test case as well as checked in some change to help with some of the inconsistencies. There is now a SessionExpiredListener that listens for sessionDestroyed() events and, if they were caused programmatically via session.invalidate() will push a SessionExpiredException onto the queue which is in turn delivered to the client in our standard popup. This is more accurate than the ViewExpiredException and occurs before the WindowScope has a chance to complain which makes it fail faster (a good thing). When a session times out, the next interaction with the application will throw the ViewExpiredException. This is because there is no FacesContext available when this occurs (it's doesn't happen during a request) and the ViewExpiredException occurs when the view is being restored and still under JSF control. I've also changed how the compat versions of the "Server Internal Error" popups are being restrained. It's now wired to a NOOP rather than disabling them altogether which would have interfered with the status component.

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Deryk Sinotte
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: