org.apache.torque.util
Class LargeSelect

java.lang.Object
  extended byorg.apache.torque.util.LargeSelect
All Implemented Interfaces:
java.lang.Runnable, java.io.Serializable

public class LargeSelect
extends java.lang.Object
implements java.lang.Runnable, java.io.Serializable

This class can be used to retrieve a large result set from a database query. The query is started and then rows are returned a page at a time. The LargeSelect is meant to be placed into the Session or User.Temp, so that it can be used in response to several related requests. Note that in order to use LargeSelect you need to be willing to accept the fact that the result set may become inconsistent with the database if updates are processed subsequent to the queries being executed. Specifying a memory page limit of 1 will give you a consistent view of the records but the totals may not be accurate and the performance will be terrible. In most cases the potential for inconsistencies data should not cause any serious problems and performance should be pretty good (but read on for further warnings).

The idea here is that the full query result would consume too much memory and if displayed to a user the page would be too long to be useful. Rather than loading the full result set into memory, a window of data (the memory limit) is loaded and retrieved a page at a time. If a request occurs for data that falls outside the currently loaded window of data then a new query is executed to fetch the required data. Performance is optimized by starting a thread to execute the database query and fetch the results. This will perform best when paging forwards through the data, but a minor optimization where the window is moved backwards by two rather than one page is included for when a user pages past the beginning of the window.

As the query is performed in in steps, it is often the case that the total number of records and pages of data is unknown. LargeSelect provides various methods for indicating how many records and pages it is currently aware of and for presenting this information to users.

LargeSelect utilises the Criteria methods setOffset() and setLimit() to limit the amount of data retrieved from the database - these values are either passed through to the DBMS when supported (efficient with the caveat below) or handled by the Village API when it is not (not so efficient). At time of writing Criteria will only pass the offset and limit through to MySQL and PostgreSQL (with a few changes to DBOracle and BasePeer Oracle support can be implemented by utilising the rownum pseudo column).

As LargeSelect must re-execute the query each time the user pages out of the window of loaded data, you should consider the impact of non-index sort orderings and other criteria that will require the DBMS to execute the entire query before filtering down to the offset and limit either internally or via Village.

The memory limit defaults to 5 times the page size you specify, but alternative constructors and the class method setMemoryPageLimit() allow you to override this for a specific instance of LargeSelect or future instances respectively.

Some of the constructors allow you to specify the name of the class to use to build the returnd rows. This works by using reflection to find addSelectColumns(Criteria) and populateObjects(List) methods to add the necessary select columns to the criteria (only if it doesn't already contain any) and to convert query results from Village Record objects to a class defined within the builder class. This allows you to use any of the Torque generated Peer classes, but also makes it fairly simple to construct business object classes that can be used for this purpose (simply copy and customise the addSelectColumns() , populateObjects(), row2Object() and populateObject() methods from an existing Peer class).

Typically you will create a LargeSelect using your Criteria (perhaps created from the results of a search parameter page), page size, memory page limit and return class name (for which you may have defined a business object class before hand) and place this in user.Temp thus:

     data.getUser().setTemp("someName", largeSelect);
 

In your template you will then use something along the lines of:

    #set ($largeSelect = $data.User.getTemp("someName"))
    #set ($searchop = $data.Parameters.getString("searchop"))
    #if ($searchop.equals("prev"))
      #set ($recs = $largeSelect.PreviousResults)
    #else
      #if ($searchop.equals("goto"))
        #set ($recs
                = $largeSelect.getPage($data.Parameters.getInt("page", 1)))
      #else
        #set ($recs = $largeSelect.NextResults)
      #end
    #end
 

...to move through the records. LargeSelect implements a number of convenience methods that make it easy to add all of the necessary bells and whistles to your template.

Version:
$Id: LargeSelect.java,v 1.13 2003/08/25 16:33:23 henning Exp $
Author:
John D. McNally, Scott Eade
See Also:
Serialized Form

Field Summary
private  int blockBegin
          The record number of the first record in memory.
private  int blockEnd
          The record number of the last record in memory.
private  Criteria criteria
          The criteria used for the query.
private  int currentlyFilledTo
          How much of the memory block is currently occupied with result data.
