What I have seen done is to have an object store the query information,
including sorting options, in an object, along with a transient (so that
during failover, it gets regenerated) index, and a NON-transient
include/exclude selection list (ie either items that are included are
listed, or items that are excluded are listed, depending on how the UI
buttons are used.)  The index is typically an array of long primary key
values.  Other PK types are possible, but longs are by far the most common.
Then, on each page request, a query is made of the form:
select X from Y where Y.PK in {a,b,c,d,e,f,...}
This query can either be generated dynamically or kept as a transient
prepared statement.
If this is done carefully, then the data can come from a variety of
sources, and can have plugin interfaces for the primary key list and the
paging information.  Then, taglibs can be used of the form:

<tr> <pageHeader name="pagedObjectName" allowSort="true" column="X">Column
Header</pageHeader> </tr>
<iterate name="pagedObjectName" attribute="pageIterator"  child="lineItem">
    <tr> <td><getProperty name="lineItem" property="x"></td> </tr>
</iterate>

<nextButton name="pagedObjectName" />  <prevButton name="pagedObjectName"
/>

With a very few custom tags, this can be used to generate paging quite
effectively, while allowing selection and sorting.  Note that the sorting
requires re-generating the index list, but does not require regenrating the
selection list.

As well, for very large lists, the index generator method can be replaced
with a custom generator that pages the index list as well as the sub pages
(ie get at most 5000 hits at once, page through 100 of those at a time,
when "next" is selected, at the 5000 page boundary, load the next 5000
items.)
This system will work either with direct DB access, or going through EJB's.
I don't recommend EJB's for a high performance system, but it works fine
for lower volumes, or for initial proof of concept.   For higher volumes,
it can still work with EJB's if the EJB implements a bulk get/set operation
instead of individual item operations, or if one carefully writes the EJB
code in such a fashion as to allow access either via the EJB, or via custom
calls that create the select statements and generate return elements (this
second method was how I have seen it done - it worked very well, and
ensured that there was only one way to load any given value object into
memory, albeit via two different interfaces.)

I have seen systems that load all the data into memory, and it is very
slow.  I've also seen ones that load on each page call.  The problem with
those ones is that getting further into the list becomes slower and slower.
As well, going forward/back doesn't necessarily return the same page.  It
also doesn't support end very well.  The system presented here works
extremely well, both for paged and non-paged data, is relatively fast, and
interoperates with existing tags extremely well.  Even when used without
tags, it still works quite nicely.  Unfortunately, I don't have an
implementation of it to donate.  I might write one within a couple of
months, but I'm still discussing with my boss about when/how to contribute
internal source for external use.

Bill Wallace

(716) 214-8872
Fax: (716) 295-4718
Element K
'the knowledge catalyst'
www.elementk.com


                                                                                       
       
                    "Brian                                                             
       
                    Cochran"             To:     "Struts Developers List"              
       
                    <brian@bricom        <[EMAIL PROTECTED]>               
       
                    .com>                cc:                                           
       
                                                                                       
       
                    11/15/01             Subject:     Other possible tools  for paging 
       
                    06:31 PM             collections                                   
       
                    Please                                                             
       
                    respond to                                                         
       
                    "Struts                                                            
       
                    Developers                                                         
       
                    List"                                                              
       
                                                                                       
       
                                                                                       
       




Writing paging (i.e. next, previous, etc) iterators can be a real pain to
do
correctly (at least it is for me).
 Looking at the petstore, they seem to wuss out on doing it nice. It
occured
to me that there are a few options as far as doing iteration over pages.

1) retrieve all results and keep them in memory (in a session var i guess)
while the user pages through them.
2) go to the db every time.

3) JDBC 2.0 allows scrollable recordsets so you could have time-out-able
recordsets that essentially close themselves
   on a time expiration and may reopen themselves if needed.  (May be some
nasty concurrency problems with this)

4) create a hybrid that will cache some of the pages and go to the database
if needed. Maybe be able to configure
   the number of pages to cache. Really cool would be able to change it
dynamically.

5) somebody elses neat idea


But whatever is used there is the basic principle of getEntities(int index,
int span). So what do you guys think about
a series of paging iterators that looked something like this.

   abstract class PagingIterator
            abstract List getEntities(int startIndex, int span)
       int getPage()
       void setPage(int page)
       boolean hasNextPage()
       void nextPage()
       boolean hasPreviousPage()
       void previousPage()

   class RequeryPagingIterator extends PagingIterator  // like the petstore
           abstract List getEntities(int startIndex, int span)


   class CacheingPagingIterator extends PaginingIterator // good for a lot
of smaller datasets
      List _AllEntities = null;
           List getEntities(int startIndex, int span){
           if(_AllEntities == null){
                               getAllEntities();
                 }
              int stopIndex = max(startIndex + span, _AllEntities.size() -
1);
         return _AllEntites.subList(startIndex, stopIndex);

           }

   class MultiplePageCachingPagingIterator extends PagingIterator // great
little combination
           ...

   class ResultSetPagingIterator extends PagingIterator { // little new to
JDBC 2 so not sure bout this (suggestions)
      ... // used with JDBC 2.0
   }

The cool thing is the tags on the JSP's all work with PagingIterator so
there is no need for the page to know how
the paging is implemented.

Some other things. Currently i have a messy implementation of this running
inside struts. Works ok. but basically some
of the challenges include
 1) knowing when the query is new and when its navigation. currently I
check
for the presense of a navigate in
    the request params.
 2) where and when to stash the iterator. Currently I'm stashing it in the
session using some other custom tags.
 3) should the getEntities thing be done as an interface instead of an
abstract method? e.g
           new SomePagingIterator(ChunkableRetriever c) where
ChunkableRetriever has
a method getEntities(int start, int span)

 3) how do you cleanly handle errors (I suck at error handeling in JSPs)



Here's an example how its being used.

 ItemsByCategoryPagingIterator extends RequeryPagingIterator {
      String _CategoryId = null;

      Collection getEntities(int start, int span) throws SomeException {
                Collection col = null;
           try {
              col = itemsHome.findByCategoryId(getCategoryId());
                }catch(BusinessException e){
              throw new SomeException(e.getMessage());
                }
           return col;
           }
 }

Then i have some definition code that initiates sets all the properties
(categoryId in the above example)
and then sends it off to the jsp to do its navigation.

There is also
<list:chunk iterator="wheretheiteratorisstashed" collectionTarget="items"
navigate="<%= navoption from request %>" >
  <logic:iterate id="eachitem" name="items">
    present the properties of eachitem
  </logic:iterate>
  <list:previous>something to display if there is a previous
(link)</list:previous>
  <list:next>something to display if there is a next (link) </list:next>

</list:chunk>

Disclaimer:
 I am not an architecht. Moreover, I am just out of college and still wet
behind the ears, but I would be glad to help
out with this. I would love to hear what you guys think.


Thanks a bunch in advance and keep up the great work.
Brian








--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]
>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]
>






--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to