stephenh    2002/09/27 09:09:20

  Modified:    src/java/org/apache/torque/util LargeSelect.java
  Log:
  Newer version of LargeSelect by Scott Eade <[EMAIL PROTECTED]>.
  
  Revision  Changes    Path
  1.7       +290 -155  
jakarta-turbine-torque/src/java/org/apache/torque/util/LargeSelect.java
  
  Index: LargeSelect.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-turbine-torque/src/java/org/apache/torque/util/LargeSelect.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- LargeSelect.java  27 Jul 2002 04:55:56 -0000      1.6
  +++ LargeSelect.java  27 Sep 2002 16:09:20 -0000      1.7
  @@ -55,17 +55,21 @@
    */
   
   import java.sql.Connection;
  +import java.sql.SQLException;
   
   import java.util.List;
   import java.util.ArrayList;
  +import java.util.Hashtable;
   import java.lang.reflect.Method;
   
   import org.apache.log4j.Category;
   import org.apache.torque.Torque;
  +import org.apache.torque.TorqueException;
   import org.apache.torque.util.BasePeer;
   import org.apache.torque.util.Criteria;
   
   import com.workingdogs.village.QueryDataSet;
  +import com.workingdogs.village.DataSetException;
   
   /**
    * This class can be used to retrieve a large result set from a database query.
  @@ -180,7 +184,7 @@
       /** The record number of the last record in memory. */
       private int blockEnd;
       /** How much of the memory block is currently occupied with result data. */
  -    private int currentlyFilledTo = -1;
  +    private volatile int currentlyFilledTo = -1;
       
       /** The SQL query that this <code>LargeSelect</code> represents. */
       private String query;
  @@ -191,18 +195,25 @@
       /** Used to retrieve query results from Village. */
       private QueryDataSet qds = null;
   
  -    // I have a nagging feeling that results should be a 
  -    // Vector so that access is synchronised. (scott)
       /** The memory store of records. */
       private List results = null;
   
       /** The thread that executes the query. */
       private Thread thread = null;
  -    /** A flag used to kill the thread when the currently executing query is no 
longer required. */
  -    private boolean killThread = false;
  -    /** An indication of whether or not the current query has completed processing. 
*/
  -    private boolean queryCompleted = false;
  -    /** An indication of whether or not the totals (records and pages) are at their 
final values. */
  +    /**
  +     * A flag used to kill the thread when the currently executing query is no
  +     * longer required.
  +     */
  +    private volatile boolean killThread = false;
  +    /**
  +     * An indication of whether or not the current query has completed
  +     * processing.
  +     */
  +    private volatile boolean queryCompleted = false;
  +    /**
  +     * An indication of whether or not the totals (records and pages) are at
  +     * their final values.
  +     */
       private boolean totalsFinalized = false;
       
       /** The cursor position in the result set. */
  @@ -248,6 +259,9 @@
   
       private static int memoryPageLimit = DEFAULT_MEMORY_LIMIT_PAGES;
   
  +    /** A place to store search parameters that relate to this query. */
  +    private Hashtable params = null;
  +
       /**
        * Creates a LargeSelect whose results are returned as a <code>List</code>
        * containing a maximum of <code>pageSize</code> Village <code>Record</code>
  @@ -261,9 +275,9 @@
        * @param pageSize number of rows to return in one block.
        * @throws IllegalArgumentException if <code>criteria</code> uses one or
        * both of offset and limit, or if <code>pageSize</code> is less than 1;
  -     * @throws Exception a generic exception.
        */
  -    public LargeSelect(Criteria criteria, int pageSize) throws Exception
  +    public LargeSelect(Criteria criteria, int pageSize)
  +            throws IllegalArgumentException
       {
           this(criteria, pageSize, LargeSelect.memoryPageLimit);
       }
  @@ -284,10 +298,9 @@
        * @throws IllegalArgumentException if <code>criteria</code> uses one or
        * both of offset and limit, or if <code>pageSize</code> or
        * <code>memoryLimitPages</code> are less than 1;
  -     * @throws Exception a generic exception.
        */
       public LargeSelect(Criteria criteria, int pageSize, int memoryPageLimit)
  -        throws Exception
  +            throws IllegalArgumentException
       {
           init(criteria, pageSize, memoryPageLimit);
       }
  @@ -311,17 +324,16 @@
        * build the result records (may implement <code>addSelectColumns(Criteria)
        * </code> and must implement <code>populateObjects(List)</code>).
        * @throws IllegalArgumentException if <code>criteria</code> uses one or
  -     * both of offset and limit, or if <code>pageSize</code> is less than 1;
  -     * @throws NoSuchMethodException when a one or both of <code>
  -     * addSelectColumns(Criteria)</code> and <code>populateObjects(List)</code>
  -     * are not found in the class named <code>returnBuilderClassName</code>.
  -     * @throws Exception a generic exception.
  +     * both of offset and limit, if <code>pageSize</code> is less than 1, or if
  +     * problems are experienced locating and invoking either one or both of
  +     * <code>addSelectColumns(Criteria)</code> and <code> populateObjects(List)
  +     * </code> in the class named <code>returnBuilderClassName</code>.
        */
       public LargeSelect(
  -        Criteria criteria,
  -        int pageSize,
  -        String returnBuilderClassName)
  -        throws Exception
  +            Criteria criteria,
  +            int pageSize,
  +            String returnBuilderClassName)
  +            throws IllegalArgumentException
       {
           this(
               criteria,
  @@ -351,36 +363,45 @@
        * build the result records (may implement <code>addSelectColumns(Criteria)
        * </code> and must implement <code>populateObjects(List)</code>).
        * @throws IllegalArgumentException if <code>criteria</code> uses one or
  -     * both of offset and limit, or if <code>pageSize</code> or
  -     * <code>memoryLimitPages</code> are less than 1;
  -     * @throws NoSuchMethodException when a one or both of <code>
  -     * addSelectColumns(Criteria)</code> and <code>populateObjects(List)</code>
  -     * are not found in the class named <code>returnBuilderClassName</code>.
  -     * @throws Exception a generic exception.
  +     * both of offset and limit, if <code>pageSize</code> or <code>
  +     * memoryLimitPages</code> are less than 1, or if problems are experienced
  +     * locating and invoking either one or both of <code>
  +     * addSelectColumns(Criteria)</code> and <code> populateObjects(List)</code>
  +     * in the class named <code>returnBuilderClassName</code>.
        */
       public LargeSelect(
  -        Criteria criteria,
  -        int pageSize,
  -        int memoryPageLimit,
  -        String returnBuilderClassName)
  -        throws Exception
  -    {
  -        this.returnBuilderClass = Class.forName(returnBuilderClassName);
  -
  -        // Add the select columns if necessary.
  -        if (criteria.getSelectColumns().size() == 0)
  -        {
  -            Class[] argTypes = { Criteria.class };
  -            Method selectColumnAdder =
  -                returnBuilderClass.getMethod("addSelectColumns", argTypes);
  -            Object[] theArgs = { criteria };
  -            selectColumnAdder.invoke(returnBuilderClass.newInstance(), theArgs);
  -        }
  -
  -        // Locate the populateObjects() method - this will be used later
  -        Class[] argTypes = { List.class };
  -        populateObjectsMethod =
  -            returnBuilderClass.getMethod("populateObjects", argTypes);
  +            Criteria criteria,
  +            int pageSize,
  +            int memoryPageLimit,
  +            String returnBuilderClassName)
  +            throws IllegalArgumentException
  +    {
  +        try
  +        {
  +            this.returnBuilderClass = Class.forName(returnBuilderClassName);
  +
  +            // Add the select columns if necessary.
  +            if (criteria.getSelectColumns().size() == 0)
  +            {
  +                Class[] argTypes = { Criteria.class };
  +                Method selectColumnAdder =
  +                    returnBuilderClass.getMethod("addSelectColumns", argTypes);
  +                Object[] theArgs = { criteria };
  +                selectColumnAdder.invoke(returnBuilderClass.newInstance(),
  +                        theArgs);
  +            }
  +
  +            // Locate the populateObjects() method - this will be used later
  +            Class[] argTypes = { List.class };
  +            populateObjectsMethod =
  +                returnBuilderClass.getMethod("populateObjects", argTypes);
  +        }
  +        catch (Exception e)
  +        {
  +            throw new IllegalArgumentException(
  +                    "The class named as returnBuilderClassName does not "
  +                    + "provide the necessary facilities - see javadoc.");
  +        }
   
           init(criteria, pageSize, memoryPageLimit);
       }
  @@ -398,25 +419,26 @@
        * @throws IllegalArgumentException if <code>criteria</code> uses one or
        * both of offset and limit and if <code>pageSize</code> or
        * <code>memoryLimitPages</code> are less than 1;
  -     * @throws Exception a generic exception.
        */
       private void init(Criteria criteria, int pageSize, int memoryLimitPages)
  -        throws Exception
  +            throws IllegalArgumentException
       {
           if (criteria.getOffset() != 0 || criteria.getLimit() != -1)
           {
               throw new IllegalArgumentException(
  -                "Criteria passed to " + " must not use Offset and/or Limit.");
  +                    "criteria must not use Offset and/or Limit.");
           }
   
           if (pageSize < 1)
           {
  -            throw new IllegalArgumentException("pageSize must be greater than 
zero.");
  +            throw new IllegalArgumentException(
  +                    "pageSize must be greater than zero.");
           }
   
           if (memoryLimitPages < 1)
           {
  -            throw new IllegalArgumentException("memoryPageLimit must be greater 
than zero.");
  +            throw new IllegalArgumentException(
  +                    "memoryPageLimit must be greater than zero.");
           }
   
           this.pageSize = pageSize;
  @@ -430,23 +452,25 @@
       /**
        * Retrieve a specific page, if it exists.
        *
  -     * @param pageNumber the number of the page to be retrieved - must be greater
  -     * than zero.  An empty <code>List</code> will be returned if <code>pageNumber
  -     * </code> exceeds the total number of pages that exist.
  +     * @param pageNumber the number of the page to be retrieved - must be
  +     * greater than zero.  An empty <code>List</code> will be returned if
  +     * <code>pageNumber</code> exceeds the total number of pages that exist.
        * @return a <code>List</code> of query results containing a maximum of
        * <code>pageSize</code> results.
        * @throws IllegalArgumentException when <code>pageNo</code> is not
        * greater than zero.
  -     * @throws Exception a generic exception.
  +     * @throws TorqueException if invoking the <code>populateObjects()<code>
  +     * method runs into problems or a sleep is unexpectedly interrupted.
        */
  -    public List getPage(int pageNumber) throws Exception
  +    public List getPage(int pageNumber) throws TorqueException
       {
           if (pageNumber < 1)
           {
  -            throw new IllegalArgumentException("pageNumber must be greater than 
zero.");
  +            throw new IllegalArgumentException("pageNumber must be greater "
  +                    + "than zero.");
           }
           currentPageNumber = pageNumber;
  -        return getResults((pageNumber - 1) * pageSize, pageSize);
  +        return getResults((pageNumber - 1) * pageSize);
       }
   
       /**
  @@ -454,16 +478,17 @@
        *
        * @return a <code>List</code> of query results containing a maximum of
        * <code>pageSize</code> reslts.
  -     * @throws Exception a generic exception.
  +     * @throws TorqueException if invoking the <code>populateObjects()<code>
  +     * method runs into problems or a sleep is unexpectedly interrupted.
        */
  -    public List getNextResults() throws Exception
  +    public List getNextResults() throws TorqueException
       {
           if (!getNextResultsAvailable())
           {
               return getCurrentPageResults();
           }
           currentPageNumber++;
  -        return getResults(position, pageSize);
  +        return getResults(position);
       }
   
       /**
  @@ -482,9 +507,10 @@
        *
        * @return a <code>List</code> of query results containing a maximum of
        * <code>pageSize</code> reslts.
  -     * @throws Exception a generic exception.
  +     * @throws TorqueException if invoking the <code>populateObjects()<code>
  +     * method runs into problems or a sleep is unexpectedly interrupted.
        */
  -    public List getPreviousResults() throws Exception
  +    public List getPreviousResults() throws TorqueException
       {
           if (!getPreviousResultsAvailable())
           {
  @@ -502,7 +528,7 @@
               start = position - 2 * pageSize;
               currentPageNumber--;
           }
  -        return getResults(start, pageSize);
  +        return getResults(start);
       }
   
       /**
  @@ -511,9 +537,10 @@
        * @param start the starting row.
        * @return a <code>List</code> of query results containing a maximum of
        * <code>pageSize</code> reslts.
  -     * @throws Exception a generic exception.
  +     * @throws TorqueException if invoking the <code>populateObjects()<code>
  +     * method runs into problems or a sleep is unexpectedly interrupted.
        */
  -    public List getResults(int start) throws Exception
  +    private List getResults(int start) throws TorqueException
       {
           return getResults(start, pageSize);
       }
  @@ -526,20 +553,22 @@
        * @param size the number of rows.
        * @return a <code>List</code> of query results containing a maximum of
        * <code>pageSize</code> reslts.
  -     * @throws Exception a generic exception.
  +     * @throws IllegalArgumentException if <code>size &gt; memoryLimit</code> or
  +     * <code>start</code> and <code>size</code> result in a situation that is
  +     * not catered for.
  +     * @throws TorqueException if invoking the <code>populateObjects()<code>
  +     * method runs into problems or a sleep is unexpectedly interrupted.
        */
  -    synchronized public List getResults(int start, int size) throws Exception
  +    synchronized private List getResults(int start, int size)
  +            throws IllegalArgumentException, TorqueException
       {
  -        log.debug(
  -            "LargeSelect.getResults(start: "
  -                + start
  -                + ", size: "
  -                + size
  -                + ") invoked.");
  +        log.debug("getResults(start: " + start
  +                + ", size: " + size + ") invoked.");
   
           if (size > memoryLimit)
           {
  -            throw new Exception("Memory limit does not permit a range this large.");
  +            throw new IllegalArgumentException("size (" + size
  +                    + ") exceeds memory limit (" + memoryLimit + ").");
           }
   
           // Request was for a block of rows which should be in progess.
  @@ -547,17 +576,20 @@
           // retrieved.
           if (start >= blockBegin && (start + size - 1) <= blockEnd)
           {
  -            log.debug(
  -                "LargeSelect.getResults(): Sleeping until start+size-1 ("
  -                    + (start + size - 1)
  -                    + ") > currentlyFilledTo ("
  -                    + currentlyFilledTo
  -                    + ") && !queryCompleted (!"
  -                    + queryCompleted
  -                    + ")");
  +            log.debug("getResults(): Sleeping until "
  +                    + "start+size-1 (" + (start + size - 1)
  +                    + ") > currentlyFilledTo (" + currentlyFilledTo
  +                    + ") && !queryCompleted (!" + queryCompleted + ")");
               while (((start + size - 1) > currentlyFilledTo) && !queryCompleted)
               {
  -                Thread.currentThread().sleep(500);
  +                try
  +                {
  +                    Thread.currentThread().sleep(500);
  +                }
  +                catch (InterruptedException e)
  +                {
  +                    throw new TorqueException("Unexpected interruption", e);
  +                }
               }
           }
   
  @@ -565,12 +597,8 @@
           // might want at least 2 sets of data.
           else if (start < blockBegin && start >= 0)
           {
  -            log.debug(
  -                "LargeSelect.getResults(): Paging backwards as start ("
  -                    + start
  -                    + ") < blockBegin ("
  -                    + blockBegin
  -                    + ") && start >= 0");
  +            log.debug("getResults(): Paging backwards as start (" + start
  +                    + ") < blockBegin (" + blockBegin + ") && start >= 0");
               stopQuery();
               if (memoryLimit >= 2 * size)
               {
  @@ -593,13 +621,9 @@
           // Assume we are moving on, do not retrieve any records prior to start.
           else if ((start + size - 1) > blockEnd)
           {
  -            log.debug(
  -                "LargeSelect.getResults(): "
  -                    + "Paging past end of loaded data as start+size-1 ("
  -                    + (start + size - 1)
  -                    + ") > blockEnd ("
  -                    + blockEnd
  -                    + ")");
  +            log.debug("getResults(): Paging past end of loaded data as "
  +                    + "start+size-1 (" + (start + size - 1)
  +                    + ") > blockEnd (" + blockEnd + ")");
               stopQuery();
               blockBegin = start;
               blockEnd = blockBegin + memoryLimit - 1;
  @@ -610,29 +634,33 @@
   
           else
           {
  -            throw new Exception("Parameter configuration not accounted for.");
  +            throw new IllegalArgumentException("Parameter configuration not "
  +                    + "accounted for.");
           }
   
           int fromIndex = start - blockBegin;
           int toIndex = fromIndex + Math.min(size, results.size() - fromIndex);
  -        log.debug(
  -            "LargeSelect.getResults(): "
  -                + "Retrieving records from results elements start-blockBegin ("
  -                + fromIndex
  -                + ") through "
  +        log.debug("getResults(): Retrieving records from results elements "
  +                + "start-blockBegin (" + fromIndex + ") through "
                   + "fromIndex + Math.min(size, results.size() - fromIndex) ("
  -                + toIndex
  -                + ")");
  +                + toIndex + ")");
           List returnResults = results.subList(fromIndex, toIndex);
   
           if (null != returnBuilderClass)
           {
               // Invoke the populateObjects() method
               Object[] theArgs = { returnResults };
  -            returnResults =
  -                (List) populateObjectsMethod.invoke(
  -                    returnBuilderClass.newInstance(),
  -                    theArgs);
  +            try
  +            {
  +                returnResults =
  +                    (List) populateObjectsMethod.invoke(
  +                        returnBuilderClass.newInstance(),
  +                        theArgs);
  +            }
  +            catch (Exception e)
  +            {
  +                throw new TorqueException("Unable to populate results", e);
  +            }
           }
           position = start + size;
           lastResults = returnResults;
  @@ -644,12 +672,11 @@
        */
       public void run()
       {
  +        int size = pageSize;
           try
           {
               // Add 1 to memory limit to check if the query ends on a page break.
               results = new ArrayList(memoryLimit + 1);
  -            currentlyFilledTo = -1;
  -            queryCompleted = false;
   
               // Use the criteria to limit the rows that are retrieved to the
               // block of records that fit in the predefined memoryLimit.
  @@ -662,10 +689,10 @@
               db = Torque.getConnection(dbName);
   
               // Execute the query.
  -            log.debug("LargeSelect.run(): query = " + query);
  -            log.debug("LargeSelect.run(): memoryLimit = " + memoryLimit);
  -            log.debug("LargeSelect.run(): blockBegin = " + blockBegin);
  -            log.debug("LargeSelect.run(): blockEnd = " + blockEnd);
  +            log.debug("run(): query = " + query);
  +            log.debug("run(): memoryLimit = " + memoryLimit);
  +            log.debug("run(): blockBegin = " + blockBegin);
  +            log.debug("run(): blockEnd = " + blockEnd);
               qds = new QueryDataSet(db, query);
   
               // Continue getting rows one page at a time until the memory limit
  @@ -680,17 +707,16 @@
                   if ((currentlyFilledTo + pageSize) >= blockEnd)
                   {
                       // Add 1 to check if the query ends on a page break.
  -                    pageSize = blockEnd - currentlyFilledTo + 1;
  +                    size = blockEnd - currentlyFilledTo + 1;
                   }
   
  -                log.debug(
  -                    "LargeSelect.run(): "
  -                        + "Invoking BasePeer.getSelectResults(qds, "
  -                        + pageSize
  -                        + ", false)");
  -                List tempResults = BasePeer.getSelectResults(qds, pageSize, false);
  +                log.debug("run(): Invoking BasePeer.getSelectResults(qds, "
  +                        + size + ", false)");
  +
  +                List tempResults
  +                        = BasePeer.getSelectResults(qds, size, false);
   
  -                for (int i = 0; i < tempResults.size(); i++)
  +                for (int i = 0, n = tempResults.size(); i < n; i++)
                   {
                       results.add(tempResults.get(i));
                   }
  @@ -707,7 +733,7 @@
                   }
   
                   if (results.size() > 0
  -                    && blockBegin + currentlyFilledTo > totalRecords)
  +                    && blockBegin + currentlyFilledTo >= totalRecords)
                   {
                       // Add 1 because index starts at 0
                       totalRecords = blockBegin + currentlyFilledTo + 1;
  @@ -728,24 +754,26 @@
                   qds.clearRecords();
               }
               
  -            log.debug(
  -                "LargeSelect.run(): While loop terminated "
  -                    + "because either:");
  -            log.debug(
  -                "LargeSelect.run(): 1. qds.allRecordsRetrieved(): "
  +            log.debug("run(): While loop terminated because either:");
  +            log.debug("run(): 1. qds.allRecordsRetrieved(): "
                       + qds.allRecordsRetrieved());
  -            log.debug("LargeSelect.run(): 2. killThread: " + killThread);
  -            log.debug(
  -                "LargeSelect.run(): 3. !(currentlyFilledTo + "
  -                    + "size <= blockEnd): !"
  +            log.debug("run(): 2. killThread: " + killThread);
  +            log.debug("run(): 3. !(currentlyFilledTo + size <= blockEnd): !"
                       + (currentlyFilledTo + pageSize <= blockEnd));
  -            log.debug(
  -                "LargeSelect.run(): - currentlyFilledTo: " + currentlyFilledTo);
  -            log.debug("LargeSelect.run(): - size: " + pageSize);
  -            log.debug("LargeSelect.run(): - blockEnd: " + blockEnd);
  -            log.debug("LargeSelect.run(): - results.size(): " + results.size());
  +            log.debug("run(): - currentlyFilledTo: " + currentlyFilledTo);
  +            log.debug("run(): - size: " + pageSize);
  +            log.debug("run(): - blockEnd: " + blockEnd);
  +            log.debug("run(): - results.size(): " + results.size());
           }
  -        catch (Exception e)
  +        catch (TorqueException e)
  +        {
  +            log.error(e);
  +        }
  +        catch (SQLException e)
  +        {
  +            log.error(e);
  +        }
  +        catch (DataSetException e)
           {
               log.error(e);
           }
  @@ -759,7 +787,11 @@
                   }
                   db.close();
               }
  -            catch (Exception e)
  +            catch (SQLException e)
  +            {
  +                log.error(e);
  +            }
  +            catch (DataSetException e)
               {
                   log.error(e);
               }
  @@ -770,11 +802,12 @@
        * Starts a new thread to retrieve the result set.
        *
        * @param initialSize the initial size for each block.
  -     * @throws Exception a generic exception.
        */
  -    private void startQuery(int initialSize) throws Exception
  +    private void startQuery(int initialSize)
       {
           pageSize = initialSize;
  +        currentlyFilledTo = -1;
  +        queryCompleted = false;
           thread = new Thread(this);
           thread.start();
       }
  @@ -783,14 +816,21 @@
        * Used to stop filling the memory with the current block of results, if it
        * has been determined that they are no longer relevant.
        *
  -     * @throws Exception a generic exception.
  +     * @throws TorqueException if a sleep is interrupted.
        */
  -    private void stopQuery() throws Exception
  +    private void stopQuery() throws TorqueException
       {
           killThread = true;
           while (thread.isAlive())
           {
  -            Thread.currentThread().sleep(100);
  +            try
  +            {
  +                Thread.currentThread().sleep(100);
  +            }
  +            catch (InterruptedException e)
  +            {
  +                throw new TorqueException("Unexpected interruption", e);
  +            }
           }
           killThread = false;
       }
  @@ -833,7 +873,7 @@
           {
               return true;
           }
  -        return blockBegin + currentlyFilledTo > pageSize;
  +        return blockBegin + currentlyFilledTo + 1 > pageSize;
       }
   
       /**
  @@ -900,6 +940,14 @@
       }
   
       /**
  +     * Retrieve the more pages/records indicator.
  +      */
  +    public static String getMoreIndicator()
  +    {
  +        return LargeSelect.moreIndicator;
  +    }
  +
  +    /**
        * 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.
  @@ -913,6 +961,16 @@
       }
   
       /**
  +     * 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.
  +     */
  +    public static int getMemoryPageLimit()
  +    {
  +        return LargeSelect.memoryPageLimit;
  +    }
  +
  +    /**
        * A convenience method that provides text showing progress through the
        * selected rows on a page basis.
        *
  @@ -942,12 +1000,11 @@
        */
       public int getCurrentPageSize()
       {
  -        if (getCurrentPageNumber() < getTotalPages()
  -            || getTotalRecords() % getPageSize() == 0)
  +        if (null == lastResults)
           {
  -            return getPageSize();
  +            return 0;
           }
  -        return getTotalRecords() % getPageSize();
  +        return lastResults.size();
       }
   
       /**
  @@ -971,7 +1028,12 @@
        */
       public int getLastRecordNoForPage()
       {
  -        return (getCurrentPageNumber() - 1) * getPageSize() + getCurrentPageSize();
  +        if (0 == currentPageNumber)
  +        {
  +            return 0;
  +        }
  +        return (getCurrentPageNumber() - 1) * getPageSize()
  +                + getCurrentPageSize();
       }
   
       /**
  @@ -1023,6 +1085,79 @@
               return false;
           }
           return true;
  +    }
  +
  +    /**
  +     * Indicates if any results are available.
  +     *
  +     * @return <code>true</code> of any results are available.
  +     */
  +    public boolean hasResultsAvailable()
  +    {
  +        return getTotalRecords() > 0;
  +    }
  +
  +    /**
  +     * 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.
  +     */
  +    public void invalidateResult() throws TorqueException
  +    {
  +        stopQuery();
  +        blockBegin = 0;
  +        blockEnd = 0;
  +        currentlyFilledTo = -1;
  +        qds = null;
  +        results = null;
  +        position = 0;
  +        totalPages = -1;
  +        totalRecords = 0;
  +        // todo Perhaps store the oldPageNumber and immediately restart the query.
  +        // oldPageNumber = currentPageNumber;
  +        currentPageNumber = 0;
  +        queryCompleted = false;
  +        totalsFinalized = false;
  +        lastResults = null;
  +    }
  +
  +    /**
  +     * 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.
  +     *
  +     * @param name the search parameter key to retrieve.
  +     * @return the value of the search parameter.
  +     */
  +    public String getSearchParam(String name)
  +    {
  +        if (null == params)
  +        {
  +            return "";
  +        }
  +        return (String) params.get(name);
  +    }
  +
  +    /**
  +     * Set a parameter used to retrieve the last set of results.
  +     *
  +     * @param name the search parameter key to set.
  +     * @param value the value of the search parameter to store.
  +     */
  +    public void setSearchParam(String name, String value)
  +    {
  +        if (null == params)
  +        {
  +            params = new Hashtable();
  +        }
  +        if (name != null && value != null)
  +        {
  +            params.put(name, value);
  +        }
       }
   
   }
  
  
  

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

Reply via email to