7 Replies Latest reply on Feb 3, 2008 5:37 PM by Pete Muir

    Manager.switchConversation via Ajax4JSF actionListener doesn

    Karl Traunmüller Newbie

      Hi all,

      I'm using Seam 1.2.1 GA on JBoss 4.0.5.

      I have a conversation list dropdown in my facelet view, like this:

      <h:selectOneMenu id="conversations" class="navlist"
       value="#{switcher.conversationIdOrOutcome}" >
       <f:selectItems value="#{switcher.selectItems}"/>
       <a:support event="onchange"
       onsubmit="showLoading('NavForm:conversations')"
       oncomplete="hideLoading();"
       actionListener="#{switcher.select}"
       reRender="navlists" />
      </h:selectOneMenu>


      Switching conversations with a:support doesn't work in a stable manner. In particular, the ce.lock() call in the following code snippet (from org.jboss.seam.core.Manager) returns false (tryLock times out) under circumstances I don't really understand:

      public boolean switchConversation(String id)
      {
       ConversationEntry ce = ConversationEntries.instance().getConversationEntry(id);
       if (ce!=null)
       {
       if ( ce.lock() )
       {
       unlockConversation();
       setCurrentConversationId(id);
       setCurrentConversationIdStack( ce.getConversationIdStack() );
       setLongRunningConversation(true);
       return true;
       }
       else
       {
       return false; // <-- times out (sometimes, not always), conversation not switched
       }
       }
       else
       {
       return false;
       }
      }


      What does the call to ce.lock() really mean? And can anybody explain why this would fail?

      Is there a problem with calling switcher.select() from an a:support? And is that in any way related to http://jira.jboss.org/jira/browse/JBSEAM-1832?

      thanks,
      Karl

        • 1. Re: Manager.switchConversation via Ajax4JSF actionListener d
          Karl Traunmüller Newbie

          What I forgot to mention is how conversations are started in the first place. I have an "Actions" dropdown box in the view, which triggers an actionMenuSelectionChanged handler:

          <h:selectOneMenu value="#{navigation.actionMenuSelection}"
           class="navlist" >
           <f:selectItems value="#{navigation.actionMenu}" />
           <a:support event="onchange"
           actionListener="#{navigation.actionMenuSelectionChanged}"
           ajaxSingle="true"
           reRender="navlists" />
          </h:selectOneMenu>


          The actionMenuSelectionChanged method looks like this:

          public void actionMenuSelectionChanged() {
           if (ActionMenuItems.NEW_CONVERSATION.toString().equals(actionMenuSelection)) {
           Conversation.instance().leave();
           Manager.instance().beginConversation("navigator");
           Manager.instance().redirect(Views.COMPUTATION.toString());
           }
          }


          In the meantime, I found a deterministic way to reproduce the problem:

          • Start a new conversation (through the NEW_CONVERSATION entry in the action list)
          • Start another conversation in the same way
          • Hit F5 (generate a GET request)
          • Try to switch from the current (second) conversation to the first one
          • -> ce.lock() in Manager.switchConversation times out


            I have stepped through Seam's JSF phase handling and conversation management, but didn't fully understand what happens.

            However, after adding the cid and clr parameters to the AJAX request the problem seems to be gone:

            <a:support event="onchange"
             onsubmit="showLoading('NavForm:conversations')"
             oncomplete="hideLoading();"
             actionListener="#{switcher.select}">
             <a:actionparam name="cid" value="#{conversation.id}" />
             <a:actionparam name="clr" value="true" />
            </a:support>


            Can anyone confirm that this is a plausible solution?

            Karl


          • 2. Re: Manager.switchConversation via Ajax4JSF actionListener d
            Karl Traunmüller Newbie

            Forget the previous post, didn't work either.

            However, I found out that the cases in which the ce.lock() call fails is when the thread trying the ce.lock() is not the ConversationEntry's lock owner. I guess that's exactly the point of this whole locking story, but I don't understand why there are two threads in play here.

            For example, the Debug View shows that the active thread is:
            Daemon Thread [http-0.0.0.0-8080-2] (Suspended (breakpoint at line 802 in org.jboss.seam.core.Manager)),
            while the Variables view shows that ce.lock.sync.owner is Thread[http-0.0.0.0-8080-3,5,jboss]

            Wouldn't that mean that my browser was using two threads to (concurrently) access my web application (forcing Tomcat to accept the second client thread's request on another server thread) and that the second thread tried to ce.lock() a conversation entry that was not yet unlocked by the first thread?

            Karl

            • 3. Re: Manager.switchConversation via Ajax4JSF actionListener d
              Pete Muir Master

               

              "objectbay" wrote:
              What does the call to ce.lock() really mean? And can anybody explain why this would fail?


              It means, get a lock on the conversation. It would fail if the conversation was in use by another thread.

              Is there a problem with calling switcher.select() from an a:support?


              I would guess yes. It's not the issue in http://jira.jboss.org/jira/browse/JBSEAM-1832. I guess you could file a feature request to allow this to be supported...

              • 4. Re: Manager.switchConversation via Ajax4JSF actionListener d
                Karl Traunmüller Newbie

                Thanks for answering, Pete.

                What I don't understand is why the first conversation in my steps-to-reproduce scenario is locked at that point in time (when trying to switch from the active conversation 2 back to conversation 1).

                This would imply that my code for starting a new conversation

                Conversation.instance().leave();
                Manager.instance().beginConversation("navigator");
                Manager.instance().redirect(Views.COMPUTATION.toString());


                leaves the current conversation in a locked state, wouldn't it?

                The other thing that puzzles me, is that the problem only occurs after a GET request.

                As long as the current page is either submitted via a POST, or the conversation switched without POSTing just through the dropdown box, switching works fine. But as soon as a GET-request hits a conversation, switching breaks (i.e., the timeout problem occurs).

                Does that mean that the GET request has a side-effect on the lock-state of conversations? Shouldn't all conversations get unlocked during Manager.endRequest?

                thanks,
                Karl

                • 5. Re: Manager.switchConversation via Ajax4JSF actionListener d
                  Pete Muir Master

                  I don't think its got anything to do with how you start the conversation. You probably just have concurrent calls to the conversation.

                  • 6. Re: Manager.switchConversation via Ajax4JSF actionListener d
                    Karl Traunmüller Newbie

                    Hello again,

                    I have put a call to ConversationEntry.unlock() into my AJAX handler, and now conversation switching seems to work reliably:

                    public void actionMenuSelectionChanged() {
                     ConversationEntry ce = Manager.instance().getCurrentConversationEntry();
                     if (ce != null && ce.isLockedByCurrentThread()) {
                     ce.unlock();
                     }
                     if (ActionMenuItems.NEU_LEBEN.toString().equals(actionMenuSelection)) {
                     Manager.instance().leaveConversation();
                     Manager.instance().beginConversation("navigator");
                     Manager.instance().redirect(Views.LEBEN_BERECHNUNG.toString());
                     }
                    }


                    Does that look like a plausible solution?

                    It seems to me that Manager.leaveConversation(), which in turn calls initializeTemporaryConversation() doesn't unlock the current conversation, possibly leaving it in a locked state. Can anyone confirm this hypothesis?

                    regards,
                    Karl

                    • 7. Re: Manager.switchConversation via Ajax4JSF actionListener d
                      Pete Muir Master

                      You can file a JIRA bug report for this - Ajax switching of conversations.