public abstract class BaseRecord extends java.lang.Object implements DmoState, Persistable
Access to the internal state of this class is not thread-safe. Thus, instances are not intended to be accessed from more than one thread.
| Modifier and Type | Field and Description |
|---|---|
private RecordBuffer |
activeBuffer
The currently active buffer when state is changing
|
protected int |
activeOffset
The offset of the property currently being modified, if any (else
-1) |
private java.lang.Object |
activePropPreviousValue
The most recent value of the property currently being modified, for rollback purposes
|
private ChangeSet |
changeSet
Object which tracks change to enable rollback of the record's data and state
|
protected java.lang.Object[] |
data
The data represented by this record, in it's low-level (database friendly) form
|
private java.util.BitSet |
dirtyProps
Map of properties touched, each bit corresponds with a property in the data array
|
protected java.lang.Long |
id
Surrogate primary key of the record
|
private IndexState |
indexState
Tracker to manage which indices have been updated by property updates
|
private static CentralLogger |
LOG
Logger
|
private java.util.BitSet |
nullProps
Map of properties currently set to null, indicating unknown value
|
static java.lang.reflect.Method |
PK_GETTER
The cached getter method for the PK property.
|
protected java.util.BitSet |
readFields
For an incomplete record, this holds the fields which were read or assigned in this record.
|
private RecordIdentifier<java.lang.String> |
recid
Record identifier (lock variant, which uses table name) for this record (created lazily)
|
protected long |
references
Count of references to this DMO; while positive, it must remain in the current session cache.
|
private java.util.concurrent.atomic.AtomicIntegerArray |
sharedVersion
Shared version data structure, for version updates and stale checks
|
protected RecordState |
state
Current state of the record
|
private java.util.BitSet |
unvalidated
Map of properties currently requiring validation
|
private int |
version
Current version number, for stale checks
|
| Modifier | Constructor and Description |
|---|---|
protected |
BaseRecord()
Default constructor which can only be invoked by subclasses.
|
| Modifier and Type | Method and Description |
|---|---|
java.util.BitSet |
_getReadFields()
Get the
readFields. |
protected abstract RecordMeta |
_recordMeta()
Get the static record metadata for the concrete subclass.
|
private void |
bulkDataChanged(java.util.List<java.lang.Integer> offsets,
java.util.List<java.lang.Object> datums)
Multiple property values have changed.
|
protected void |
checkIncomplete(int index)
Check if for an incomplete record, the specified field was read or assigned.
|
boolean |
checkState(int flags)
Checks whether a set of record state flags are set for this record.
|
(package private) void |
clearDirtyState(Session session)
Reset record and property state after database is synchronized with the record's data
(i.e., the most recent set of changes have been persisted).
|
(package private) void |
commit()
The current application transaction has been committed.
|
void |
copy(BaseRecord from)
Makes this a copy of a source
BaseRecord object. |
static boolean |
copy(BaseRecord to,
BaseRecord from,
boolean b4reserved)
Copy the source record to the destination record.
|
private void |
dataChanged(int offset,
java.lang.Object datum)
A property's value has changed.
|
BaseRecord |
deepCopy()
Copy this record's data and record state, including its primary key.
|
(package private) int |
getActiveOffset()
Get the offset of the property currently being updated, if any.
|
java.lang.Object[] |
getActiveUpdateDiffs()
Get a two element array representing the old and new values of the property currently being changed.
|
protected java.lang.String |
getCodePage(int offset)
Obtain the codepage of the
clob object at position offset. |
java.lang.Object[] |
getData(PropertyMapper pm)
This accessor allows direct access to private
data array only to
instances of PropertyMapper. |
java.lang.Object[] |
getData(RecordBuffer rb)
This accessor allows direct access to private
data array only to
instances of RecordBuffer. |
protected java.lang.Object |
getDatum(int offset)
Get the field's value on the specified offset.
|
private java.util.BitSet |
getDirtyIndices(java.util.BitSet[] indices,
int dirtyOffset,
java.util.BitSet filter,
boolean full)
Get a bit set representing dirty unique or non-unique indices, subject to the conditions described by
the parameters.
|
java.util.BitSet |
getDirtyIndices(int dirtyOffset,
boolean unique,
boolean remaining)
Get a bit set representing dirty unique or non-unique indices, subject to the conditions described by
the parameters.
|
java.util.BitSet |
getDirtyProps()
Return the set of bits which are marked dirty.
|
IndexState |
getIndexState()
Get the update state of this record's indices.
|
(package private) java.util.BitSet |
getNullProps()
Get a bit set indicating the positions of data elements which currently are set to
null. |
RecordIdentifier<java.lang.String> |
getRecordLockIdentifier()
Get the unique identifier for this record, comprised of its table name and primary key.
|
long |
getSize()
Get the size of the record.
|
private java.lang.String |
getTable()
Get the name of the primary table associated with this record.
|
(package private) java.util.BitSet |
getUnvalidatedIndices(int dirtyOffset,
boolean allUnvalidated)
Get a bit set representing the unique indices, if any, which are either fully or partially updated
and which have not already been validated.
|
(package private) void |
indexUpdated(int idxUid)
An index was updated.
|
void |
initialize(boolean setDefaults)
Initialize this record instance, by setting all fields to their default values and also initializing
the
indexState, unvalidated and nullProps states. |
void |
initialize(Session session,
boolean setDefaults)
Populate the record's data with its default, initial values and update the record and
property states accordingly.
|
boolean |
isAnyIndexFullyDirty()
Indicate whether all index components for any index on this record are dirty (i.e., have been touched,
not necessarily changed..
|
(package private) boolean |
isAnyIndexFullyDirty(java.util.BitSet[] indices)
Compare the bitsets in the given array with the bitset of dirty properties for this record
and indicate whether all index components for any index in the array are dirty.
|
boolean |
isDirty()
Indicate whether any property in the record currently is dirty (i.e., touched, not necessarily changed).
|
boolean |
isIndexed()
Report whether the table associated with this record has any (legacy) index.
|
boolean |
isInUse()
Indicate whether this DMO is "in use"; that is, whether buffers reference it or it is being tracked
for UNDO processing.
|
(package private) boolean |
isPropertyDirty(int offset)
Indicate whether the property at the given offset in the DMO's data array is dirty (i.e., has been
touched, but not necessarily changed).
|
(package private) boolean |
isStale()
Indicate whether this record's data is stale, based on changes committed by other user contexts.
|
boolean |
isValid()
Indicate whether the record has passed validation.
|
private boolean |
lockForUpdate()
Obtain an exclusive lock for the current record on behalf of the active buffer, if any.
|
(package private) void |
markIncomplete(Session session)
Mark this record as incomplete.
|
(package private) void |
markValidated()
Mark all dirty properties as having been validated.
|
(package private) void |
markValidated(int bit)
Mark a single property as having been validated.
|
boolean |
needsValidation()
Indicate whether any of this record's validatable properties are dirty and have not been validated.
|
private int |
prepareChangeSet(Session session)
If this is the first update to this record since an application transaction began, prepare a
change set to track updates made to the record during the transaction, to be used for full or
sub-transaction rollback, if needed.
|
java.lang.Long |
primaryKey()
Get the database identifier for this persistable object.
|
void |
primaryKey(java.lang.Long id)
Set the database identifier for this persistable object (i.e., surrogate primary key).
|
(package private) int |
readProperty(int propOffset,
java.sql.ResultSet rs,
int rsOffset)
Read a property directly from a
ResultSet. |
(package private) int |
readProperty(int propOffset,
java.sql.ResultSet rs,
int rsOffset,
boolean skip)
Read a property directly from a
ResultSet. |
void |
restoreActiveState()
Restore to default active buffer, offset, and datum value.
|
(package private) void |
rollback(int txLevel)
Perform a full or sub-transaction level rollback of this record to its state as it was immediately
before the block of the specified transaction nesting level was entered.
|
java.lang.Runnable |
setActiveBuffer(RecordBuffer buffer)
Set the record buffer which is currently active for this record.
|
protected boolean |
setAllData(BaseRecord source)
Set all data in the data array.
|
protected void |
setDatum(int offset,
java.lang.Object datum)
Set a single datum into the data array, and update the record and property state accordingly.
|
java.lang.String |
toString()
Return a string representation of this object, primarily for debug purposes.
|
java.lang.String |
toString(boolean includeData)
Return a string representation of this object, primarily for debug purposes, optionally including the
record's data in the output.
|
void |
undoActive() |
private void |
updateState(int flags,
boolean set)
Updates the set of state flags for this record.
|
void |
updateState(Session session,
int flags,
boolean set)
Updates the set of state flags for this record.
|
(package private) void |
version(java.util.concurrent.atomic.AtomicIntegerArray sharedVersion)
Set this record's version to the canonical, shared version number for this record.
|
private static final CentralLogger LOG
public static final java.lang.reflect.Method PK_GETTER
protected java.lang.Long id
protected final java.lang.Object[] data
protected java.util.BitSet readFields
protected final RecordState state
protected long references
private final java.util.BitSet dirtyProps
private final java.util.BitSet unvalidated
private final java.util.BitSet nullProps
private final IndexState indexState
private RecordIdentifier<java.lang.String> recid
private RecordBuffer activeBuffer
protected int activeOffset
-1)private java.lang.Object activePropPreviousValue
private ChangeSet changeSet
private int version
private transient java.util.concurrent.atomic.AtomicIntegerArray sharedVersion
protected BaseRecord()
initialize(Session, boolean) method should be invoked after construction.public static boolean copy(BaseRecord to, BaseRecord from, boolean b4reserved)
The records are checked first to decide whether they are compatible (I.e. the number of properties
matches and also the type for each field, including the optional extent attribute). If not, the method
returns false and not copy operation is executed.
If the records pass validation, all properties are copied from source (from) to destination
to). At the same time, the status flags are updated so that the destination record can be
correctly saved.
to - The destination record.from - The source record.b4reserved - If true the before-table specific attributes are copied, too. Otherwise only the normal
properties are processed.true if the copy was performed (record's tables match).public void initialize(Session session, boolean setDefaults)
This method should be invoked only once, immediately after the object is constructed. It is not invoked directly from the constructor, because the only use case which requires the initialization performed here is a new data record being created on behalf of application logic.
This is done separately from construction because there are use cases where an instance of this class is needed, but we do not need the overhead of initializing the data with default values, as they will be overwritten anyway. For instance, if the object is read from the database or a copy/snapshot is being made, the data array will be populated with the values retrieved from the database or copied from the other record, respectively.
It is not invoked optionally from the constructor, because a default constructor called from subclasses is preferable, as the subclasses are often constructed by reflection.
This operation updates the not-null bitset, based on the values of non-nullable columns.
session - Database session, which is needed if this record must have its changes tracked for
UNDO/rollback purposes; otherwise, may be null.setDefaults - If true, set all default property values; if false, leave data array
filled with null values.public void initialize(boolean setDefaults)
indexState, unvalidated and nullProps states.
This method should be invoked only once, immediately after the object is constructed. It is not invoked directly from the constructor, because the only use case which requires the initialization performed here is a new data record being created on behalf of application logic.
This will be used by, JSON deserialization when creating a new record for an
instance associated with the web service request (either request or response).
setDefaults - If true, set all default property values; if false, leave data array
filled with null values.public boolean isInUse()
true if in use by the above definition, else false.public IndexState getIndexState()
public final java.lang.Long primaryKey()
null for DMO instances which have
not yet been persisted to the database.primaryKey in interface Persistablepublic final void primaryKey(java.lang.Long id)
primaryKey in interface Persistableid - Unique, database identifier to be associated with this object.public BaseRecord deepCopy()
Session cache.public void copy(BaseRecord from)
BaseRecord object. For permanent databases, the
internal data and the id of the BaseRecord are copied.
The only state copied is that of which properties are dirty (all of them after the copy). Thus, this method is for specialized, internal use only, such as creating a new record in order to copy data from one temp-table buffer to another.
from - The source to copy data from.public boolean checkState(int flags)
flags - One or more RecordState flags, bitwise OR'd together.true if ALL flags are set.RecordStatepublic boolean isValid()
true if this record has passed validation and has not since had any of its
properties changed, else false.public void updateState(Session session, int flags, boolean set)
set parameter, the
flags can be set (when true) or removed (when false). If one flag is already
set and set == true that flag remains unchanged. The same applies for un-setting an
inactive flag.session - Database session (used for UNDO purposes).flags - A set of OR-ed RecordState flags to be updated.set - If true the flags will be set, otherwise they will be unset.RecordStatepublic RecordIdentifier<java.lang.String> getRecordLockIdentifier()
public boolean isIndexed()
true if there is at least one legacy index defined in the table of this record.public java.lang.Runnable setActiveBuffer(RecordBuffer buffer)
A call to this method must be bracketed with a call to run the Runnable returned by
this method. This allows nested invocations and ensures that the active buffer and related state are
reset properly after the update work is done.
buffer - The buffer which is considered the "active" buffer for a subsequent unit of update
work.Runnable which MUST be executed in a finally block when the update work
for which the active buffer was set is finished.public void restoreActiveState()
public boolean isDirty()
true if any property was touched, else false.public boolean isAnyIndexFullyDirty()
true if any index is fully dirty.public void undoActive()
public java.lang.String toString()
toString in class java.lang.Objectpublic java.lang.String toString(boolean includeData)
includeData - true to include the record's data. If false, all other state still will be
included.public java.lang.Object[] getData(PropertyMapper pm)
data array only to
instances of PropertyMapper. This is needed because the these instances need direct
and fast access the data and avoid normal status management of a record when the
properties are accessed using the Record's setters and getters. Instances of
PropertyMapper are created only when the import is run so that management is not
required nor needed.pm - The PropertyMapper which requests access.data array if the passed parameter is a
PropertyMapperjava.lang.NullPointerException - If the passed in parameter is null.public java.lang.Object[] getData(RecordBuffer rb)
data array only to
instances of RecordBuffer.rb - The RecordBuffer which requests access.data array if the passed parameter is a
RecordBufferjava.lang.NullPointerException - If the passed in parameter is null.public boolean needsValidation()
true if record needs validation, else false.public java.util.BitSet getDirtyIndices(int dirtyOffset,
boolean unique,
boolean remaining)
dirtyOffset - Optional offset of a dirty property which must be a component of the indices returned. If
less than 0, all dirty properties are considered. If a non-negative offset is provided,
but the corresponding property is not dirty, an empty bit set is returned.unique - true to return dirty unique indices; false to return dirty non-unique indices.remaining - If true, only unvalidated indices are returned. Otherwise, validation is not
considered.null is returned when no indices are found.public java.lang.Object[] getActiveUpdateDiffs()
null is returned.
Note: this method will only return a non-null result while a property update is
active; that is, while a DMO property is being updated via the RecordBuffer invocation handler.
It is only at that moment that the previous value for the property being changed is guaranteed to
contain meaningful data.
public java.util.BitSet getDirtyProps()
public java.util.BitSet _getReadFields()
readFields.readFields.protected void setDatum(int offset,
java.lang.Object datum)
offset - Zero-based offset of the datum in the data array.datum - Value to be set into the data array.protected boolean setAllData(BaseRecord source)
source - A record from which the data will be copied to this data array.true if a valid copying could be done; so the properties match in type and extent and
the number of properties match (except the reserved ones).protected java.lang.Object getDatum(int offset)
offset - Zero-based offset of the datum in the data array.protected abstract RecordMeta _recordMeta()
protected java.lang.String getCodePage(int offset)
clob object at position offset.
Note: in order for this method to work, the activeBuffer must be set in advance. After the
method was invoked, it is recommended to clear its value.
offset - The position for clob field.clob field at position offset. If a codepage is
not specified or if the field is not a clob, null is returned.protected void checkIncomplete(int index)
index - The field index.void markIncomplete(Session session)
session - Database session (used for UNDO purposes).void indexUpdated(int idxUid)
idxUid - Index identifier.boolean isAnyIndexFullyDirty(java.util.BitSet[] indices)
indices - Array of bitsets, where each set bit represents a component of an index.true if all of the components of any index represented in the array are
dirty, else false.void markValidated()
void markValidated(int bit)
bit - 0-based index of bit representing the property which has been validated.java.util.BitSet getUnvalidatedIndices(int dirtyOffset,
boolean allUnvalidated)
dirtyOffset - Optional offset of a dirty property which must be a component of the indices returned. If
less than 0, all dirty properties are considered. If a non-negative offset is provided,
but the corresponding property is not dirty, an empty bit set is returned.allUnvalidated - If true, then any unique index containing any property not previously validated is
included in the returned bit set. If false, then only indices containing properties
that have been explicitly made dirty are included. Setting this to true effectively
considers all properties with untouched, default values in the check.null is returned if no index is found.int getActiveOffset()
The active state may be reset by this method. This should only be done from a Validation object.
-1 if no offset is
currently being updated.void clearDirtyState(Session session) throws PersistenceException
This method does not turn off the INVALID flag.
PersistenceExceptionboolean isPropertyDirty(int offset)
offset - Zero-based offset of the target property.true if the property is dirty, else false.java.util.BitSet getNullProps()
null.final int readProperty(int propOffset,
java.sql.ResultSet rs,
int rsOffset)
throws PersistenceException
ResultSet.propOffset - The index of the property to be read.rs - The result set to read from.rsOffset - The index in ResultSet to read from. If the property is a multiple column
then more than one column will ve read from ResultSet.ResultSet.PersistenceExceptionfinal int readProperty(int propOffset,
java.sql.ResultSet rs,
int rsOffset,
boolean skip)
throws PersistenceException
ResultSet.propOffset - The index of the property to be read.rs - The result set to read from.rsOffset - The index in ResultSet to read from. If the property is a multiple column
then more than one column will ve read from ResultSet.skip - Flag indicating if this property will not be read from the result-set.ResultSet.PersistenceExceptionvoid version(java.util.concurrent.atomic.AtomicIntegerArray sharedVersion)
sharedVersion - DMO version information.boolean isStale()
Always returns false for temp-table records.
true if this record's version does not match the canonical, shared version of the
record known to the FWD runtime; false if the versions match or if versioning is
disabled for this record.void commit()
void rollback(int txLevel)
throws PersistenceException
txLevel - The nesting level of sub-transactions of the block being rolled back, where 0 represents
the full transaction block, and a positive number represents that number of nested
sub-transactions.PersistenceExceptionprivate java.util.BitSet getDirtyIndices(java.util.BitSet[] indices,
int dirtyOffset,
java.util.BitSet filter,
boolean full)
indices - The array of bit sets representing the indices to be checked. This must be either the set of
unique indices or non-unique indices associated with the record. Only one or the other can be
checked by a call to this method.dirtyOffset - Optional offset of a dirty property which must be a component of the indices returned. If
less than 0, all dirty properties are considered. If a non-negative offset is provided,
but the corresponding property is not dirty, an empty bit set is returned.filter - An inclusive filter to apply to the results. If non-empty, each bit in the filter's bit set
represents the position of an index to be checked in the indices parameter. If empty,
the returned bit set will be empty.full - If true, ALL index components must be dirty for an index to be considered dirty.
If false, one or more index components must be dirty for an index to be considered
dirty.null is returned when no indices are found.private void dataChanged(int offset,
java.lang.Object datum)
throws PersistenceException
offset - The datum's offset in the record's data array.datum - The new value of the datum (may be null).PersistenceExceptionprivate void bulkDataChanged(java.util.List<java.lang.Integer> offsets,
java.util.List<java.lang.Object> datums)
throws PersistenceException
offsets - A list of offsets for the changed values in record's data array.datums - A list of new values for the changed datums.PersistenceExceptionprivate void updateState(int flags,
boolean set)
add parameter, the
flags can be set (when true) or removed (when false. If one flag is already
set and add == true that flag remains unchanged. The same stands for un-setting a
not active flag.flags - A set of OR-ed RecordState flags to be updated.set - If true the flags will be set, otherwise they will be unset.RecordStateprivate int prepareChangeSet(Session session) throws PersistenceException
For a change set to be prepared, the following conditions must be met:
If a change set for the current transaction already exists, another is not created.
A non-negative return value indicates a change set exists and is ready to track changes.
session - Database session to be interrogated for transaction information.PersistenceExceptionprivate boolean lockForUpdate()
true if the lock is successfully obtained, or if it is unneeded due to system state,
or if there is no active buffer. false if there was an error obtaining the lock (and
we are in silent error mode).private java.lang.String getTable()
public long getSize()