public final class DatabaseManager
extends java.lang.Object
Persistence
class, but since it
contains generally useful methods, it has been made public.
During server bootstrap, this class reads configuration data from the directory service. This information includes the names of databases which must be configured and be permanently accessible, as well as those which are considered "transient". A transient database is one which can be connected to and disconnected from (in the Progress sense) on demand, from application code.
When a database is initialized for use via Hibernate, whether permanent
or transient, additional configuration data, including Hibernate's
configuration properties, is read from the directory service. This is
assembled into a Properties
object and passed to Hibernate's
configuration subsystem.
Each database is represented by a Hibernate SessionFactory
object, which is the object which the Persistence
class uses
to create database Session
s lazily. In addition to the
configuration options read from the directory, each session factory
requires the list of ORM mapping classes which will be used to represent
database tables in any session established with that database.
SessionFactory
objects for transient databases are created on
demand, which can be an expensive process. A session factory for a
transient database is required when at least one client session connects
dynamically to that database. A reference count is maintained across
client sessions for each transient database, such that a session factory
need not be created for one client context, if another is already using it.
Session factory objects for transient databases thus are not discarded
while any context is connected to the associated database.
This class can both register remote databases for local use, as well as
serve requests from remote servers to provide access to local databases.
Whether a database is remote or local is transparent to users of this
class. Both are registered using the registerDatabase(Database)
method.
Implementation Note: several methods of this class synchronizes on two objects:
configLock
sessionFactories
configLock
is the less granular of these. It is important
that any code path which requires access to both locks simultaneously
always acquire configLock
first, then
sessionFactories
, to avoid deadlock.
Modifier and Type | Class and Description |
---|---|
private static interface |
DatabaseManager.Activator
Database activator.
|
private static class |
DatabaseManager.AutoConnected
The guarded set of auto-connected sessions for the local database
|
private static class |
DatabaseManager.Context
A class containing context-specific data.
|
static interface |
DatabaseManager.DatabaseConfigFetcher
Interface for a remote object whose purpose is to fetch a local
DatabaseConfig
object and deliver it to the remote caller. |
static class |
DatabaseManager.DatabaseConfigFetcherImpl
Concrete implementation of the
DatabaseConfigFetcher interface. |
Modifier and Type | Field and Description |
---|---|
private static java.lang.String |
CFG_AUTO_CONNECT
session auto-connection registry key
|
private static java.lang.Object |
configLock
Object upon which configuration routines synchronize
|
private static ContextLocal<DatabaseManager.Context> |
context
Context local data
|
static java.lang.String |
CP_ACQUIRE_INCREMENT
Connection pool acquire increment key name
|
static java.lang.String |
CP_INIT_POOL_SIZE
Initial connection pool size key name
|
static java.lang.String |
CP_MAX_POOL_SIZE
Maximum connection pool size key name
|
static java.lang.String |
CP_MIN_POOL_SIZE
Minimum connection pool size key name
|
private static java.util.Map<Database,DatabaseConfig> |
dbConfigs
Map of local DatabaseConfig objects, keyed by database info objects
|
private static java.util.Map<Database,DatabaseManager.AutoConnected> |
dbSessions
Map of session auto-connected databases to the guarded sets of connected sessions.
|
private static java.util.Map<Database,Dialect> |
dialects
Map of databases to database
Dialect objects |
private static java.util.Set<Database> |
dirtyDBs
Registered dirty databases
|
static boolean |
FORCE_NO_UNDO_TEMP_TABLES
Flag indicating temp-tables must be NO-UNDO application-wide
|
private static boolean |
initialized
Flag indicating persistence has been initialized
|
private static java.util.List<java.lang.String> |
loadedOnStartupDBs
Local databases configured as 'load_at_statup'
|
private static java.util.Map<Database,LockTableUpdater> |
lockTableUpdaters
Map of LockTableUpdater instances, keyed by database
|
private static java.util.logging.Logger |
log
Logger.
|
private static java.util.Set<Database> |
managed
Set of all databases managed by the local P2J server instance
|
static int |
MIXED_MODE_SSL_PORT
Port for mixed mode, remote, SSL connections to embedded databases
|
static java.lang.String |
PRIMARY_KEY
Reserved name of primary key identifier column/property
|
private static java.util.Set<java.lang.String> |
readOnly
Set of DMO entity names which correspond to read-only tables
|
private static java.util.concurrent.ScheduledExecutorService |
scheduler
Auto-connections' cleanup executor
|
private static java.util.Map<Database,java.lang.String> |
schemaByDatabase
Map of schema names, keyed by database
|
static Database |
TEMP_TABLE_DB
Temp table database information object
|
static java.lang.String |
TEMP_TABLE_SCHEMA
Reserved name of temp table schema
|
private static java.util.Map<Database,java.lang.Integer> |
transientDatabases
Map of transient databases to reference counts of registrations
|
private static boolean |
useMeta
Flag indicating that the metadata manager was initialized
|
Modifier | Constructor and Description |
---|---|
private |
DatabaseManager()
This class cannot be instantiated; all methods are static.
|
Modifier and Type | Method and Description |
---|---|
static void |
activate(java.lang.String pdb)
Activate local primary database.
|
private static void |
activateAndRegister(java.lang.Integer sessionId,
Database db,
DatabaseManager.Activator activator)
Activate and register the database for the user session.
|
private static void |
activateDb(DatabaseConfig cfg,
Database database)
Activate database - register the database with the persistence framework.
|
private static void |
activateMetaDb(java.lang.String schema,
Database primaryDB,
Database metaDB)
Activate meta database.
|
static void |
autoConnect()
Auto-connect databases configured to be auto-connected on session start
|
private static void |
checkRemoteConnectURL(Database database,
Settings settings)
Validate and possibly modify the remote connection URL.
|
private static Settings |
createDefaultTempSettings()
This method returns the ORM settings which should be used when connecting to the primary
temp-table database.
|
private static Settings |
createEmbeddedSettings(Database database)
This method returns the Hibernate properties which should be used when connecting to a
secondary (e.g., dirty or metadata) database associated with a normal database.
|
private static void |
deactivate(Database db,
long deactivateIfNotUsedSec)
Deactivate session auto-connected database.
|
static void |
deactivate(java.lang.Integer sessionId,
Database db,
boolean cleanup)
Deactivate session auto-connected database.
|
(package private) static boolean |
deregisterDatabase(Database database)
Deregister the specified, transient database, if and only if all other
contexts using the database have deregistered it.
|
(package private) static void |
deregisterDynamicTable(java.lang.Class<? extends DataModelObject> dmoIface)
Deregister dynamic table represented by the given DMO interface and persistent class.
|
static RecordLockInfo[] |
getAllRecordLockInfo()
Gather snapshots of all record locks for all, non-temporary, permanently
connected databases which are authoritatively managed by this P2J server
instance.
|
static java.lang.String |
getBackingTableName(java.lang.Class<? extends Record> dmoClass)
Retrieve the database table name for a given DMO implementation class.
|
static java.util.Map<java.lang.String,java.lang.String> |
getColumnToPropertyMap(Database database,
java.lang.Class<? extends Record> dmoClass,
java.util.Set<java.lang.String> columnNames,
boolean includePK)
Get a mapping of column names to property names for the given DMO in the given database.
|
static DatabaseConfig |
getConfiguration(Database database)
Get the database configuration.
|
(package private) static DatabaseConfig |
getDatabaseConfig(Database database)
Get the local or remote configuration for the given database.
|
static java.util.List<java.lang.String> |
getDatabaseDMOs(Database database)
Get the table DMO names of the given database.
|
static java.util.List<java.lang.String> |
getDatabaseTables(Database database)
Get the tables of the given database.
|
static Dialect |
getDialect(Database database)
Report the database dialect in use for the given database.
|
static java.lang.String |
getEntityNameByTableName(Database database,
java.lang.String table)
Get the entity name which corresponds the given table of the given database.
|
(package private) static java.lang.Boolean |
getIgnoreCase(java.lang.Class<? extends Record> dmoClass,
java.lang.String property)
For a given DMO property which may represent an indexed text column, indicate whether that
column is set to ignore case.
|
private static DatabaseConfig |
getLocalConfiguration(Database database)
Get all data necessary to configure a database managed by the current
P2J server instance.
|
static LockTableUpdater |
getLockTableUpdater(Database database)
Return the lock table updater associated with the given database, if any.
|
static java.util.List<Database> |
getManagedDatabases()
Get a list of all configured databases managed by this P2J server instance.
|
private static DatabaseConfig |
getRemoteConfiguration(Database database)
Get all data necessary to configure a database managed by a remote P2J server instance.
|
static java.lang.String |
getSchema(Database database)
Lookup the schema name associated with the given physical database
name.
|
static character |
getTenantName()
Implementation of the TENANT-NAME() builtin function.
|
static character |
getTenantName(character db)
Implementation of the TENANT-NAME() builtin function.
|
static character |
getTenantName(java.lang.String db)
Implementation of the TENANT-NAME() builtin function.
|
private static void |
initDb(java.lang.String pdb)
Initialize local database.
|
(package private) static void |
initialize()
Initialize the persistence framework.
|
private static void |
initMetaDb(java.lang.String schema,
Database primaryDB,
Database metaDB)
Initialize meta database
|
private static void |
initTempDb()
Initialize _temp database.
|
(package private) static boolean |
isAuthoritative(Database database)
Indicate whether this P2J server instance is authoritative for the given
database.
|
static logical |
isDbMultiTenant()
Implementation of the IS-DB-MULTITENANT() builtin function.
|
static logical |
isDbMultiTenant(character db)
Implementation of the IS-DB-MULTITENANT() builtin function.
|
static logical |
isDbMultiTenant(java.lang.String db)
Implementation of the IS-DB-MULTITENANT() builtin function.
|
static boolean |
isInitializing()
Indicate whether the database manager is currently initializing.
|
(package private) static boolean |
isPermamentDB(Database database)
Check if the specified database is a permanent database.
|
static boolean |
isReadOnly(java.lang.String entity)
Check if the DMO class corresponds to the read-only table
|
(package private) static boolean |
isTempTable(java.lang.Class<?> dmoClass)
Helper method to determine whether the specified class or interface
represents the DMO front-end for temp table records.
|
static java.util.List<java.lang.String> |
loadedOnStartup()
Get list of local databases loaded on startup.
|
private static Settings |
loadSettings(Database database)
Load configuration from the P2J directory service and return it as a
Settings
object. |
private static DatabaseConfig |
readDatabaseConfig(Database database)
Read from the directory all data necessary to configure a database
managed by the current P2J server instance.
|
private static void |
readOrmSettings(DirectoryService ds,
java.lang.String id,
java.lang.String prefix,
Settings settings)
Read ORM configuration properties from the directory and populate a properties file which
will be passed to the ORM subsystem to configure database access.
|
(package private) static boolean |
registerDatabase(Database database)
Register an individual database with the persistence framework.
|
private static boolean |
registerDatabase(DatabaseConfig dbConfig,
Database database,
boolean bootstrap,
boolean updateRefCount)
Register an individual database with the persistence framework.
|
private static void |
registerDb(Database database)
Register database.
|
(package private) static boolean |
registerDirtyDatabase(Database database)
Given a normal database, this method will register its associated dirty database with the
persistence framework.
|
private static boolean |
registerDirtyDatabase(DatabaseConfig dbConfig,
Database database,
boolean bootstrap)
Given a normal database, this method will register its associated dirty database; the
created dirty database will have the same name as the original database.
|
(package private) static void |
registerDynamicTable(java.lang.Class<? extends DataModelObject> dmoIface)
Register dynamic table represented by the given DMO interface.
|
private static int |
updateTransientRefCount(Database database,
boolean increment)
Update the reference count of registrations of the specified database
across all contexts.
|
private static int |
updateTransientRefCountWorker(Database database,
int delta)
Update the reference count of registrations of the specified database.
|
private static final java.util.logging.Logger log
private static final java.lang.String CFG_AUTO_CONNECT
public static final java.lang.String TEMP_TABLE_SCHEMA
public static final Database TEMP_TABLE_DB
public static final boolean FORCE_NO_UNDO_TEMP_TABLES
public static final java.lang.String PRIMARY_KEY
public static final int MIXED_MODE_SSL_PORT
public static final java.lang.String CP_INIT_POOL_SIZE
public static final java.lang.String CP_MIN_POOL_SIZE
public static final java.lang.String CP_MAX_POOL_SIZE
public static final java.lang.String CP_ACQUIRE_INCREMENT
private static final java.util.Map<Database,DatabaseConfig> dbConfigs
private static final java.util.Map<Database,java.lang.String> schemaByDatabase
private static final java.util.List<java.lang.String> loadedOnStartupDBs
private static final java.util.Map<Database,DatabaseManager.AutoConnected> dbSessions
private static final java.util.concurrent.ScheduledExecutorService scheduler
private static java.util.Set<Database> dirtyDBs
private static final java.util.Map<Database,Dialect> dialects
Dialect
objectsprivate static final java.util.Map<Database,java.lang.Integer> transientDatabases
private static final java.util.Set<Database> managed
private static final java.util.Set<java.lang.String> readOnly
private static boolean useMeta
private static final ContextLocal<DatabaseManager.Context> context
private static final java.lang.Object configLock
private static java.util.Map<Database,LockTableUpdater> lockTableUpdaters
private static volatile boolean initialized
private DatabaseManager()
public static java.util.List<java.lang.String> loadedOnStartup()
public static Dialect getDialect(Database database)
database
- Database information object.database
.public static java.lang.String getSchema(Database database)
database
- Database information object. May be null
if
dmoClass
represents a temporary table.public static java.lang.String getBackingTableName(java.lang.Class<? extends Record> dmoClass)
dmoClass
- DMO implementation class to which the table is mapped.public static java.util.List<Database> getManagedDatabases()
public static RecordLockInfo[] getAllRecordLockInfo()
public static java.lang.String getEntityNameByTableName(Database database, java.lang.String table)
database
- Database which contains the target table.table
- Target tablepublic static java.util.List<java.lang.String> getDatabaseTables(Database database)
database
- Target database.public static java.util.List<java.lang.String> getDatabaseDMOs(Database database)
database
- Target database.public static java.util.Map<java.lang.String,java.lang.String> getColumnToPropertyMap(Database database, java.lang.Class<? extends Record> dmoClass, java.util.Set<java.lang.String> columnNames, boolean includePK)
database
- Target database.dmoClass
- Target DMO implementation class.columnNames
- Set of column names to be mapped to properties. If null
, all of the table's
columns will be mapped to DMO property names.includePK
- true
to include the reserved mapping of primary "recid" to reserved
property name "recid"; false
to omit this mapping.public static boolean isReadOnly(java.lang.String entity)
entity
- DMO entity name.true
if the DMO entity corresponds to a read-only table.public static logical isDbMultiTenant()
public static logical isDbMultiTenant(java.lang.String db)
db
- The db name.public static logical isDbMultiTenant(character db)
db
- The db name.public static character getTenantName()
public static character getTenantName(java.lang.String db)
db
- The db name.public static character getTenantName(character db)
db
- The db name.public static DatabaseConfig getConfiguration(Database database) throws PersistenceException
database
- the database which configuration is requestedPersistenceException
- if an error occurs accessing configuration data.public static void autoConnect()
public static void deactivate(java.lang.Integer sessionId, Database db, boolean cleanup)
sessionId
- User session Id, if null
get from the SecurityManager.db
- Database to be deactivated.cleanup
- Flag indicating that session cleanup is in progress.static boolean isTempTable(java.lang.Class<?> dmoClass)
dmoClass
- A DMO interface or implementation class.true
if dmoClass
is assignable from
the Temporary
marker interface; else
false
.static boolean isPermamentDB(Database database)
true
only if
the database is neither a dirty database nor the temporary database.database
- The database to be checked.true
if this database object is configured for a
permanent DB.static void initialize() throws PersistenceException
Remote database service provider exports are registered at this time as well. This includes services to fetch database configurations for remote requesters, record locking services, and the tracking of dirty records within uncommitted transactions.
Databases and the DMO classes associated with them are determined by reading the DMO index configuration file. The location of this file is read from the P2J directory. Hibernate configuration properties for each session factory are read from the directory as well.
The logic flow is:
Configuration
;
SessionFactory
from the
configuration and store it in a map, keyed by the database
name (not the schema name, which may be different)
java.lang.IllegalStateException
- if invoked more than once.PersistenceException
- if any error is encountered initializing the persistence
framework.private static void deactivate(Database db, long deactivateIfNotUsedSec)
db
- Database to be deactivated.deactivateIfNotUsedSec
- Idle period threshold for deactivation in sec.private static void initDb(java.lang.String pdb) throws PersistenceException
pdb
- Database name.PersistenceException
- on initialization failure.private static void activateMetaDb(java.lang.String schema, Database primaryDB, Database metaDB) throws PersistenceException
schema
- Schema name.primaryDB
- Primary database.metaDB
- Meta database.PersistenceException
- on initialization failure.private static void activateDb(DatabaseConfig cfg, Database database) throws PersistenceException
cfg
- Database configuration.database
- Database to be activated.PersistenceException
- on initialization failure.public static void activate(java.lang.String pdb) throws PersistenceException
pdb
- Database name.PersistenceException
- on initialization failure.private static void activateAndRegister(java.lang.Integer sessionId, Database db, DatabaseManager.Activator activator) throws PersistenceException
sessionId
- The user session Id.db
- Database to be activated and registered.activator
- Database DatabaseManager.Activator
PersistenceException
- on activation failure.private static void initMetaDb(java.lang.String schema, Database primaryDB, Database metaDB) throws PersistenceException
schema
- Schema nameprimaryDB
- Primary database.metaDB
- Meta database.PersistenceException
- on initialization failure.private static void registerDb(Database database) throws PersistenceException
database
- Database to be registered.PersistenceException
- on initialization failure.private static void initTempDb() throws PersistenceException
initialize()
.PersistenceException
- on initialization failure.public static boolean isInitializing()
true
if database manager is initializing, else false
if
initialization is complete.static boolean registerDatabase(Database database) throws PersistenceException
database
- Database to be configured.true
if the database was newly registered; false
if the database already was
registered, and only the reference count was incremented, or if this registration attempt was
redundant in the local context.PersistenceException
- if database
is not recognized, based upon configuration information in the directory.static boolean registerDirtyDatabase(Database database) throws PersistenceException
database
- Database to be configured.true
if the database was newly registered; false
if the database already was
registered, and only the reference count was incremented, or if this registration attempt was
redundant in the local context.PersistenceException
- if database
is not recognized, based upon configuration information in the directory.static void registerDynamicTable(java.lang.Class<? extends DataModelObject> dmoIface)
dmoIface
- DMO interface class.static void deregisterDynamicTable(java.lang.Class<? extends DataModelObject> dmoIface)
dmoIface
- DMO interface class.public static LockTableUpdater getLockTableUpdater(Database database)
database
- A primary database for which the lock table updater is needed.null
if lock metadata is not used by the
current application.java.lang.IllegalArgumentException
- if lock metadata is used by the current application, but no lock table updater is
found for the given database.static DatabaseConfig getDatabaseConfig(Database database) throws PersistenceException
database
- The database instance.PersistenceException
private static DatabaseConfig getLocalConfiguration(Database database) throws PersistenceException
database
- A locally managed database.PersistenceException
- if an error occurs accessing configuration data.private static DatabaseConfig getRemoteConfiguration(Database database) throws PersistenceException
database
- A remotely managed database.PersistenceException
- if the specified database is not managed by the remote server.private static void checkRemoteConnectURL(Database database, Settings settings) throws PersistenceException
settings
object and confirming it
begins with the necessary jdbc:
prefix.
The URL setting is modified in the event it specifies a localhost/loopback address. Such an
address specification is relative to the remote server and is most likely invalid for the
requesting server. The host in such a case is replaced the host name specified in database
, and the modified URL is set back into settings
under the appropriate
key.
NOTE: this approach assumes the local and remote servers share a DNS which will resolve the given connection URL to the same physical address.
database
- Object containing address information for the remotely managed database.settings
- ORM configuration as reported by the remote server. This is a local copy of the
remote settings; it is modified by this method.PersistenceException
- if the connection URL specified in settings
is missing or invalid.private static DatabaseConfig readDatabaseConfig(Database database) throws PersistenceException
database
- A locally managed database.PersistenceException
- if an error occurs accessing configuration data.static boolean deregisterDatabase(Database database)
database
, without
first building a new session factory (an expensive process).database
- Database to be deregistered.true
if database
was deregistered;
else false
. Note that the latter does not
represent an error condition, but rather indicates that the
database could not be deregistered because other contexts
still referenced it, or because it is a permanent database.java.lang.IllegalArgumentException
- if database
is not currently registered.static boolean isAuthoritative(Database database)
database
- Database information object.true
if this server instance is authoritative for
the specified database.static java.lang.Boolean getIgnoreCase(java.lang.Class<? extends Record> dmoClass, java.lang.String property)
dmoClass
- DMO implementation class.property
- DMO property name.true
to ignore case, false
to preserve case sensitivity,
null
if the property does not represent an indexed text column.private static boolean registerDirtyDatabase(DatabaseConfig dbConfig, Database database, boolean bootstrap) throws PersistenceException
The dirty database is hard-coded to be an in-memory H2 database. See
createEmbeddedSettings(Database)
method for the Hibernate settings used.
dbConfig
- Configuration properties for the given database.database
- Database to be configured.bootstrap
- true
if this method is invoked during bootstrap
initialization at server start-up; false
if
invoked otherwise. If false
, it is assumed that
database
represents a transient database.true
if the dirty database was newly registered;
false
if the database was already registered, and
only the reference count was incremented (transient only), or
if this registration attempt was redundant in the local
context.PersistenceException
- If there is an error configuring the Hibernate framework.java.lang.IllegalStateException
- if database
is permanent and already has been
registered.java.lang.IllegalArgumentException
- if database
is not recognized, based upon
configuration information in the directory.private static boolean registerDatabase(DatabaseConfig dbConfig, Database database, boolean bootstrap, boolean updateRefCount) throws PersistenceException
Configuration
;
SessionFactory
from the
configuration and store it in a map, keyed by the database
name (not the schema name, which may be different)
This method may be invoked during bootstrap initialization, to register a permanent database, or after initialization, to dynamically register a transient database.
dbConfig
- Configuration properties for the given database.database
- Database to be configured.bootstrap
- true
if this method is invoked during bootstrap
initialization at server start-up; false
if
invoked otherwise. If false
, it is assumed that
database
represents a transient database.updateRefCount
- true
if the transient reference count should be updated;
else false
.true
if the (permanent or transient) database was
newly registered;
false
if the database was already registered, and
only the reference count was incremented (transient only), or
if this registration attempt was redundant in the local
context.PersistenceException
- If there is an error configuring the Hibernate framework.java.lang.IllegalStateException
- if database
is permanent and already has been
registered.private static int updateTransientRefCount(Database database, boolean increment)
The reference count is either incremented by 1, decremented by 1, or left unchanged, based upon the following rules:
increment
is true
:
database
is already registered in the local
context, no change is made;
increment
is false
:
database
is not registered in the local
context, no change is made;
This logic ensures that attempts to register and deregister the same database, if not properly bracketed, will not corrupt the global reference count.
database
- A transient database.increment
- true
to increment reference count by 1;
false
to decrement reference count by 1;
See above for the implications of this.database
after the update; or -1 if
database
was not recognized.private static int updateTransientRefCountWorker(Database database, int delta)
delta
have been correctly computed,
respectively updateTransientRefCount()
where the current context is inspected
to see if incrementation is needed, or from context clean when all databases from context
should be de-ref counted (and delta
is -1).database
- A transient database.delta
- Specifies the direction of change (1 = increment, -1 decrement, 0 = no change);
See updateTransientRefCount() for details.database
after the update; or -1 if
database
was not recognized.private static Settings loadSettings(Database database) throws PersistenceException
Settings
object. The contents of this object must match the properties expected by the ORM
framework.database
- Database for which properties are to be loaded. This differentiates the directory
key by database name.PersistenceException
- if no configuration properties for the specified database were found, or if the
directory service is unavailable.private static Settings createEmbeddedSettings(Database database)
database
- The database information object for the embedded database.private static Settings createDefaultTempSettings()
private static void readOrmSettings(DirectoryService ds, java.lang.String id, java.lang.String prefix, Settings settings)
Properties are organized hierarchically in the directory. This method recursively walks the tree and adds a new property entry when it reaches any directory entry terminus. Keys are qualified with the given prefix, if any.
This method does not know or care about the names of individual properties; it simply performs a depth-first enumeration of a directory subtree and composes the property names from the directory entry names it encounters. Error checking of property names and values is left to the ORM configuration subsystem.
ds
- Directory service instance.id
- Directory entry key for the node currently being visited.prefix
- Prefix to prepend to key (may be empty string, but not null
.settings
- Object to which settings are added.