private  int currentPageNumber
          The number of the page that was last retrieved.
private  java.lang.String dbName
          The database name to get from Torque.
static int DEFAULT_MEMORY_LIMIT_PAGES
          The default value for the maximum number of pages of data to be retained in memory - you can provide your own default value using setMemoryPageLimit().
static java.lang.String DEFAULT_MORE_INDICATOR
          The default value (">") used to indicate that the total number of records or pages is unknown.
private  boolean killThread
          A flag used to kill the thread when the currently executing query is no longer required.
private  java.util.List lastResults
          The last page of results that were returned.
private static org.apache.commons.logging.Log log
          Logging
private  int memoryLimit
          The maximum number of records to maintain in memory.
private static int memoryPageLimit
           
private static java.lang.String moreIndicator
           
private  int pageSize
          The number of records that a page consists of.
private  java.util.Hashtable params
          A place to store search parameters that relate to this query.
private  java.lang.reflect.Method populateObjectsMethod
          A reference to the method in the return builder class that will convert the Village Records to the desired class.
private  int position
          The cursor position in the result set.
private  com.workingdogs.village.QueryDataSet qds
          Used to retrieve query results from Village.
private  java.lang.String query
          The SQL query that this LargeSelect represents.
private  boolean queryCompleted
          An indication of whether or not the current query has completed processing.
private  java.util.List results
          The memory store of records.
private  java.lang.Class returnBuilderClass
          The class that is possibly used to construct the criteria and used to transform the Village Records into the desired OM or business objects.
private  java.lang.Thread thread
          The thread that executes the query.
private  boolean threadRunning
          A flag that indicates whether or not the query thread is running.
private  int totalPages
          The total number of pages known to exist.
private  int totalRecords
          The total number of records known to exist.
private  boolean totalsFinalized
          An indication of whether or not the totals (records and pages) are at their final values.
 
Constructor Summary
LargeSelect(Criteria criteria, int pageSize)
          Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize Village Record objects at a time, maintaining a maximum of LargeSelect.memoryPageLimit pages of results in memory.
LargeSelect(Criteria criteria, int pageSize, int memoryPageLimit)
          Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize Village Record objects at a time, maintaining a maximum of memoryPageLimit pages of results in memory.
LargeSelect(Criteria criteria, int pageSize, int memoryPageLimit, java.lang.String returnBuilderClassName)
          Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize objects of the type defined within the class named returnBuilderClassName at a time, maintaining a maximum of memoryPageLimit pages of results in memory.
LargeSelect(Criteria criteria, int pageSize, java.lang.String returnBuilderClassName)
          Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize objects of the type defined within the class named returnBuilderClassName at a time, maintaining a maximum of LargeSelect.memoryPageLimit pages of results in memory.
 
Method Summary
 int getCurrentPageNumber()
          Retrieve the number of the current page.
 java.util.List getCurrentPageResults()
          Provide access to the results from the current page.
 int getCurrentPageSize()
          Provides a count of the number of rows to be displayed on the current page - for the last page this may be less than the configured page size.
 int getFirstRecordNoForPage()
          Provide the record number of the first row included on the current page.
 int getLastRecordNoForPage()
          Provide the record number of the last row included on the current page.
static int getMemoryPageLimit()
          Retrieves the multiplier that will be used to compute the memory limit when a constructor with no memory page limit is used - the memory limit will be this number multiplied by the page size.
static java.lang.String getMoreIndicator()
          Retrieve the more pages/records indicator.
 java.util.List getNextResults()
          Gets the next page of rows.
 boolean getNextResultsAvailable()
          Indicates if further result pages are available.
 java.util.List getPage(int pageNumber)
          Retrieve a specific page, if it exists.
 java.lang.String getPageProgressText()
          A convenience method that provides text showing progress through the selected rows on a page basis.
 int getPageSize()
          Retrieve the page size.
 boolean getPaginated()
          Provide an indication of whether or not paging of results will be required.
 java.util.List getPreviousResults()
          Gets the previous page of rows.
 boolean getPreviousResultsAvailable()
          Indicates if previous results pages are available.
 java.lang.String getRecordProgressText()
          A convenience method that provides text showing progress through the selected rows on a record basis.
