ICEfaces
  1. ICEfaces
  2. ICE-4186

Spring webflow Loses State in 1.8 on reload

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8RC1
    • Fix Version/s: 1.8RC2, 1.8
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      ICEfaces 1.8 RC1, Spring Framework 2.5.5, Spring Webflow 2.0.3.

      Description

      If the user presses the reload button in a Spring + ICEfaces application, the state is lost, and the application starts over again. I confirm that this problem exists with the swf-booking-icefaces demonstration application.

      This is a continuation of bug #3708, which has been closed and invalidated.

        Activity

        Hide
        Greg Dick added a comment -

        Firstly, the notion in the original JIRA that commenting out some lines in the BridgeFacesContext is a workaround no longer works in 1.8 RC1.

        On observing the application in ICEFaces vs the original Spring+JSF application, it is obvious that the original application is an application in the POST-Process-Redirect model. Each page transition between webflow states is achieved via redirect, and as a result, the URL location bar always contains the latest webflow Flow ID, (like e2s3, e2s4, etc.) whereas in the ICEFaces example this is not true. The ICEfaces example is purely POST->UPDATE in style. The webflow ID is encapsulated in a hidden field in the forms by the FormRenderer, but this parameter is not included in any GET request of the page so the Webflow can never be resumed on any GET operation. As a result, the Webflow in this case is restarted, and the initial page of the flow is rendered.

        Our documentation recommends having the "always-redirect-on-pause" parameter set to false for Ajax applications.

        <!-- Executes flows: the central entry point into the Spring Web Flow system -->
        <webflow:flow-executor id="flowExecutor">
        <webflow:flow-execution-attributes>
        <webflow:always-redirect-on-pause value="false" />

        If this is false, reloads will never work. Period. Nor will any form of navigation using redirection. Note that you can have the default as false, but still have individual transitions defined to be using redirection, but not vice-versa.

        So I enabled redirection for the application, but redirection wasn't happening. The flowId [executionId:snapshotId] showed up in the navigation bar once, but was never updated. That was because the common sendRedirect() method in SwfLifecycleExecutor is trying to set headers and use response codes, rather than calling the externalContext to do the redirection. So after navigating to the third page of the application, the location bar would still read e1s1 (for example) and hitting reload at this point threw an exception because that key is out of date. I changed this code to use the redirect method on the externalContext which helped.

        Also, the flow Id argument when posted in the URL ("execution") is different from the name of the hidden field ("org.springframework.webflow.FlowExecutionKey"). I modified the apply() method to look for the "execution" parameter if the org......FlowExecutionKey" parameter is missing and this finds the proper flow id key for webflow resumption in all cases.

        This method had problems too with the FacesContext no longer being bound to the ThreadLocal at the end of the apply() method. A FacesContext reference was passed to the original apply() method in SwfLifecycleExecutor, so I refactored the redirection methods to take the FacesContext as an argument and this now seems to work. I'm not sure why this was null. I'm also not sure about the reentrancy requirements of this method, so I'll leave the FacesContext as an argument to other internal methods.

        I also can't find a compile time constant for the URL argument being generated by Spring: "execution". This is a likely a point of failure going forward as no one seems able to leave their argument names alone from one version to the next.

        At this stage, the application seems to work fine if both redirecting and non-redirecting navigation is used. non-redirecting traffic resembles a normal AJAX application, is much faster feeling, but doesn't work in the case of reload. We could recommend this to clients who don't care about reload and/or for portions of the application where quick response is desired.

        Redirecting navigation seems like an important aspect of some applications (banking, purchasing, etc.) where dual posting of page particulars would be a bad thing. See the description in the following page: http://www.ervacon.com/products/swf/tips/tip4.html

        Show
        Greg Dick added a comment - Firstly, the notion in the original JIRA that commenting out some lines in the BridgeFacesContext is a workaround no longer works in 1.8 RC1. On observing the application in ICEFaces vs the original Spring+JSF application, it is obvious that the original application is an application in the POST-Process-Redirect model. Each page transition between webflow states is achieved via redirect, and as a result, the URL location bar always contains the latest webflow Flow ID, (like e2s3, e2s4, etc.) whereas in the ICEFaces example this is not true. The ICEfaces example is purely POST->UPDATE in style. The webflow ID is encapsulated in a hidden field in the forms by the FormRenderer, but this parameter is not included in any GET request of the page so the Webflow can never be resumed on any GET operation. As a result, the Webflow in this case is restarted, and the initial page of the flow is rendered. Our documentation recommends having the "always-redirect-on-pause" parameter set to false for Ajax applications. <!-- Executes flows: the central entry point into the Spring Web Flow system --> <webflow:flow-executor id="flowExecutor"> <webflow:flow-execution-attributes> <webflow:always-redirect-on-pause value="false" /> If this is false, reloads will never work. Period. Nor will any form of navigation using redirection. Note that you can have the default as false, but still have individual transitions defined to be using redirection, but not vice-versa. So I enabled redirection for the application, but redirection wasn't happening. The flowId [executionId:snapshotId] showed up in the navigation bar once, but was never updated. That was because the common sendRedirect() method in SwfLifecycleExecutor is trying to set headers and use response codes, rather than calling the externalContext to do the redirection. So after navigating to the third page of the application, the location bar would still read e1s1 (for example) and hitting reload at this point threw an exception because that key is out of date. I changed this code to use the redirect method on the externalContext which helped. Also, the flow Id argument when posted in the URL ("execution") is different from the name of the hidden field ("org.springframework.webflow.FlowExecutionKey"). I modified the apply() method to look for the "execution" parameter if the org......FlowExecutionKey" parameter is missing and this finds the proper flow id key for webflow resumption in all cases. This method had problems too with the FacesContext no longer being bound to the ThreadLocal at the end of the apply() method. A FacesContext reference was passed to the original apply() method in SwfLifecycleExecutor, so I refactored the redirection methods to take the FacesContext as an argument and this now seems to work. I'm not sure why this was null. I'm also not sure about the reentrancy requirements of this method, so I'll leave the FacesContext as an argument to other internal methods. I also can't find a compile time constant for the URL argument being generated by Spring: "execution". This is a likely a point of failure going forward as no one seems able to leave their argument names alone from one version to the next. At this stage, the application seems to work fine if both redirecting and non-redirecting navigation is used. non-redirecting traffic resembles a normal AJAX application, is much faster feeling, but doesn't work in the case of reload. We could recommend this to clients who don't care about reload and/or for portions of the application where quick response is desired. Redirecting navigation seems like an important aspect of some applications (banking, purchasing, etc.) where dual posting of page particulars would be a bad thing. See the description in the following page: http://www.ervacon.com/products/swf/tips/tip4.html
        Hide
        Greg Dick added a comment -

        I also checked in a change to the application itself to enable redirect mode for testing purposes. The full path is:

        spring-framework-2.5.5\spring-webflow-2.0.3.RELEASE\projects\spring-webflow-samples\swf-booking-icefaces\src\main\webapp\WEB-INF\config\webflow-config.xml

        Show
        Greg Dick added a comment - I also checked in a change to the application itself to enable redirect mode for testing purposes. The full path is: spring-framework-2.5.5\spring-webflow-2.0.3.RELEASE\projects\spring-webflow-samples\swf-booking-icefaces\src\main\webapp\WEB-INF\config\webflow-config.xml
        Hide
        Joanne Bai added a comment -

        On builds/releases prior to build 7, QA did not test the reload button specifically. The application works fine if the reload button is not touched during booking. On build 7, clicking on the reload button after searching hotels and filling the booking info does not redirect user to any other page.

        Once user finishes filling the booking form, clicks the Proceed button, and then the Confirm button, the Current Hotel booking page displays listing the hotel(s) that user just booked. However, if the reload button is clicked now, the following exception throws:

        org.springframework.webflow.execution.repository.NoSuchFlowExecutionException: No flow execution could be found with key 'e2s5' – perhaps this executing flow has ended or expired? This could happen if your users are relying on browser history (typically via the back button) that references ended flows.
        org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:178)
        org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getLock(AbstractFlowExecutionRepository.java:122)
        org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:149)
        com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:61)
        com.icesoft.faces.context.View$2$1.respond(View.java:47)
        com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:167)
        com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36)
        com.icesoft.faces.context.View$2.serve(View.java:72)
        com.icesoft.faces.context.View.servePage(View.java:130)
        com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:53)
        com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11)
        com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114)
        com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
        com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160)
        com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:30)
        com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19)
        com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63)
        com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:50)
        com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
        com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:95)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359)
        org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
        org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:173)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:271)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174)
        org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
        org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

        root cause

        org.springframework.webflow.conversation.NoSuchConversationException: No conversation could be found with id '2' – perhaps this conversation has ended?
        org.springframework.webflow.conversation.impl.ConversationContainer.getConversation(ConversationContainer.java:125)
        org.springframework.webflow.conversation.impl.SessionBindingConversationManager.getConversation(SessionBindingConversationManager.java:116)
        org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:176)
        org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getLock(AbstractFlowExecutionRepository.java:122)
        org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:149)
        com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:61)
        com.icesoft.faces.context.View$2$1.respond(View.java:47)
        com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:167)
        com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36)
        com.icesoft.faces.context.View$2.serve(View.java:72)
        com.icesoft.faces.context.View.servePage(View.java:130)
        com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:53)
        com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11)
        com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114)
        com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
        com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160)
        com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:30)
        com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19)
        com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63)
        com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:50)
        com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
        com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:95)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359)
        org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
        org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:173)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:271)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235)
        org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53)
        org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371)
        org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174)
        org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236)
        org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)

        Show
        Joanne Bai added a comment - On builds/releases prior to build 7, QA did not test the reload button specifically. The application works fine if the reload button is not touched during booking. On build 7, clicking on the reload button after searching hotels and filling the booking info does not redirect user to any other page. Once user finishes filling the booking form, clicks the Proceed button, and then the Confirm button, the Current Hotel booking page displays listing the hotel(s) that user just booked. However, if the reload button is clicked now, the following exception throws: org.springframework.webflow.execution.repository.NoSuchFlowExecutionException: No flow execution could be found with key 'e2s5' – perhaps this executing flow has ended or expired? This could happen if your users are relying on browser history (typically via the back button) that references ended flows. org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:178) org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getLock(AbstractFlowExecutionRepository.java:122) org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:149) com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:61) com.icesoft.faces.context.View$2$1.respond(View.java:47) com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:167) com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36) com.icesoft.faces.context.View$2.serve(View.java:72) com.icesoft.faces.context.View.servePage(View.java:130) com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:53) com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11) com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114) com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24) com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160) com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:30) com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19) com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63) com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:50) com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23) com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:95) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359) org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:173) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:271) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174) org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236) org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167) root cause org.springframework.webflow.conversation.NoSuchConversationException: No conversation could be found with id '2' – perhaps this conversation has ended? org.springframework.webflow.conversation.impl.ConversationContainer.getConversation(ConversationContainer.java:125) org.springframework.webflow.conversation.impl.SessionBindingConversationManager.getConversation(SessionBindingConversationManager.java:116) org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getConversation(AbstractFlowExecutionRepository.java:176) org.springframework.webflow.execution.repository.support.AbstractFlowExecutionRepository.getLock(AbstractFlowExecutionRepository.java:122) org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:149) com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:61) com.icesoft.faces.context.View$2$1.respond(View.java:47) com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:167) com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet$ThreadBlockingRequestResponse.respondWith(ThreadBlockingAdaptingServlet.java:36) com.icesoft.faces.context.View$2.serve(View.java:72) com.icesoft.faces.context.View.servePage(View.java:130) com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:53) com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11) com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:114) com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24) com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet.service(MainSessionBoundServlet.java:160) com.icesoft.faces.webapp.http.servlet.SessionDispatcher$1.service(SessionDispatcher.java:30) com.icesoft.faces.webapp.http.servlet.ThreadBlockingAdaptingServlet.service(ThreadBlockingAdaptingServlet.java:19) com.icesoft.faces.webapp.http.servlet.EnvironmentAdaptingServlet.service(EnvironmentAdaptingServlet.java:63) com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:50) com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23) com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:95) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359) org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109) org.springframework.security.intercept.web.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.SessionFixationProtectionFilter.doFilterHttp(SessionFixationProtectionFilter.java:67) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.ExceptionTranslationFilter.doFilterHttp(ExceptionTranslationFilter.java:101) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.providers.anonymous.AnonymousProcessingFilter.doFilterHttp(AnonymousProcessingFilter.java:105) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.rememberme.RememberMeProcessingFilter.doFilterHttp(RememberMeProcessingFilter.java:116) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter.doFilterHttp(SecurityContextHolderAwareRequestFilter.java:91) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.basicauth.BasicProcessingFilter.doFilterHttp(BasicProcessingFilter.java:173) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.AbstractProcessingFilter.doFilterHttp(AbstractProcessingFilter.java:271) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.ui.logout.LogoutFilter.doFilterHttp(LogoutFilter.java:89) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.context.HttpSessionContextIntegrationFilter.doFilterHttp(HttpSessionContextIntegrationFilter.java:235) org.springframework.security.ui.SpringSecurityFilter.doFilter(SpringSecurityFilter.java:53) org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:371) org.springframework.security.util.FilterChainProxy.doFilter(FilterChainProxy.java:174) org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:236) org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
        Hide
        Greg Dick added a comment - - edited

        The WebflowKey does increase its numeric value each time the application goes through a step in the webflow. As for the terminal state/page of the webflow, it's also expected that the webflow is no longer valid at that stage. Other applications tend to navigate to some other page that isn't part of a webflow in order to avoid any exceptions based on flow expiry. I'll have a look at the original booking application to see if this is an application bug.

        At the end of the booking webflow, the original application starts a new webflow with new numbering and returns to the first page. If the application ends at e2s5 (for example) it then redirects to the first page and opens a webflow numbered e3s1 when it is displaying the list of hotels booked. This then can be reloaded.

        The icefacesApplication does not do this. The ICEfaces demonstration returns to the first page of the application (As noted) but the address in the URL remains what it was during the execution of the last step. Also, the hourglass appears as if the client is waiting for something.

        The user can carry on using the application, but has to enter the next phase twice. In this application the first page of the application is the hotel search page. You have to type something, search, and then search again for the application to redirect to next page. The webflow Key number goes like this:

        at final page e2s5.
        done final page e2s5 (and showing first page)
        enter search string press search e2s5
        press search again, navigate to search results e3s2 (e3s1 having never shown up)

        I'll have a quick look into why this might be.

        Show
        Greg Dick added a comment - - edited The WebflowKey does increase its numeric value each time the application goes through a step in the webflow. As for the terminal state/page of the webflow, it's also expected that the webflow is no longer valid at that stage. Other applications tend to navigate to some other page that isn't part of a webflow in order to avoid any exceptions based on flow expiry. I'll have a look at the original booking application to see if this is an application bug. At the end of the booking webflow, the original application starts a new webflow with new numbering and returns to the first page. If the application ends at e2s5 (for example) it then redirects to the first page and opens a webflow numbered e3s1 when it is displaying the list of hotels booked. This then can be reloaded. The icefacesApplication does not do this. The ICEfaces demonstration returns to the first page of the application (As noted) but the address in the URL remains what it was during the execution of the last step. Also, the hourglass appears as if the client is waiting for something. The user can carry on using the application, but has to enter the next phase twice. In this application the first page of the application is the hotel search page. You have to type something, search, and then search again for the application to redirect to next page. The webflow Key number goes like this: at final page e2s5. done final page e2s5 (and showing first page) enter search string press search e2s5 press search again, navigate to search results e3s2 (e3s1 having never shown up) I'll have a quick look into why this might be.
        Hide
        Greg Dick added a comment -

        I have a fix for this exact issue, although the general purpose code that allows a FlowHandler instance to handle the flow execution on termination is still broken.

        The problem that I fixed is more of the improper redirection code found in a different place, in the defaultHandleExecutionOutcome.

        The Spring DispatcherServlet sets up a general case handler infrastructure for handling a number of webflow events and transition outcomes. It is access to this chain of handlers that we do not have in the SwfLifecycleExecutor so we are completely exposed to problems with an application that uses an instance of one of these handlers. In this case, however, the handler mechanism for post webflow outcome handling is null, so the missing access to these structures is not missed.

        Show
        Greg Dick added a comment - I have a fix for this exact issue, although the general purpose code that allows a FlowHandler instance to handle the flow execution on termination is still broken. The problem that I fixed is more of the improper redirection code found in a different place, in the defaultHandleExecutionOutcome. The Spring DispatcherServlet sets up a general case handler infrastructure for handling a number of webflow events and transition outcomes. It is access to this chain of handlers that we do not have in the SwfLifecycleExecutor so we are completely exposed to problems with an application that uses an instance of one of these handlers. In this case, however, the handler mechanism for post webflow outcome handling is null, so the missing access to these structures is not missed.
        Hide
        Joanne Bai added a comment -

        QA verified the fix on ICEfaces 1.8.0 build 9

        • The swf-booking-faces example works well on each page when user presses the reload button

        Tested on FF2 + Tomcat6

        Show
        Joanne Bai added a comment - QA verified the fix on ICEfaces 1.8.0 build 9 The swf-booking-faces example works well on each page when user presses the reload button Tested on FF2 + Tomcat6
        Hide
        Keith Garry Boyce added a comment -

        Up until dr2 always-redirect-on-pause = false worked.

        The webflow state was not retained by the request parameters supplied to the URL... It seems the fix force you to do a redirect on each webflow submit in order to put the webflow key on the url thus allowing webflow mechanism to pick it up. This is not correct.. Restoring the view should retain the state of the flow.

        In the test application I sent there is never a redirect and always-redirect-on-pause = false since of course this is an AJAX application.

        As I say it worked up until dr2. Please advise...

        Please

        Show
        Keith Garry Boyce added a comment - Up until dr2 always-redirect-on-pause = false worked. The webflow state was not retained by the request parameters supplied to the URL... It seems the fix force you to do a redirect on each webflow submit in order to put the webflow key on the url thus allowing webflow mechanism to pick it up. This is not correct.. Restoring the view should retain the state of the flow. In the test application I sent there is never a redirect and always-redirect-on-pause = false since of course this is an AJAX application. As I say it worked up until dr2. Please advise... Please
        Hide
        Greg Dick added a comment - - edited

        We'd like to define always-redirect-on-pause as false for AJAX requests, but define individual flow steps that would benefit from the security and utility of reload as using redirection. Unfortunately the way this is documented in the above page: http://www.ervacon.com/products/swf/tips/tip4.html, namely:

        <view-state id="displaySomeView" view="redirect:someView">
        <transition on="someEvent" to="someState" />
        </view-state>

        doesn't work even in a stock spring application. In fact, it doesn't work if we only specify the view like this:
        <view-state id="displaySomeView" view="someView">
        <transition on="someEvent" to="someState" />
        </view-state>

        which should certainly work. The issue is that the code seems to redirect more than once, leading to a webflow key that doesn't match the actual existing webflow.

        Show
        Greg Dick added a comment - - edited We'd like to define always-redirect-on-pause as false for AJAX requests, but define individual flow steps that would benefit from the security and utility of reload as using redirection. Unfortunately the way this is documented in the above page: http://www.ervacon.com/products/swf/tips/tip4.html , namely: <view-state id="displaySomeView" view="redirect:someView"> <transition on="someEvent" to="someState" /> </view-state> doesn't work even in a stock spring application. In fact, it doesn't work if we only specify the view like this: <view-state id="displaySomeView" view="someView"> <transition on="someEvent" to="someState" /> </view-state> which should certainly work. The issue is that the code seems to redirect more than once, leading to a webflow key that doesn't match the actual existing webflow.
        Hide
        Greg Dick added a comment -

        I've added this parameter com.icesoft.faces.retainViewRoot to allow the line in BridgeFacesContext to be skipped.

        if (com.icesoft.util.SeamUtilities.isSpring2Environment()) {
        if (!retainViewRoot)

        { this.viewRoot = null; }


        }

        Show
        Greg Dick added a comment - I've added this parameter com.icesoft.faces.retainViewRoot to allow the line in BridgeFacesContext to be skipped. if (com.icesoft.util.SeamUtilities.isSpring2Environment()) { if (!retainViewRoot) { this.viewRoot = null; } }

          People

          • Assignee:
            Unassigned
            Reporter:
            Greg Dick
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: