You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by albartell <al...@gmail.com> on 2006/12/11 17:17:41 UTC

How are you paging large datasets?

Now that I know the datascroller component most likely will not work for my
large datasets, I am curious to know how others that are writing enterprise
level apps with MyFaces have accomplished the task.  Note that my problem
with datascroller is that you can't initialize it to be at a particular page
and have it reflect that in the hyperlinked page numbers.
 
Specifically:
 
1. How are you loading large datasets x number of records at a time into
MyFaces components? (I have figured this out using my own method which is
detailed in this forum post: http://tinyurl.com/ym2l73)
 
2. What UI component are you using to allow the user to go to the
next/previous page? Did you create your own? Is there an existing component?
 
Thanks in advance for any help,
Aaron Bartell

Re: How are you paging large datasets?

Posted by Andrew Robinson <an...@gmail.com>.
1) create a custom data model that returns the correct total number of rows,
but only loads the current page of data internally
2) use tomahawk's data scroller, but you will need to customize it & the
data table to fix the "bug" it has with not using EL expressions on set.


Lazy data model:
public class LazyDataModel<T>
  extends DataModel
{
  public final static int DEFAULT_PAGE_SIZE = 20;

  private int pageSize = DEFAULT_PAGE_SIZE;
  private List<T> items;
  private int startAt = 0;
  private int rowIndex = -1;
  private int rowCount = 0;

  public int getPageSize()
  {
    return this.pageSize;
  }

  public void setPageSize(int pageCount)
  {
    if (this.pageSize == pageCount) return;
    this.pageSize = pageCount;
    items = null;
    fireRequestLoad(Reason.PAGE_SIZE_CHANGED);
  }

  public List<T> getItems()
  {
    return this.items;
  }

  public void setItems(List<T> items)
  {
    this.items = items;
  }

  @Override
  public int getRowCount()
  {
    return this.rowCount;
  }

  public void setRowCount(int rowCount)
  {
    if (this.rowCount == rowCount) return;
    this.rowCount = rowCount;
    items = null;
    fireRequestLoad(Reason.ROW_COUNT_CHANGED);
  }

  public int getRowIndex()
  {
    return this.rowIndex;
  }

  public void setRowIndex(int rowIndex)
  {
    if (this.rowIndex == rowIndex) return;
    this.rowIndex = rowIndex;

    if (rowIndex >= 0)
    {
      int startAt = rowIndex - (rowIndex % pageSize);
      if (items == null || startAt != this.startAt)
      {
        this.startAt = startAt;
        fireRequestLoad(Reason.START_AT_CHANGED);
      }
    }

    Object data = isRowAvailable() ? getRowData() : null;
    DataModelEvent event = new DataModelEvent(this, this.rowIndex, data);

    for (DataModelListener listener : getDataModelListeners())
      listener.rowSelected(event);
  }

  public int getStartAt()
  {
    return this.startAt;
  }

  /**
   * @param startAt the startAt to set
   */
  public void setStartAt(int startAt)
  {
    if (this.startAt == startAt) return;
    this.startAt = startAt;
    fireRequestLoad(Reason.START_AT_CHANGED);
  }

  /**
   * @see javax.faces.model.DataModel#getRowData()
   */
  @Override
  public Object getRowData()
  {
    if (!isRowAvailable()) return null;
    return items.get(rowIndex - startAt);
  }

  /**
   * @see javax.faces.model.DataModel#getWrappedData()
   */
  @Override
  public Object getWrappedData()
  {
    return items;
  }

  /**
   * @see javax.faces.model.DataModel#setWrappedData(java.lang.Object)
   */
  @Override @SuppressWarnings("unchecked")
  public void setWrappedData(Object data)
  {
    items = (List<T>)data;
  }

  /**
   * @see javax.faces.model.DataModel#isRowAvailable()
   */
  @Override
  public boolean isRowAvailable()
  {
    return rowIndex >= startAt &&
      items != null && rowIndex < (items.size() + startAt);
  }

  @SuppressWarnings("unchecked")
  private void fireRequestLoad(Reason reason)
  {
    LazyDataModelLoadRequestedEvent<T> evt =
      new LazyDataModelLoadRequestedEvent<T>(this, reason);

    for (DataModelListener listener : getDataModelListeners())
      if (listener instanceof LazyDataModelListener)
        ((LazyDataModelListener)listener).onRequestLoad(evt);
  }
}

Lazy data model event:
public class LazyDataModelEvent<T>
  extends DataModelEvent
{
  private LazyDataModel<T> model;

  public LazyDataModelEvent(LazyDataModel<T> model, int index, Object data)
  {
    super(model, index, data);
    this.model = model;
  }

  /**
   * @see javax.faces.model.DataModelEvent#getDataModel()
   */
  @Override
  public LazyDataModel<T> getDataModel()
  {
    return model;
  }
}

Listener:
public interface LazyDataModelListener<T>
  extends DataModelListener
{
  public void onRequestLoad(LazyDataModelLoadRequestedEvent<T> evt);
}

Load request event:
public class LazyDataModelLoadRequestedEvent<T>
  extends DataModelEvent
{
  public enum Reason
  {
    START_AT_CHANGED,
    INDEX_CHANGED,
    PAGE_SIZE_CHANGED,
    ROW_COUNT_CHANGED,
  }

  private LazyDataModel<T> model;
  private Reason reason;

  public LazyDataModelLoadRequestedEvent(LazyDataModel<T> model,
    Reason reason)
  {
    super(model, 0, -1);
    this.model = model;
    this.reason = reason;
  }

  /**
   * @see javax.faces.model.DataModelEvent#getDataModel()
   */
  @Override
  public LazyDataModel<T> getDataModel()
  {
    return model;
  }

  public Reason getReason()
  {
    return this.reason;
  }
}

Extended data table to make sure that the "first" value always comes from
the EL binding instead of the local UIData value:
/**
 * UI Data component with functionality to
 * store values in the backing bean using EL instead
 * of in the component
 *
 * @author arobinson
 */
public class ExtendedELUIData
  extends HtmlDataTable
{
  /**
   * @see javax.faces.component.UIData#setFirst(int)
   */
  @Override
  public void setFirst(int first)
  {
    ValueBinding vb = getValueBinding("first");
    if (vb != null)
    {
      vb.setValue(getFacesContext(), first);
      return;
    }
    else
      super.setFirst(first);
  }
}



On 12/11/06, albartell <al...@gmail.com> wrote:
>
>  Now that I know the datascroller component most likely will not work for
> my large datasets, I am curious to know how others that are writing
> enterprise level apps with MyFaces have accomplished the task.  Note that my
> problem with datascroller is that you can't initialize it to be at a
> particular page and have it reflect that in the hyperlinked page numbers.
>
> *Specifically:*
>
> 1. How are you loading large datasets x number of records at a time into
> MyFaces components? (I have figured this out using my own method which is
> detailed in this forum post: *http://tinyurl.com/ym2l73*)
>
> 2. What UI component are you using to allow the user to go to the
> next/previous page? Did you create your own? Is there an existing component?
>
> Thanks in advance for any help,
> Aaron Bartell
>

Re: How are you paging large datasets?

Posted by Jeff Bischoff <jb...@klkurz.com>.
Andrew is right, you can do this fairly easily without touching the 
myfaces/tomahawk codebase. We even have a wiki page [1] on it. :)

[1] http://wiki.apache.org/myfaces/ManagingDataScrollerPage

Regards,

Jeff Bischoff
Kenneth L Kurz & Associates, Inc.

Andrew Robinson wrote:
> "using datascroller then you cannot convey starting at the middle of a
> result upon returning from another page"
> 
> Yes you can. See my code for the extended data table:
> 
>  public void setFirst(int first)
>  {
>    ValueBinding vb = getValueBinding("first");
>    if (vb != null)
>    {
>      vb.setValue(getFacesContext(), first);
>      return;
>    }
>    else
>      super.setFirst(first);
>  }
> 
> Then use EL in your data table:
> 
> <t:dataTable first="#{myBean.first}" >...
> 
> 
> There is no bug to fix, but you have to work around the fact that the
> dataScroller calls UIData.setFirst(number). By default, all JSF components,
> when invoked with a set method (and not a value binding set), store the
> local value as a member value and never check the value binding value 
> again.
> By overriding the behavior of the HtmlDataTable, you can make sure that
> calls to setFirst update the EL expression value instead of the UIData's
> member variable. So it will always use EL to determine the first row.
> 
> -Andrew
> 
> 
> On 12/11/06, albartell <al...@gmail.com> wrote:
>>
>> That is actually what I used as the basis for my code I posted in my 
>> link.
>> The problem is that scrolling functionality is not included in the 
>> example
>> so I am left to believe that he is using datascroller, and if he is using
>> datascroller then you cannot convey starting at the middle of a result
>> upon
>> returning from another page without modifying bugs in the tomahawk 
>> release
>> (per another response in this thread).
>>
>> Maybe my situation is unique in that I am trying to preposition the 
>> result
>> to a page other than the first page.
>>
>> Aaron Bartell
>>
>> -----Original Message-----
>> From: Hazem Saleh [mailto:hazem.saleh@gmail.com]
>> Sent: Monday, December 11, 2006 10:42 AM
>> To: MyFaces Discussion
>> Subject: Re: How are you paging large datasets?
>>
>> Check Cagatay solution for that problem
>>
>> http://www.jroller.com/page/cagataycivici?entry=jsf_datatable_with_custom_pa 
>>
>> ging
>> It was really a great solution.
>>
>> On 12/11/06, albartell <al...@gmail.com> wrote:
>> >
>> > Now that I know the datascroller component most likely will not work
>> > for my large datasets, I am curious to know how others that are
>> > writing enterprise level apps with MyFaces have accomplished the task.
>> > Note that my problem with datascroller is that you can't initialize it
>> > to be at a particular page and have it reflect that in the hyperlinked
>> page numbers.
>> >
>> > Specifically:
>> >
>> > 1. How are you loading large datasets x number of records at a time
>> > into MyFaces components? (I have figured this out using my own method
>> > which is detailed in this forum post: http://tinyurl.com/ym2l73)
>> >
>> > 2. What UI component are you using to allow the user to go to the
>> > next/previous page? Did you create your own? Is there an existing
>> component?
>> >
>> > Thanks in advance for any help,
>> > Aaron Bartell
>>
>>
>> -- 
>> Hazem Ahmed Saleh Ahmed
>> IBM Egypt Cairo TDC ( Technology Development Center ) WebSphere Business
>> Integration Modeler Software Engineer
>> http://www.jroller.com/page/HazemBlog
>>
>>
> 



Re: How are you paging large datasets?

Posted by Andrew Robinson <an...@gmail.com>.
"using datascroller then you cannot convey starting at the middle of a
result upon returning from another page"

Yes you can. See my code for the extended data table:

  public void setFirst(int first)
  {
    ValueBinding vb = getValueBinding("first");
    if (vb != null)
    {
      vb.setValue(getFacesContext(), first);
      return;
    }
    else
      super.setFirst(first);
  }

Then use EL in your data table:

<t:dataTable first="#{myBean.first}" >...


There is no bug to fix, but you have to work around the fact that the
dataScroller calls UIData.setFirst(number). By default, all JSF components,
when invoked with a set method (and not a value binding set), store the
local value as a member value and never check the value binding value again.
By overriding the behavior of the HtmlDataTable, you can make sure that
calls to setFirst update the EL expression value instead of the UIData's
member variable. So it will always use EL to determine the first row.

-Andrew


On 12/11/06, albartell <al...@gmail.com> wrote:
>
> That is actually what I used as the basis for my code I posted in my link.
> The problem is that scrolling functionality is not included in the example
> so I am left to believe that he is using datascroller, and if he is using
> datascroller then you cannot convey starting at the middle of a result
> upon
> returning from another page without modifying bugs in the tomahawk release
> (per another response in this thread).
>
> Maybe my situation is unique in that I am trying to preposition the result
> to a page other than the first page.
>
> Aaron Bartell
>
> -----Original Message-----
> From: Hazem Saleh [mailto:hazem.saleh@gmail.com]
> Sent: Monday, December 11, 2006 10:42 AM
> To: MyFaces Discussion
> Subject: Re: How are you paging large datasets?
>
> Check Cagatay solution for that problem
>
> http://www.jroller.com/page/cagataycivici?entry=jsf_datatable_with_custom_pa
> ging
> It was really a great solution.
>
> On 12/11/06, albartell <al...@gmail.com> wrote:
> >
> > Now that I know the datascroller component most likely will not work
> > for my large datasets, I am curious to know how others that are
> > writing enterprise level apps with MyFaces have accomplished the task.
> > Note that my problem with datascroller is that you can't initialize it
> > to be at a particular page and have it reflect that in the hyperlinked
> page numbers.
> >
> > Specifically:
> >
> > 1. How are you loading large datasets x number of records at a time
> > into MyFaces components? (I have figured this out using my own method
> > which is detailed in this forum post: http://tinyurl.com/ym2l73)
> >
> > 2. What UI component are you using to allow the user to go to the
> > next/previous page? Did you create your own? Is there an existing
> component?
> >
> > Thanks in advance for any help,
> > Aaron Bartell
>
>
> --
> Hazem Ahmed Saleh Ahmed
> IBM Egypt Cairo TDC ( Technology Development Center ) WebSphere Business
> Integration Modeler Software Engineer
> http://www.jroller.com/page/HazemBlog
>
>

RE: How are you paging large datasets?

Posted by albartell <al...@gmail.com>.
That is actually what I used as the basis for my code I posted in my link.
The problem is that scrolling functionality is not included in the example
so I am left to believe that he is using datascroller, and if he is using
datascroller then you cannot convey starting at the middle of a result upon
returning from another page without modifying bugs in the tomahawk release
(per another response in this thread).

Maybe my situation is unique in that I am trying to preposition the result
to a page other than the first page.

Aaron Bartell 

-----Original Message-----
From: Hazem Saleh [mailto:hazem.saleh@gmail.com] 
Sent: Monday, December 11, 2006 10:42 AM
To: MyFaces Discussion
Subject: Re: How are you paging large datasets?

Check Cagatay solution for that problem
http://www.jroller.com/page/cagataycivici?entry=jsf_datatable_with_custom_pa
ging
It was really a great solution.

On 12/11/06, albartell <al...@gmail.com> wrote:
>
> Now that I know the datascroller component most likely will not work 
> for my large datasets, I am curious to know how others that are 
> writing enterprise level apps with MyFaces have accomplished the task.  
> Note that my problem with datascroller is that you can't initialize it 
> to be at a particular page and have it reflect that in the hyperlinked
page numbers.
>
> Specifically:
>
> 1. How are you loading large datasets x number of records at a time 
> into MyFaces components? (I have figured this out using my own method 
> which is detailed in this forum post: http://tinyurl.com/ym2l73)
>
> 2. What UI component are you using to allow the user to go to the 
> next/previous page? Did you create your own? Is there an existing
component?
>
> Thanks in advance for any help,
> Aaron Bartell


--
Hazem Ahmed Saleh Ahmed
IBM Egypt Cairo TDC ( Technology Development Center ) WebSphere Business
Integration Modeler Software Engineer http://www.jroller.com/page/HazemBlog


Re: How are you paging large datasets?

Posted by Hazem Saleh <ha...@gmail.com>.
Check Cagatay solution for that problem
http://www.jroller.com/page/cagataycivici?entry=jsf_datatable_with_custom_paging
It was really a great solution.

On 12/11/06, albartell <al...@gmail.com> wrote:
>
> Now that I know the datascroller component most likely will not work for my
> large datasets, I am curious to know how others that are writing enterprise
> level apps with MyFaces have accomplished the task.  Note that my problem
> with datascroller is that you can't initialize it to be at a particular page
> and have it reflect that in the hyperlinked page numbers.
>
> Specifically:
>
> 1. How are you loading large datasets x number of records at a time into
> MyFaces components? (I have figured this out using my own method which is
> detailed in this forum post: http://tinyurl.com/ym2l73)
>
> 2. What UI component are you using to allow the user to go to the
> next/previous page? Did you create your own? Is there an existing component?
>
> Thanks in advance for any help,
> Aaron Bartell


-- 
Hazem Ahmed Saleh Ahmed
IBM Egypt Cairo TDC ( Technology Development Center )
WebSphere Business Integration Modeler Software Engineer
http://www.jroller.com/page/HazemBlog