10 Replies Latest reply on Aug 26, 2007 10:33 AM by steve tynor

    How to end converstation when user doesn't cooperate?

    steve tynor Novice

      Seam 1.2.1-GA, seam-gen derived infrastructure (Home classes, etc.)

      My recent discovery of the need to use MANUAL flushing on a certain page has gotten me to pay more attention to conversational lifespan than I had in earlier phases of our app's development. I am now worried about the following use case / bug which I can easily produce in my app (NOTE: this is on a page that is not using MANUAL flushing - it's orthogonal to the flush-mode):

      User selects "Edit Widget" which instantiates a new instance of WidgetHome and loads Widget #1 into its getInstance(). page.xml for this page sets up the conversation:

      <begin-conversation join="true"/>


      As long as the user ends his interaction with the form in one of the "expected" ways (Save, Remove, Cancel), he will trigger a corresponding
      <end-conversation>
      specified either in the navigation rules in page.xml, or via a propagation="end" in the xhtml.

      However: what happens if the user exits the form by some other means (e.g. a link off the global menu.xhtml, a bookmarked link, etc.). The conversation will not end. Let's say that menu link gets him back to the page where he can click "Create Widget". Normally, this would create a new WidgetHome and a brand spanking fresh createInstance() call would create a new Widget instance. But since I'm still in the old conversation, I end up reusing the old WidgetHome from the "improperly" exited form page -- and my "Create Widget" screen is populated with the Widget #1 I was visiting before I so rudely left the page with a Menu link instead of a Cancel.

      I can't find any provision in the Seam navigation model for blanket ending a conversation. For the global navigation menu, perhaps I could add propogate="end" to all the s:link's (I'd have to think that through - I'm not sure I'd _always_ want to do that). but that doesn't help with other cases (a bookmarked link, the user typing a URL into the address bar, etc.).

      The only think I can think of is to create some sort of AJAX-y event that I can call from an onunload Javascript event to end the conversation no matter why the user is navigating away from the page. This feels dirty. It can't be how Seam intends conversations to work...

      Help?


        • 1. Re: How to end converstation when user doesn't cooperate?
          steve tynor Novice

          I note that Michael Yuan touches on this in his book and suggests just letting unused conversations "time out". (section 7.2.4). However, I don't see how this works when one selects join="true" (as does seamgen, and in fact, as he does in the previous section of the book). When one revisits a page marked join="true", we'll reuse the old conversation, not create a new one and let the old one go stale.

          Should I consider using join="false" instead? (i.e. create a new conversation for each page?)


          • 2. Re: How to end converstation when user doesn't cooperate?
            Adrian Mitev Master

            When the user leaves the conversation it will time out.

            • 3. Re: How to end converstation when user doesn't cooperate?
              Christian Bauer Master

               


              However: what happens if the user exits the form by some other means (e.g. a link off the global menu.xhtml, a bookmarked link, etc.). The conversation will not end.


              It will time out.

              • 4. Re: How to end converstation when user doesn't cooperate?
                steve tynor Novice

                 

                It will time out.


                Thanks Christian and Amitev -- that does seem to be the intent. However it doesn't match what I observe. Here's the order of play:

                User visits WidgetList.xhtml -- this does a join="true" - perhaps creating a new conversation, perhaps joining an existing one.

                User clicks a link to end up in WidgetEdit.xhtml -- this also does a join="true" and reuses the existing conversation. Here we're viewing Widget#1. OK so far.

                User navigates directly back to WidgetList.xhtml via a menu link. (no end-conversation).

                User clicks "Create Widget" button, ending up back in WidgetEdit.xhtml, but since we've used join="true", we're still in the long running conversation and reuse the old WidgetHome, which is holding onto the Widget#1. Instead of a "new" widget, we're editing an old one.

                I've tried marking the Create Widget button as propagation="none" and propagation="end", but I still see the bad behavior (create widget edits the already existing Widget#1). I've tried setting join="false, nested="true" - that doesnt work (the old Home instance is still reused). I can't find a way to avoid it.

                Steve


                • 5. Re: How to end converstation when user doesn't cooperate?
                  Christian Bauer Master

                  Two solutions:

                  - make your FooList.xhtml page non-conversational as is the normal case, I don't know why that would be a conversational screen

                  - "Instead of a "new" widget, we're editing an old one." Even if you stay inside the same conversation that should not happen if you pass the identifier of the edited item correctly from the list to the edit screen.

                  • 6. Re: How to end converstation when user doesn't cooperate?
                    steve tynor Novice

                    Thanks for sticking with me Christian - I'm sure I'll come to enlightenment with your help.


                    - make your FooList.xhtml page non-conversational as is the normal case, I don't know why that would be a conversational screen


                    Recall that these are seam-gen generated views and Home classes -- and they are indeed generated as conversational:
                    <page no-conversation-view-id="/WidgetList.xhtml"
                     login-required="true">
                     <begin-conversation join="true"/>
                     <action execute="#{widgetHome.wire}"/>
                    ...
                    


                    Perhaps this should be considered a "bug" in seam-gen?


                    - "Instead of a "new" widget, we're editing an old one." Even if you stay inside the same conversation that should not happen if you pass the identifier of the edited item correctly from the list to the edit screen.


                    Yes: if I pass pass a widgetId, I will edit the proper widget, as here:
                     <s:link view="/#{empty from ? 'Widget' : from}.xhtml"
                     value="Select"
                     id="widget">
                     <f:param name="widgetWidgetId"
                     value="#{widget.widgetId}"/>
                     </s:link>
                    


                    however, when I try to invoke the same view with a freshly created widget , I end up reusing the most recently edited instance (in cases where I have not explicitly ended the conversation as in my previous message):

                     <s:div styleClass="actionButtons" rendered="#{empty from}">
                     <s:button view="/WidgetEdit.xhtml"
                     id="create"
                     value="Create widget">
                     <f:param name="widgetWidgetId"/>
                     </s:button>
                     </s:div>
                    
                    


                    (again, this is straight seam-gen conventions from a "seam generate-entities"-- if it's "wrong", then perhaps we need to log a JIRA against seamgen?)


                    • 7. Re: How to end converstation when user doesn't cooperate?
                      steve tynor Novice

                      My last reply prompted me to confirm that the following button does in fact reset the id in the home class:

                       <s:div styleClass="actionButtons" rendered="#{empty from}">
                       <s:button view="/WidgetEdit.xhtml"
                       id="create"
                       value="Create widget">
                       <f:param name="widgetWidgetId"/>
                       </s:button>
                       </s:div>
                      


                      You'd think that that means that setWidgetWidgetId() would get called with null (which would in turn call setId(null) and reset the instance to null). In fact, it's never called! So maybe my problems are not conversational so much as due to the fact that the mechanism for setting id is broken or otherwise not being invoked. Is there something wrong with the above? Can I pass a null explicitly?

                      I've tried
                       <f:param name="widgetWidgetId" value="#{null}"/>
                      

                      but my breakpoint in setId() is never called for my Create Button...



                      • 8. Re: How to end converstation when user doesn't cooperate?
                        Matt Drees Master

                         

                        "tynor" wrote:

                        Recall that these are seam-gen generated views and Home classes -- and they are indeed generated as conversational:
                        <page no-conversation-view-id="/WidgetList.xhtml"
                         login-required="true">
                         <begin-conversation join="true"/>
                         <action execute="#{widgetHome.wire}"/>
                        ...
                        



                        That code ought to be in WidgetEdit.page.xml, which is for the edit page, which is conversational. I think you'll find the WidgetList.page.xml file doesn't start a conversation.

                        I agree that if you are going to be editing a widget, you want it to happen in a new conversation. And I'm pretty sure seamgen does this correctly.

                        In seamgen, if you're on an edit screen (in a conversation), the links to get out (either the menu or the cancel/done button) either end the conversation (cancel/done) or don't propagate it (menu.xhtml links). So, the conversation won't be re-used the next time you edit or create a new widget.



                        • 9. Re: How to end converstation when user doesn't cooperate?
                          Christian Bauer Master

                          Matt is right, your list page has a wrong page descriptor that is definitely not from seam-gen.

                          • 10. Re: How to end converstation when user doesn't cooperate?
                            steve tynor Novice

                            Thanks Matt and Christian! As you had no doubt already concluded, this was self-inflicted.

                            My page.xml's were correct (begin-converstation join=true in the Edit pages, not begin-conversation in the List pages), but I had edited menu.xhtml and removed the propagation="none" from the s:links there.

                            Slap head.

                            I hope this thread helps others understand better how page level conversations are configured in seam-gen -- there's are a few misleading thoughts from me, but in the end I at least have a much better understanding of how it all hangs together.

                            Thanks again!