8 Replies Latest reply on Jun 10, 2009 8:48 PM by lucas84

    before-redirect="true" doesn't destroy conversation before redirect

    lucas84
      hi guys,

      on first screen I have form with following button








      `<s:button action="offers" value="#{messages['button.label.search']}" \>`







      here is the page.xml for that page:



      `<page xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd"

              <rewrite pattern="/" />
              <navigation>
                      <rule if-outcome="offers">
                              <end-conversation before-redirect="true"/>
                              <redirect view-id="/offers/index.xhtml" />
                      </rule>
              </navigation>
      </page>`



      I feel in, and submit the form (values are binded to conveersional component, but I don't promote to long running). So in my understanding between invoke application and issuing redirect, the conversation (temporary) context should be destroyed, so after redirect I get fresh context. In my case it doesn't work as I expect, cause after redirect I work on the same component. I created component as follows, just to double check if context isn't destroyed
      `
      @Name("conversationListener")
      public class ConversationListener {

          @Observer(value = "org.jboss.seam.preDestroyContext.Conversation", create = true)
          public void onConversationPreDestroy() {
              System.out.println("\n\n\n preDestroy \n\n\n");
          }

          @Observer(value = "org.jboss.seam.postDestroyContext.Conversation", create = true)
          public void onConversationPostDestroy() {
              System.out.println("\n\n\n postDestroy \n\n\n");
          }

      }
      `
      Between invoke application and redirect these observer methods aren't invoked.




      The page.xml to page I am referring after redirection looks like follows:
          
      `
      <rewrite pattern="/offers/" />
      <param name="phrase" value="#{quickSearch.searchPhrase}" />
      <param name="location" value="#{searchActionDelegate.location}" />
      <param name="range" value="#{searchActionDelegate.range}" />
             
      <param name="model" value="#{advancedSearchAction.modelId}"/>
             
      <begin-conversation join="true"/>
      `

      When I get redirected to that page I promote conversation to long-running. Does it affect, that the conversation before redirection isn't destroyed? Or anyway I should get fresh one.

      I am working with seam 2.1.2.CR2

        • 1. Re: before-redirect="true" doesn't destroy conversation before redirect
          andygibson.contact.andygibson.net

          The conversation isn't destroyed, it is re-used and it contains the same data you had when you ended the conversation. If you add to your template at the bottom : conv id = #{Conversation.id} you can see that the number should be the same from both pages.


          This often trips people up and is especially painful when coming out of a pageflow. I've found that the only easy way to do it is to invalidate the objects in the conversation prior to ending it and navigating or not propagating the conversation at all (i.e. using an s:link with propagation set to none) from the initial page.



          Cheers,


          Andy Gibson



          • 2. Re: before-redirect="true" doesn't destroy conversation before redirect
            lucas84

            let me quote the reference guide:


            beforeRedirect - by default, the conversation will not actually be destroyed until after any redirect has occured. Setting beforeRedirect true specifies that the conversation should be destroyed at the end of the current request, and that the redirect will be processed in a new temporary context


            <navigation>
              <rule if-outcome="offers">
                <end-conversation before-redirect="true"/>
                <redirect view-id="/offers/index.xhtml" />
              </rule>
            </navigation>
            


            so in my case I set before-redirect to true in order to destroy conversational context before redirection is issued, so when the new request comes back due to redirection I get new conversational context.


            If I am wrong, please correct me and explain the usage of before-redirect



            • 3. Re: before-redirect="true" doesn't destroy conversation before redirect
              andygibson.contact.andygibson.net

              When a conversation ends, the only thing that happens is the long running conversation flag is set to false. When a conversation beings, the long running conversation flag is set to true. It seems that this is done prior or post redirect depending on whether the before-redirect flag is set or not. The documentation is somewhat incorrect when it talks about destroying conversations, a more accurate version might replace the word 'destroy' with 'end' (unless something has changed in recent versions and conversations are no longer re-used).


              Looking at the source, in the Manager, when a conversation is ended, if it is before the redirect it is promoted to a long running conversation so it spans the redirect and then demoted again after the redirect.


              Take a look at this thread for more details and also possible solutions.


              Cheers,


              Andy Gibson


              • 4. Re: before-redirect="true" doesn't destroy conversation before redirect
                lucas84

                let's say I have button that fires an action on some component annotated with @End, and I have long-running conversation. When invoking this method, ConversationInterceptor, as it encounters @end annotation will change state of the conversation from long-running to temporary, but the same conversation remains till Render Response has finished, which is after redirection.


                @End
                public String fireAction() {
                ....
                }
                



                How does adding before-redirect to this annotation change flow??


                @End (beforeRedirect = true)
                public String fireAction() {
                ....
                }



                In this case after invoking method, the state of conversation is changed from long-running to temporary, and redirection occurs, which uses the same conversation. In both cases I use the same conversation, which is before and after redirection. Still I don't see any differnce with before-redirect or without.



                Of corse in both cases, the method doesn't throw any exception and returns non null string which fires navigation (in this case redirection)



                tomorrow I will get familiar with thread that you advised

                • 5. Re: before-redirect="true" doesn't destroy conversation before redirect
                  lucas84

                  Seam in action 2009 says the same, paragraph 7.3.5, table 7.6.



                  before-redirect - if set to true, instructs Seam to terminate the conversation prior to issuing a redirect. The default is to propagate the conversation across the redirect and terminate it once the response is complete.
                  



                  so why doesn't it work in my case, as I prefer getting fresh context, rather having the same after redirection

                  • 6. Re: before-redirect="true" doesn't destroy conversation before redirect
                    lucas84

                    Found solution.



                    public class Manager
                    {
                    ...
                       public void endConversation(boolean beforeRedirect)
                       {
                          if ( isLongRunningConversation() )
                          {
                             log.debug("Ending long-running conversation");
                             if ( Events.exists() ) Events.instance().raiseEvent(EVENT_CONVERSATION_END);
                             setLongRunningConversation(false);
                             destroyBeforeRedirect = beforeRedirect;
                             endNestedConversations( getCurrentConversationId() );
                             storeConversationToViewRootIfNecessary();
                          }
                       }
                    
                    ...
                    }
                    




                    The problem was that interceptor didn't fire, because the conversation was temporary, isLongRunningConversation() returned false. Annontating method with @end din't affect conversation at all. To achive a goal I had to annotate method like follows:


                    @Begin
                    @End (beforeRedirect = true)
                    public String fireAction() {
                    ....
                    }
                    



                    After invoking method I promote conversation to long running, and immediately back to temporary, so beforeRedirect instructs seam to destroy conversation. In result after redirection I get fresh context, which I needed




                    • 7. Re: before-redirect="true" doesn't destroy conversation before redirect
                      wangliyu
                      • 8. Re: before-redirect="true" doesn't destroy conversation before redirect
                        lucas84

                        Wang Liyu wrote on Jun 10, 2009 14:46:


                        Hi,
                        I guess you have the same issue, check this: http://www.seamframework.org/Community/HowToEndAndBeginANewConversationWithOneSignleSlink



                        Thanks a lot, I am facing that problem either and was looking for solution