9 Replies Latest reply on Mar 1, 2011 10:20 PM by xtrycatchx

    Richfaces Datascroler, EntityQuery and pagination

      Last time i was trying to use rich:dataTable, rich:datascroller with large tables and I want to use for this EntityQuery and do some pagination.


      I asume that i need some custom DataModel extending  org.ajax4jsf.model.ExtendedDataModel (thanks to this post 'Here is a Richfaces Ajax Datascroler and Seam Example'.


      So here it is - my solution:



      import java.io.IOException;
      import java.io.Serializable;
      import java.lang.reflect.Method;
      import java.lang.reflect.ParameterizedType;
      import java.util.ArrayList;
      import java.util.HashMap;
      import java.util.List;
      import java.util.Map;
      
      import javax.faces.context.FacesContext;
      
      import org.ajax4jsf.model.DataVisitor;
      import org.ajax4jsf.model.ExtendedDataModel;
      import org.ajax4jsf.model.Range;
      import org.ajax4jsf.model.SequenceRange;
      import org.jboss.seam.framework.EntityQuery;
      
      import pl.xxx.model.AbstractEntity;
      
      public abstract class EntityDataModel<T extends AbstractEntity, ID extends Serializable> extends ExtendedDataModel {
           private static final String ID_METHOD_NAME = "getId";
           
           private EntityQuery entityQuery;
           private Class<T> entityClass;
           private ID currentId;
           private Map<ID, T> wrappedData = new HashMap<ID, T>();
           private List<ID> wrappedKeys;
           
           public EntityDataModel() {
               //entityClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
                Class clazz = getClass();
                while(!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {
                     clazz = clazz.getSuperclass();
                }
                entityClass = (Class<T>) ((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0];
          }
           
           public void setEntityQuery(EntityQuery entityQuery) {
                this.entityQuery = entityQuery;
           }
           
           @Override
           public Object getRowKey() {
                return currentId;
           }
      
           /*
            * This method normally called by Visitor before request Data Row.
            */
           @Override
           public void setRowKey(Object key) {
                currentId = (ID)key;
           }
      
           @Override
           public void walk(FacesContext fCtx, DataVisitor visitor, Range range, Object argument)
           throws IOException {
                int firstResult = ((SequenceRange)range).getFirstRow();
                int maxResults = ((SequenceRange)range).getRows();
      
                entityQuery.setFirstResult(firstResult);
                entityQuery.setMaxResults(maxResults);
                List<T> list = entityQuery.getResultList();
                
                wrappedKeys = new ArrayList<ID>();
                wrappedData = new HashMap<ID, T>();
                for (T row : list) {
                     ID id = getId(row);
                     wrappedKeys.add(id);
                     wrappedData.put(id, row);
                     visitor.process(fCtx, id, argument);
                }               
           }
      
           @Override
           public int getRowCount() {
                return entityQuery.getResultCount().intValue();
           }
      
           @Override
           public Object getRowData() {
                if (currentId == null) {
                     return null;
                } else {
                     T ret = wrappedData.get(currentId);
                     if (ret == null) {
                          ret = (T)entityQuery.getEntityManager().find(entityClass, currentId);
                          wrappedData.put(currentId, ret);
                          return ret;
                     } else {
                          return ret;
                     }
                }
           }
           
           @Override
           public int getRowIndex() {
                return 0;
           }
      
           /**
            * Unused rudiment from old JSF staff.
            */
           @Override
           public Object getWrappedData() {
                throw new UnsupportedOperationException();
           }
           
           @Override
           public boolean isRowAvailable() {
                if (currentId == null) {
                     return false;
                } else {
                     for (T row : (List<T>)entityQuery.getResultList()) {
                          ID rowId = getId(row);
                          if (rowId.equals(currentId)) {
                               return true;
                          }
                     }
                     return false;
                }          
           }
           
           /**
            * Unused rudiment from old JSF staff.
            */
           @Override
           public void setRowIndex(int newRowIndex) { }
      
           /**
            * Unused rudiment from old JSF staff.
            */
           @Override
           public void setWrappedData(Object data) {
                throw new UnsupportedOperationException();
           }
      
           private ID getId(T row) {
                ID id;
              try {
                   Method idMethod = row.getClass().getMethod(ID_METHOD_NAME, new Class[0]);
                   Class<?> idType = idMethod.getReturnType();
                   id = (ID)idMethod.invoke(row, new Object[0]);
              } catch (Exception e) {
                  throw new javax.faces.FacesException("Failed to obtain row id", e);
              }
              return id;
           }
           
      }



      Next can use this abstrac EntityDataModel for our custom entity data model like this:


      import org.jboss.seam.annotations.Create;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.framework.EntityQuery;
      
      import pl.xxx.model.User;
      
      @Name("userList")
      public class UserDataModel extends EntityDataModel<User, Long> {
           
           @In(create=true)
           private EntityQuery users;
           
           @Create
           public void create() {
                setEntityQuery(users);
           }
      }



      In components.xml we need to define our EntityQuery:


           <fwk:entity-query name="users" entity-manager="#{em}"
                ejbql="select u from User u"
                order="u.username"
                max-results="10">
                <fwk:restrictions>
                     <value>lower(u.username) like lower('%' || #{exampleUser.username})</value>
                     <value>lower(u.lastName) like lower('%' || #{exampleUser.lastName})</value>
                </fwk:restrictions>
           </fwk:entity-query>
           
           <component name="exampleUser" class="pl.xxx.model.User" scope="session"/>



      Now the users.xhtml:


          <rich:panel header="#{messages['userList.header']}">
               <h:form>
                    <h:outputLabel value="Filter by username" for="username"></h:outputLabel>
                     <h:inputText id="username" value="#{exampleUser.username}">
                          <a4j:support reRender="userList" event="onkeyup" requestDelay="1" />
                     </h:inputText>
                     <a4j:status>
                          <f:facet name="start"><h:graphicImage value="/img/spinner.gif" /></f:facet>
                     </a4j:status>              
               </h:form>
      
               <h:form>
                <rich:dataTable id="userList" value="#{userList}" var="user" rows="10">
                     <rich:column>
                          <f:facet name="header">#{messages['user.username']}</f:facet>
                          <s:link action="user">
                               <h:outputText value="#{user.username}" />
                               <f:param name="uid" value="#{user.id}" />
                          </s:link>
                     </rich:column>
                     <rich:column>
                          <f:facet name="header">#{messages['user.firstName']}</f:facet>
                          <h:outputText value="#{user.firstName}"/>
                     </rich:column>
                     <rich:column>
                          <f:facet name="header">#{messages['user.lastName']}</f:facet>
                          <h:outputText value="#{user.lastName}"/>
                     </rich:column>
                     <rich:column>
                          <f:facet name="header">#{messages['user.email']}</f:facet>
                          <h:outputText value="#{user.email}"/>
                     </rich:column>
                     <f:facet name="footer">
                          <rich:datascroller/>
                     </f:facet>               
                </rich:dataTable>
                </h:form>
                <div class="actionButtons">
                     <s:button action="user" value="#{messages['button.add']}">
                          <f:param name="uid" value=""/>
                     </s:button>
                </div>
           </rich:panel>



      I also use some ajax support for filtering data but there is one problem. Suppose i have shown all users and i'm on the last page. After doing some filtering datascroller is not reacting properly on the data range change. I don't know how to fix this.


      What do you think about this solution?


      Jarek

        • 1. Re: Richfaces Datascroler, EntityQuery and pagination
          enda

          Looks good,


          I just would like there sorting. I do not think that it possible with Map.


          I think that Trinidad table has good solution to that with their
          CollectionModel and SortableModel


          Were you thinking about it too?


          Tomas

          • 2. Re: Richfaces Datascroler, EntityQuery and pagination

            You can parametrize the user entity-query like this:


            
                 <fwk:entity-query name="users" entity-manager="#{em}"
            
                      ejbql="select u from User u"
            
                      order="#{userOrder}"
            
                      max-results="10">
            
                      <fwk:restrictions>
            
                           <value>lower(u.username) like lower('%' || #{exampleUser.username})</value>
            
                           <value>lower(u.lastName) like lower('%' || #{exampleUser.lastName})</value>
            
                      </fwk:restrictions>
            
                 </fwk:entity-query>
            
            



            and set userOrder properly. Of cource you have to construct some interface for this (select box or links in the table headers).


            I have to look at Trinidad tales too :)


            Regards


            Jarek

            • 3. Re: Richfaces Datascroler, EntityQuery and pagination
              loebb01

              Hi,


              that all looks fine with RichFaces 3.1.4, but with 3.2.0 the datascroller does not show any entries anymore.


              Any Ideas?


              Bye, dl

              • 4. Re: Richfaces Datascroler, EntityQuery and pagination
                loebb01

                Hi again,


                the problem seems to be that if you start sorting the table using the richfaces column feature, the data from the origin datamodel is  wrapped into a new ListSequenceDataModel in method ModifiableModel.walk. Seriously the new datamodel only contains data from the origin one before started paging.


                Without sorting everything works as expected.


                Are there any ideas to solve this in RichFaces?


                Bye, dl

                • 5. Re: Richfaces Datascroler, EntityQuery and pagination
                  kinson516

                  Daniel,
                  I face the same problem with you.
                  the ListSequenceDataModel uses Integer as rowKey type. but my row key type is Long. Is this the richfaces bug?  I post the stack.
                  If I change the return type of getRowKey to Integer. the error disppear, but when I click the sorter, no results displayed.
                  How to solve it? thanks in adcance.




                  SEVERE: Error Rendering View
                  javax.faces.convert.ConverterException: userListForm:userList: Could not convert '0' to a string.
                       at javax.faces.convert.LongConverter.getAsString(LongConverter.java:140)
                       at org.ajax4jsf.component.UIDataAdaptor.getClientId(UIDataAdaptor.java:716)
                       at javax.faces.component.UIComponent.getContainerClientId(UIComponent.java:324)
                       at javax.faces.component.UIComponentBase.getClientId(UIComponentBase.java:272)
                       at org.richfaces.renderkit.CellRenderer.doEncodeBegin(CellRenderer.java:66)
                       at org.ajax4jsf.renderkit.RendererBase.encodeBegin(RendererBase.java:101)
                       at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:788)
                       at org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:280)
                       at org.richfaces.renderkit.AbstractRowsRenderer.encodeCellChildren(AbstractRowsRenderer.java:285)
                       at org.richfaces.renderkit.AbstractTableRenderer.encodeOneRow(AbstractTableRenderer.java:313)
                       at org.richfaces.renderkit.AbstractRowsRenderer.process(AbstractRowsRenderer.java:86)
                       at org.richfaces.model.ListSequenceDataModel.walk(ListSequenceDataModel.java:70)
                       at org.richfaces.model.ModifiableModel.walk(ModifiableModel.java:118)
                       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.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.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
                       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.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
                       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
                       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
                       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
                       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
                       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
                       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)
                       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                       at java.lang.Thread.run(Thread.java:619)
                  Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
                       at javax.faces.convert.LongConverter.getAsString(LongConverter.java:138)
                       ... 65 more



                  Daniel Löbbe wrote on Jun 03, 2008 16:31:


                  Hi again,

                  the problem seems to be that if you start sorting the table using the richfaces column feature, the data from the origin datamodel is  wrapped into a new ListSequenceDataModel in method ModifiableModel.walk. Seriously the new datamodel only contains data from the origin one before started paging.

                  Without sorting everything works as expected.

                  Are there any ideas to solve this in RichFaces?

                  Bye, dl


                  Click HELP for text formatting instructions. Then edit this text and check the preview.

                  • 6. Re: Richfaces Datascroler, EntityQuery and pagination
                    davidintx.david.dsheth.com

                    I did sorting and paginating in the database using richfaces, and wrote up my experience here: 


                    link

                    • 7. Re: Richfaces Datascroler, EntityQuery and pagination
                      Hi,

                      My application is built up on JBoss5.0.0, MySQL5.1, Seam2.1.1 (EJB3.0, Hibernate3.4.0, JSF2.0, Richface3.3.0)

                      I need to display list from a table which has few million of records using rich:extendedDataTable component. For this, I do require database pagination. I came across multiple forums and blogs for the solution (mostly user's own grown solution) but couldn't get the proper and exect "Seam-way" to implement database pagination concept for rich:extendedDataTable component.

                      http://www.seamframework.org/Community/SelfwrittenDataModelAsDataModelForTruePagination
                      http://www.seamframework.org/21214.lace
                      http://www.seamframework.org/Community/RichfacesDatascrolerEntityQueryAndPagination
                      http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4112998
                      http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4060199
                      http://i-proving.ca/space/Tom+McGrady/blog
                      http://eclecticprogrammer.com/2008/07/30/a-generic-superclass-for-sorting-and-paginating-in-the-database-with-richfaces/
                      http://eclecticprogrammer.com/2008/06/25/sorting-and-paginating-in-the-database-with-richfaces/

                      Am going to buy the book "Seam Framework: Experience the Evolution of Java EE (Jboss), Second Edition - Michael Juntao Yuan". I hope to find some solution there. Meanwhile, Could anyone suggest please ?

                      Thanks in advance.
                      • 8. Re: Richfaces Datascroler, EntityQuery and pagination
                        balazska

                        Hy!


                        Did you find any suggestion for this?
                        thanks.

                        • 9. Re: Richfaces Datascroler, EntityQuery and pagination
                          xtrycatchx

                          i found an implementation of the basic datatable pagination here - http://www.adobocode.com/jsf/richfaces-datatable-pagination/