2 Replies Latest reply on Mar 16, 2010 5:46 AM by afrontczak

    SerializableDataModel.walk range problem

    afrontczak

      I want to implement ExtendedD

      ataGrid with DataScroller with
      loading data from DB only for current page. I need also to use implemented in the grid sorting
      and external filtering.

       

      Unfortunatelly I couldn't find any example of such scenario. I found only examples with data taken from internal array instead
      of partially loading from DB.

       

      I implemented the solution according to example from Richfaces Demo - so I used SerializedDataModel and DataProvider.
      I encountered following problems:

       

      1) loading/reloading of the dataTable - dataModel.walk method is invoked 6 times, the first 4 invocations have Range set properly
      with first row and number of rows, but the last two have always Range from 0, and nr or rows=-1 - so all rows are read from DB instead of
      only proper range.
      2) page change on DataScroller - dataModel.walk method is invoked 2 times, Range from 0, and nr or rows=-1 - so all rows are read from DB instead of
      only proper range.
      3) sorting by any sortable column results in properly sorted whole set of items, but the table behaves the same as during loading/reloading - 6 invocations of dataModel.walk and whole set of items read

       

      Questions:

      1) Am I doing something wrong with dataLoading for dataTable page?
      2) How to get sort params from dataTable to pass them to DB query?

       

      Details of my implementation:
      1) JBoss 4.2.3, Richfaces 3.3.3CR1 (also tested on 3.3.2SR1)
      2) DataModel and DataProvider stored in statefull session bean

       

      DataModel, DataProvider and part of xhtml page sources:
      #############################################################################
      public class TestDataModel extends SerializableDataModel {
         
         private TestDataProvider dataProvider;
         private Integer currentPk;
         private Map<Integer,TestDbStoredItem> wrappedData = new HashMap<Integer,TestDbStoredItem>();
         private List<Integer> wrappedKeys = null;
         private static final long serialVersionUID = -1956179896877538628L;
         @Override
         public Object getRowKey() {
             return currentPk;
         }
         @Override
         public void setRowKey(Object key) {
             this.currentPk = (Integer) key;
         }
         @Override
         public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
             int firstRow = ((SequenceRange)range).getFirstRow();
             int numberOfRows = ((SequenceRange)range).getRows();
             wrappedKeys = new ArrayList<Integer>();
             for (TestDbStoredItem item:dataProvider.getItemsByrange(new Integer(firstRow), numberOfRows, null, true)) {
                 wrappedKeys.add(item.getPk());
                 wrappedData.put(item.getPk(), item);
                 visitor.process(context, item.getPk(), argument);
             }
         }
         @Override
         public int getRowCount() {
             return getDataProvider().getRowCount();
         }
         @Override
         public Object getRowData() {
             if (currentPk==null) {
                 return null;
             } else {
                 TestDbStoredItem ret = wrappedData.get(currentPk);
                 if (ret==null) {
                     ret = getDataProvider().getItemByKey(currentPk);
                     wrappedData.put(currentPk, ret);
                     return ret;
                 } else {
                     return ret;
                 }
             }
         }
         @Override
         public int getRowIndex() {
             throw new UnsupportedOperationException();
         }
         @Override
         public Object getWrappedData() {
             throw new UnsupportedOperationException();
         }
         @Override
         public boolean isRowAvailable() {
             if (currentPk==null) {
                 return false;
             } else {
                 return getDataProvider().hasEventByPk(currentPk);
             }
         }
         @Override
         public void setRowIndex(int rowIndex) {
          //ignore
         }
         @Override
         public void setWrappedData(Object data) {
             throw new UnsupportedOperationException();
         }
         public  SerializableDataModel getSerializableModel(Range range) {
             if (wrappedKeys!=null) {
                 return this;
             } else {
                 return null;
             }
         }
         public TestDataProvider getDataProvider() {
             return dataProvider;
         }
         public void setDataProvider(TestDataProvider dataProvider) {
             this.dataProvider = dataProvider;
         }
          @Override
          public void update() {
              //nothing to do due in readonly datamodel
          }
      }
      #############################################################################
      public class TestDataProvider implements DataProvider<TestDbStoredItem> {
          private static final long serialVersionUID = -4888516018080762650L;
          private List<TestDbStoredItem> wrappedtems = new ArrayList<TestDbStoredItem>();
          private TestStatefulBean testStatefullBean;
          public EventDataProvider(TestStatefulBean testStatefullBean) {
              this.testStatefullBean = testStatefullBean;
          }
          public boolean hasEventByPk(Integer pk) {
              for (TestDbStoredItem item : wrappedtems) {
                  if (item.getPk().equals(pk)) {
                      return true;
                  }
              }
              return false;
          }
          public List<TestDbStoredItem> getItemsByrange(Integer startPk,
                  int numberOfRows, String sortField, boolean ascending) {
              wrappedtems = testStatefullBean.getDbStoredItemsByRange(startPk,
                      numberOfRows, sortField, ascending);
              return wrappedtems;
          }
          public void update() {
              // nothing need to do
          }
          public int getRowCount() {
              return testStatefullBean.getNumberOfFilteredEvents();
          }
          @Override
          public TestDbStoredItem getItemByKey(Object key) {
              TestDbStoredItem item = null;
              if (key != null) {
                  for (TestDbStoredItem itemTmp : wrappedtems) {
                      if (itemTmp.getPk().equals(key)) {
                          item = itemTmp;
                      }
                  }
                  if (item == null) {
                      item = testStatefullBean
                              .getDbStoredItemByPK(Integer.parseInt(key.toString()));
                  }
              }
              return item;
          }
          @Override
          public List<TestDbStoredItem> getItemsByRange(int firstRow, int endRow) {
              //not used
              return new ArrayList<TestDbStoredItem>();
          }
          @Override
          public Object getKey(TestDbStoredItem item) {
              return item.getPk();
          }
      }
      #############################################################################
      <rich:extendedDataTable id="sequencesTable" var="item"
          rowKeyVar="rkv"
          value="#{backing_guiListVotingSeq.eventDataModel}"
          tableState="#{backing_guiListVotingSeq.sequencesTableState}"
          selection="#{backing_guiListVotingSeq.activeSequenceSelection}"
          selectionMode="single" width="870px" height="385px" rows="12">
          <a4j:support event="ondblclick" ajaxSingle="true"
              process="sequencesTable"
              action="#{backing_guiListVotingSeq.sequenceRowDblClick_action}"
              eventsQueue="ajaxEventQueue" ignoreDupResponses="true"
              requestDelay="500" />
          <a4j:support event="onselectionchange" ajaxSingle="true"
              actionListener="#{backing_guiListVotingSeq.activeSequenceSelectionChanged}"
              process="sequencesTable" reRender="messagesTable,locations"
              eventsQueue="ajaxEventQueue" ignoreDupResponses="true"
              requestDelay="500" />
          <rich:column sortable="false" label="" width="50px">
              <h:selectBooleanCheckbox value="#{item.selected}"
                  onclick="checkBoxClick(this,#{item.pk})" />
          </rich:column>
          <rich:column sortable="true" sortBy="#{item.pk}"
              sortOrder="#{backing_guiListVotingSeq.tableVotingsOrderingId}"
              label="#{extMsg['voting.gui.id']}" width="75px">
              <f:facet name="header">
                  <h:outputText value="#{extMsg['voting.gui.id']}" />
              </f:facet>
              <h:outputText value="#{item.pk}" />
          </rich:column>
          <rich:column sortable="true" sortBy="#{item.event.name}"
              sortOrder="#{backing_guiListVotingSeq.tableVotingsOrderingName}"
              label="#{msg['voting.VotingSequence.name']}" width="350px">
              <f:facet name="header">
                  <h:outputText value="#{msg['voting.VotingSequence.name']}" />
              </f:facet>
              <h:outputText value="#{item.event.name}"
                  styleClass="normalWrappedText" />
          </rich:column>

       

          <f:facet name="footer">
              <rich:datascroller id="seqTableDatascroller" align="left"
                  maxPages="20"
                  page="#{backing_guiListVotingSeq.eventTableScrollerPage}"
                  reRender="messagesTable,locations"
                  actionListener="#{backing_guiListVotingSeq.sequencesTablePageChanged}" />
          </f:facet>
      </rich:extendedDataTable>