4 Replies Latest reply on Jul 12, 2010 6:07 PM by jabailo

    ExtendedDataModel and rich:dataScroller

      Hi,

      I'm using the ExtendedDataModel with rich:dataScroller and rich:dataTable to display data. To do this, I've adapted the example below to suit my needs:

      http://jboss.com/index.html?module=bb&op=viewtopic&t=125952

      My pagination/lazy-loading is performing much slower than I had hoped. One thing I notice, is there are two calls to walk() (and thus, two db hits) every time I use the dataScroller to go to the next page. For example, if I'm on page 1 displaying 10 items/page and click page 2... the first call to walk() queries the db for the old values (rows 0-9) and the second call to walk() queries the db for the new values (rows 10-19). The calls appear to be happening in the ApplyRequestValues and RenderResponse phases, respectively.

      Why is the db queried in the ApplyRequestValues phase? Shouldn't that data already be loaded into memory? It's a real performance drain on my app, is there anything I can do? Is this just expected?

      I can provide stack traces for the calls to walk() if that would be helpful.

      Thanks.

        • 1. Re: ExtendedDataModel and rich:dataScroller

          Anyone have any ideas?

          • 2. Re: ExtendedDataModel and rich:dataScroller

            I can only guess so check:

            scope of your bean (should be session to keep your data stored - in case to return to an already view page the data should be loaded from bean not from the database).

            also take care your walk method onyl access db once for each page
            the isRowAvailable Method should NOT access the database the getRowData Method should NOT access the database too... (only in cases no data is existing but data should always exist becase walk() is called first an fetches the data before the other methods are called


            If it does not help post you complete bean for a better analysis. It depends how you implement your methods...


            • 3. Re: ExtendedDataModel and rich:dataScroller
              alvarot

              hello
              this is my code

              /*
               * To change this template, choose Tools | Templates
               * and open the template in the editor.
               */
              package com.redi5.backingbean.sortableTableBean;
              
              import java.io.IOException;
              import java.math.BigDecimal;
              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.Range;
              import org.ajax4jsf.model.SequenceRange;
              import org.ajax4jsf.model.ExtendedDataModel;
              import org.apache.log4j.Logger;
              import com.redi5.util.LogFactory;
              import java.io.Serializable;
              
              /**
               *
               * @author alvaro
               */
              public class ExtendListDataModel extends ExtendedDataModel implements Serializable {
              
               private static Logger log = LogFactory.getLogger(ExtendListDataModel.class);
              
               private boolean detached = false;
               private Integer currentPk;
               private Map wrappedData = new HashMap();
               private List<Integer> wrappedKeys = null;
               private ExtendedFetchList fetchList = null;
               private int rowIndex;
               private static final long serialVersionUID = 1L;
               /* (non-Javadoc)
               * @see org.ajax4jsf.model.SerializableDataModel#update()
               */
              
              
               /* (non-Javadoc)
               * @see org.ajax4jsf.model.ExtendedDataModel#getRowKey()
               */
              
               @Override
               public Object getRowKey() {
              // TODO Auto-generated method stub
               return currentPk;
               }
               /* (non-Javadoc)
               * @see org.ajax4jsf.model.ExtendedDataModel#setRowKey(java.lang.Object)
               */
              
               @Override
               public void setRowKey(Object key) {
              // TODO Auto-generated method stub
               this.currentPk = (Integer) key;
               }
               /* (non-Javadoc)
               * @see org.ajax4jsf.model.ExtendedDataModel#walk(javax.faces.context.FacesContext, org.ajax4jsf.model.DataVisitor, org.ajax4jsf.model.Range, java.lang.Object)
               */
              
               @Override
               public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
               int firstRow = ((SequenceRange) range).getFirstRow();
               int numberOfRows = ((SequenceRange) range).getRows();
              
               if (detached) { // Is this serialized model
              // Here we just ignore current Rage and use whatever data was saved in serialized model.
              // Such approach uses much more getByPk() operations, instead of just one request by range.
              // Concrete case may be different from that, so you can just load data from data provider by range.
              // We are using wrappedKeys list only to preserve actual order of items.
              
               for (Integer key : wrappedKeys) {
               setRowKey(key);
               visitor.process(context, key, argument);
               }
               } else { // if not serialized, than we request data from data provider
               log.info("se calcula los datos en walk");
               wrappedKeys = new ArrayList();
               for (Object obj : fetchList.fetchList(firstRow, numberOfRows)) {
               log.info("se calcula datps para "+fetchList.getPk(obj)+" "+obj);
               wrappedKeys.add(fetchList.getPk(obj));
               wrappedData.put(fetchList.getPk(obj), obj);
               visitor.process(context, fetchList.getPk(obj), argument);
               }
               }
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#getRowCount()
               */
              
               @Override
               public int getRowCount() {
              // TODO Auto-generated method stub
              //return fetchList.getListSize();
               return fetchList.getMaxListSize();
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#getRowData()
               */
              
               @Override
               public Object getRowData() {
              // TODO Auto-generated method stub
               if (currentPk == null) {
               return null;
               } else {
               Object ret = wrappedData.get(currentPk);
               return ret;
               }
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#getRowIndex()
               */
              
               @Override
               public int getRowIndex() {
              // TODO Auto-generated method stub
              //throw new UnsupportedOperationException();
               return rowIndex;
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#getWrappedData()
               */
              
               @Override
               public Object getWrappedData() {
              // TODO Auto-generated method stub
               throw new UnsupportedOperationException();
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#isRowAvailable()
               */
              
               @Override
               public boolean isRowAvailable() {
              // TODO Auto-generated method stub
               if (currentPk == null) {
               return false;
               } else {
               return wrappedData.containsKey(currentPk);
               }
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#setRowIndex(int)
               */
              
               @Override
               public void setRowIndex(int arg0) {
              // TODO Auto-generated method stub
              //throw new UnsupportedOperationException();
               rowIndex = arg0;
               return;
               }
               /* (non-Javadoc)
               * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
               */
              
               @Override
               public void setWrappedData(Object arg0) {
              // TODO Auto-generated method stub
               throw new UnsupportedOperationException();
               }
              
              
              
               /**
               * @return the fetchList
               */
               public ExtendedFetchList getFetchList() {
               return fetchList;
               }
              
              
               /**
               * @param fetchList the fetchList to set
               */
               public void setFetchList(ExtendedFetchList fetchList) {
               log.info("seteando el fetchlist");
               this.fetchList = fetchList;
               }
              }
              


              /*
               * To change this template, choose Tools | Templates
               * and open the template in the editor.
               */
              package com.redi5.backingbean.sortableTableBean;
              
              import java.io.Serializable;
              import com.redi5.util.LogFactory;
              import org.apache.log4j.Logger;
              
              /**
               *
               * @author alvaro
               */
              public class RichReofferListModel implements Serializable {
              
               private static Logger log = LogFactory.getLogger(RichReofferListModel.class);
              
              
               private ExtendedFetchList fetchList;
               private static final long serialVersionUID = 102136548978979L;
               private ExtendListDataModel exampleList = new ExtendListDataModel();
               /**
               * @return the exampleList
               */
               public ExtendListDataModel getExampleList() {
               return exampleList;
               }
              
               /**
               * @param exampleList the exampleList to set
               */
               public void setExampleList(ExtendListDataModel exampleList) {
               this.exampleList = exampleList;
               }
              
               /**
               * @return the fetchList
               */
               public ExtendedFetchList getFetchList() {
               return fetchList;
               }
              
               /**
               * @param fetchList the fetchList to set
               */
               public void setFetchList(ExtendedFetchList fetchList) {
               log.info("se setea el fetcfhlist en elreofferlistmodel");
              
               this.fetchList = fetchList;
               exampleList.setFetchList(fetchList);
               }
              }
              
              


              this is a innerclass in the backingbean
               public class ReofferFetchList implements ExtendedFetchList, Serializable {
              
               private static final long serialVersionUID = 1L;
               private int listSize;
               private int maxListSize;
              
              
               public synchronized List fetchList(int startRow, int size) {
               List list = new Vector();
               FacesContext context = FacesContext.getCurrentInstance();
              // boolean renderResponse = context.getRenderResponse();
              // if (!renderResponse)
              // return Collections.EMPTY_LIST;
              
              //call some method here to populate the list
              //For example
              
               /* if(lastIndex!=-2&& lastIndex==startRow && lastList!=null && lastList.size()>0)
               {
               log.info("ya etaba la lista "+lastList.size());
               setMaxListSize(lastSize);
               setListSize(lastListSize);
               progress=10;
               progress=20;
               progress=40;
               progress=80;
               progress=100;
              
               return lastList;
               }*/
               log.info("llamando fetchlist"+startRow+" "+size);
               progress = 30;
               progress = 60;
               list= getDataList(startRow, size);
               progress = 70;
              
              
               setListSize(list.size());
               setMaxListSize(calculateCountList());
               progress = 80;
               progress = 100;
               lastList=Arrays.asList(new Object[list.size()]);;
               log.info("se va a llenar el last list con el list"+list.size());
               Collections.copy(lastList,list);
              
               lastIndex=startRow;
               lastSize=getMaxListSize();
               lastListSize=getListSize();
               log.info("se lleno el lastList lastlist"+lastList.size()+ " ");
               return list;
               }
              
               @SuppressWarnings("unchecked")
               public Integer getPk(Object obj) {
               ReofferVO columns = (ReofferVO) obj;
               return columns.getIdReoffer();
               }
               public void update() {}
              
               public int getListSize(){
               return listSize;
               }
              
              
              
              
               public int getMaxListSize(){return maxListSize;}
              /**
              * @param listSize the listSize to set
              */
               public void setListSize(int listSize) {
               this.listSize = listSize;
               }
              /**
              * @param maxListSize the maxListSize to set
              */
               public void setMaxListSize(int maxListSize) {
               this.maxListSize = maxListSize;
               }
              
              
               }
              
              


              the jsf

               <rich:dataTable value="#{reoffermanager.listRich.exampleList}" var="item" rows="10"
               id="listRich" rowKeyVar="row" headerClass="cabecerafondoRojo" binding="#{reoffermanager.tableRich}"
              
               >
              
              
               <rich:column rowspan="2">
              
              
               <h:panelGrid columns="1">
               <!-- Tipo de inmueble: Casa, apartamento, oficina, bodega, lote, otro: con iconos -->
               <a4jr:commandButton image="#{item.propertyType=='Casa'?'../icons/house.png':'../icons/building.png'}" >
               <rich:toolTip>
               <h:outputText value="#{item.propertyType}"/>
               </rich:toolTip>
               </a4jr:commandButton>
               <!-- Venta, arriendo, otro: con iconos -->
               <a4jr:commandButton image="#{item.dealType=='Venta'?'../icons/icono_venta.png':'../icons/icono_arrienda.png'}" >
               <rich:toolTip>
               <h:outputText value="#{item.dealType}"/>
              
               </rich:toolTip>
               </a4jr:commandButton>
              
               <a4jr:commandLink actionListener="#{reoffermanager.changePreference}" id="botomPref1" reRender="pgPref">
               <h:panelGroup id="pgPref">
               <h:graphicImage value="../icons/th_Icon_star_gris.png"
               rendered="#{item.preference==null || item.preference.idConst==76}" style="border: 0;"/>
               <h:graphicImage value="../icons/th_Icon_star.png"
               rendered="#{item.preference!=null && item.preference.idConst==74}" style="border: 0;"/>
               <h:graphicImage value="../icons/cross.png"
               rendered="#{item.preference!=null && item.preference.idConst==75}" style="border: 0;"/>
               </h:panelGroup>
               <f:param value="#{row}" name="idReoffer"/>
              
               </a4jr:commandLink>
              
              
              
              
               </h:panelGrid>
               </rich:column>
              
               <!-- Foto -->
               <rich:column rowspan="2">
               <f:facet name="header">
               <h:outputText value="Foto"/>
               </f:facet>
               <h:panelGrid columns="1" id="panelGridImage" styleClass="image60px">
              
              
               <h:commandLink action="#{reoffermanager.editReofferLink}" immediate="true" rendered="#{item.idImage!=null}" styleClass="image60px">
               <a4jr:mediaOutput element="img" cacheable="false" session="request" styleClass="image60px"
               createContent="#{imageBean.paintTemporalLow}" value="#{item.idImage}" mimeType="image/*" />
              
              
              
               <f:param name="idReoffer" value="#{item.idReoffer}"/>
               </h:commandLink>
              
              
               <!-- Código i5 -->
              
               </h:panelGrid>
               </rich:column>
               <rich:column>
               <f:facet name="header">
              
               <h:panelGrid columns="2">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="Barrio" name="sortColumn"/>
               <h:outputText value="Barrio"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.suburbName}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:outputText value="Estrato"/>
               </f:facet>
               <h:outputText value="#{item.strata}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="price" name="sortColumn"/>
               <h:outputText value="Valor"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.priceFormated}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <h:outputText value="Area"/>
               <f:param value="Area" name="sortColumn"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.areaFormatted}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <h:outputText value="Valor m2"/>
               <f:param value="PriceM2" name="sortColumn"/>
               </a4jr:commandLink>
               </f:facet>
               <h:outputText value="#{item.priceM2}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="numBedRoom" name="sortColumn"/>
               <h:outputText value="N.Hab"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.numBedRoom}"/>
               </rich:column>
              
              
              
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="numBathRoom" name="sortColumn"/>
               <h:outputText value="N.Bañ"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.numBathRoomformatted}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="numGarages" name="sortColumn"/>
               <h:outputText value="N.Gar"/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value=" #{item.numGarages}"/>
               </rich:column>
               <rich:column>
               <f:facet name="header">
               <h:panelGrid columns="2">
               <a4jr:commandLink action="#{reoffermanager.orderList}" reRender="listRich,dsListRich">
               <f:param value="datePublish" name="sortColumn"/>
               <h:outputText value="Fecha Publicacion."/>
               </a4jr:commandLink>
               </h:panelGrid>
               </f:facet>
               <h:outputText value="#{item.datePublish}"/>
               </rich:column>
               <rich:column rowspan="2">
               <f:facet name="header">
               <h:outputText value="Edicion"/>
               </f:facet>
               <h:panelGrid columns="1">
               <a4jr:commandButton image="../icons/pencil.png" action="#{reoffermanager.editReoffer}" rendered="#{item.isEditable}">
               <rich:toolTip>
               <span style="white-space:nowrap">
               Editar oferta: <strong><h:outputText value="#{item.idReoffer}"/></strong>
               </span>
               </rich:toolTip>
               </a4jr:commandButton>
               <a4jr:commandButton action="#{reoffermanager.consultReoffer}" rendered="#{!item.isEditable}" immediate="true" value="Consultar"
               image="../icons/information.png"
               >
              
               <rich:toolTip>
               <span style="white-space:nowrap">
               Consultar oferta: <strong><h:outputText value="#{item.idReoffer}"/></strong>
               </span>
               </rich:toolTip>
               </a4jr:commandButton>
               <a4jr:commandButton image="../icons/logotipo_eltiempo.gif" rendered="#{item.idSource==1}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton>
               <a4jr:commandButton image="../icons/icono_elpais.gif" rendered="#{item.idSource==2}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
               <a4jr:commandButton image="../icons/logo_metrocuadrado.gif" rendered="#{item.idSource==3}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
               <a4jr:commandButton image="../icons/elheraldo_logo.gif" rendered="#{item.idSource==4}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
              
               <a4jr:commandButton image="../icons/icono_elcolombiano.gif" rendered="#{item.idSource==5}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
               <a4jr:commandButton image="../icons/fincaraiz_icono.gif" rendered="#{item.idSource==6}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
               <a4jr:commandButton image="../icons/favicon.ico" rendered="#{item.idSource==10}" >
               <rich:toolTip>
               <span style="white-space:nowrap">
               <h:outputText value="#{item.sourceName}"/>
               </span>
               </rich:toolTip>
               </a4jr:commandButton >
              
              
               <a4jr:commandButton image="../icons/phone.png" >
               <rich:toolTip >
               <t:dataList value="#{item.listResponsable}" var="res">
               <h:panelGroup>
               <h:outputText value="#{res}"/> <br/>
               </h:panelGroup>
               </t:dataList>
               </rich:toolTip>
               </a4jr:commandButton>
               </h:panelGrid>
               </rich:column>
               <rich:subTable value="#{reoffermanager.listAux}" var="list" >
               <rich:column colspan="9">
               <h:outputText value="#{item.description}"/>
              
               </rich:column>
              
              
               </rich:subTable>
               <rich:subTable value="#{reoffermanager.listAux}" var="list" >
               <rich:column colspan="12" styleClass="cabecerafondoRojo" >
              
              
               </rich:column>
              
              
               </rich:subTable>
               <!-- onMouseOver="mOver(this);" onMouseOut="mOut(this);" -->
              
              
              
               </rich:dataTable>
              
               <rich:datascroller for="listRich" ajaxSingle="false" id="dsListRich" />
              


              my problen is that the method fetchlist is called many times, around of 4 or more, the first time is before of the immediate actions. and the bd is too big and slow.
              some one know how run this class?
              org.ajax4jsf.model.ExtendedDataModel;

              thanks

              • 4. Re: ExtendedDataModel and rich:dataScroller
                jabailo

                I'm still a little lost as to what the contents of list referred to in fetchList should look like.

                 

                You load it with

                 

                 list= getDataList(startRow, size);


                But getDataList() is not described.  I am not using an RDBMS datasource that can be layered with DAO or Hibernate.

                 

                Can you simply show me the format of how the list should look using hardcoded examples?

                 

                Is it as easy as

                 

                list.add("One");

                list.add("Two");

                 

                And so on?  Or do I need a key here?  What is the requirement of my list?