11 Replies Latest reply on Mar 7, 2007 11:18 AM by raffaele camanzo

    Can I end a conversation programmatically?

    raffaele camanzo Newbie

      Hi All,

      I'm facing a problem trying to end a conversation programmatically.

      The scenario:
      We have an application (for a full description refer to my previous post: "Problems with application-like behaviour") with a menu and a tabbed view of the services offered to the users; each tab is a conversation with a given id in order to provide to the user the ability to switch between the opened tabs. A user should be able to ask for a service, make the work and then close the tab and then, after a while, ask again for the same service. When the user asks for the tab to be closed the application should clean up all the data related to; this means that we have to remove the tabs control data and the tab content-specific data (the conversation one).
      The tab remotion request is handled in a generic way by a session scoped stateful bean (which handles the application behaviour), it removes the control data and then calls the Manager in order to remove the conversation of the current tab and switch to the conversation of the one focused.

      The problem:
      In order to clean the conversation data the action related to the tab remotion makes these Seam API calls:

      Manager.instance().endConversation(false);
      Manager.instance().switchConversation(currentTab.getConversationId());
      



      I think that this should work because the current conversation when I invoke the Manager is the one I want to remove and I hold the data of the one I want to activate.

      The effect:
      Unfortunately when the user selects the link related to the conversation I tried to remove, Seam, instead of create a brand new conversation with the given identifier, resumes the old conversation and shows the tab exactly like when I perform a tab switch.

      I hope that the description is clear and I hope that someone can help me.

      Thanks in advice.
      Regards,
      Raffaele Camanzo

        • 1. Re: Can I end a conversation programmatically?
          Gavin King Master

          Why not Conversation.instance().end()?

          • 2. Re: Can I end a conversation programmatically?
            raffaele camanzo Newbie

            Hi Gavin,

            unfortunately this solution does not fit, or better, it does not work in my application. Having a look at the Seam source code I've seen that Conversation.instance().end() calls directly, and only, the Manager.instance().endConversation(false) exactly as I did in my first solution.

            I don't know if this is a Seam bug related to the conversation with a given id (caches the information and then even if the conversation is marked to be removed when I ask for the same id it resumes a removed one) or is a misuse of the functionality (I don't know... I can call the Manager.instance().endConversation(bool) only in a method, JSF action handler, inside the class which defines the conversation).

            I call the Manager.instance().endConversation(bool) from a method (JSF action handler) defined in a stateful session bean; the session bean has a Seam name and is stored in the session context but I'm sure, because I print such data, to be in the long running conversation with the id that I want to remove when the method is called (when the user presses the close button on the tab label); I have the method in the stateful session bean because is generic for all the tabs and because I can manipulate directly the application control data in order to remove also the tab label and the references from the control structure.


            Help appreciated!
            Regards,
            Raffaele Camanzo

            • 3. Re: Can I end a conversation programmatically?
              raffaele camanzo Newbie

              Hi Gavin,

              creating a specific test case it's been useful to better understand the Seam behaviour when I try to create a conversation with a given id or remove a conversation and switch to a different one. Ok, this is what I've seen:

              1 - Conversation creation with a given ID: If I create a conversation with a given id (@Begin(join=true, id="myId1")), Seam creates a conversation with the given identifier, but if I have two (but I think also more than two) defined as follows:

              
              ActionOne.java:
              
              @Name("actionOne")
              @Scope(ScopeType.CONVERSATION)
              public class ActionOne {
              
               @Begin(join=true, id="actionone")
               public String startConversation() {
               .....
               return "one";
               }
              }
              
              
              
              ActionTwo.java:
              
              @Name("actionTwo")
              @Scope(ScopeType.CONVERSATION)
              public class ActionTwo {
              
               @Begin(join=true, id="actiontwo")
               public String startConversation() {
               .....
               return "two";
               }
              }
              
              


              When I start the first conversation, say actionone, everything is ok, the conversation has the given identifier; but when I start the second one the conversation identifier is the same for both: the first one 'actionone', even if the two actions maintain different view ids.

              If I pass the conversation identifier as a <f:param> and the param name is other than "conversationId" the conversation identifier is ignored.
              If I pass a parameter named as conversationId in a <s:link> to start a conversation with a static identifier defined in the @Begin annotation the identifier is completely ignored and the conversation gets the value of the conversationId parameter.

              As a recap:
              I can create, correctly, only named conversations following these guidelines:

              - The link to the conversation begin method must contain a parameter named conversationId, for example:

              <s:link action="#{actionTwo.startConversation}">
               <h:outputText value="Start Conversation" />
               <f:param name="conversationId" value="<something static or EL>" />
              </s:link>
              


              - The conversation begin method must be defined as follows:

              @Name("actionOne")
              @Scope(ScopeType.CONVERSATION)
              public class ActionOne {
              
               @Begin(join=true, id="#{param.conversationId}")
               public String startConversation() {
               .....
               return "one";
               }
              }
              


              Maybe I discovered the hot water... But I did not find all these rules to follow in the documentation, but probably I did not read very well the documentation; so if there's someone else like me... maybe he can loose less time than me to get the right way.

              2 - Remove a conversation and switch to a different one: Conversation.instance().end() works (but does not execute the @End method), removes the current conversation, but does not do enough, indeed, in my application I need to switch to a different conversation in order to show the tab content of the tab which reaches the focus after the tab remotion, then I need to do this (or something equivalent):

               Conversation.instance().end();
               Manager.instance().switchConversation(focusedTabConversationId);
              


              but this unfortunately does not work (as I would) and, more precisely, happens:
              - if I call only the Conversation.instance().end() Seam does not switch to the conversation of the tab which reaches the focus and then does not show the correct data, moreover, in my situation the outcome of the tab removed and of the tab focused can be the same (and in my tests were the same) with the effect that the screen is frozen with the data I just removed;
              - if I call both the methods Seam performs the conversation switch correctly and shows the correct tab but does not perform any conversation remotion

              an example of my scenario: I have a search tab, a user can search for something, when finds what he needs selecting the related link opens a new tab with the detail and then closes the search tab, if he needs to open again the search tab is to search something else but everything he made before is already on the screen.

              So, this is what I found... But I need a little of help to understand if I made something wrong, if it's a known behaviour a bug.....

              Regards,
              Raffaele Camanzo


              • 4. Re: Can I end a conversation programmatically?
                Gavin King Master

                I really do not understand what you think is buggy or unexpected here. The id attribute of @Begin should *always* be contain a value binding that uniquely identifies the conversation. That's the whole point. If two conversations have the same id, they are the same conversation!

                I also don't understand why you think that calling end() should result in a call to some @End method.

                Perhaps you are just trying to get "too complicated" here? Why not start out trying to understand conversations w/o all these exotic features, and once you've got that down, worry about the "extra" stuff like explicit conversation ids.

                • 5. Re: Can I end a conversation programmatically?
                  raffaele camanzo Newbie

                  Hi Gavin,

                  probably I did not explain correctly what I asked to you then I try to explain what I found strange in the Seam behaviour replying to your post but with a little description of the starting scenario:

                  At the moment 0 I have two tabs opened: one with a search function to search for A stuff and one with a search function to search for B stuff, they share the same *outcome* but, obviously, not the same conversation.

                  At the moment 1 the user search for his A stuff finds what he needs and clicks on the link which opens a new tab with both different conversation and different outcome.

                  At the moment 2 the user selects the search stuff A tab (which gets the focus) and closes it because he found what he needs.

                  Now I find the problem:
                  I get the conversation id and the outcome of the tab immediately after the one the user wants to close in order to resume the conversation and switch to the correct view id after having removed the current conversation, in my scenario I get the data of the search stuff B tab (same outcome of the search stuff A but different conversation)

                  - If I execute only

                  Conversation.instance().end();
                  

                  and return the outcome of the tab which reaches the focus (the search stuff B) Seam ends the conversation of search stuff A tab but freezes the screen (maybe because gets back the same outcome and then does nothing)

                  - If I execute
                  Conversation.instance().end();
                  Manager.instance().switchConversation(newTabConvId);
                  

                  and return the outcome of the tab which reaches the focus Seam switches correctly to the search stuff B tab but when I try to ask again for the search stuff A from the menu (I want to search for some other A stuff) the tab contains the data of the conversation I thought to be removed.

                  I made a test case really less complicated than my application and what I see can be resumed as follows:

                  - If I call only the Conversation.instance().end() Seam ends the conversation but I cannot switch to what I need for
                  - If I call both the methods Seam switches to what I need for but does not end the conversation


                  One last thing:
                  [cite]
                  I also don't understand why you think that calling end() should result in a call to some @End method.
                  [/cite]

                  This means that I cannot expect that calling the end of a conversation programmatically can cause the execution of the @End method of the conversation I'm ending?

                  Hope you can help me.

                  Regards,
                  Raffaele Camanzo

                  • 6. Re: Can I end a conversation programmatically?
                    Gavin King Master

                    This is all totally expected behavior. Anyway Manager is not a public API and you use it at your own risk.

                    Currently there is no API in Seam to end a toplevel conversation and switch to some other conversation, you are supposed to use nested conversations if this is the kind of behavior you want.

                    However, you can probably do it using something like this:

                    Conversation.instance().end();
                    Redirect.instance().setViewId("/....xhtml");
                    Redirect.instance().setConversationPropagationEnabled(false);
                    Redirect.instance().setParameter("conversationId", ....);
                    Redirect.instance().execute();


                    Let me know if that works.




                    • 7. Re: Can I end a conversation programmatically?
                      Tino Nitze Newbie

                       


                      This means that I cannot expect that calling the end of a conversation programmatically can cause the execution of the @End method of the conversation I'm ending?


                      Correct! And it's not meant to do that. The invocation of that method ends the conversation though :)

                      • 8. Re: Can I end a conversation programmatically?
                        raffaele camanzo Newbie

                        Hi Gavin,

                        works!

                        but:


                        Currently there is no API in Seam to end a toplevel conversation and switch to some other conversation, you are supposed to use nested conversations if this is the kind of behavior you want.


                        means that your solution uses another not public library and what I need to do is not currently "officially" provided by Seam, am I right?

                        Unfortunately I cannot use nested conversations because, if I'm right, if I end a nested conversation which is parent of other conversations also the children ones are ended with it and this behaviour does not fit my needs because each conversation is a tab and if I close the leftmost I don't want to remove the conversations of all the tabs on its right.

                        Is it possible to expose in a public API the remotion of a top level conversation and the redirection to another top level one?

                        Thanks for the support Gavin!

                        Regards,
                        Raffaele Camanzo

                        • 9. Re: Can I end a conversation programmatically?
                          raffaele camanzo Newbie

                          Hi atzbert,


                          Correct! And it's not meant to do that. The invocation of that method ends the conversation though :)


                          I'm sure that there is a reason for this, but I think that is reasonable execute some user code when the conversation ends (something I think you can put in the conversation @End method) also when I want to remove the conversation programmatically, something like the @Destroy method of the SFSB, anyway, fortunately I don't have (at least) this problem now, then, I know how it works and can design to avoid to need it (I hope) :).

                          Regards,
                          Raffaele Camanzo

                          • 10. Re: Can I end a conversation programmatically?
                            Gavin King Master

                            My solution uses only public APIs.

                            You can get a callback at the end of a conversation by listening to the Seam built-in event, or by adding an @Destroy method to a conversation scoped component.

                            • 11. Re: Can I end a conversation programmatically?
                              raffaele camanzo Newbie

                              Hi Gavin,

                              then this is exactly what I need for and I definitely add the solution to my source code, I was afraid that this behaviour could be discontinued or modified but you used only public APIs and then I'm confident that the behaviour will remain the same.

                              Thank you again for the support!

                              Regards,
                              Raffaele Camanzo