Class Database
- java.lang.Object
-
- io.permazen.core.Database
-
public class Database extends Object
Provides an object database abstraction on top of a key/value database.Includes support for:
- Objects and fields defined by a
SchemaModel
, with positive schema verification - Simple values fields containing any atomic type, reference or custom
FieldType
- Complex fields of type
List
,NavigableSet
, andNavigableMap
- Invertable reference fields with strong referential integrity and configurable delete cascading
- Configurable indexing of any simple field or complex sub-field
- Composite indexes on multiple simple fields
- Notification of object creation and deletion
- Notification of object field changes, as seen through an arbitrary path of references
- Automatic schema tracking and object versioning with schema change notification support
See
Transaction
for further details on the above functionality.This class defines an abstraction layer that usually sits below a
Permazen
but is completely independent ofPermazen
and can be used on its own. Compared toPermazen
, aDatabase
has these differences:- A
SchemaModel
must be explicitly provided to define the schema in use, whereas when using aPermazen
the schema is derived automatically from annotated Java model classes. - Object references are represented by
ObjId
s instead of Java objects, and there is no notion of object sub-type. However, reference fields may be configured with a restricted set of referrable types. - All object types and fields are referenced by explicit storage ID.
- Enum values are represented by
EnumValue
objects. - There is no automatic validation support.
- See Also:
Transaction
,io.permazen
- Objects and fields defined by a
-
-
Field Summary
Fields Modifier and Type Field Description static int
MAX_INDEXED_FIELDS
The maximum number of fields that may be indexed in a composite index (4).
-
Constructor Summary
Constructors Constructor Description Database(KVDatabase kvdb)
Constructor.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description SnapshotTransaction
createSnapshotTransaction(KVStore kvstore, SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a "snapshot" transaction based on the provided key/value store.Transaction
createTransaction(KVTransaction kvt, SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a newTransaction
on this database using an already-openedKVTransaction
and specified schema.Transaction
createTransaction(SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a new transaction.Transaction
createTransaction(SchemaModel schemaModel, int version, boolean allowNewSchema, Map<String,?> kvoptions)
Create a newTransaction
on this database and use the specified schema version to access objects and fields.FieldTypeRegistry
getFieldTypeRegistry()
Get theFieldTypeRegistry
associated with this instance.KVDatabase
getKVDatabase()
Get theKVDatabase
underlying this instance.static void
validateSchema(FieldTypeRegistry fieldTypeRegistry, SchemaModel schemaModel)
Validate aSchemaModel
.void
validateSchema(SchemaModel schemaModel)
Validate aSchemaModel
against this instance.static void
validateSchemas(FieldTypeRegistry fieldTypeRegistry, Collection<SchemaModel> schemaModels)
Check whether a collection ofSchemaModel
s are individually valid and mutually consistent.
-
-
-
Field Detail
-
MAX_INDEXED_FIELDS
public static final int MAX_INDEXED_FIELDS
The maximum number of fields that may be indexed in a composite index (4).- See Also:
- Constant Field Values
-
-
Constructor Detail
-
Database
public Database(KVDatabase kvdb)
Constructor.- Parameters:
kvdb
- the underlying key/value store in which to store information- Throws:
IllegalArgumentException
- ifkvdb
is null
-
-
Method Detail
-
getFieldTypeRegistry
public FieldTypeRegistry getFieldTypeRegistry()
Get theFieldTypeRegistry
associated with this instance.- Returns:
- field type registry associated with this instance
-
getKVDatabase
public KVDatabase getKVDatabase()
Get theKVDatabase
underlying this instance.- Returns:
- underlying key/value database
-
createTransaction
public Transaction createTransaction(SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a new transaction.Convenience method; equivalent to:
createTransaction(schemaModel, version, allowNewSchema, null);
- Parameters:
schemaModel
- schema to use with the new transaction, or null to use the schema already recorded in the databaseversion
- the schema version number corresponding toschemaModel
, zero to use the highest version already recorded in the database, or -1 to use an auto-generated schema versionallowNewSchema
- whether creating a new schema version is allowed- Returns:
- newly created transaction
- Throws:
IllegalArgumentException
- ifversion
is less than -1, or equal to -1 whenschemaModel
is nullInvalidSchemaException
- ifschemaModel
is invalid (i.e., does not pass validation checks)SchemaMismatchException
- ifschemaModel
does not match schema versionversion
as recorded in the databaseSchemaMismatchException
- if schema versionversion
is not recorded in the database andallowNewSchema
is falseSchemaMismatchException
- if schema versionversion
is not recorded in the database,allowNewSchema
is true, butschemaModel
is incompatible with one or more other schemas already recorded in the database (i.e., the same storage ID is used inconsistently between schema versions)SchemaMismatchException
- if the database is uninitialized andversion == 0
orschemaModel
is nullInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalStateException
- if no underlyingKVDatabase
has been configured for this instance
-
createTransaction
public Transaction createTransaction(SchemaModel schemaModel, int version, boolean allowNewSchema, Map<String,?> kvoptions)
Create a newTransaction
on this database and use the specified schema version to access objects and fields.Schema Versions
Within each
Database
is stored a record of all schema versions previously used with the database. When creating a new transaction, the caller provides an expected schema version and correspondingSchemaModel
. Both of these are optional: a schema version of zero means "use the highest version recorded in the database", and a nullSchemaModel
means "use theSchemaModel
already recorded in the database underversion
".When this method is invoked, the following checks are applied:
- If a schema with version number
version != 0
is recorded in the database, andschemaModel
is null or matches it, then this method succeeds, and theTransaction
will use that schema. - If a schema with version number
version
(or the highest numbered schema ifversion == 0
) is recorded in the database, andschemaModel
is not null and does not match it, then this method fails and throws aSchemaMismatchException
. - If
allowNewSchema
is false, and no schema with version numberversion != 0
has yet been recorded in the database, then this method fails and throws aSchemaMismatchException
. - If
allowNewSchema
is true, and no schema with version numberversion != 0
has yet been recorded in the database, then ifschemaModel
is null aSchemaMismatchException
is thrown; otherwiseschemaModel
is checked for compabitility with the schemas previously recorded in the database; if compatible, this method succeeds,schema
is recorded in the database under the new version numberversion
, and theTransaction
will use schema versionversion
; otherwise aSchemaMismatchException
is thrown. - If the database is uninitialized and
version == 0
orschemaModel
is null, aSchemaMismatchException
is thrown.
For two schemas to "match", they must be identical in all respects, except that object, field, and index names may differ. In the core API, objects and fields are identified by storage ID, not name.
Schemas must also be compatible with all other schemas previously recorded in the database. Basically this means storage IDs must be used consistently from a structural point of view:
- Once a storage ID is assigned, it cannot be re-assigned to a different type of item (object or field).
- Fields must have a consistent type and structural parent (object type or complex field).
However, object types and fields may be added or removed across schema versions, field indexing may change, and reference field
DeleteAction
s may change.Object Versions
Each object in a
Database
contains an internal version number that indicates its current schema version; this in turn dictates what fields that object contains.When an object is accessed during a
Transaction
, the object's version is compared to theversion
associated with thatTransaction
. If the versions are the same, no version change occurs and fields are accessed normally.If the object has a version
oldVersion
different fromversion
, then depending on whichTransaction
method is invoked, the object version may be automatically updated toversion
. This will cause fields to be added or removed, as follows:- Fields that are common to both schema versions remain unchanged (necessarily such fields have the same storage ID, type, and structural parent).
- Fields that exist in
oldVersion
but not inversion
are removed. - Fields that exist in
version
but not inoldVersion
are initialized to their default values. - All
VersionChangeListener
s registered with theTransaction
are notified.
Note that compatibility between schema versions does not depend on the field name, nor does it depend on whether the field is indexed, or its
DeleteAction
(for reference fields). A field's index may be added or removed between schema versions without losing information, however, querying a field's index will only return those objects whose schema version corresponds to a schema in which the field is indexed. Similarly, theDeleteAction
taken when a referenced object is deleted depends on theDeleteAction
configured in the schema version of the object containing the reference.Note that an object's current schema version can go up as well as down, may change non-consecutively, and in fact nothing requires schema version numbers to be consecutive.
- Parameters:
schemaModel
- schema to use with the new transaction, or null to use the schema already recorded in the databaseversion
- the schema version number corresponding toschemaModel
, zero to use the highest version already recorded in the database, or -1 to use an auto-generated schema versionallowNewSchema
- whether creating a new schema version is allowedkvoptions
- optionalKVDatabase
-specific transaction options; may be null- Returns:
- newly created transaction
- Throws:
IllegalArgumentException
- ifversion
is less than -1, or equal to -1 whenschemaModel
is nullInvalidSchemaException
- ifschemaModel
is invalid (i.e., does not pass validation checks)SchemaMismatchException
- ifschemaModel
does not match schema versionversion
as recorded in the databaseSchemaMismatchException
- if schema versionversion
is not recorded in the database andallowNewSchema
is falseSchemaMismatchException
- if schema versionversion
is not recorded in the database,allowNewSchema
is true, butschemaModel
is incompatible with one or more other schemas already recorded in the database (i.e., the same storage ID is used inconsistently between schema versions)SchemaMismatchException
- if the database is uninitialized andversion == 0
orschemaModel
is nullInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalStateException
- if no underlyingKVDatabase
has been configured for this instance
- If a schema with version number
-
createTransaction
public Transaction createTransaction(KVTransaction kvt, SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a newTransaction
on this database using an already-openedKVTransaction
and specified schema. The givenKVTransaction
will be committed or rolled-back along with the returnedTransaction
.See
createTransaction(SchemaModel, int, boolean)
for details on schema and object versions.- Parameters:
kvt
- already opened key/value store transactionschemaModel
- schema to use with the new transaction, or null to use the schema already recorded in the databaseversion
- the schema version number corresponding toschemaModel
, zero to use the highest version already recorded in the database, or -1 to use an auto-generated schema versionallowNewSchema
- whether creating a new schema version is allowed- Returns:
- newly created transaction
- Throws:
IllegalArgumentException
- ifkvt
is nullIllegalArgumentException
- ifversion
is less than -1, or equal to -1 whenschemaModel
is nullInvalidSchemaException
- ifschemaModel
is invalid (i.e., does not pass validation checks)SchemaMismatchException
- ifschemaModel
does not match schema versionversion
as recorded in the databaseSchemaMismatchException
- if schema versionversion
is not recorded in the database andallowNewSchema
is falseSchemaMismatchException
- if schema versionversion
is not recorded in the database,allowNewSchema
is true, butschemaModel
is incompatible with one or more other schemas already recorded in the database (i.e., the same storage ID is used inconsistently between schema versions)SchemaMismatchException
- if the database is uninitialized andversion == 0
orschemaModel
is nullInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalStateException
- if no underlyingKVDatabase
has been configured for this instance
-
createSnapshotTransaction
public SnapshotTransaction createSnapshotTransaction(KVStore kvstore, SchemaModel schemaModel, int version, boolean allowNewSchema)
Create a "snapshot" transaction based on the provided key/value store.The key/value store will be initialized if necessary (i.e.,
kvstore
may be empty), otherwise it will be validated against the schema information associated with this instance.The returned
SnapshotTransaction
does not supportcommit()
,rollback()
, oraddCallback()
, and can be used indefinitely.If
kvstore
is aCloseableKVStore
, then it will beclose()
'd if/when the returnedSnapshotTransaction
is.- Parameters:
kvstore
- key/value store, empty or having content compatible with this transaction'sDatabase
schemaModel
- schema to use with the new transaction, or null to use the schema already recorded in the databaseversion
- the schema version number corresponding toschemaModel
, zero to use the highest version already recorded in the database, or -1 to use an auto-generated schema versionallowNewSchema
- whether creating a new schema version inkvstore
is allowed- Returns:
- snapshot transaction based on
kvstore
- Throws:
IllegalArgumentException
- ifversion
is less than -1, or equal to -1 whenschemaModel
is nullInvalidSchemaException
- ifschemaModel
is invalid (i.e., does not pass validation checks)SchemaMismatchException
- ifschemaModel
does not match schema versionversion
as recorded in the databaseSchemaMismatchException
- if schema versionversion
is not recorded in the database andallowNewSchema
is falseSchemaMismatchException
- if schema versionversion
is not recorded in the database,allowNewSchema
is true, butschemaModel
is incompatible with one or more other schemas already recorded in the database (i.e., the same storage ID is used inconsistently between schema versions)SchemaMismatchException
- if the database is uninitialized andversion == 0
orschemaModel
is nullSchemaMismatchException
- ifkvstore
contains incompatible or missing schema informationInconsistentDatabaseException
- if inconsistent or invalid meta-data is detected in the databaseInconsistentDatabaseException
- if an uninitialized database is encountered but the database is not emptyIllegalArgumentException
- ifkvstore
is null- See Also:
Transaction.createSnapshotTransaction()
-
validateSchema
public void validateSchema(SchemaModel schemaModel)
Validate aSchemaModel
against this instance.This is a convenience method, equivalent to:
Database.validateSchema
(this.getFieldTypeRegistry(), schemaModel)
.- Parameters:
schemaModel
- schema to validate- Throws:
InvalidSchemaException
- ifschemaModel
is invalidIllegalArgumentException
- ifschemaModel
is null
-
validateSchema
public static void validateSchema(FieldTypeRegistry fieldTypeRegistry, SchemaModel schemaModel)
Validate aSchemaModel
.This method only statically checks the schema; it does not validate the schema against any other existing schema versions that may be previously recorded in a database.
To validate a schema against a particular database, simply attempt to create a transaction via
createTransaction()
. To validate that a collection of schemas are mutually consistent independently from any database, usevalidateSchemas()
.- Parameters:
fieldTypeRegistry
- registry of simple field typesschemaModel
- schema to validate- Throws:
InvalidSchemaException
- ifschemaModel
is invalidIllegalArgumentException
- if either parameter is null
-
validateSchemas
public static void validateSchemas(FieldTypeRegistry fieldTypeRegistry, Collection<SchemaModel> schemaModels)
Check whether a collection ofSchemaModel
s are individually valid and mutually consistent.This method verifies each schema via
validateSchema()
, and also verifies that the schemas are mututally consistent, i.e., that they do not use storage ID's incompatibly.- Parameters:
fieldTypeRegistry
- registry of simple field typesschemaModels
- schemas to validate (null elements are ignored)- Throws:
InvalidSchemaException
- if an element inschemaModels
is invalidInvalidSchemaException
- if theschemaModels
are not mutally consistentIllegalArgumentException
- if either parameter is null
-
-