1 Reply Latest reply on May 26, 2011 1:49 PM by robshep

    Conversations, Injections, Wicket and Ajax - Strange Behaviour

    robshep

      Dear Seam Users,


      Hopefully somebody can help explain this seemingly odd behaviour that I've seen with AJAX requests using Wicket.


      Essentially, Conversations and Conversation-scoped beans are being created when they shouldn't.



      The most basic example of this which I've yet to strip down completely) there is a Form, within which there is an AjaxButton with an onSubmit(target) method. 


      I've added lots of trace info printing out the various details, which I will show now with some description.




      First the request to a bookmarkable page via entering the url into the address bar.  (No conversation propagation)


      18:00:38,471 INFO  [STDOUT] *****************************************************
      18:00:38,472 INFO  [STDOUT] *** @Create-ing manager object hashCode: 1783935998 cid:311
      18:00:38,472 INFO  [STDOUT] *****************************************************
      18:00:38,476 DEBUG [ConversationListenerReport] Conversation Started
      18:00:38,974 WARN  [AddNewChannel] onDetach() -> Rendered WebPage with Conversation ID: 311 (LRC: true)
      18:00:38,975 WARN  [AddNewChannel] onDetach() -> Rendered WebPage with Conversation ID: 311 (LRC: true)
      



      In the above output we can see the SEAM POJO @Scope(ScopeType.Conversation) being created prior to injection into the wicket page @In(create=true)
      The ConversationListenderReport is just an observer for LRC's beginning, which is started by the SEAM bean. 
      The page is rendered fine and the Page onDetach() method prints the conversation details.



      OK, No problems here. There is a long running conversation with ID 311.



      Next, The following output is the result of a single click on the AjaxButton.




      18:00:45,139 INFO  [STDOUT] *****************************************************
      18:00:45,139 INFO  [STDOUT] *** @Create-ing manager object hashCode: 178165655 cid:329
      18:00:45,139 INFO  [STDOUT] *****************************************************
      18:00:45,139 INFO  [STDOUT] after super.OnPageAttached() -> injectedObject is not null: true
      18:00:45,142 INFO  [STDOUT] after super.OnPageAttached() -> injectedObject: 178165655
      18:00:45,142 INFO  [STDOUT] after super.OnPageAttached() -> Conversation - id: 329 pid: null rid: 329 lrc: false
      18:00:45,146 INFO  [STDOUT] AjaxButton.onSubmit() -> Conversation id:311 long-running: true
      18:00:45,148 INFO  [STDOUT] AjaxButton.onSubmit() -> injected Manager hashcode: 178165655
      18:00:45,148 WARN  [AddNewChannel] onDetach() -> Rendered WebPage with Conversation ID: 311 (LRC: true)
      18:00:45,150 INFO  [STDOUT]  after super.onDetach() -> injected object hashcode: 178165655
      18:00:45,152 WARN  [AddNewChannel] onDetach() -> Rendered WebPage with Conversation ID: 311 (LRC: true)
      18:00:45,155 INFO  [STDOUT]  after super.onDetach() -> injected object hashcode: 178165655
      





      Here we see that for some reason a new SEAM bean is being made and it thinks it is in Conversation ID no.329.


      I've overridden onPageAttached() to inspect a bit of this lifecycle, and here we see that the page has had
      the freshly created SEAM Bean injected in - This is not expected.



      Furthermore, this is happening in a new fresh temporary conversation.


      Moreover, next when the button's onClick() is performed IT thinks it is back in Conversation 311 but has a reference
      to Conversation 329's SEAM Bean.


      Finally when the page's onDetach() is run, the page now think's it is back on the old Conv, but has a reference
      to the SEAM Bean constructed on the new Conv.





      I'm baffeld by this - suffice to say it only happens in some cases - I'm trying to find a small example of Good and Bad.


      Is there anyway I could have programmed this to get this behaviour?


      Thanks for any input.


      Rob.



      Note. All conversation ID's are  result of printing Conversation.instance().getId() directly.


        • 1. Re: Conversations, Injections, Wicket and Ajax - Strange Behaviour
          robshep

          I am fairly satisfied that I have found a bug in the Wicket/SEAM integration.


          My earlier post (above) for web forum readers describes the problem and the symptoms.


          In this post I will show the code examples and a way of provoking such a failure.


          Here is a SEAM BEAN.




          @Name("ajaxConversationBean")
          @Scope(ScopeType.CONVERSATION)
          @AutoCreate
          public class AjaxConversationBean 
          {
               private UUID uuid = UUID.randomUUID();
               
               @Create
               public void onCreate()
               {
                    System.out.println("AjaxConversationBean.onCreate() - @Create-ing with id: " + uuid.toString());
               }
               
               public String speak() {
                    return "I am AjaxConversationBean: " + uuid.toString() + " - and I am in Conversation: " + Manager.instance().getCurrentConversationId() + " (" + Conversation.instance().getId() + ")";
               }
          
               public void startLRC() 
               {
                    System.out.println("Raising Conversation to LRC - current cid: " + Conversation.instance().getId());
                    Conversation.instance().begin(true, false);
               }
          }
          



          And here is a page which uses this bean in a AJAX fashion.


          public class AjaxConversationPage extends WebPage 
          {
               @In AjaxConversationBean ajaxConversationBean;
               
               public AjaxConversationPage() 
               {
                    ajaxConversationBean.startLRC();
                    
                    add(new Form("theForm"){{
                         
                         add(new AjaxButton("theAjaxButton"){
          
                              @Override
                              protected void onSubmit(AjaxRequestTarget target, Form<?> form) 
                              {
                                   System.out.println(getClass().getSimpleName() + ".AjaxButton.onSubmit() -> " + ajaxConversationBean.speak());
                              }
                              
                         });
                         
                    }});
               }
               
               @Override
               protected void onDetach() {
                    super.onDetach();
                    System.out.println(getClass().getSimpleName() + ".onDetach() -> " + Conversation.instance().getId());
                    System.out.println(getClass().getSimpleName() + ".onDetach() -> nulling ajaxConversationBean... => " + ajaxConversationBean.speak());
               }
          }



          and it's HTML for completeness.....


          <html>
          <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <title>Insert title here</title>
          </head>
          <body>
          <form wicket:id="theForm">
               <a wicket:id="theAjaxButton">AjaxButton</a>
          </form>
          </body>
          </html>




          Here is the output of rendering the page...


          18:33:43,654 INFO  [STDOUT] AjaxConversationBean.onCreate() - @Create-ing with id: 968f7539-6400-4dc3-8858-e3c4eec30079
          18:33:43,655 INFO  [STDOUT] Raising Conversation to LRC - current cid: 2
          18:33:43,671 DEBUG [ConversationListenerReport] Conversation Started
          18:33:43,886 INFO  [STDOUT] AjaxConversationPage.onDetach() -> 2
          18:33:43,887 INFO  [STDOUT] AjaxConversationPage.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 968f7539-6400-4dc3-8858-e3c4eec30079 - and I am in Conversation: 2 (2)
          18:33:43,888 INFO  [STDOUT] AjaxConversationPage.onDetach() -> 2
          18:33:43,888 INFO  [STDOUT] AjaxConversationPage.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 968f7539-6400-4dc3-8858-e3c4eec30079 - and I am in Conversation: 2 (2)
          



          Here is the output from clicking the link....


          18:33:50,837 INFO  [RequestListenerInterface] registered listener interface [RequestListenerInterface name=INewBrowserWindowListener, method=public abstract void org.apache.wicket.markup.html.INewBrowserWindowListener.onNewBrowserWindow()]
          18:33:50,866 INFO  [STDOUT] .AjaxButton.onSubmit() -> I am AjaxConversationBean: 968f7539-6400-4dc3-8858-e3c4eec30079 - and I am in Conversation: 2 (2)
          18:33:50,868 INFO  [STDOUT] AjaxConversationPage.onDetach() -> 2
          18:33:50,891 INFO  [STDOUT] AjaxConversationPage.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 968f7539-6400-4dc3-8858-e3c4eec30079 - and I am in Conversation: 2 (2)
          18:33:50,892 INFO  [STDOUT] AjaxConversationPage.onDetach() -> 2
          18:33:50,892 INFO  [STDOUT] AjaxConversationPage.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 968f7539-6400-4dc3-8858-e3c4eec30079 - and I am in Conversation: 2 (2)
          



          This seems fine - no problems here......



          However, here is a small modification to the original page class.


          public class AjaxConversationPage_with_oPA extends AjaxConversationPage
          {
               @Override
               public void onPageAttached() {
                    super.onPageAttached();
                    System.out.println(getClass().getSimpleName() + ".onPageAttached() -> " + Conversation.instance().getId());
                    System.out.println(getClass().getSimpleName() + ".onPageAttached() -> " + ajaxConversationBean.speak());
               }
          }
          



          And here is the output of rendering the page and then clicking the ajax button.


          18:34:07,500 INFO  [STDOUT] AjaxConversationBean.onCreate() - @Create-ing with id: 2a25196b-4afc-4053-b2b6-3efc361e7899
          18:34:07,558 INFO  [STDOUT] Raising Conversation to LRC - current cid: 12
          18:34:07,564 DEBUG [ConversationListenerReport] Conversation Started
          18:34:07,611 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> 12
          18:34:07,612 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 2a25196b-4afc-4053-b2b6-3efc361e7899 - and I am in Conversation: 12 (12)
          18:34:07,612 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> 12
          18:34:07,613 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: 2a25196b-4afc-4053-b2b6-3efc361e7899 - and I am in Conversation: 12 (12)
          
          
          
          
          
          18:34:15,604 INFO  [STDOUT] AjaxConversationBean.onCreate() - @Create-ing with id: a3815da4-938d-4c01-aba7-d4b802b6c6fd
          18:34:15,605 INFO  [STDOUT] AjaxConversationPage_with_oPA.onPageAttached() -> 20
          18:34:15,606 INFO  [STDOUT] AjaxConversationPage_with_oPA.onPageAttached() -> I am AjaxConversationBean: a3815da4-938d-4c01-aba7-d4b802b6c6fd - and I am in Conversation: 20 (20)
          18:34:15,607 INFO  [STDOUT] .AjaxButton.onSubmit() -> I am AjaxConversationBean: a3815da4-938d-4c01-aba7-d4b802b6c6fd - and I am in Conversation: 12 (12)
          18:34:15,608 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> 12
          18:34:15,608 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: a3815da4-938d-4c01-aba7-d4b802b6c6fd - and I am in Conversation: 12 (12)
          18:34:15,609 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> 12
          18:34:15,609 INFO  [STDOUT] AjaxConversationPage_with_oPA.onDetach() -> nulling ajaxConversationBean... => I am AjaxConversationBean: a3815da4-938d-4c01-aba7-d4b802b6c6fd - and I am in Conversation: 12 (12)
          




          As you can see, the conversation-bound instances of the Bean are now out of sync, with detrimental effect
          to the subsequent page behaviour.


          So, it appears that the onPageAttached is run by wicket before SEAM has had a chance to manage the existing conversations.


          The workaround for this ought to be simple - Don't override onPageAttached() !!!!


          I will report this in JIRA - Do I need to package this into a full project - or are these code snippets enough.


          Regards


          Rob