4 Replies Latest reply on Mar 28, 2007 6:22 PM by raffaele.camanzo

    Planning to remove @Begin(id=..)? Help Needed!

    raffaele.camanzo

      Hi all,

      reading comments to JBSEAM-976 (http://jira.jboss.com/jira/browse/JBSEAM-976) I read this:


      Gavin King [20/Mar/07 08:27 PM]

      Anyway, now that we have the now < conversation > stuff in pages.xml, we should deprecate @Begin(id=....).


      I had a look both at the current documentation and software provided (1.2.0PATCH1) and the roadmap to SEAM 1.3.0BETA1 and I did not find any (but if I'm wrong please tell me how) other thing which makes available such feature (<conversation-begin> seems not to support the id parameter and I did not find other stuff related to the pages.xml to handle it).


      Gavin King [20/Mar/07 08:27 PM]

      Right, its not a bug. You should not expect @Begin(join=true, id="#{..}") to do anything if there is an existing long-running conversation. That would be totally evil. You would be switching from one LRC to another.


      What can I say.. Yes, I would be (and I can with the current Seam code) switching from one LRC to another, and I do not understand why this is evil, indeed, the conversation management of Seam actually detects for me if the user asks for a service he asked for before and automatically resumes the correct conversation and it's data. I cannot base my app on pageflow or navigation rules because I'm trying to provide a set of services to the end user collected in the same *workspace*.

      The workspace loads the modules at compile time through a configuration file and some rules, e.g. interfaces, the modules have to adhere to be plugged in the workspace, each module lives in its conversation; the navigation rules are trivial: when a user asks for a service.. do it (display the page -> open a tab.. the workspace looks like a desktop app (everything *se(a)ems* :) to be in the same page) with a list of the services available on the left and a working area on the right, arranged as a tabbed view to allow a fast switch between a service and another).

      A service can have more than one instance (same service in more than a tab), this means that I have the same outcome, the same view-id but not the same conversation id.

      Each service *needs* a top level long running conversation and cannot work with nested ones because the user can close a tab (end a conversation) and I need a way to remove a conversation without removing all the other conversations nested in it (because if a user asks for the remotion of one service he does not.. and all the others I opened after it).

      Is this that evil? And if, why?

      Now I would like to say something about the JBSEAM-976 rejection.


      Shane Bryzak [20/Mar/07 08:14 PM]

      The submitted test case does not start a new conversation. Besides, this feature is going to become deprecated in favour of the new natural conversation ids feature.


      If you say from the second call to the @Begin method.. yes, it's true, but it's not the reason of the submitted issue, indeed, from doc's 6.6:

      Clearly, these example result in the same conversation id every time a particular hotel, blog or task is selected.
      So what happens if a conversation with the same conversation id already exists when the new conversation begins?
      <b>Well, Seam detects the existing conversation and redirects to that conversation without running the
      @Begin method again.</b> This feature helps control the number of workspaces that are created when using workspace
      management.


      then I expect that the @Begin method will no more called after the first time (for the same conversation id), but since the 1.1.1GA it does.
      I made some tests on it modifying a little the test case: I added another action and a "catchall" action in the pages.xml

      <pages>
       <page view-id="/*" action="#{sessionHandler.checkConversation}"></page>
      </pages>
      


      the checkConversation is trivial.. prints on the server the conversation status
       public String checkConversation() {
       String result = null;
      
       Logger.getLogger(this.getClass()).info("<CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: " + (Conversation.instance().isLongRunning() ? "YES" : "NO"));
       Logger.getLogger(this.getClass()).info("<CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: " + (Conversation.instance().isNested() ? "YES" : "NO"));
       Logger.getLogger(this.getClass()).info("<CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: " + Conversation.instance().getId());
       Logger.getLogger(this.getClass()).info("<CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: " + Conversation.instance().getViewId());
       Logger.getLogger(this.getClass()).info("<CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: " + Conversation.instance().getDescription());
      
       return result;
       }
      


      and I checked the behaviour, these are the results:

      when the app starts the catchall method prints out this:
      2007-03-27 10:56:13,868 INFO [org.jboss.seam.contexts.Lifecycle] starting up: org.jboss.seam.security.identity
      2007-03-27 10:56:13,918 INFO [org.jboss.seam.core.Pages] reading pages.xml
      2007-03-27 10:56:14,376 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      2007-03-27 10:56:14,376 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      2007-03-27 10:56:14,376 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: 1
      2007-03-27 10:56:14,378 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      2007-03-27 10:56:14,379 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      

      as expected a temporary conversation is created with id 1 and will not be promoted because there's no conversation to begin.

      Case 1 - @Begin(id=#{param.conversationId})
      This should cover the case described in the documentation:
      Clearly, these example result in the same conversation id every time a particular hotel, blog or task is selected.
      <b>So what happens if a conversation with the same conversation id already exists when the new conversation begins?</b>
      Well, Seam detects the existing conversation and redirects to that conversation without running the
      @Begin method again. This feature helps control the number of workspaces that are created when using workspace
      management.

      I read, but maybe I'm wrong, when the @Begin method is called more than once on the same id, Seam catches this situation, switches to the long running and does not execute the @Begin method again (but we know that the last is not true), anyway, what happens:

      a) I call the @Begin method of the actionone and the catchall (plus the actionone prints) say:
      2007-03-27 10:57:14,509 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      2007-03-27 10:57:14,509 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      2007-03-27 10:57:14,509 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: 2
      2007-03-27 10:57:14,509 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      2007-03-27 10:57:14,509 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <ACTIONONE> START CONVERSATION METHOD CALLED
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION ID IS: actionone
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      2007-03-27 10:57:14,558 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      

      Creating the temporary conversation with id actionone which will be promoted to a long running because we are starting a conversation

      b) I call the @Begin method of the actionone again and the catchall says:
      2007-03-27 10:57:39,699 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: YES
      2007-03-27 10:57:39,699 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      2007-03-27 10:57:39,699 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: actionone
      2007-03-27 10:57:39,699 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: /actionone.xhtml
      2007-03-27 10:57:39,699 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      


      great found and handled but...

      2007-03-27 10:45:45,441 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
      2007-03-27 10:45:45,441 DEBUG [org.jboss.seam.core.Events] Processing event:org.jboss.seam.postSetVariable.actionOne
      2007-03-27 10:45:45,442 ERROR [org.jboss.seam.jsf.SeamPhaseListener] uncaught exception
      javax.faces.el.EvaluationException: Exception while invoking expression #{actionOne.startConversation}
       at org.apache.myfaces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:153)
       at org.jboss.seam.actionparam.ActionParamBindingHelper.invokeTheExpression(ActionParamBindingHelper.java:58)
       at org.jboss.seam.actionparam.ActionParamMethodBinding.invoke(ActionParamMethodBinding.java:75)
       at org.jboss.seam.core.Expressions$2.invoke(Expressions.java:106)
       at org.jboss.seam.core.Pages.callAction(Pages.java:466)
       at org.jboss.seam.core.Pages.enterPage(Pages.java:275)
      
      
       ....
      
      Caused by: java.lang.IllegalStateException: begin method invoked from a long running conversation, try using @Begin(join=true) on method: start
      Conversation
       at org.jboss.seam.interceptors.ConversationInterceptor.aroundInvoke(ConversationInterceptor.java:45)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:69)
       at org.jboss.seam.interceptors.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:27)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:69)
      


      The programmer did not specify to join them and they did not join.. debug window, then, either I did not understand what's written in 6.6 or the doc is not complete because it does not work without a join.


      Case 2 - @Begin(join=true, id=#{param.conversationId})

      a) I call the @Begin method of the actionone and the catchall (plus the actionone prints) say:

      007-03-27 10:49:08,939 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      007-03-27 10:49:08,939 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:08,939 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: 2
      007-03-27 10:49:08,939 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      007-03-27 10:49:08,939 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      007-03-27 10:49:08,991 INFO [it.seam.testcase.ActionOne] <ACTIONONE> START CONVERSATION METHOD CALLED
      007-03-27 10:49:08,992 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      007-03-27 10:49:08,992 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:08,992 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION ID IS: actionone
      007-03-27 10:49:08,992 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      007-03-27 10:49:08,992 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      


      Creating the temporary conversation with id actionone which will be promoted to a long running because we are starting a conversation.

      b) I call the @Begin method of the actiontwo and the catchall (plus the actiontwo prints) say:

      007-03-27 10:49:19,257 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      007-03-27 10:49:19,257 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:19,257 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: 3
      n007-03-27 10:49:19,257 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      007-03-27 10:49:19,257 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <ACTIONTWO> START CONVERSATION METHOD CALLED
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: NO
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION ID IS: actiontwo
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: null
      007-03-27 10:49:19,279 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      


      Creating the temporary conversation with id actiontwo which will be promoted to a long running because we are starting a conversation.

      c) I call the @Begin method of the actionone again and the catchall (plus the actionone prints) say:

      007-03-27 10:49:27,811 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: YES
      007-03-27 10:49:27,811 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:27,811 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: actionone
      007-03-27 10:49:27,811 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: /actionone.xhtml
      007-03-27 10:49:27,811 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <ACTIONONE> START CONVERSATION METHOD CALLED
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: YES
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION ID IS: actionone
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: /actionone.xhtml
      007-03-27 10:49:27,812 INFO [it.seam.testcase.ActionOne] <START CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      


      Found actionone conversation and switched to (everything handled).

      d) I call the @Begin method of the actiontwo again and the catchall (plus the actiontwo prints) say:

      007-03-27 10:49:38,523 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: YES
      007-03-27 10:49:38,523 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:38,523 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION ID IS: actiontwo
      007-03-27 10:49:38,523 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: /actiontwo.xhtml
      007-03-27 10:49:38,523 INFO [it.seam.testcase.SessionHandler] <CHECK CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <ACTIONTWO> START CONVERSATION METHOD CALLED
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> IS THERE A LONG RUNNING CONVERSATION: YES
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> IS THERE A NESTED CONVERSATION: NO
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION ID IS: actiontwo
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION VIEW ID IS: /actiontwo.xhtml
      007-03-27 10:49:38,523 INFO [it.seam.testcase.ActionTwo] <START CONVERSATION> LONG RUNNING CONVERSATION DESCRIPTION IS: null
      


      Found actiontwo conversation and switched to (everything handled).

      Everything seems to work properly except the reason of the issue JBSEAM-976, indeed the @Begin method is called more than once.

      I tried also without ids in the @Begin, this causes the creation of a brand new conversation for every call to the @Begin method, but this is not enough for the app I'm building.


      I don't know if you plan to remove the join=true related to a @Begin(id=...) but please don't remove the explicit id facility, we wrote a lot of code based on this and the remotion causes the loss of a huge amount of time.


      Regards,
      Raffaele Camanzo



        • 1. Re: Planning to remove @Begin(id=..)? Help Needed!
          spambob

          +1 to let @Begin(id=..) stay - I find it really useful!

          Further I would like to ask how one is supposed to set a custom conversation id within pages.xml or what Shane meant in jira with "the new natural conversation ids feature" because I haven't found an example in the docs or examples - although it wouldn't be the first time that I have been blind.

          • 2. Re: Planning to remove @Begin(id=..)? Help Needed!
            shane.bryzak

            This feature is not really "official" yet because it's not documented or demonstrated in any of the example apps. It's actually part of the groundwork we needed to do for the upcoming JBossWS/Seam integration in 1.3.0. To configure it, you need to add an entry like this to your pages.xml:

            <conversation name="upgradeCustomer"
             parameter-name="customerId"
             parameter-value="#{customer.id}"/>


            You can then refer to this conversation in your page configuration/s:

            <page view="/upgrade-customer.xhtml"
             conversation="upgradeCustomer">
            


            Then instead of using a synthetic conversation id (e.g. cid=123) it will use the "natural" id, i.e. the primary key value of the customer ( customerId=444) to identify the conversation.


            • 3. Re: Planning to remove @Begin(id=..)? Help Needed!
              gavin.king

              I don't know why you just spent so many words on explaining me the current behavior. I know what the current behavior is. I know how it behaved in the test case you submitted. I'm happy with it.

              There is a massive difference between what happens when you call @Begin(id="...") when there is no long-running conversation in progress, and what happens when there is already one in progress. The stuff written in the documentation refers to the case where there is no conversation in progress.

              Nevertheless, both cases are at least somewhat broken because they result in changing the conversation context in the middle of a request.

              You should use the new functionality for defining "natural" conversation ids, since it is not vulnerable to this problem.

              Yes, I understand that this is not yet documented, but its pretty easy to figure out.

              • 4. Re: Planning to remove @Begin(id=..)? Help Needed!
                raffaele.camanzo

                 


                This feature is not really "official" yet because it's not documented or demonstrated in any of the example apps.
                It's actually part of the groundwork we needed to do for the upcoming JBossWS/Seam integration in 1.3.0.


                Thank you Shane for the preview, I tried it out on Seam 1.2.1GA modifying my test case, unfortunately I did not find a way to keep alive a long running conversation using that stuff.
                Anyway, you did not release it officially and then I don't want to bother you with my results, if you are interested I will post you the details.


                I don't know why you just spent so many words on explaining me the current behavior.
                I know what the current behavior is. I know how it behaved in the test case you submitted. I'm happy with it.


                Gavin, I spent all those words for two reasons: the former is to have a feedback from you on the way I use, understand (or misunderstand) the framework
                the latter is to understand if what I'm doing with Seam is reasonable and into the bounds of the Seam philosophy.
                But probably I'm not, or not completely and about this I would like to make you a(nother) question, or better, I try to tell you what I would reach:
                my application is really near to the Seam's workspace management, but this feature does not give me enough access to the conversation's list.
                I should wrap the conversationsList to render it as a tabbed view, unfortunately I cannot because I have to group sub-lists of conversations, indeed we have two levels of tabs,
                in the lower there are the actions, one per conversation, in the upper there is a logical grouping (tabs are grouped for functionality);
                then I should have a way to access and switch to a conversation both if the user asks for a particular functionality (the lower tab label)
                and if the user asks for another group of tabs (the upper tab label, switching to the 'opened' one in that group).
                In my app there's the same logical error you found in the test case: trying to switch to another conversation from an already long running, but this is quite simple to solve, I guess:
                I avoid to propagate the current conversation (the current tab viewed) when a user asks for a new service (from the menu, new open tab)
                or when refers to an already opened (selecting a tab label).
                I think this happens in conversationsList/conversationsStack stuff in the workspace management example.
                There's another little big problem with the conversationsList or conversationsStack: I tried to render it as an unordered list (what's behind the tabbed view) and the list provided
                changes everytime I switch from a conversation to another; this for a tabbed view of services is not reasonable.
                This is why I keep track of the conversations (storing the conversation identifier, passed as parameter to the related tab label link) to create the two levels tabbed view
                and use explicit conversation ids.

                Hope you have the time to read this and to give me advice about.

                Regards,
                Raffaele Camanzo