1 2 Previous Next 27 Replies Latest reply on Jul 22, 2011 10:03 PM by holly_bony Go to original post
      • 15. Re: Troubles to use datascroller and ExtendedDataModel
        davidintx.david.dsheth.com

        Hi,


        In regard to your two questions:


        We're using JPA underneath, and so the findFolders method basically does the following: 



        1. Create the query in JPA QL as a string, using the sort field and descending information.

        2. Create a javax.persistence.Query object from that string--i.e. Query query = getEntityManager().createQuery(queryString);

        3. Call setFirstResult() and setMaxResults() on the JPA query object to cause the underlying database to only return the proper number of rows.

        4. Get the result list

        5. Cast the results to the proper type.  We push this to a separate GenericsUtils library so that we don't incur the Generics warning in our DAO--so, we actually do something like List<FolderDTO> folders = GenericsUtils.convers(FolderDTO.class, query.getResultList();



        In regard to your other question:  I declare
        private boolean descending
        in the class .  This is then modified as needed in the update method, as shown on the blog post.


        • 16. Re: Troubles to use datascroller and ExtendedDataModel

          Hi David,
          I´ve tried your solution. I have had to implement getRowIndex and setRowIndex to avoid UnsupportedOperationException. I have just done it this way:



               
                  private int rowIndex;
          
                  @Override
               public void setRowIndex(int index) {
                   //throw new UnsupportedOperationException();
                    this.rowIndex = index;
               }
          
               @Override
               public int getRowIndex() {
                   //throw new UnsupportedOperationException();
                    return this.rowIndex;
               }
          



          It works ok for me and true pagination is accomplished fetching only the needed data.
          On the other hand,I have also tried to use this with rich:column and their sortBy, doing that a -1 is passed to numberOfRows and it ends in the following error:


          java.lang.IllegalArgumentException: Negative (-1) parameter passed in to setMaxResults
               at org.hibernate.ejb.QueryImpl.setMaxResults(QueryImpl.java:106)
               at es.rbcdexia.risk.online.action.BenchmarkList.getResultList(BenchmarkList.java:112)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
               at java.lang.reflect.Method.invoke(Method.java:597)
               at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)
               at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
               at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:46)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.transaction.TransactionInterceptor$1.work(TransactionInterceptor.java:38)
               at org.jboss.seam.util.Work.workInTransaction(Work.java:41)
               at org.jboss.seam.transaction.TransactionInterceptor.aroundInvoke(TransactionInterceptor.java:32)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
               at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:166)
               at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:102)
               at es.rbcdexia.risk.online.action.BenchmarkList_$$_javassist_7.getResultList(BenchmarkList_$$_javassist_7.java)
               at es.rbcdexia.risk.online.util.BenchExtDataModel.walk(BenchExtDataModel.java:125)
               at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
               at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
               at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
               at java.lang.reflect.Method.invoke(Method.java:597)
               at org.jboss.seam.util.Reflections.invoke(Reflections.java:21)
               at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:31)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56)
               at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:31)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:46)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:42)
               at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68)
               at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107)
               at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:166)
               at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:102)
               at es.rbcdexia.risk.online.util.BenchExtDataModel_$$_javassist_15.walk(BenchExtDataModel_$$_javassist_15.java)
               at org.richfaces.model.ModifiableModel.prepareCollection(ModifiableModel.java:142)
               at org.richfaces.model.ModifiableModel.walk(ModifiableModel.java:111)
               at org.ajax4jsf.component.UIDataAdaptor.walk(UIDataAdaptor.java:1127)
               at org.richfaces.renderkit.AbstractRowsRenderer.encodeRows(AbstractRowsRenderer.java:106)
               at org.richfaces.renderkit.AbstractRowsRenderer.encodeRows(AbstractRowsRenderer.java:91)
               at org.richfaces.renderkit.AbstractRowsRenderer.encodeChildren(AbstractRowsRenderer.java:138)
               at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:812)
               at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:282)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:125)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:68)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:116)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:68)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:116)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:68)
               at org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:116)
               at org.ajax4jsf.renderkit.AjaxContainerRenderer.encodeAjax(AjaxContainerRenderer.java:123)
               at org.ajax4jsf.component.AjaxViewRoot.encodeAjax(AjaxViewRoot.java:673)
               at org.ajax4jsf.component.AjaxViewRoot.encodeChildren(AjaxViewRoot.java:544)
               at javax.faces.component.UIComponent.encodeAll(UIComponent.java:886)
               at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:592)
               at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
               at org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:189)
               at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:106)
               at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
               at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:144)
               at javax.faces.webapp.FacesServlet.service(FacesServlet.java:245)
               at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
               at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
               at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
               at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
               at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:73)
               at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:154)
               at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:260)
               at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:366)
               at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:493)
               at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
               at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
               at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
               at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
               at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
               at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
               at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
               at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
               at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
               at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
               at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
               at org.jboss.web.tomcat.se
          13:11:20,640 ERROR [STDERR] curity.SecurityAssociationValve.invoke(SecurityAssociationValve.java:179)
               at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:432)
               at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:84)
               at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
               at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
               at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:157)
               at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
               at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:262)
               at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
               at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
               at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:446)
               at java.lang.Thread.run(Thread.java:619)
          
          



          The code where I assign the numberOfRows is this:


               @SuppressWarnings("unchecked")
               public List<Benchmark> getResultList(int firstRow, int numberOfRows) {
          List<Benchmark> lista = entityManager.createQuery(this.getEjbql()).setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
                  return lista;
               }   
          




          Any idea to solve this? I´ve tried to control this in the walk method assigning a constant, the number of rows I want, when a negative number is received but it does not work properly.
          I´ll post this in your blog as well.
          any idea? thank you!


          • 17. Re: Troubles to use datascroller and ExtendedDataModel

            Jaime, you are ahead of me and rightly so. I'm very new to Seam, Hibernate etc.., so please bear with me.


            David, thanks for your quick response.


            I'm just copying your code to get it work, refactor later.
            I gathered that IFormsService implements an interface FormsSevice



            Here is my IFormsService



            @Name("service")
            public class IFormsService implements FormsService {
                @In
                 private EntityManager entityManager;
            
                 List<Burst> bursts = new ArrayList<Burst>();
            
                 private String burstQuery = "select burst from Burst burst";
            
                 
                 public int countBursts() {
                      return bursts.size();
                 }
            
                 public Burst getBurst(Integer id) {
                      // ???
                      return null;
                      
                 }
            
                 public List<Burst> findBursts(int firstRow, int numberOfRows,
                           String sortField, boolean descending) {
                      
                      String query = "select burst from Burst burst";
                      
                      if ( sortField != null && sortField.trim().length() > 0 ) 
                           query += " order by " + sortField;
                      
                      if ( descending )
                           query += " desc ";
            
                 
                      //I will ignore generic warnings for now.     
                     bursts = entityManager.createQuery(query)
                      .setMaxResults(numberOfRows)
                      .setFirstResult(firstRow)
                      .getResultList();
            
                      return bursts;
                 }
            
            
            }
            



            Is findBursts() right ?


            I am not sure how to code -


            countBursts()
            getBurst(Integer id)



            Here is my datamodel



            public class BurstDataModel extends SerializableDataModel {
                 @Override
                 public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException
                 {
                     if (detached && getSortFieldObject() != null)
                     {
                         for (Integer key : wrappedKeys)
                         {
                             setRowKey(key);
                             visitor.process(context, key, argument);
                         }
                     } else
                     {
                         int firstRow = ((SequenceRange) range).getFirstRow();
                         int numberOfRows = ((SequenceRange) range).getRows();
                         wrappedKeys = new ArrayList<Integer>();
                         for (Burst burst : serviceForms.findBursts(firstRow, numberOfRows, sortField, descending) )
                         {
                             wrappedKeys.add(burst.getBurstId());
                             wrappedData.put(burst.getBurstId(), burst);
                             visitor.process(context, burst.getBurstId(), argument);
                         }
                     }
                 }
            
            } 




            Replace your FolderDTO with Burst which is a JPA @Entiy , is that correct ?


            Don't I need create=true when injecting IFormsService ?


            Thanks, again I apologize for my inexperience.



            Franco



            • 18. Re: Troubles to use datascroller and ExtendedDataModel

              Franco, I´ll try to help you.
              In my app I have a war project (no EJBs) and I use injected EntityManager as well as EntityQuery children components.
              So, apart from a new component that extends from SerializableDataModel, I rely on a PojoList component created by seam-gen with some modifications, that´s why I´m not using any interfaces like David.


              To manage countBursts(), in my case I´m using getResultCount() from EntityQuery.
              In my case:(be careful getResultCount returns a Long and a int is expected)


                  @Override
                  public int getRowCount()
                  {
                      if (rowCount == null)
                      {
                          rowCount = Integer.valueOf(benchList.getResultCount().intValue());
                      }
                      return rowCount;
                  }
              



              where benchList is a component wixh extends from EntityQuery and has a query for benchmarks.(benchmark is the pojo I´m dealing with, same way you have bursts)


              On the other hand, to manage getBurst(Integer id) I´m using entitymanager find method this way: (Benchmark.class is my pojo class, and benchmarkCode is the pojo id)



              @In
              private EntityManager entityManager;
              ...
              entityManager.find(Benchmark.class,benchmarkCode);
              


              hope this helps you!
              Jaime


              • 19. Re: Troubles to use datascroller and ExtendedDataModel

                Moving along ...


                - wrote IFormsService.getBurst() as


                     public Burst getBurst(Integer id) {
                          for (Burst burst: bursts  ) {
                               if (burst.getBurstId().equals(id)) {
                                    return burst;
                               }
                          }
                          throw new RuntimeException("Burst pk = "+ id.toString()+ " not found");
                          
                     }
                



                - declared @Name(burstDataModel) on data model.


                - wrote view as bursts.xhtml


                <h:form>
                <rich:dataTable id="bursts" value="#{burstDataModel}"
                              var="_burst" rows="5" width="100%">
                    <rich:column>
                        <f:facet name="header">
                            <a4j:commandLink value="Name" reRender="bursts">
                                <a4j:actionparam name="sortField" value="attribute(burstName)" />
                            </a4j:commandLink>
                        </f:facet>
                        <h:outputText
                            value="#{_burst.burstName}" />
                    </rich:column>
                </rich:dataTable>
                     
                <rich:datascroller for="bursts" maxPages="5" />
                </h:form>
                




                Results -


                #{_burst.attributes['burstName']}"

                reports error
                   Property 'attributes' not found on type ...


                So replaced that with

                <h:outputText  value="#{_burst.burstName}" />

                to get view working.


                View renders first 5 rows, but datascroller page buttons are inactive. so can't go to next page. Problems in my datamodel ?
                Clicking header works fine but with same 5 rows. I do not understand why attribute  in actionparam works and why attributes in outputText does not. Could not find anything in docs for a4j:actionparam


                Further questions (sorry) if I get this working -


                I was using EntityQuery before. search fields were tied in to limit results with where clauses.  How do I pass params and make my query in my extended datamodel a dynamic query ?


                Thanks


                Franco


                • 20. Re: Troubles to use datascroller and ExtendedDataModel

                  I've posted the question regarding true pagination with rich:column sortBy in the richfaces. In case you would like to follow the thread:
                  Pagination in the Richfaces Forum

                  • 21. Re: Troubles to use datascroller and ExtendedDataModel

                    Jaime, I am doing a war project too.


                    I started Hibernate & Seam 4 months ago and I am only doing it as Proof of Concept for now, hopefully replace my current production app with an improved Seam app.


                    The last month or so I put I put in a lot of effort to customize seam-gen to give me a template with a Richfaces datascroller on every page. So I was real bummed out when I found the issues with large datasets.


                    Using your tips, I got datascroller true pagination to work !!!, query uses Oracle rownum.  Thanks for the tip that I can use EntityQuery objects. I dropped the interface and use a BurstList pojo now.


                    Sorry for being a pain, I still have 1 issue and then I am home.
                    findBursts() is in the list POJO now


                         public List<Burst> findBursts(int firstRow, int numberOfRows,
                                   String sortField, boolean descending) {
                              
                              
                              String orderBy = new String();
                              
                              setFirstResult(firstRow);
                              setMaxResults(numberOfRows);
                              
                              if ( sortField != null && sortField.trim().length() > 0 ) { 
                                   orderBy = sortField + ( ( descending == false ) ? " desc " : " asc " );
                              }     
                              
                              setOrder(orderBy);
                              refresh();
                                        return getResultList();
                    
                         }     
                    





                    I then put in my search form (EntityQuery based) back on the list page. 


                    <a4j:commandButton id="search" value="#{messages.search}" 
                               action="#{burstList.refresh}" reRender="bursts" /> 
                    



                    This executed with the proper parameters from my search form. But now I have 2 queries getting fired when the search button is clicked - EntityQuery.refresh() and findBursts() called by walk() again.  Also if my search returns only 1 row, the datascroller still shows multiple pages, it is not getting reset.
                    I understand I don't need 2 queries here, but I can't figure out the steps for a new parametized query ? - My findBursts() should not be doing a refresh , right ?


                    Should my search button call a method directly in my extended datamodel ?


                    So the question is how to get a single query going when I do a search ?



                    - sorting as per David's method clicking on the header does not work as expected for me. The walk() method is called before update() so the descending variable does not toggle. Do I need to put extended model in conversation scope ?


                    That also raises the point to what you are trying to achieve - using the sortBy ?
                    I gave it a shot and of course got the Negative (-1) parameter passed in to setMaxResults error same as you. I am not sure why you would want to use the sortBy, if David's solution works for you, is that not doing the same toggle sorting  ?. I'd like to help if I can with my limited knowledge :(


                    Thanks for your help, appreciate it.


                    Franco



                    • 22. Re: Troubles to use datascroller and ExtendedDataModel

                      I think I got it - Jaime can you concur if this is the right way ?


                      I left findBursts() as is.


                      Hooked search form to datamodel calls




                      //in view
                      
                           <h:commandButton value="Find" action="#{burstDataModel.update}" /> 
                           <h:commandButton value="Clear" action="#{burstDataModel.reset}"  /> 
                      
                      
                      // in datamodel 
                      
                           public void reset() {
                                burstList.clearFilter();
                                update();
                           }
                      
                      // in list pojo
                      
                           public void clearFilter() {
                                this.burst = new Burst();
                           }
                      
                      
                      


                      Now, I tried doing the same with Ajax buttons which don't work as expected - datascroller out of sync with results. Any ideas why ?


                                  <a4j:commandButton value="Search 2" 
                                           action="#{burstDataModel.update}" reRender="bursts" >
                                      <a4j:actionparam name="sortField" value="burstName" />
                                  </a4j:commandButton>
                      



                      Sorting using David's method is still not working, debugging that now.


                      Thanks



                      • 23. Re: Troubles to use datascroller and ExtendedDataModel

                        My head hurts!


                        Ignore my last problem, ok with non-Ajax buttons for now. Still not confident that I glued my extended datamodel and burstList pojo correctly.
                        When I click a page button in the scroller, query is fired twice - by EntityQuery.refresh() I think the 1st time and the 2nd time in walk(). This is a real showstopper for me.


                        Here is where I am at.


                        findBurts() - no change.


                        burstList is now in conversation mode, but did not start a long running conversation, do I have to and when ?


                        @Name("burstList")
                        @Scope(ScopeType.CONVERSATION) 
                        



                        Extended Datamodel is NOT in conversation scope.


                        @Name("burstDataModel")
                        public class BurstDataModel extends SerializableDataModel {
                        
                           ///I have injected burstList like this.
                             @In(create=true)
                             private BurstList burstList;
                        



                        If I remove create=true I get the error - In attribute requires non-null ...



                        Jaime, sorry to direct this to you again - but can you help here again since you have it working with EntityQuery already ?



                        Sorry for the many posts here everyone but this is very important to me and am sure to a lot of others wanting to go this way.



                        Thanks


                        Franco

                        • 24. Re: Troubles to use datascroller and ExtendedDataModel
                          hristo
                          Hi,
                          Thank you for this interesting discussion. I've also read some other posts regarding pagination and rich:datascroller  but I still can't solve one problem .
                          I cannot set my datascroller to show the correct number of pages. The reason for this is that ListSequenceDataModel is used for calculating the number of pages instead of my ExtendedDataModel.
                          I have TestDataModel class which extends SerializableDataModel where in wrappedData I have just 10 elements but my getRowCount method returns the number of all records in the database which is 500. The datascroller though shows that there is only one page.
                          I debug the richfaces code to see how the datascroller is rendered.
                          This is done mainly in DatascrollerTemplate and DataScrollerRenderer in package org.richfaces.renderkit.html. As expected the datascroller uses the DataModel of the DataTable to calculate the number of pages:
                          org.richfaces.component.UIDatascroller.getRowCount(UIData data)
                          and after:
                          UIDataAdapter.getRowCount(){   
                          ...                                                                                     return getExtendedDataModel().getRowCount();
                          }

                          Here getExtendedDataModel() returns an instance of ModifiableModel which field "originalModel" contains my custom TestDataModel. So modifiableModel.getOriginalModel.getRowCount will return 500 as I need. But look at the implementation of modifiableModel.getRowCount:

                                  public int getRowCount() {
                                          return delegate.getRowCount();
                                  }

                          !!!???
                          delegate is an instance of ListSequenceDataModel which contains the list wrappedKeys. So getRowCount() returns wrappedKeys.size() which is 10 so the datascroller renders with only one page.

                          At the time of rendering the dataTable when the model is created () both fields: originalModel and delegate are set to TestDataModel. But at some point before delegate is set to ListSequenceDataModel and returns the size of the list.

                          Here is example of my code:

                          @Name("testDataModel")
                          @Scope(ScopeType.SESSION)
                          public class TestDataModel extends SerializableDataModel {

                                  private Integer currentPk;

                                  private boolean detached = false;
                                  private List<Integer> wrappedKeys = null;
                                  private final Map<Integer, User> wrappedData = new HashMap<Integer, User>();
                                  private Integer rowCount;

                                  @In(create = true)
                                  private UserService userManager;

                                  @Override
                                  public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
                                          if (detached){
                                                  for (Integer key : wrappedKeys) {
                                                          setRowKey(key);
                                                          visitor.process(context, key, argument);
                                                  }
                                          } else {
                                                  int firstRow = ((SequenceRange) range).getFirstRow();
                                                  int numberOfRows =((SequenceRange) range).getRows();
                                                  wrappedKeys = new ArrayList<Integer>();
                                                  for (User user : userManager.findUsersPaged(firstRow, numberOfRows, null, null)) {
                                                          wrappedKeys.add(user.getId());
                                                          wrappedData.put(user.getId(), user);
                                                          visitor.process(context, user.getId(), argument);
                                                  }
                                          }
                                  }

                          ...
                                  @Override
                                  public int getRowCount() {
                                                  rowCount = userManager.countUsers();
                                          return rowCount;
                                  }

                          @Scope(ScopeType.SESSION)
                          @Name("userManager")
                          public class UserAction implements UserService{
                          ...
                                  public List<User> findUsersPaged(int firstRow, int numberOfRows, String sortField, boolean descending) {
                                          List<User> users = entityManager.createQuery("select u from User u").setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
                                          return users;
                                  }

                          Another thing is that there is no way to set the number of pages directly to the UIDatascroller component either by an attribute or by the API
                          I'm very interested to see how this problem can be solved.
                          If anyone is familiar  with this could you give me a tip.

                          Many thanks,
                          Hristo
                          • 25. Re: Troubles to use datascroller and ExtendedDataModel
                            deanhiller2000

                            anyone know how


                            1. clear rowCount on refresh of page so it is not incorrect
                            2. clear rowCount when user goes to next page
                            3. NOT clear rowCount when a value is selected in the table


                            ie. there is a bug where rowCount stays at 40 but the result set is shrinking to let's say 30 but the rowCount was not updated so the number of pages is too many(or there is more results and there is a page missing and user has to rerun the entire query).  Any fixes to this?

                            • 26. Re: Troubles to use datascroller and ExtendedDataModel
                              holly_bony
                              Sorry for my bad english. I dont like ExtendedDataModel, i think is possible to do an implementation from List<T> so i share my solution:



                              /**
                              *  Dummy implementation
                              *
                              * @author cjuarez
                              */
                              public abstract class ListAdapter<E> implements List<E> , java.io.Serializable{

                                  public boolean contains(Object o) {
                                      throw new UnsupportedOperationException("Not supported yet.");
                                  }

                                  public Iterator<E> iterator() {
                                      throw new UnsupportedOperationException("Not supported yet.");
                                  }
                                   //     .
                                   //     .
                                   //     . all methods...
                              }

                              /**
                              * Represents a page data model
                              *
                              * @author cjuarez
                              */
                              public class Page<E> implements Serializable {

                                  private int totalRows;
                                  private List<E> rows = new ArrayList<E>();

                                  public void setRows(List<E> pageItems) {
                                      this.rows = pageItems;
                                  }

                                  public List<E> getRows() {
                                      return rows;
                                  }

                                  /**
                                   * @return the totalRows
                                   */
                                  public int getTotalRows() {
                                      return totalRows;
                                  }

                                  /**
                                   * @param totalRows the totalRows to set
                                   */
                                  public void setTotalRows(int totalRows) {
                                      this.totalRows = totalRows;
                                  }
                              }

                              /**
                              * Hook for retrieve pages from a String Dao, JPA, etc...

                              * @author cjuarez
                              */
                              public interface ProviderPage<E> {

                                  public Page<E> getPage(int firstRow, int numOfRows);

                              }

                              /**
                              * Paginated list, the get method decides if return object from current
                              * page or call to getPage method from providerPage
                              *
                              * @author cjuarez
                              */
                              public class PaginatedList<E> extends ListAdapter<E>{

                                  private ProviderPage<E> providerPage;
                                  private Page<E> currentPage;
                                  private E fistRow;
                                  private int pageSize;
                                  private int numPage;

                                  public PaginatedList(ProviderPage<E> providerPage, int pageSize){
                                      this.providerPage = providerPage;
                                      this.pageSize = pageSize;
                                      currentPage = null;
                                      fistRow = null;
                                  }

                                  public int size() {
                                      fetchFirstPage();
                                      return currentPage.getTotalRows();
                                  }

                                  public boolean isEmpty() {
                                      fetchFirstPage();
                                      return currentPage.getRows().isEmpty();
                                  }

                                  public synchronized E get(int index) {
                                      fetchFirstPage();
                                      if(index==0){
                                          return fistRow;
                                      }else{
                                          if(index>=(numPage-1)*pageSize&&index<numPage*pageSize){
                                              return currentPage.getRows().get(index-(numPage-1)*pageSize);
                                          }else{
                                              currentPage = providerPage.getPage(index/pageSize*pageSize, pageSize);
                                              numPage = index/pageSize + 1;
                                              return currentPage.getRows().get(index-(numPage-1)*pageSize);
                                          }
                                      }
                                  }

                                  private void fetchFirstPage(){
                                      if(currentPage==null){
                                          currentPage = providerPage.getPage(0, pageSize);
                                          numPage = 1;
                                          if(!currentPage.getRows().isEmpty()){
                                              fistRow = currentPage.getRows().get(0);
                                          }
                                      }
                                  }

                                  @Override
                                  public Iterator<E> iterator() {
                                      fetchFirstPage();
                                      return providerPage.getPage(0, currentPage.getTotalRows()).getRows().iterator();       
                                  }


                              }


                              ///So this is my EJB, is really easy

                              @Stateful
                              @Name("itemsSearcher")
                              @Scope(ScopeType.SESSION)
                              @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                              public class ItemsSearcher implements ItemsSearcherLocal {

                                  private List<Item> itemsFound;

                                  public void filterItems(final String searchPattern) {
                                      try {
                                          ServiceLocator sl;
                                          sl = ServiceLocator.getInstance();
                                          DataSource ds = sl.lookupDataSource("TCADB");
                                          final ItemDao sellerDao = new ItemDao(ds);
                                         
                                          itemsFound = new PaginatedList<Item>(
                                                  new ProviderPage<Item>() {
                                                      public Page<Item> getPage(int firstRow, int numOfRows) {
                                                          log.debug("the sellerDao : " + sellerDao);
                                                          return sellerDao.filterItemsPage(searchPattern, _profile, firstRow, numOfRows);
                                                      }
                                                  }, 10);

                                      } catch (NamingException ex) {
                                          log.error(null,ex);
                                          throw new RuntimeException(ex);
                                      }
                                  }

                                  /**
                                   * @return the itemsFound
                                   */
                                  public List<Item> getItemsFound() {
                                      return itemsFound;
                                  }

                              }

                                        <h:panelGrid columns="4">
                                          <rich:layout>
                                              <rich:layoutPanel position="top">
                                                  <a4j:form>
                                                      <h:panelGrid columns="4">
                                                          <h:outputLabel for="searchPattern" value="#{messages['global.search']}"/>
                                                          <h:inputText id="searchPattern" value="#{searchPatternTyped}"/>
                                                          <a4j:commandButton id="searchItems"
                                                                             action="#{itemsSearcher.filterItems(searchPatternTyped)}"
                                                                             value="#{messages['global.ok']}" reRender="itemsFound">
                                                              <s:defaultAction/>
                                                          </a4j:commandButton>
                                                      </h:panelGrid>
                                                  </a4j:form>
                                              </rich:layoutPanel>
                                          </rich:layout>
                                      </h:panelGrid>
                                      <h:form id="itemsForm">
                                              <rich:extendedDataTable id="itemsFound" width="580px" height="400px"
                                                                      value="#{itemsSearcher.itemsFound}" var="currentItem"
                                                                      selectionMode="multi"  tableState="#{someVar}">
                                                  <rich:column label="id">
                                                      <f:facet name="header"><h:outputText value="#{messages['item.id']}"/></f:facet>
                                                      <h:outputText value="#{currentItem.id}"/>
                                                  </rich:column>
                                                  <rich:column label="desc" filterBy="#{currentItem.description}" filterEvent="onkeyup">
                                                      <f:facet name="header"><h:outputText value="#{messages['item.description']}"/></f:facet>
                                                      <h:outputText value="#{currentItem.description}"/>
                                                  </rich:column>
                                                  <rich:column label="price" filterBy="#{currentItem.price}" filterEvent="onkeyup">
                                                      <f:facet name="header"><h:outputText value="#{messages['item.price']}"/></f:facet>
                                                      <h:outputText value="#{currentItem.price}">
                                                      </h:outputText>
                                                  </rich:column>
                                              </rich:extendedDataTable>
                                              <rich:datascroller align="left" for="itemsFound" maxPages="10"/>
                                      </h:form>



                              This really work...  


                              • 27. Re: Troubles to use datascroller and ExtendedDataModel
                                holly_bony
                                correcting the previous code...

                                public class PaginatedList<E> extends ListAdapter<E>{

                                    private ProviderPage<E> providerPage;
                                    private Page<E> currentPage;
                                    private E fistRow;
                                    private int pageSize;
                                    private int numPage;

                                    public PaginatedList(){
                                        this(null,0);
                                    }

                                    public PaginatedList(ProviderPage<E> providerPage, int pageSize){
                                        this.providerPage = providerPage;
                                        this.pageSize = pageSize;
                                        currentPage = null;
                                        fistRow = null;
                                    }

                                    public int size() {
                                        fetchFirstPage();
                                        return currentPage.getTotalRows();
                                    }

                                    public boolean isEmpty() {
                                        fetchFirstPage();
                                        return currentPage.getRows().isEmpty();
                                    }

                                    public synchronized E get(int index) {
                                        fetchFirstPage();
                                        if(index==0){
                                            return fistRow;
                                        }else{
                                            if(index>=(numPage-1)*getPageSize()&&index<numPage*getPageSize()){
                                                return currentPage.getRows().get(index-(numPage-1)*getPageSize());
                                            }else{
                                                currentPage = getProviderPage().getPage(index/getPageSize()*getPageSize(), getPageSize());
                                                numPage = index/getPageSize() + 1;
                                                return currentPage.getRows().get(index-(numPage-1)*getPageSize());
                                            }
                                        }
                                    }

                                    private void fetchFirstPage(){
                                        if(currentPage==null){
                                            currentPage = getProviderPage().getPage(0, getPageSize());
                                            numPage = 1;
                                            if(!currentPage.getRows().isEmpty()){
                                                fistRow = currentPage.getRows().get(0);
                                            }
                                        }
                                    }

                                    @Override
                                    public Iterator<E> iterator() {
                                        fetchFirstPage();
                                        return getProviderPage().getPage(0, currentPage.getTotalRows()).getRows().iterator();
                                    }

                                    /**
                                     * @return the providerPage
                                     */
                                    public ProviderPage<E> getProviderPage() {
                                        return providerPage;
                                    }

                                    /**
                                     * @param providerPage the providerPage to set
                                     */
                                    public void setProviderPage(ProviderPage<E> providerPage) {
                                        this.providerPage = providerPage;
                                    }

                                    /**
                                     * @return the pageSize
                                     */
                                    public int getPageSize() {
                                        return pageSize;
                                    }

                                    /**
                                     * @param pageSize the pageSize to set
                                     */
                                    public void setPageSize(int pageSize) {
                                        this.pageSize = pageSize;
                                    }


                                }
                                1 2 Previous Next