0 Replies Latest reply on Feb 12, 2009 8:01 PM by dolanp.dolanp.gmail.com

    Problem with ajax datascroller intantiating multiple beans

    dolanp.dolanp.gmail.com

      A problem I've encountered while developing an application is that in using the rich:datascroller component if the ajax request does not complete before the next one comes through, it instantiates a second backing bean to handle the request.  This can (and does) cause all sorts of problems with keeping properties synchronized.  Some of it can be abated by carefully bijecting the right properties but the behavior overall seems undesirable.


      Here's an example I put together:


      ScrollerTestBean.java


      import java.util.ArrayList;
      import java.util.List;
      
      import javax.ejb.Stateless;
      
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Factory;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.log.Log;
      import org.jboss.seam.faces.FacesMessages;
      
      @Stateless
      @Scope(ScopeType.SESSION)
      @Name("scrollerTest")
      public class ScrollerTestBean implements ScrollerTest {
      
          @Logger private Log log;
      
          @In FacesMessages facesMessages;
      
          //@In(create=true) @Out
          private List<String> myList;
          
          //@In(create=true) @Out
          private int myPage = 1;
      
          public void scrollerTest()
         {
      
         }
          
          @Factory
           public List<String> getMyList() {
                log.info("Getting list " + "(" + this + ")");
                if(myList == null) {
                     log.info("Creating new list");
                     myList = new ArrayList<String>();
                     for(int i=0;i<200;i++)
                          myList.add("Entry" + i);
                }
                try {
                     Thread.sleep(750);
                } catch (InterruptedException e) {}
                return myList;
           }
      
           public void setMyList(List<String> myList) {
                this.myList = myList;
           }
      
           @Factory
           public int getMyPage() {
                if(myPage == 0)
                     myPage = 1;
                log.info("Returning page " + myPage + "(" + this + ")");
                return myPage;
           }
      
           public void setMyPage(int myPage) {
                log.info("Setting page " + myPage + "(" + this + ")");
                this.myPage = myPage;
           }
      
      }
      


      ScrollerTest.java


      
      import java.util.List;
      
      import javax.ejb.Local;
      
      @Local
      public interface ScrollerTest {
      
           public void scrollerTest();
           public List<String> getMyList();
           public void setMyList(List<String> myList);
           public int getMyPage();
           public void setMyPage(int myPage);
      }
      



      scrollerTest.xhtml


      
      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                                   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                      xmlns:s="http://jboss.com/products/seam/taglib"
                      xmlns:ui="http://java.sun.com/jsf/facelets"
                      xmlns:f="http://java.sun.com/jsf/core"
                      xmlns:h="http://java.sun.com/jsf/html"
                      xmlns:rich="http://richfaces.org/rich"
                      xmlns:a="http://richfaces.org/a4j"
                      template="layout/template.xhtml">
      
      <ui:define name="body">
      
          <h:form id="scrollerTestForm">
      
              <rich:panel>
      
                     <rich:dataTable id="myTable" rows="10" value="#{scrollerTest.myList}" var="entry">
                           <h:column>
                               <f:facet name="header">Entry</f:facet>
                                #{entry}
                           </h:column> 
                     </rich:dataTable>
      
                     <rich:datascroller for="myTable" pageIndexVar="pageIndex" pagesVar="pages" 
                          fastStep="10" page="#{scrollerTest.myPage}" eventsQueue="myQ"/>
                     
      
                  <div style="clear:both"/>
      
              </rich:panel>
      
              <div class="actionButtons">
                  <h:commandButton id="scrollerTest" value="scrollerTest"
                          action="#{scrollerTest.scrollerTest}"/>
              </div>
      
          </h:form>
      
      </ui:define>
      
      </ui:composition>
      



      What happens here is I introduced a delay in the getter for myList to simulate some background processing.  If you continue to click on the 'next' button on the datascroller, you'll notice the logger telling you that it's actually a different instantiation of the ScrollerTestBean class.  So you'll have two different beans responding to you.  Click next and you'll get a response from one class which has one copy of myPage and myList, click next again and you'll get a response from the second copy of myPage and myList, which can be different.  So it's like you're scrolling through two different lists and the same time, going back and forth.  If you uncomment the bijection annotations on the properties, it can work.  However you are still getting responses from two beans, they are just sharing the context variables this time.


      Here is the logger output if I click next, then click on the faststep next, then click next a few times.


      12:57:20,473 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:20,473 INFO  [ScrollerTestBean] Creating new list
      12:57:21,238 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:21,254 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:22,035 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:28,109 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:28,109 INFO  [ScrollerTestBean] Creating new list
      12:57:28,858 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:29,608 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:29,608 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:29,608 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:29,608 INFO  [ScrollerTestBean] Returning page 1(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:29,608 INFO  [ScrollerTestBean] Setting page 2(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:29,624 INFO  [ScrollerTestBean] Setting page 11(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:29,639 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:30,389 INFO  [ScrollerTestBean] Returning page 11(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:30,389 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:31,154 INFO  [ScrollerTestBean] Returning page 11(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:33,199 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:33,949 INFO  [ScrollerTestBean] Returning page 2(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:33,949 INFO  [ScrollerTestBean] Returning page 2(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:33,949 INFO  [ScrollerTestBean] Setting page 3(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:33,965 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:34,714 INFO  [ScrollerTestBean] Returning page 3(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:34,714 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:35,479 INFO  [ScrollerTestBean] Returning page 3(com.mckesson.Migrations.session.ScrollerTestBean@7811df)
      12:57:36,401 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,150 INFO  [ScrollerTestBean] Returning page 11(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,166 INFO  [ScrollerTestBean] Returning page 11(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,166 INFO  [ScrollerTestBean] Setting page 12(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,166 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,931 INFO  [ScrollerTestBean] Returning page 12(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:37,931 INFO  [ScrollerTestBean] Getting list (com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      12:57:38,680 INFO  [ScrollerTestBean] Returning page 12(com.mckesson.Migrations.session.ScrollerTestBean@11644e1)
      




      Any thoughts on a more proper way to address this?