1 2 Previous Next 23 Replies Latest reply on Feb 22, 2011 9:50 AM by blabno

    RichFaces Datascroller with Seam EntityQuery

    sandman202

      Is it possible to use Richface's Datascroller with Seam's EntityQuery?


      I have seen various sites with this issue raised and solutions, but these are several months old and in some cases a couple of years old.


      I do have the basic paging working, but would like to show what page I am on and how many pages exist on my search. Just adding rich:datascroller to the table doesn't work.


      Thanks,
      Scott

        • 1. Re: RichFaces Datascroller with Seam EntityQuery
          hapacur

          Yes, that works just fine.



          • In your view make sure that datatable and datascroller are enclosed in a form.

          • Don't use setMaxResults instead use the rows attribute in datatable.






          • 2. Re: RichFaces Datascroller with Seam EntityQuery
            sandman202

            Thanks Björn! It is working.

            • 3. Re: RichFaces Datascroller with Seam EntityQuery

              when i have more than 1000 records to display, the getResultList method takes very long time to retrieve the records. so, do u have any idea to solve this problem?

              • 4. Re: RichFaces Datascroller with Seam EntityQuery
                sandman202

                My suggestion would be to check your indexes and possibly adjust them. Right now, I do not have 1000 records to be displayed.

                • 5. Re: RichFaces Datascroller with Seam EntityQuery

                  Could someone please post a sample code here.  I am trying to display rich:dataScroller.  I am able to display it on top of the table, but I am not able to go through the pages.  If sample code is posted, I can cross verify with it.

                  • 6. Re: RichFaces Datascroller with Seam EntityQuery
                    sandman202

                    Here is how I am using dataScroller.




                         <a4j:form id="phoneTableForm">
                                        
                              <div class="association" id="phones">
                                             
                                     <h:outputText value="No phone number exists" 
                                            rendered="#{newUzer ? true : empty phoneList.resultList}"/>
                                                  
                                     <rich:dataTable id="phoneList" 
                                                    var="_phone"
                                                value="#{phoneList.resultList}" 
                                              rendered="#{newUzer ? false : not empty phoneList.resultList}"
                                              rows="#{optionsCache.load().maxTableRows}">
                                              
                    
                                        <rich:column rendered="#{phoneFrom eq '/role/admin/PhoneList'}">
                                             <f:facet name="header">
                                                  <s:decorate template="/layout/sort.xhtml">
                                                       <ui:param name="entityListName" value="phoneList"/>
                                                       <ui:param name="entityList" value="#{phoneList}"/>
                                                       <ui:param name="propertyLabel" value="Name"/>
                                                       <!-- doesn't support two sort fields -->
                                                       <ui:param name="propertyPath" value="uzer.name"/>
                                                  </s:decorate>
                                             </f:facet>
                                             <s:link id="view" value="#{_phone[1].name}" view="/role/admin/Uzer.xhtml" propagation="none">
                                                  <f:param name="uzerFrom" value="/role/admin/PhoneList"/>
                                                  <f:param name="selectedTab" value="PhoneTab"/>
                                              <f:param name="phoneListSort" value="phone.type"/>
                                                  <f:param name="uzerId" value="#{_phone[1].id}"/>
                                             </s:link>
                                        </rich:column>                                        
                                        
                         
                                      <rich:column>
                                             <f:facet name="header">
                                                  <s:decorate template="/layout/sort.xhtml">
                                                       <ui:param name="entityListName" value="phoneList"/>
                                                       <ui:param name="entityList" value="#{phoneList}"/>
                                                       <ui:param name="propertyLabel" value="Type"/>
                                                       <!-- doesn't support two sort fields -->                              
                                                       <ui:param name="propertyPath" value="phone.type"/>
                                                  </s:decorate>
                                             </f:facet>
                                          #{_phone[0].type}
                                        </rich:column>                    
                         
                         
                                        <rich:column>
                                             <f:facet name="header">
                                                  <s:decorate template="/layout/sort.xhtml">
                                                       <ui:param name="entityListName" value="phoneList"/>
                                                       <ui:param name="entityList" value="#{phoneList}"/>
                                                       <ui:param name="propertyLabel" value="Number"/>
                                                       <!-- doesn't support two sort fields -->
                                                       <ui:param name="propertyPath" value="phone.phoneNumber"/>
                                                  </s:decorate>
                                             </f:facet>
                                          #{_phone[0].phoneNumber}
                                        </rich:column>          
                                        
                                                   
                                       <rich:column>
                                             <f:facet name="header">
                                                  <s:decorate template="/layout/sort.xhtml">
                                                       <ui:param name="entityListName" value="phoneList"/>
                                                       <ui:param name="entityList" value="#{phoneList}"/>
                                                       <ui:param name="propertyLabel" value="Ext"/>
                                                       <!-- doesn't support two sort fields -->
                                                       <ui:param name="propertyPath" value="uzer.ext"/>
                                                  </s:decorate>
                                             </f:facet>
                                          #{_phone[0].ext}
                                      </rich:column>
                         
                                                        
                                      <rich:column>
                                          <f:facet name="header">Action</f:facet>
                                          <s:link view="#{empty from ? '/role/admin/Phone' : from}.xhtml" 
                                                 value="Select" 
                                                    id="phoneSelect">
                                                 <!-- Do not use propagation="none", because it will turn off the lookups -->                                
                                              <f:param name="phoneFrom" value="/role/admin/PhoneList"/>
                                              <f:param name="phoneId" value="#{_phone[0].id}"/>
                                          </s:link>
                                      </rich:column>
                                      
                                        <f:facet name="footer">
                                             <rich:datascroller pageIndexVar="pageIndex" pagesVar="pages" maxPages="25"/>
                                             <ui:remove>
                                             <rich:datascroller pageIndexVar="pageIndex" pagesVar="pages" boundaryControls="hide" stepControls="hide" fastControls="show">
                                                  <f:facet name="pages">
                                                       <h:outputText style="whitespace: nowrap" value="Page #{pageIndex} of #{pages}"></h:outputText>
                                                  </f:facet>
                                             </rich:datascroller>
                                             </ui:remove>
                                        </f:facet>                  
                                         
                                     </rich:dataTable>
                                   
                               </div>
                               
                    
                         </a4j:form>
                    



                    • 7. Re: RichFaces Datascroller with Seam EntityQuery
                      blabno

                      Problem with rich datascroller and EntityQuery is that datamodel provided by Seam causes entityQuery to fetch all entities and pagination happens on datascroller component. This is why your app gets slow. You need database pagination. I've written very usefull datamodel to solve this.


                      import javax.faces.model.DataModel;
                      import javax.persistence.EntityManager;
                      import java.lang.reflect.Type;
                      import java.lang.reflect.ParameterizedType;
                      import java.lang.reflect.TypeVariable;
                      
                      public class EntityQuery<T> extends org.jboss.seam.framework.EntityQuery<T> {
                      
                          private EntityQueryDataModel entityQueryDataModel;
                          private Integer currentPage;
                      
                          @Override
                          public DataModel getDataModel() {
                              if (entityQueryDataModel == null) {
                                  entityQueryDataModel = EntityQueryDataModel.getInstance(this);
                              }
                              return entityQueryDataModel;
                          }
                      
                          @Override
                          public void clearDataModel() {
                              entityQueryDataModel = null;
                          }
                      
                          public Integer getCurrentPage() {
                              return currentPage;
                          }
                      
                          public void setCurrentPage(Integer page) {
                              if (getMaxResults() != null) {
                                  setFirstResult(page * getMaxResults());
                              }
                              this.currentPage = page;
                          }
                      
                      }



                      public class EntityQueryDataModel<T, K> extends ExtendedDataModel {
                      
                          private K rowKey;
                          private EntityQuery<T> dataProvider;
                          private Field idField;
                          private Method idGetter;
                          private Map<K, T> wrappedData = new HashMap<K, T>();
                          private Class<T> itemClass;
                          private int rowCount = -1;
                          protected Log log = Logging.getLog(EntityQueryDataModel.class);
                      
                          public static EntityQueryDataModel getInstance(EntityQuery query) {
                              return new EntityQueryDataModel(query);
                          }
                      
                          @SuppressWarnings("unchecked")
                          public EntityQueryDataModel(EntityQuery<T> query) {
                              dataProvider = query;
                              this.itemClass = (Class) ((ParameterizedType) dataProvider.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
                      
                              Class iClass = itemClass;
                              do {
                                  for (Field field : iClass.getDeclaredFields()) {
                                      if (field.getAnnotation(Id.class) != null) {
                                          idField = field;
                                          break;
                                      }
                                  }
                                  iClass = iClass.getSuperclass();
                              } while (idField == null && iClass.getSuperclass() != null);
                              if (idField == null) {
                                  for (Method method : itemClass.getMethods()) {
                                      if (method.getAnnotation(Id.class) != null) {
                                          idGetter = method;
                                          break;
                                      }
                                  }
                              } else if (!Modifier.isPublic(idField.getModifiers())) {
                                  String idGetterName = "get" + idField.getName().substring(0, 1).toUpperCase() + idField.getName().substring(1);
                                  try {
                                      idGetter = itemClass.getMethod(idGetterName);
                                  } catch (NoSuchMethodException e) {
                                      throw new IllegalArgumentException("@Id annotated field " + idField.getName() + " is not public and there is no public accessor " + idGetterName);
                                  }
                              }
                              if (idField == null && idGetter == null) {
                                  throw new IllegalArgumentException("Entity must have @Id annotated property.");
                              }
                          }
                      
                          @SuppressWarnings("unchecked")
                          public void setRowKey(Object o) {
                              rowKey = (K) o;
                          }
                      
                          public Object getRowKey() {
                              return rowKey;
                          }
                      
                          public void walk(FacesContext facesContext, DataVisitor dataVisitor, Range range, Object o) throws IOException {
                              int firstRow = ((SequenceRange) range).getFirstRow();
                              int numberOfRows = ((SequenceRange) range).getRows();
                              log.trace("Walking over #1 rows from #0", firstRow, numberOfRows);
                              List<K> wrappedKeys = new ArrayList<K>();
                              if (dataProvider.getFirstResult() == null || dataProvider.getFirstResult() != firstRow) {
                                  dataProvider.setFirstResult(firstRow);
                              }
                              if (dataProvider.getMaxResults() == null || dataProvider.getMaxResults() != numberOfRows) {
                                  dataProvider.setMaxResults(numberOfRows);
                              }
                              int i = 0;
                              for (T item : dataProvider.getResultList()) {
                                  log.trace("Retrived item #0", i++);
                                  K id = getId(item);
                                  wrappedKeys.add(id);
                                  wrappedData.put(id, item);
                                  dataVisitor.process(facesContext, id, o);
                              }
                              log.trace("Walking done");
                          }
                      
                          public boolean isRowAvailable() {
                              if (getRowKey() == null) {
                                  return false;
                              } else {
                                  log.trace("Checking if row with id #0 is available", getRowKey());
                                  return null != wrappedData.get(getRowKey());
                              }
                          }
                      
                          public int getRowCount() {
                              log.trace("Getting results count");
                              if (rowCount == -1) {
                                  rowCount = dataProvider.getResultCount().intValue();
                              }
                              log.trace("Results count is #0", rowCount);
                              return rowCount;
                          }
                      
                          public Object getRowData() {
                              if (getRowKey() == null) {
                                  return null;
                              } else {
                                  T item = wrappedData.get(getRowKey());
                                  if (item == null) {
                                      log.trace("Row data for key #0 not found in cache. Retriving from data provider.", getRowKey());
                                      item = getCurrentItem();
                                      wrappedData.put((K) getRowKey(), item);
                                      return item;
                                  } else {
                                      log.trace("Row data found in cache as #0", item);
                                      return item;
                                  }
                              }
                          }
                      
                          public int getRowIndex() {
                              throw new UnsupportedOperationException();
                          }
                      
                          public void setRowIndex(int i) {
                              throw new UnsupportedOperationException();
                          }
                      
                          public Object getWrappedData() {
                              throw new UnsupportedOperationException();
                          }
                      
                          public void setWrappedData(Object o) {
                              throw new UnsupportedOperationException();
                          }
                      
                          @SuppressWarnings("unchecked")
                          private K getId(T item) {
                              try {
                                  return (K) (idGetter != null ? idGetter.invoke(item) : idField.get(item));
                              } catch (Exception e) {
                                  throw new RuntimeException(e);
                              }
                          }
                      
                          private T getCurrentItem() {
                              log.trace("Fetching current row item for key #0", getRowKey());
                              return dataProvider.getEntityManager().find(itemClass, getRowKey());
                          }
                      }



                      Now you can use it like this :


                      <rich:dataTable value="#{query.dataModel}" var="item" rows="#{personsVotes.maxResults}">
                      ...
                      <rich:datascroller page="#{query.currentPage}"/>

                      • 8. Re: RichFaces Datascroller with Seam EntityQuery
                        hitcurst

                        Thansk for solution, very good !

                        • 9. Re: RichFaces Datascroller with Seam EntityQuery
                          sandman202

                          Bernard, I implemented the code you provided and came across something strange. When I have a listing that spans multiple pages and click next to go from page 1 to page 2, it works fine. However, when I click next again to go from page 2 to page 3, it takes me back to page 1.


                          Have you run across this problem?


                          Scott

                          • 10. Re: RichFaces Datascroller with Seam EntityQuery
                            sandman202

                            I did a little more investigation and found that the individual page number buttons are working correctly. It is the next button that is causing the problems.


                            Scott

                            • 11. Re: RichFaces Datascroller with Seam EntityQuery
                              blabno

                              No, I haven't come across anything like it. Maybe there is a problem with scopes?

                              • 12. Re: RichFaces Datascroller with Seam EntityQuery
                                sandman202

                                The strange thing is on another listing where I did not make the changes above, the paging, first, last, next and previous works fine. On the listing where I was testing the above changes, the only parts not working are the next and previous. So, the reason I asked if you had noticed the same problems was I was wondering if I needed to change the next and previous code like you did to the page code.


                                My listings are using the event scope. I will try later other scope types to see if it starts working.


                                Do you think it might have to do with the version of Richfaces or Seam? I am using 2.1.1.GA Seam and 3.3.0.GA Richfaces.

                                • 13. Re: RichFaces Datascroller with Seam EntityQuery
                                  blabno

                                  Absolutely not a version problem. Try using broader scope first.

                                  • 14. Re: RichFaces Datascroller with Seam EntityQuery
                                    sandman202

                                    I changed the scope from EVENT to CONVERSATION and the results are the same.

                                    1 2 Previous Next