final class ProgressiveResults extends java.lang.Object implements Results
Results
interface which is backed by
Results
sets of progressively increasing size.
This results object is best used in queries which start at the beginning
of a result set and scroll forward sequentially. While non-linear access
to records is possible, it is not the best choice for random access to
results. In fact certain operations currently are disallowed, such as
testing whether the current position is the last available. Thus, the
associated methods throw UnsupportedOperationException
in the
current implementation.
This implementation is designed to balance the need for an immediate initial result with the need for fast access to a large number of results.
To accomplish this, results are retrieved in brackets. The initial fetch retrieves a bracket containing a single record. Each subsequent bracket fetch retrieves a maximum size which is calculated by raising a base number to a power one higher than that applied to the previous bracket. So, for a base number of 10, the first bracket would have maximum 10^0 (or 1) record. The second bracket (if any) would have maximum 10^1 (or 10) records. The third, 10^2 (or 100), and so on. The default base value is 10.
The exponential progression of bracket sizes ensures that the first result is retrieved as quickly as possible, and subsequent brackets are retrieved with reasonable efficiency. Thus, queries which fall to the smaller end of the spectrum will benefit from the quick retrieval of the first few brackets, while the up front expense of retrieving larger brackets will be amortized more evenly for those queries which process larger data sets.
Note that currently, this progression is (effectively) not capped, which presumes a reasonable JDBC fetch size to prevent a JDBC driver from caching too many records and overrunning memory.
When considered end-to-end, in order of increasing size, all brackets together form the virtualized set of results to a database query. This object keeps track of the virtual index position as it moves through the various brackets. Methods which accept an absolute row index expect this value to represent the absolute offset of the target row in this overall, virtualized result set, such that the bracketing implementation is an implementation detail which is transparent to users of this class.
Only the most recently created result set bracket is retained. Once all records in a bracket have been retrieved and the walk proceeds to the next record, the current bracket is discarded and a new one is retrieved. Users of this class which require the ability to perform non-linear, non first-to-last access must instantiate this class in scrolling mode. In this mode, a cache of visited records is maintained. If a previously accessed record must be re-retrieved, it is pulled from the cache. Accordingly, scrolling instances may have a higher memory requirement.
Modifier and Type | Class and Description |
---|---|
private static class |
ProgressiveResults.Locator
A descriptor object used to locate results brackets and store
information used to access them.
|
Modifier and Type | Field and Description |
---|---|
private int |
actualMaxExponent
Actual maximum exponent in use
|
private java.lang.Object[] |
args
Substitution parameters, if any, to be applied to the query
|
private static int |
BASE
Base value used for exponential bracket size progression
|
private int |
bracket
Index of the active delegate
|
private java.util.List<java.lang.Object[]> |
cache
Cached results (scrolling mode only); arrays of DMOs or IDs
|
private boolean |
closed
Flag indicates results are closed
|
private Results |
delegate
Result set to which record retrieval work is delegated
|
private java.lang.String[] |
entities
Names of entities involved in the query associated with these results
|
private java.lang.String |
hql
HQL query string used to select records
|
private int |
lastValid
Most recent valid "real" position in the virtualized result set
|
private static java.util.logging.Logger |
LOG
Logger
|
private static int |
MAX_EXPONENT
Maximum exponent to which BASE can be raised (to limit bracket size)
|
private Persistence |
persistence
Object which provides persistence services
|
private Persistence.Context |
persistenceContext
The
Persistence context. |
private int |
position
Current "real" position in the overall, virtualized result set
|
private java.util.List<VirtualResultsListener> |
resultsChangeListeners
List of results change listeners
|
private org.hibernate.type.Type[] |
types
Types of the query substitution parameters
|
Constructor and Description |
---|
ProgressiveResults(Persistence persistence,
java.lang.String hql,
java.lang.Object[] args,
org.hibernate.type.Type[] types,
boolean scrolling,
java.lang.String[] entities)
Convenience constructor which sets all variables required for record retrieval.
|
Modifier and Type | Method and Description |
---|---|
void |
addResultsChangeListener(VirtualResultsListener listener)
Register results change listener.
|
private boolean |
advanceCache(Results results,
int row)
Sequentially retrieve records and store them in the cache until either
there are no more records, or until the current position has reached
row . |
void |
cleanup()
Close an open result set, if any, and clear the cache, if any.
|
private void |
closeDelegate()
Close the delegate result set, if any.
|
private void |
fireResultsChanged()
Notify all listeners about changes in obtained results.
|
boolean |
first()
Move to the first result row.
|
java.lang.Object[] |
get()
Get the array of objects at the current result row.
|
java.lang.Object |
get(int column)
Get the object at the current result row, at the specified column.
|
java.io.Serializable |
getID(int column)
Get the primary key ID at the current result row, at the specified
column.
|
private Results |
getResults(int bracket)
Access the delegate result set object for the given bracket index.
|
private Results |
getResults(ProgressiveResults.Locator locator)
Access the delegate result set object defined by the given locator.
|
int |
getRowNumber()
Get the row number currently under the cursor.
|
boolean |
isFirst()
Is the cursor on the first row in the result set?
|
boolean |
isLast()
Indicate whether the current record is the last row in the overall,
virtualized result set.
|
boolean |
last()
Move to the last result row.
|
private ProgressiveResults.Locator |
locateBracket(int bracket)
Generate a descriptor object which is used to locate the bracket
at the given index among all results brackets.
|
private ProgressiveResults.Locator |
locateRow(int row)
Generate a descriptor object which is used to locate the bracket
containing the specified row and the row's location within the bracket.
|
private boolean |
moveTo(int row)
Attempt to move to a specific row offset within the virtualized result
set, and report whether a record exists at that row.
|
private boolean |
moveTo(int row,
boolean force)
Attempt to move to a specific row offset within the virtualized result
set, and report whether a record exists at that row.
|
boolean |
next()
Move cursor to the next result row.
|
boolean |
previous()
Move cursor to the previous result row.
|
void |
reset()
Reset the cursor to its natural starting position, before the first
result row.
|
boolean |
scroll(int rows)
Scroll the cursor ahead by the specified number of rows.
|
void |
sessionClosing()
Respond to a session closing event by caching a batch of this results
object's records.
|
boolean |
setRowNumber(int row)
Set the row number currently under the cursor.
|
private static final java.util.logging.Logger LOG
private static final int BASE
private static final int MAX_EXPONENT
private final Persistence persistence
private final Persistence.Context persistenceContext
Persistence
context. Only used at cleanup time when the getter is not accessible
any more.private final java.lang.String hql
private final java.lang.Object[] args
private final org.hibernate.type.Type[] types
private final java.util.List<java.lang.Object[]> cache
private final int actualMaxExponent
private final java.lang.String[] entities
private Results delegate
private int position
private int lastValid
private int bracket
private java.util.List<VirtualResultsListener> resultsChangeListeners
private boolean closed
ProgressiveResults(Persistence persistence, java.lang.String hql, java.lang.Object[] args, org.hibernate.type.Type[] types, boolean scrolling, java.lang.String[] entities) throws PersistenceException
persistence
- Object which provides persistence services.hql
- HQL query string used to select records.args
- Substitution parameters, if any, to be applied to the query.types
- Types of the query substitution parameters.scrolling
- true
to allow results to be scrollable. If false
, it will only
be possible to move forward through results, beginning at the first result;
random access will be disallowed.entities
- Names of entities associated with these results.PersistenceException
- if there is an error beginning an implicit transaction.public boolean first()
public boolean last()
public boolean next()
public boolean previous()
public boolean isFirst()
public boolean isLast()
This method is not supported by this implementation.
public java.lang.Object[] get()
public java.lang.Object get(int column)
public java.io.Serializable getID(int column)
public int getRowNumber()
getRowNumber
in interface Results
-1
if the cursor is not currently on a result.public boolean setRowNumber(int row)
setRowNumber
in interface Results
row
- Zero-based index of the row to be set as the current row.true
if there is a row at the specified row
number; else false
.public boolean scroll(int rows)
public void reset()
public void sessionClosing()
sessionClosing
in interface Results
public void cleanup()
public void addResultsChangeListener(VirtualResultsListener listener)
listener
- Listener to add.private ProgressiveResults.Locator locateRow(int row)
The object returned does not reflect the state of records or whether the target record actually exists in the result set. Rather, this method calculates where the record should be located based upon the bracketing algorithm in use.
row
- 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).private ProgressiveResults.Locator locateBracket(int bracket)
The object returned does not reflect the state of records or whether the target bracket actually exists. Rather, this method calculates the parameters required to request the records which would comprise the bracket, according to the bracketing algorithm in use.
The Locator
object returned will contain the specified
bracket, an offset of 0, the size of the bracket, and its row will
reflect the zero-based offset (in the virtualized result set) of the
row which starts the target bracket.
bracket
- 0-based index of the target bracket in the virtualized result
set.private boolean moveTo(int row)
This method updates the internal state variables which track the current virtualized row index and bracket index. Both are set to their default values if the target row does not exist.
row
- 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).true
if there is a row at the specified row
number; else false
.java.lang.UnsupportedOperationException
- if a backwards move is requested for a non-scrolling results
object.private boolean moveTo(int row, boolean force)
This method updates the internal state variables which track the current virtualized row index and bracket index. Both are set to their default values if the target row does not exist.
row
- 0-based index of the target record in the virtualized result
set (i.e., the record's "real" position among the full result
set of the query, ignoring bracketing).force
- Force move even if the target row matches the current row.
Allows to initialize delegate in some cases.true
if there is a row at the specified row
number; else false
.java.lang.UnsupportedOperationException
- if a backwards move is requested for a non-scrolling results
object.private boolean advanceCache(Results results, int row)
row
.results
- Delegate results object from which to retrieve records.row
- Target row index. Retrieval halts when the current record
position reaches this row.true
if the last attempt to retrieve a record was
successful; false
if we reached the end of the
delegate result set bracket before reaching our target row.java.lang.IllegalStateException
- if the current position is not at the last record in the
cache.private Results getResults(int bracket) throws PersistenceException
bracket
- 0-based index of the target bracket.Results
for the given bracket,
or null
if no such bracket exists.PersistenceException
private Results getResults(ProgressiveResults.Locator locator) throws PersistenceException
locator
- Descriptor of the target bracket.Results
for the given bracket,
or null
if no such bracket exists.PersistenceException
- if there is an error retrieving a result set.private void closeDelegate()
private void fireResultsChanged()