private  java.util.List getResults(int start)
          Gets a page of rows starting at a specified row.
private  java.util.List getResults(int start, int size)
          Gets a block of rows starting at a specified row and containing a specified number of rows.
 java.lang.String getSearchParam(java.lang.String name)
          Retrieve a search parameter.
 java.lang.String getSearchParam(java.lang.String name, java.lang.String defaultValue)
          Retrieve a search parameter.
 int getTotalPages()
          Retrieve the total number of pages of search results that are known to exist (this will be the actual value when the query has completeted (see getQyeryCompleted()).
 int getTotalRecords()
          Retrieve the total number of search result records that are known to exist (this will be the actual value when the query has completeted (see getTotalsFinalized()).
 boolean getTotalsFinalized()
          Provide access to indicator that the total values for the number of records and pages are now accurate as opposed to known upper limits.
 boolean hasResultsAvailable()
          Indicates if any results are available.
private  void init(Criteria criteria, int pageSize, int memoryLimitPages)
          Called by the constructors to start the query.
 void invalidateResult()
          Clear the query result so that the query is reexecuted when the next page is retrieved.
 void removeSearchParam(java.lang.String name)
          Remove a value from the search parameters.
 void run()
          A background thread that retrieves the rows.
static void setMemoryPageLimit(int memoryPageLimit)
          Sets the multiplier that will be used to compute the memory limit when a constructor with no memory page limit is used - the memory limit will be this number multiplied by the page size.
static void setMoreIndicator(java.lang.String moreIndicator)
          Provide a way of changing the more pages/records indicator.
 void setSearchParam(java.lang.String name, java.lang.String value)
          Set a search parameter.
private  void startQuery(int initialSize)
          Starts a new thread to retrieve the result set.
private  void stopQuery()
          Used to stop filling the memory with the current block of results, if it has been determined that they are no longer relevant.
 java.lang.String toString()
          Provide something useful for debugging purposes.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

pageSize

private int pageSize
The number of records that a page consists of.


memoryLimit

private int memoryLimit
The maximum number of records to maintain in memory.


blockBegin

private int blockBegin
The record number of the first record in memory.


blockEnd

private int blockEnd
The record number of the last record in memory.


currentlyFilledTo

private volatile int currentlyFilledTo
How much of the memory block is currently occupied with result data.


query

private java.lang.String query
The SQL query that this LargeSelect represents.


dbName

private java.lang.String dbName
The database name to get from Torque.


qds

private com.workingdogs.village.QueryDataSet qds
Used to retrieve query results from Village.


results

private java.util.List results
The memory store of records.


thread

private java.lang.Thread thread
The thread that executes the query.


killThread

private volatile boolean killThread
A flag used to kill the thread when the currently executing query is no longer required.


threadRunning

private volatile boolean threadRunning
A flag that indicates whether or not the query thread is running.


queryCompleted

private volatile boolean queryCompleted
An indication of whether or not the current query has completed processing.


totalsFinalized

private boolean totalsFinalized
An indication of whether or not the totals (records and pages) are at their final values.


position

private int position
The cursor position in the result set.


totalPages

private int totalPages
The total number of pages known to exist.


totalRecords

private int totalRecords
The total number of records known to exist.


currentPageNumber

private int currentPageNumber
The number of the page that was last retrieved.


criteria

private Criteria criteria
The criteria used for the query.


lastResults

private java.util.List lastResults
The last page of results that were returned.


returnBuilderClass

private java.lang.Class returnBuilderClass
The class that is possibly used to construct the criteria and used to transform the Village Records into the desired OM or business objects.


populateObjectsMethod

private java.lang.reflect.Method populateObjectsMethod
A reference to the method in the return builder class that will convert the Village Records to the desired class.


DEFAULT_MORE_INDICATOR

public static final java.lang.String DEFAULT_MORE_INDICATOR
The default value (">") used to indicate that the total number of records or pages is unknown. You can use setMoreIndicator() to change this to whatever value you like (e.g. "more than").

See Also:
Constant Field Values

moreIndicator

private static java.lang.String moreIndicator

DEFAULT_MEMORY_LIMIT_PAGES

public static final int DEFAULT_MEMORY_LIMIT_PAGES
The default value for the maximum number of pages of data to be retained in memory - you can provide your own default value using setMemoryPageLimit().

See Also:
Constant Field Values

memoryPageLimit

private static int memoryPageLimit

params

private java.util.Hashtable params
A place to store search parameters that relate to this query.


log

private static org.apache.commons.logging.Log log
Logging

Constructor Detail

LargeSelect

public LargeSelect(Criteria criteria,
                   int pageSize)
            throws java.lang.IllegalArgumentException
Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize Village Record objects at a time, maintaining a maximum of LargeSelect.memoryPageLimit pages of results in memory.

Parameters:
criteria - object used by BasePeer to build the query. In order to allow this class to utilise database server implemented offsets and limits (when available), the provided criteria must not have any limit or offset defined.
pageSize - number of rows to return in one block.
Throws:
java.lang.IllegalArgumentException - if criteria uses one or both of offset and limit, or if pageSize is less than 1;

LargeSelect

public LargeSelect(Criteria criteria,
                   int pageSize,
                   int memoryPageLimit)
            throws java.lang.IllegalArgumentException
Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize Village Record objects at a time, maintaining a maximum of memoryPageLimit pages of results in memory.

Parameters:
criteria - object used by BasePeer to build the query. In order to allow this class to utilise database server implemented offsets and limits (when available), the provided criteria must not have any limit or offset defined.
pageSize - number of rows to return in one block.
memoryPageLimit - maximum number of pages worth of rows to be held in memory at one time.
Throws:
java.lang.IllegalArgumentException - if criteria uses one or both of offset and limit, or if pageSize or memoryLimitPages are less than 1;

LargeSelect

public LargeSelect(Criteria criteria,
                   int pageSize,
                   java.lang.String returnBuilderClassName)
            throws java.lang.IllegalArgumentException
Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize objects of the type defined within the class named returnBuilderClassName at a time, maintaining a maximum of LargeSelect.memoryPageLimit pages of results in memory.

Parameters:
criteria - object used by BasePeer to build the query. In order to allow this class to utilise database server implemented offsets and limits (when available), the provided criteria must not have any limit or offset defined. If the criteria does not include the definition of any select columns the addSelectColumns(Criteria) method of the class named as returnBuilderClassName will be used to add them.
pageSize - number of rows to return in one block.
returnBuilderClassName - The name of the class that will be used to build the result records (may implement addSelectColumns(Criteria) and must implement populateObjects(List)).
Throws:
java.lang.IllegalArgumentException - if criteria uses one or both of offset and limit, if pageSize is less than 1, or if problems are experienced locating and invoking either one or both of addSelectColumns(Criteria) and populateObjects(List) in the class named returnBuilderClassName.

LargeSelect

public LargeSelect(Criteria criteria,
                   int pageSize,
                   int memoryPageLimit,
                   java.lang.String returnBuilderClassName)
            throws java.lang.IllegalArgumentException
Creates a LargeSelect whose results are returned as a List containing a maximum of pageSize objects of the type defined within the class named returnBuilderClassName at a time, maintaining a maximum of memoryPageLimit pages of results in memory.

Parameters:
criteria - object used by BasePeer to build the query. In order to allow this class to utilise database server implemented offsets and limits (when available), the provided criteria must not have any limit or offset defined. If the criteria does not include the definition of any select columns the addSelectColumns(Criteria) method of the class named as returnBuilderClassName will be used to add them.
pageSize - number of rows to return in one block.
memoryPageLimit - maximum number of pages worth of rows to be held in memory at one time.
returnBuilderClassName - The name of the class that will be used to build the result records (may implement addSelectColumns(Criteria) and must implement populateObjects(List)).
Throws:
java.lang.IllegalArgumentException - if criteria uses one or both of offset and limit, if pageSize or memoryLimitPages are less than 1, or if problems are experienced locating and invoking either one or both of addSelectColumns(Criteria) and populateObjects(List) in the class named returnBuilderClassName.
Method Detail

init

private void init(Criteria criteria,
                  int pageSize,
                  int memoryLimitPages)
           throws java.lang.IllegalArgumentException
Called by the constructors to start the query.

Parameters:
criteria - Object used by BasePeer to build the query. In order to allow this class to utilise database server implemented offsets and limits (when available), the provided criteria must not have any limit or offset defined.
pageSize - number of rows to return in one block.
memoryLimitPages - maximum number of pages worth of rows to be held in memory at one time.
Throws:
java.lang.IllegalArgumentException - if criteria uses one or both of offset and limit and if pageSize or memoryLimitPages are less than 1;

getPage

public java.util.List getPage(int pageNumber)
                       throws TorqueException
Retrieve a specific page, if it exists.

Parameters:
pageNumber - the number of the page to be retrieved - must be greater than zero. An empty List will be returned if pageNumber exceeds the total number of pages that exist.
Returns:
a List of query results containing a maximum of pageSize results.
Throws:
java.lang.IllegalArgumentException - when pageNo is not greater than zero.
TorqueException - if invoking the populateObjects() method runs into problems or a sleep is unexpectedly interrupted.

getNextResults

public java.util.List getNextResults()
                              throws TorqueException
Gets the next page of rows.

Returns:
a List of query results containing a maximum of pageSize reslts.
Throws:
TorqueException - if invoking the populateObjects() method runs into problems or a sleep is unexpectedly interrupted.

getCurrentPageResults

public java.util.List getCurrentPageResults()
Provide access to the results from the current page.

Returns:
a List of query results containing a maximum of pageSize reslts.

getPreviousResults

public java.util.List getPreviousResults()
                                  throws TorqueException
Gets the previous page of rows.

Returns:
a List of query results containing a maximum of pageSize reslts.
Throws:
TorqueException - if invoking the populateObjects() method runs into problems or a sleep is unexpectedly interrupted.

getResults

private java.util.List getResults(int start)
                           throws TorqueException
Gets a page of rows starting at a specified row.

Parameters:
start - the starting row.
Returns:
a List of query results containing a maximum of pageSize reslts.
Throws:
TorqueException - if invoking the populateObjects() method runs into problems or a sleep is unexpectedly interrupted.

getResults

private java.util.List getResults(int start,
                                  int size)
                           throws java.lang.IllegalArgumentException,
                                  TorqueException
Gets a block of rows starting at a specified row and containing a specified number of rows.

Parameters:
start - the starting row.
size - the number of rows.
Returns:
a List of query results containing a maximum of pageSize reslts.
Throws:
java.lang.IllegalArgumentException - if size > memoryLimit or start and size result in a situation that is not catered for.
TorqueException - if invoking the populateObjects() method runs into problems or a sleep is unexpectedly interrupted.

run

public void run()
A background thread that retrieves the rows.

Specified by:
run in interface java.lang.Runnable

startQuery

private void startQuery(int initialSize)
Starts a new thread to retrieve the result set.

Parameters:
initialSize - the initial size for each block.

stopQuery

private void stopQuery()
                throws TorqueException
Used to stop filling the memory with the current block of results, if it has been determined that they are no longer relevant.

Throws:
TorqueException - if a sleep is interrupted.

getCurrentPageNumber

public int getCurrentPageNumber()
Retrieve the number of the current page.

Returns:
the current page number.

getTotalRecords

public int getTotalRecords()
Retrieve the total number of search result records that are known to exist (this will be the actual value when the query has completeted (see getTotalsFinalized()). The convenience method getRecordProgressText() may be more useful for presenting to users.

Returns:
the number of result records known to exist (not accurate until getTotalsFinalized() returns true).

getPaginated

public boolean getPaginated()
Provide an indication of whether or not paging of results will be required.

Returns:
true when multiple pages of results exist.

getTotalPages

public int getTotalPages()
Retrieve the total number of pages of search results that are known to exist (this will be the actual value when the query has completeted (see getQyeryCompleted()). The convenience method getPageProgressText() may be more useful for presenting to users.

Returns:
the number of pages of results known to exist (not accurate until getTotalsFinalized() returns true).

getPageSize

public int getPageSize()
Retrieve the page size.

Returns:
the number of records returned on each invocation of getNextResults()/getPreviousResults().

getTotalsFinalized

public boolean getTotalsFinalized()
Provide access to indicator that the total values for the number of records and pages are now accurate as opposed to known upper limits.

Returns:
true when the totals are known to have been fully computed.

setMoreIndicator

public static void setMoreIndicator(java.lang.String moreIndicator)
Provide a way of changing the more pages/records indicator.

Parameters:
moreIndicator - the indicator to use in place of the default (">").

getMoreIndicator

public static java.lang.String getMoreIndicator()
Retrieve the more pages/records indicator.


setMemoryPageLimit

public static void setMemoryPageLimit(int memoryPageLimit)
Sets the multiplier that will be used to compute the memory limit when a constructor with no memory page limit is used - the memory limit will be this number multiplied by the page size.

Parameters:
memoryPageLimit - the maximum number of pages to be in memory at one time.

getMemoryPageLimit

public static int getMemoryPageLimit()
Retrieves the multiplier that will be used to compute the memory limit when a constructor with no memory page limit is used - the memory limit will be this number multiplied by the page size.


getPageProgressText

public java.lang.String getPageProgressText()
A convenience method that provides text showing progress through the selected rows on a page basis.

Returns:
progress text in the form of "1 of > 5" where ">" can be configured using setMoreIndicator().

getCurrentPageSize

public int getCurrentPageSize()
Provides a count of the number of rows to be displayed on the current page - for the last page this may be less than the configured page size.

Returns:
the number of records that are included on the current page of results.

getFirstRecordNoForPage

public int getFirstRecordNoForPage()
Provide the record number of the first row included on the current page.

Returns:
The record number of the first row of the current page.

getLastRecordNoForPage

public int getLastRecordNoForPage()
Provide the record number of the last row included on the current page.

Returns:
the record number of the last row of the current page.

getRecordProgressText

public java.lang.String getRecordProgressText()
A convenience method that provides text showing progress through the selected rows on a record basis.

Returns:
progress text in the form of "26 - 50 of > 250" where ">" can be configured using setMoreIndicator().

getNextResultsAvailable

public boolean getNextResultsAvailable()
Indicates if further result pages are available.

Returns:
true when further results are available.

getPreviousResultsAvailable

public boolean getPreviousResultsAvailable()
Indicates if previous results pages are available.

Returns:
true when previous results are available.

hasResultsAvailable

public boolean hasResultsAvailable()
Indicates if any results are available.

Returns:
true of any results are available.

invalidateResult

public void invalidateResult()
                      throws TorqueException
Clear the query result so that the query is reexecuted when the next page is retrieved. You may want to invoke this method if you are returning to a page after performing an operation on an item in the result set.

Throws:
TorqueException - if a sleep is interrupted.

getSearchParam

public java.lang.String getSearchParam(java.lang.String name)
Retrieve a search parameter. This acts as a convenient place to store parameters that relate to the LargeSelect to make it easy to get at them in order to repopulate search parameters on a form when the next page of results is retrieved - they in no way effect the operation of LargeSelect.

Parameters:
name - the search parameter key to retrieve.
Returns:
the value of the search parameter.

getSearchParam

public java.lang.String getSearchParam(java.lang.String name,
                                       java.lang.String defaultValue)
Retrieve a search parameter. This acts as a convenient place to store parameters that relate to the LargeSelect to make it easy to get at them in order to repopulate search parameters on a form when the next page of results is retrieved - they in no way effect the operation of LargeSelect.

Parameters:
name - the search parameter key to retrieve.
defaultValue - the default value to return if the key is not found.
Returns:
the value of the search parameter.

setSearchParam

public void setSearchParam(java.lang.String name,
                           java.lang.String value)
Set a search parameter. If the value is null then the key will be removed from the parameters.

Parameters:
name - the search parameter key to set.
value - the value of the search parameter to store.

removeSearchParam

public void removeSearchParam(java.lang.String name)
Remove a value from the search parameters.

Parameters:
name - the search parameter key to remove.

toString

public java.lang.String toString()
Provide something useful for debugging purposes.

Returns:
some basic information about this instance of LargeSelect.


Copyright © 2000-2003 Apache Software Foundation. All Rights Reserved.