Methods Summary |
---|
private void | QuickSort(int[] a, int lowIndex, int highIndex, RecordComparator inp_comparator)Quicksort helper function for sorting the records.
/*
* A different sorting algorithm may be preferred, because a
* large recursive quicksort can consume lots of
* stack. Quicksort is very fast for most random sequences
* however...
*/
int left = lowIndex; // the "left" index
int right = highIndex; // the "right" index
/*
* First partition the data into two regions, where every
* element on the left side of the partition is less than
* every element on the right side of the element.
*/
if (highIndex > lowIndex) {
/*
* Arbitrarily choose the initial pivot point to be the
* middle of the array.
*/
int ind = (lowIndex + highIndex) / 2;
int pivotIndex = a[ind];
byte[] pivotData = recordStore.getRecord(pivotIndex);
// loop through the array until the indices cross
while (left <= right) {
/*
* Starting on the left, scan right until the
* first element greater than or equal to the
* pivot element is found.
*/
while ((left < highIndex) &&
(inp_comparator.compare(recordStore.getRecord(a[left]),
pivotData) ==
RecordComparator.PRECEDES)) {
left++;
}
/*
* Starting on the right, scan left until the
* first element that is less than or equal to the
* pivot element is found.
*/
while ((right > lowIndex) &&
(inp_comparator.compare(recordStore.getRecord(a[right]),
pivotData) ==
RecordComparator.FOLLOWS)) {
right--;
}
// if the indexes haven't crossed, swap the elements
if (left <= right) {
int tmp = a[left];
a[left] = a[right];
a[right] = tmp;
left++;
right--;
}
}
// Sort the left side of the partition
if (lowIndex < right) {
QuickSort(a, lowIndex, right, inp_comparator);
}
// Sort the right side of the partition
if (left < highIndex) {
QuickSort(a, left, highIndex, inp_comparator);
}
}
|
private void | checkDestroyed()Helper method that checks if this enumeration can be used.
If this enumeration has been destroyed, an exception is thrown.
if (recordStore == null) {
throw new IllegalStateException();
}
|
public synchronized void | destroy()Implements RecordEnumeration.destroy() interface. Called
to signal that this enumeration will no longer be used, and that
its resources may be collected.
checkDestroyed();
if (keepEnumUpdated) {
recordStore.removeRecordListener(this);
}
filter = null;
comparator = null;
records = null;
recordStore = null; // a signal that this is destroyed!
|
private void | filterAdd(int recordId)Used to add a record to an already filtered and sorted
records array. More efficient than
reFilterSort because it relies on
records being in sorted order.
First ensures that record recordId
meets this enumeration's filter criteria.
If it does it is added to records as array element
0. If a comparator is defined for this enumeration,
the helper method sortAdd is called to
properly position recordId within the ordered
records array.
Should be called from within a
synchronized (recordStore.rsLock) block.
int insertPoint = -1;
if (filter != null) {
try {
if (!filter.matches(recordStore.getRecord(recordId))) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_RMS,
"Unexpected case in filterAdd: " +
"recordId filtered out");
}
return; // recordId filtered out
}
} catch (RecordStoreException rse) {
return; // recordId does not exist
}
}
// the new record has been accepted by the filter
int[] newrecs = new int[records.length + 1];
newrecs[0] = recordId; // insert new record at front of list
System.arraycopy(records, 0, newrecs, 1, records.length);
records = newrecs;
if (comparator != null) { // move the new record into place
try {
insertPoint = sortInsert();
} catch (RecordStoreException rse) {
// NOTE: - should never be here
// throw a RSE? destroy record enumeration?
if (Logging.TRACE_ENABLED) {
Logging.trace(rse, "Unexpected case in filterAdd: " +
"caught RSE");
}
}
}
// keep index up to date as well
if (index != NO_SUCH_RECORD && insertPoint <= index) {
index++;
}
|
private int | findIndexOfRecord(int recordId)Find the index in records of record recordId
and return it.
int idx;
int recIndex = -1;
for (idx = records.length - 1; idx >= 0; idx--) {
if (records[idx] == recordId) {
recIndex = idx;
break;
}
}
return recIndex;
|
public boolean | hasNextElement()Returns true if more elements exist in the next direction.
checkDestroyed();
if (records.length == 0 || !recordStore.isOpen()) {
return false;
}
return (index != records.length - 1);
|
public boolean | hasPreviousElement()Returns true if more elements exist in the previous direction.
checkDestroyed();
if (records.length == 0 || !recordStore.isOpen()) {
return false; // no records in the enumeration
}
return (index != 0);
|
public boolean | isKeptUpdated()Returns true if the enumeration keeps its enumeration
current with any changes in the records.
checkDestroyed();
return keepEnumUpdated;
|
public void | keepUpdated(boolean keepUpdated)Used to set whether the enumeration should be registered
as a listener of the record store, and rebuild its internal
index with every record addition/deletion in the record store.
Note that this should be used carefully due to the potential
performance cost associated with maintaining the
enumeration with every change.
checkDestroyed();
if (keepUpdated != keepEnumUpdated) {
keepEnumUpdated = keepUpdated;
if (keepUpdated) {
recordStore.addRecordListener(this);
rebuild();
} else {
recordStore.removeRecordListener(this);
}
}
|
public synchronized byte[] | nextRecord()Returns a copy of the next record in this enumeration,
where next is defined by the comparator and/or filter
supplied in the constructor of this enumerator. The byte array
returned is a copy of the record. Any changes made to this array
will NOT be reflected in the record store. After calling
this method, the enumeration is advanced to the next available
record.
checkDestroyed();
return recordStore.getRecord(nextRecordId());
|
public synchronized int | nextRecordId()Returns the recordId of the next record in this enumeration,
where next is defined by the comparator and/or filter
supplied in the constructor of this enumerator. After calling
this method, the enumeration is advanced to the next available
record.
checkDestroyed();
if (index == records.length - 1) {
throw new InvalidRecordIDException();
}
if (index == NO_SUCH_RECORD) {
index = 0;
} else {
index++;
}
return records[index];
|
public synchronized int | numRecords()Returns the number of records available in this enumeration's
set. That is, the number of records that have matched the
filter criterion. Note that this forces the RecordEnumeration
to fully build the enumeration by applying the filter to all
records, which may take a non-trivial amount
of time if there are a lot of records in the record store.
checkDestroyed();
return records.length;
|
public synchronized byte[] | previousRecord()Returns a copy of the previous record in this enumeration,
where previous is defined by the comparator and/or filter
supplied in the constructor of this enumerator. The byte array
returned is a copy of the record. Any changes made to this array
will NOT be reflected in the record store. After calling
this method, the enumeration is advanced to the next (previous)
available record.
checkDestroyed();
return recordStore.getRecord(previousRecordId());
|
public synchronized int | previousRecordId()Returns the recordId of the previous record in this enumeration,
where previous is defined by the comparator and/or filter
supplied in the constructor of this enumerator. After this method
is called, the enumeration is advanced to the next (previous)
available record.
checkDestroyed();
if (index == 0 || records.length == 0) {
throw new InvalidRecordIDException();
}
if (index == NO_SUCH_RECORD) {
index = records.length - 1;
} else {
index--;
}
return records[index];
|
private void | reFilterSort(int[] filtered)Internal helper method for filtering and sorting records if
necessary. Called from rebuild().
Should be called from within a synchronized(recordStore.rsLock) block
int filteredIndex = 0;
if (filter == null) {
/*
* If this enumeration doesn't have any filters, the
* recordId's returned by getRecordIDs should be
* used as they are.
*/
records = filtered;
} else {
/*
* If a filter has been specified, filter the recordStore
* records to determine the subset to be used for this
* enumeration.
*/
for (int i = 0; i < filtered.length; i++) {
// if this record matches the filter keep it
try {
if (filter.matches(recordStore.getRecord(filtered[i]))) {
// need revisit : if element overlap is allowed
if (filteredIndex != i) {
filtered[filteredIndex++] = filtered[i];
} else {
filteredIndex++;
}
}
} catch (RecordStoreException rse) {
// if a record can't be found it doesn't match
}
}
records = new int[filteredIndex];
System.arraycopy(filtered, 0, records, 0, filteredIndex);
}
/*
* If a comparator has been specified, sort the remaining
* records by comparing records against each other using
* the comparator the application provides.
*/
if (comparator != null) {
try {
QuickSort(records, 0, records.length - 1, comparator);
}
catch (RecordStoreException rse) {
// NOTE: - should never be here
// throw a RSE? destroy record enumeration?
if (Logging.TRACE_ENABLED) {
Logging.trace(rse, "Unexpected case in reFilterSort:" +
" caught RSE");
}
}
}
reset(); // reset the current index of this enumeration
|
public void | rebuild()Request that the enumeration be updated to reflect the current
record set. Useful for when an application makes a number of
changes to the record store, and then wants an existing
RecordEnumeration to enumerate the new changes.
checkDestroyed();
int[] tmp = recordStore.getRecordIDs();
reFilterSort(tmp);
|
public synchronized void | recordAdded(RecordStore inp_recordStore, int recordId)From the RecordListener interface. This method is called if
a record is added to recordStore .
checkDestroyed();
filterAdd(recordId);
|
public synchronized void | recordChanged(RecordStore inp_recordStore, int recordId)From the RecordListener interface. This method is called if
a record in recordStore is modified.
checkDestroyed();
int recIndex = findIndexOfRecord(recordId);
if (recIndex >= 0) {
removeRecordAtIndex(recIndex);
} // else record not previously in the enumeration
filterAdd(recordId);
|
public synchronized void | recordDeleted(RecordStore inp_recordStore, int recordId)From the RecordListener interface. This method is called when a
record in recordStore is deleted.
checkDestroyed();
/*
* Remove the deleted element from the records array.
* No resorting is required.
*/
int recIndex = findIndexOfRecord(recordId);
if (recIndex < 0) {
return; // not in the enumeration
}
// remove this record from the enumeration
removeRecordAtIndex(recIndex);
|
private void | removeRecordAtIndex(int recIndex)Internal helper method which
removes the array element at index recIndex
from the internal records array.
recIndex should be non negative.
int[] tmp = new int[records.length - 1];
System.arraycopy(records, 0, tmp, 0, recIndex);
System.arraycopy(records, recIndex + 1, tmp,
recIndex, (records.length - recIndex) - 1);
records = tmp;
/*
* If a record prior to current index was deleted
* update index so nothing is skipped
*/
if (index != NO_SUCH_RECORD && recIndex <= index) {
index --;
} else if (index == records.length) {
// last element in records removed
index --;
}
|
public void | reset()Returns the index point of the enumeration to the beginning.
checkDestroyed();
index = NO_SUCH_RECORD;
|
private int | sortInsert()Helper method called by filterAdd .
Moves the possibly unsorted element zero in the
records array to its sorted position
within the array.
// bubble sort the first record in records into place
int tmp;
int i;
int j;
for (i = 0, j = 1; i < records.length - 1; i++, j++) {
if (comparator.compare(recordStore.getRecord(records[i]),
recordStore.getRecord(records[j])) ==
RecordComparator.FOLLOWS) {
// if i follows j swap them in records
tmp = records[i];
records[i] = records[j];
records[j] = tmp;
} else {
break; // done sorting if compare returns EQUALS or PRECEDES
}
}
return i; // final index of new record in records
|