Class AbstractSchemaUpdater<D,T>
- Type Parameters:
D- database typeT- database transaction type
- Direct Known Subclasses:
PersistentObjectSchemaUpdater,SQLSchemaUpdater
In this class, a database is some stateful object whose structure and/or content may need to change over time. Updates are uniquely named objects capable of making such changes. Databases are also capable of storing the names of the already-applied updates.
Given a database and a set of current updates, this class will ensure that a database is initialized if necessary and up-to-date with respect to the updates.
The primary method is initializeAndUpdateDatabase(), which will:
- Initialize an empty database (if necessary);
- Apply any outstanding
SchemaUpdates as needed, ordered properly according to their predecessor constraints; and - Keep track of which
SchemaUpdates have already been applied across restarts.
-
Field Summary
Fields -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected voidapply(T transaction, DatabaseAction<T> action) Execute a database action within an existing transaction.protected voidapplyInTransaction(D database, DatabaseAction<T> action) Execute a database action.protected abstract voidcommitTransaction(T transaction) Commit a previously opened transaction.protected abstract booleandatabaseNeedsInitialization(T transaction) Determine if the database needs initialization.protected StringgenerateMultiUpdateName(SchemaUpdate<T> update, int index) Generate the update name for one action within a multi-action update.Get the names of all updates including multi-action updates.getAppliedUpdateNames(T transaction) Determine which updates have already been applied to the database.protected Comparator<SchemaUpdate<T>>Determine the preferred ordering of two updates that do not have any predecessor constraints (including implied indirect constraints) between them.Collection<? extends SchemaUpdate<T>>Get the configured updates.voidinitializeAndUpdateDatabase(D database) Perform database schema initialization and updates.protected abstract voidinitializeDatabase(T transaction) Initialize an uninitialized database.booleanDetermine whether unrecognized updates are ignored or cause an exception.static booleanisValidUpdateName(String updateName) Determine if the given schema update name is valid.protected abstract TopenTransaction(D database) Begin a transaction on the given database.protected abstract voidrecordUpdateApplied(T transaction, String name) Record an update as having been applied to the database.protected abstract voidrollbackTransaction(T transaction) Roll back a previously opened transaction.voidsetIgnoreUnrecognizedUpdates(boolean ignoreUnrecognizedUpdates) Configure behavior when an unknown update is registered as having already been applied in the database.voidsetUpdates(Collection<? extends SchemaUpdate<T>> updates) Configure the updates.
-
Field Details
-
log
-
-
Constructor Details
-
AbstractSchemaUpdater
public AbstractSchemaUpdater()
-
-
Method Details
-
getUpdates
Get the configured updates. This property is required.- Returns:
- configured updates
- See Also:
-
setUpdates
Configure the updates. This should be the set of all updates that may need to be applied to the database.For any given application, ideally this set should be "write only" in the sense that once an update is added to the set and applied to one or more actual databases, the update and its name should thereafter never change. Otherwise, it would be possible for different databases to have inconsistent schemas even though the same updates were recorded.
Furthermore, if not configured to ignore unrecognized updates already applied (the default behavior), then updates must never be removed from this set as the application evolves; see
setIgnoreUnrecognizedUpdates(boolean)for more information on the rationale.- Parameters:
updates- all updates; each update must have a uniquename.- See Also:
-
isIgnoreUnrecognizedUpdates
public boolean isIgnoreUnrecognizedUpdates()Determine whether unrecognized updates are ignored or cause an exception.- Returns:
- true if unrecognized updates should be ignored, false if they should cause an exception to be thrown
- See Also:
-
setIgnoreUnrecognizedUpdates
public void setIgnoreUnrecognizedUpdates(boolean ignoreUnrecognizedUpdates) Configure behavior when an unknown update is registered as having already been applied in the database.The default behavior is
false, which results in an exception being thrown. This protects against accidental downgrades (i.e., running older code against a database with a newer schema), which are not supported. However, this also requires that all updates that might ever possibly have been applied to the database be present in the set of configured updates.Setting this to
truewill result in unrecognized updates simply being ignored. This setting loses the downgrade protection but allows obsolete schema updates to be dropped over time.- Parameters:
ignoreUnrecognizedUpdates- whether to ignore unrecognized updates- See Also:
-
initializeAndUpdateDatabase
Perform database schema initialization and updates.This method applies the following logic: if the database needs initialization, then initialize the database and record each update as having been applied; otherwise, apply any unapplied updates as needed.
Note this implies the database initialization must initialize the database to its current, up-to-date state (with respect to the set of all available updates), not its original, pre-update state.
The database initialization step, and each of the update steps, is performed within its own transaction.
- Parameters:
database- the database to initialize (if necessary) and update- Throws:
Exception- if an update failsUnrecognizedUpdateException- if this instance is not configured to ignore unrecognized updates and an unrecognized update has already been appliedIllegalArgumentException- if two configured updates have the same nameIllegalArgumentException- if any configured update has a required predecessor which is not also a configured update (i.e., if the updates are not transitively closed under predecessors)
-
isValidUpdateName
Determine if the given schema update name is valid. Valid names are non-empty and have no leading or trailing whitespace.- Parameters:
updateName- schema update name- Returns:
- true if
updateNameis valid
-
databaseNeedsInitialization
Determine if the database needs initialization.If so,
initializeDatabase(T)will eventually be invoked.- Parameters:
transaction- open transaction- Returns:
- true if the database needs initialization
- Throws:
Exception- if an error occurs while accessing the database
-
initializeDatabase
Initialize an uninitialized database. This should create and initialize the database schema and content, including whatever portion of that is used to track schema updates.- Parameters:
transaction- open transaction- Throws:
Exception- if an error occurs while accessing the database
-
openTransaction
Begin a transaction on the given database. The transaction will always eventually either be committed or rolled back.- Parameters:
database- database- Returns:
- transaction handle
- Throws:
Exception- if an error occurs while accessing the database
-
commitTransaction
Commit a previously opened transaction.- Parameters:
transaction- open transaction previously returned fromopenTransaction()- Throws:
Exception- if an error occurs while accessing the database
-
rollbackTransaction
Roll back a previously opened transaction. This method will also be invoked ifcommitTransaction()throws an exception.- Parameters:
transaction- open transaction previously returned fromopenTransaction()- Throws:
Exception- if an error occurs while accessing the database
-
getAppliedUpdateNames
Determine which updates have already been applied to the database.- Parameters:
transaction- open transaction- Returns:
- set of already-applied updates
- Throws:
Exception- if an error occurs while accessing the database
-
recordUpdateApplied
Record an update as having been applied to the database.- Parameters:
transaction- open transactionname- update name- Throws:
IllegalStateException- if the update has already been recorded in the databaseException- if an error occurs while accessing the database
-
getOrderingTieBreaker
Determine the preferred ordering of two updates that do not have any predecessor constraints (including implied indirect constraints) between them.The
Comparatorreturned by the implementation inAbstractSchemaUpdatersimply sorts updates by name. Subclasses may override if necessary.- Returns:
- a
Comparatorthat sorts incomparable updates in the order they should be applied
-
generateMultiUpdateName
Generate the update name for one action within a multi-action update.The implementation in
AbstractSchemaUpdaterjust adds a suffix usingindex + 1, padded to 5 digits, producing names likename-00001,name-00002, etc.- Parameters:
update- the schema updateindex- the index of the action (zero based)- Returns:
- update name
- See Also:
-
getAllUpdateNames
Get the names of all updates including multi-action updates.- Returns:
- list of update names
- Throws:
Exception- if an error occurs
-
apply
Execute a database action within an existing transaction.All database operations in
AbstractSchemaUpdaterare performed via this method; subclasses are encouraged to follow this pattern.The implementation in
AbstractSchemaUpdatersimply invokesaction.apply(); subclasses may override if desired.- Parameters:
transaction- transaction within which to applyactionaction- operation to perform- Throws:
Exception- if an error occurs while accessing the database
-
applyInTransaction
Execute a database action. A new transaction will be created, used, and closed. Delegates toapply()for the actual execution of the action.If the action or
commitTransaction()fails, the transaction is rolled back.- Parameters:
database- database to applyactiontoaction- operation to perform- Throws:
Exception- if an error occurs while accessing the database
-