ICEfaces
  1. ICEfaces
  2. ICE-5200

FileUpload in Spring Webflow can't restore state

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.2
    • Fix Version/s: 1.8.2a, 1.8.2-EE-GA_P02
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      ICEFaces FileUpload + Spring Webflow

      Description

      Using FileUpload in a Spring application fails during the FileUpload itself with an error indicating the software can't restore the view, whatever the view is.

      It turns out that ICEFaces state saving is not actually invoked in Spring applications. Looking at the code in Spring, Spring doesn't delegate state saving calls to the delegate instance unless the request is deemed not to be a Spring request, and this is established by checking if there is a RequestContext object ThreadLocal defined, and this is setup in the resume or start method of FlowExecutorImpl.

      Here's a stack trace showing the execution path to the point where the RequestContext is established as a ThreadLocal. The entry point to the Spring Webflow applications is through the MainServlet and then goes back into the Spring framework via the SwfLifecycleExecutor.

      at org.springframework.webflow.execution.RequestContextHolder.setRequestContext(RequestContextHolder.java:40)
      at org.springframework.webflow.engine.impl.FlowExecutionImpl.start(FlowExecutionImpl.java:218)
      at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:140)
      at com.icesoft.faces.webapp.http.core.FlowExecutorUtil.launchExecution(FlowExecutorUtil.java:90)
      at com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.launchExecution(SwfLifecycleExecutor.java:134)
      at com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:57)
      at com.icesoft.faces.context.View$2$1.respond(View.java:48)
      at com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.respondWith(ServletRequestResponse.java:201)
      at com.icesoft.faces.context.View$2.serve(View.java:77)
      at com.icesoft.faces.context.View.servePage(View.java:149)
      at com.icesoft.faces.webapp.http.core.MultiViewServer.service(MultiViewServer.java:79)
      at com.icesoft.faces.webapp.http.common.ServerProxy.service(ServerProxy.java:11)
      at com.icesoft.faces.webapp.http.servlet.MainSessionBoundServlet$4.service(MainSessionBoundServlet.java:149)
      at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
      at com.icesoft.faces.webapp.http.servlet.BasicAdaptingServlet.service(BasicAdaptingServlet.java:16)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:60)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:148)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359)
      at org.springframework.security.intercept.web.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)


      For the sake of interest, views are rendered by the SpringFramework treating the JSF Views as a certain type of renderable.

      at com.icesoft.faces.facelets.D2DFaceletViewHandler.renderResponse(D2DFaceletViewHandler.java:284)
      at com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:159)
      at org.springframework.faces.webflow.FlowViewHandler.renderView(FlowViewHandler.java:92)
      at org.springframework.faces.webflow.JsfView.render(JsfView.java:94)
      at org.springframework.webflow.engine.ViewState.render(ViewState.java:245)
      at org.springframework.webflow.engine.ViewState.resume(ViewState.java:204)
      at org.springframework.webflow.engine.Flow.resume(Flow.java:545)
      at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:262)
      at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:163)
      at com.icesoft.faces.webapp.http.core.FlowExecutorUtil.resumeExecution(FlowExecutorUtil.java:86)
      at com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.resumeExecution(SwfLifecycleExecutor.java:129)
      at com.icesoft.faces.webapp.http.core.SwfLifecycleExecutor.apply(SwfLifecycleExecutor.java:55)
      at com.icesoft.faces.webapp.http.core.ReceiveSendUpdates.renderCycle(ReceiveSendUpdates.java:132)
      at com.icesoft.faces.webapp.http.core.ReceiveSendUpdates.service(ReceiveSendUpdates.java:74)
      at com.icesoft.faces.webapp.http.core.RequestVerifier.service(RequestVerifier.java:31)
      at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
      at com.icesoft.faces.webapp.http.servlet.BasicAdaptingServlet.service(BasicAdaptingServlet.java:16)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:60)
      at com.icesoft.faces.webapp.http.servlet.SessionVerifier.service(SessionVerifier.java:26)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:148)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      at com.icesoft.faces.webapp.xmlhttp.BlockingServlet.service(BlockingServlet.java:56)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)


      When a FileUpload request is processed a lifecycle event is generated by the upload process in order to update the Upload progress page. Since the PathDispatcher matches the path of the FileUploadServlet execution goes down that route and doesn't have the Spring path portions in it, therefore a Spring webflow isn't resumed. Since the Spring Webflow isn't resumed, the StateSaving code executed when running the lifecycle is delegated to our StateSaving implementation which is looking for a viewRoot in the State Maps in the session.

      at com.icesoft.faces.webapp.http.core.UploadServer$2.servlet(UploadServer.java:127)
      at com.icesoft.faces.webapp.http.servlet.ServletRequestResponse.detectEnvironment(ServletRequestResponse.java:262)
      at com.icesoft.faces.webapp.http.core.UploadServer.service(UploadServer.java:69)
      at com.icesoft.faces.webapp.http.common.standard.PathDispatcherServer.service(PathDispatcherServer.java:24)
      at com.icesoft.faces.webapp.http.servlet.BasicAdaptingServlet.service(BasicAdaptingServlet.java:16)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.SessionDispatcher.service(SessionDispatcher.java:60)
      at com.icesoft.faces.webapp.http.servlet.PathDispatcher.service(PathDispatcher.java:23)
      at com.icesoft.faces.webapp.http.servlet.MainServlet.service(MainServlet.java:148)
      at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
      at com.icesoft.faces.webapp.xmlhttp.BlockingServlet.service(BlockingServlet.java:56)
      at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
      at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
      at org.springframework.security.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:359)


      Since we haven't been involved in saving the state at any time in the past, there isn't any copy of the ViewRoot in the Session when this attempt is made, hence the error.

        Activity

        Hide
        Greg Dick added a comment -

        The way that ICEFaces integrates with Spring Webflow is as follows:

        Requests to ICEFaces, and even requests that normally are mapped to Spring all go to ICEFaces. ICEfaces has an assortment of Handler classes mapped to handle requests and ICEFaces handles the request. If a Spring request, control is passed to the SwfLifecycleExecutor which either starts a new flow or resumes execution of an old one.

        Control then passes to Spring, which executes a JSF lifecycle and then returns control to ICEFaces through the VIewHandler instance which is used to render the page. The Spring state saving instance does not delegate to any other StateSaving class if the request is a Spring mapped request, which is why ICEFaces StateSaving never gets invoked, even though it is configured by default.

        The FileUpload mechanism runs a JSF lifecycle to render the progress bar at intervals. These lifecycles don't have the Spring ThreadLocal necessary for Spring to detect a webflow request, so they delegate to ICEFaces state saving. The solution to this is to launch the progress lifecycle via Spring webflow if a Spring environment is detected. This should be ok, no state transition should be executed because there will be no result from the webflow execution.

        Show
        Greg Dick added a comment - The way that ICEFaces integrates with Spring Webflow is as follows: Requests to ICEFaces, and even requests that normally are mapped to Spring all go to ICEFaces. ICEfaces has an assortment of Handler classes mapped to handle requests and ICEFaces handles the request. If a Spring request, control is passed to the SwfLifecycleExecutor which either starts a new flow or resumes execution of an old one. Control then passes to Spring, which executes a JSF lifecycle and then returns control to ICEFaces through the VIewHandler instance which is used to render the page. The Spring state saving instance does not delegate to any other StateSaving class if the request is a Spring mapped request, which is why ICEFaces StateSaving never gets invoked, even though it is configured by default. The FileUpload mechanism runs a JSF lifecycle to render the progress bar at intervals. These lifecycles don't have the Spring ThreadLocal necessary for Spring to detect a webflow request, so they delegate to ICEFaces state saving. The solution to this is to launch the progress lifecycle via Spring webflow if a Spring environment is detected. This should be ok, no state transition should be executed because there will be no result from the webflow execution.
        Hide
        Greg Dick added a comment -

        The code now executes JSF lifecycles via Spring Webflow if Webflow is detected.

        Show
        Greg Dick added a comment - The code now executes JSF lifecycles via Spring Webflow if Webflow is detected.

          People

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

            Dates

            • Created:
              Updated:
              Resolved: