Announcement Announcement Module
Collapse
No announcement yet.
Losing objects stored in HttpSession at end of flow Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Losing objects stored in HttpSession at end of flow

    Hi there,

    This is going to be quite an abstract question for now. I'm writing a web-app which uses the HttpSession to store a User object as a login flag.

    I perform this using a simple Spring FormController object for a straightforward login, or as part of a web-flow when there's a login-or-register choice.

    If as part of the login-or-register web-flow, a User is authenticated and stored in the HttpSession, the User object is lost on the flow terminating and control being restored to the 'normal' web-app code.

    I use the following code to retrieve the HttpSession within the web-flow:
    Code:
    ServletEvent.getHttpServletRequest(context.getSourceEvent())
                .getSession()
                .setAttribute(USER_BINDING, user);
    Once back within the normal code if I try to access a protected resource in the webapp, it redirects me to the standard login page as there is no longer a User object in the session (verified using debug mode). In fact, it looks as though there is an entirely new HttpSession object in use.

    I've read a few posts about using a FlowExecutionListener or a an entry action in the end-state but I can't see how these would help. The User is definitely in the HttpSession while the requests are serviced by the web-flow.

    However, If I login using the standard FormController prior to entering the login-or-register web-flow (which of course forwards me through to the end-state due to the existing login), the app doesn't lose the User from the session and hence doesn't force another login.

    As you've probably guessed I'm fairly new to SWF (14 hours straight now), it's 2am and my eyes are going square.

    Any clarification for this behaviour would be much appreciated!

    Cheers

    Mike

  • #2
    jsessionid

    Just a quick thought - untested as I'm just about to hit the sack - but if I initially hit a URL handled by SWF, without first sumitting a request that is handled by the Spring MVC framework, or even redirected to a welcome file by the container (Tomcat), will SWF encode the jsessionid into the URL? Could this be the issue here?

    Mike

    Comment


    • #3
      It may be because flow scope is kinda equivalent to session scope, so at the end of a flow, when it tidies up "flow scope" attributes, it is wiping out your user object.

      Just a guess. If SWF does distinguish between the two (which I kinda thing it does, and should) then make sure you have no flow scoped attributes called the same as your user object, just in case SWF is getting confused.

      What continuation strategy are you using, I am guessing it is HttpSession?

      Comment


      • #4
        SWF does no 'HttpSession housekeeping', so if you put something in the HttpSession while in the flow, it should still be there after the flow ends (unless you remove it ofcourse ).

        Anyway, you mention:

        In fact, it looks as though there is an entirely new HttpSession object in use.
        I'm guessing this is your problem. For some reason the plain SpringMVC requests that happen after you're done with SWF are not in the same HttpSession! Are you using cookies to maintain the session? Seems unlikely since that would make the problem very bizar. If you're using URL rewriting (which SWF does not do by itself!), make sure you're properly encoding the id of the existing HttpSession in those URLs once you're done with SWF.

        Erwin

        Comment


        • #5
          Erwin; quick question; so how does SWF store flow scope attributes? Are they not simply session attributes, or are they stored in a map on the session???

          Comment


          • #6
            jsessionid

            Hi Erwin,

            Thanks for the reply. I haven't been able to do any further work on the project since my post but I'm pretty sure that the problem relates to the lack of any session encoding in the forms I've used - because all the forms in one flow direct to the same URL, it's very easy just to write
            Code:
            <form method="POST">
            rather than
            Code:
            <form action="<c&#58;url value="/myflow.do"/>" method="POST">
            as it avoids any hard coding of URLs into participant pages, making their reuse as part of other flows easier. I guess that cookies are the alternative option, as I don't think (having had a quick look through Tomcat's innards) that using a hidden input tag to pass the session id as a parameter (with the name "JSESSIONID") will be picked up.

            Can you think of an easy, reusable way to store the servlet path (eg: "/myflow.do") currently being processed as a request attribute when working with SWF? This would make the action attribute on form tags easier to use and prevent other people falling into this kind of problem.

            Cheers

            Mike

            Comment


            • #7
              Solution?

              Hi there, I've had a look at this now and solved the dropped session problem. I'm not sure how SWF was maintaining the same session state when Spring/the Tomcat container lost it, but I guess it could be to do with the flowExecutionId being passed backwards and forwards.

              A solution to the
              Code:
              <form method="POST">
              issues I raised above can be solved within Spring as follows. You need to extend SimpleUrlHandlerMapping and override the getHandlerInternal method. For example:
              Code:
              import javax.servlet.http.HttpServletRequest;
              import org.springframework.beans.BeansException;
              import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
              import org.springframework.web.util.UrlPathHelper;
              
              public class ExposedUrlHandlerMapping extends SimpleUrlHandlerMapping &#123;
                  public static final String MAPPED_REQUEST_PATH = "mappedRequestPath";
              
                  private UrlPathHelper urlPathHelper;
                  
                  public ExposedUrlHandlerMapping&#40;&#41; &#123;
                      super&#40;&#41;;
                  &#125;
              
                  protected Object getHandlerInternal&#40;HttpServletRequest request&#41; throws Exception &#123;
                      String path = urlPathHelper.getLookupPathForRequest&#40;request&#41;;
                      request.setAttribute&#40;MAPPED_REQUEST_PATH, path&#41;;
                      return super.getHandlerInternal&#40;request&#41;;
                  &#125;
                      
                  public void setUrlPathHelper&#40;UrlPathHelper urlPathHelper&#41; &#123;
                      this.urlPathHelper = urlPathHelper;
                      super.setUrlPathHelper&#40;urlPathHelper&#41;;
                  &#125;
                  
                  public void initApplicationContext&#40;&#41; throws BeansException &#123;
                      if &#40;urlPathHelper == null&#41;&#123;
                          throw new IllegalStateException&#40;"urlPathHelper must be set on " + this.getClass&#40;&#41;&#41;;
                      &#125;
                      super.initApplicationContext&#40;&#41;;
                  &#125;
              &#125;
              As the urlPathHelper is private in the parent class, and in order to use the same instance with the same properties, you need to specify the urlPathHelper in the spring configuration document:
              Code:
              <bean id ="myHandlerMapping"  class="some.path.to.ExposedUrlHandlerMapping">
                  <property name="urlPathHelper">
                      <bean class="org.springframework.web.util.UrlPathHelper"/>
                  </property>
              ...
              </bean>
              You can then use your forms in different page flows as follows:
              Code:
              <form method="POST" action="<c&#58;url value="$&#123;mappedRequestPath&#125;"/>">
              The c:url tag encodes the jsessionid into the path if the client browser is not accepting cookies.

              SWF team, thanks for your efforts, it's a really good addition to Spring.

              Cheers,

              Mike

              Comment


              • #8
                yatesco,

                so how does SWF store flow scope attributes? Are they not simply session attributes, or are they stored in a map on the session???
                The flow scope attributes are stored using a 'FlowExecutionStorage' implementation, and the default is 'HttpSessionFlowExecutionStorage'. This basically means that the entire flow execution, which contains the flow scope 'map' is stored as on object in the HttpSession.
                So if you put something in the HttpSession directly, outside of the flow execution and its flow scope map, it will not get cleaned up when the flow execution ends.

                Erwin

                Comment


                • #9
                  klr8, thanks for the reply. I realised about the flowExecutionManager I was wondering whether the HttpSessionContinuation just stored attributes in the session, so storing an object "a" in flow scope would actually create an object "a" in session scope.

                  I didn't think it would be that naive, but thought I check

                  Comment

                  Working...
                  X