#!/usr/bin/env python import threading import os.path import sqlalchemy from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import mapper from sqlalchemy.orm import relationship from dm.common.exceptions.commandFailed import CommandFailed from dm.common.exceptions.configurationError import ConfigurationError from dm.common.utility.loggingManager import LoggingManager from dm.common.utility.configurationManager import ConfigurationManager from dm.aps_user_db.entities import apsUserDbEntityMap class ApsUserDbManager: """ Singleton class for db management. """ DB_CONNECTION_POOL_SIZE = 10 DB_CONNECTION_POOL_MAX_OVERFLOW = 2 DB_CONNECTION_POOL_RECYCYLE_TIME = 600 DB_CONNECTION_POOL_TIMEOUT = 60 DB_CONNECTION_LOGGING_FLAG = False CONFIG_SECTION_NAME = 'ApsUserDbManager' DB_KEY = 'db' DB_USER_KEY = 'dbuser' DB_HOST_KEY = 'dbhost' DB_PORT_KEY = 'dbport' DB_NAME_KEY = 'dbname' DB_SCHEMA_KEY = 'dbschema' DB_PASSWORD_FILE_KEY = 'dbpasswordfile' # Singleton. __lock = threading.RLock() __instance = None @classmethod def getInstance(cls): from dm.aps_user_db.impl.apsUserDbManager import ApsUserDbManager try: mgr = ApsUserDbManager() except ApsUserDbManager, ex: mgr = ex return mgr def __configure(self): cm = ConfigurationManager.getInstance() self.logger.debug('Configuring APS User DB Manager') self.db = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_KEY) self.logger.debug('Using APS DB: %s' % self.db) self.dbUser = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_USER_KEY) self.logger.debug('Using APS DB user: %s' % self.dbUser) self.dbHost = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_HOST_KEY) self.logger.debug('Using APS DB host: %s' % self.dbHost) self.dbPort = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_PORT_KEY) self.logger.debug('Using APS DB port: %s' % self.dbPort) self.dbName = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_NAME_KEY) self.logger.debug('Using APS DB name: %s' % self.dbName) self.dbSchema = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_SCHEMA_KEY) self.logger.debug('Using APS DB schema: %s' % self.dbSchema) self.dbPasswordFile = cm.getConfigOption(ApsUserDbManager.CONFIG_SECTION_NAME, ApsUserDbManager.DB_PASSWORD_FILE_KEY) self.logger.debug('Using APS DB password file: %s' % self.dbPasswordFile) self.dbPassword = open(self.dbPasswordFile, 'r').readline().strip() def __init__(self): ApsUserDbManager.__lock.acquire() try: if ApsUserDbManager.__instance is not None: raise ApsUserDbManager.__instance ApsUserDbManager.__instance = self self.lock = threading.RLock() self.logger = LoggingManager.getInstance().getLogger(self.__class__.__name__) self.__configure() engineUrl = '%s://%s:%s@%s:%s/%s' % (self.db, self.dbUser, self.dbPassword, self.dbHost, self.dbPort, self.dbName) #self.logger.debug('Using engine URL: %s' % engineUrl) self.engine = sqlalchemy.create_engine(engineUrl, pool_size=ApsUserDbManager.DB_CONNECTION_POOL_SIZE, max_overflow=ApsUserDbManager.DB_CONNECTION_POOL_MAX_OVERFLOW, pool_recycle=ApsUserDbManager.DB_CONNECTION_POOL_RECYCYLE_TIME, echo=ApsUserDbManager.DB_CONNECTION_LOGGING_FLAG, pool_timeout=ApsUserDbManager.DB_CONNECTION_POOL_TIMEOUT) self.metadata = sqlalchemy.MetaData(engineUrl, schema=self.dbSchema) self.logger.debug('Mapping DB tables') for (dbTableName, (dbEntityClass, dbRelationDict)) in apsUserDbEntityMap.APS_USER_DB_ENTITY_MAP.items(): self.mapTable(dbEntityClass, dbTableName, dbRelationDict) self.logger.debug('Initialized SQLalchemy engines') finally: ApsUserDbManager.__lock.release() def getLogger(self): return self.logger def inspectTables(self): from sqlalchemy import inspect inspector = inspect(self.engine) self.logger.debug('Inspecting tables') for tableName in inspector.get_table_names(): self.logger.debug('Table: %s' % tableName) for column in inspector.get_columns(tableName): self.logger.debug('Column: %s' % column['name']) def inspectTables2(self): from sqlalchemy import MetaData m = MetaData() m.reflect(self.engine) self.logger.debug('Inspecting tables via metadata') for table in m.tables.values(): self.logger.debug('Table: %s' % table.name) for column in table.c: self.logger.debug('Column: %s' % column.name) def initTable(self, tableClass, tableName): """ Initialize DB table. """ self.lock.acquire() try: tbl = sqlalchemy.Table(tableName, self.metadata, autoload=True) tableClass.columns = tbl.columns return tbl finally: self.lock.release() def mapTable(self, tableClass, tableName, relationDict): """ Map DB table to a given class. """ self.lock.acquire() try: table = sqlalchemy.Table(tableName, self.metadata, autoload=True) tableClass.columns = table.columns # Build relations from specified foreign key columns and other properties. tableRelations = {} primaryKey = None for (name, propertyDict) in relationDict.items(): if name == 'self': primaryKey = propertyDict.get('primary_key') continue lazy = propertyDict.get('lazy') parentEntity = propertyDict.get('parentEntity') foreignKeyColumns = propertyDict.get('foreignKeyColumns', []) if len(foreignKeyColumns): fkList = [] for fk in foreignKeyColumns: fkList.append(table.columns.get(fk)) tableRelations[name] = relationship(parentEntity, foreign_keys=fkList, lazy=lazy) else: tableRelations[name] = relationship(parentEntity, lazy=lazy) if primaryKey: mapper(tableClass, table, tableRelations, primary_key=table.columns.get(primaryKey)) else: mapper(tableClass, table, tableRelations) return table finally: self.lock.release() def getMetadataTable(self, table): return self.metadata.tables[table] def openSession(self): """ Open db session. """ self.lock.acquire() try: Session = sessionmaker(bind=self.engine) return Session() finally: self.lock.release() def closeSession(self, session): """ Close db session. """ self.lock.acquire() try: session.close() finally: self.lock.release() def acquireConnection(self): """ Get db connection. """ self.lock.acquire() try: return self.engine.connect() finally: self.lock.release() def releaseConnection(self, connection): """ Release db connection. """ self.lock.acquire() try: if connection: connection.close() finally: self.lock.release() ####################################################################### # Testing. if __name__ == '__main__': ConfigurationManager.getInstance().setConsoleLogLevel('debug') mgr = ApsUserDbManager.getInstance() mgr.acquireConnection() mgr.inspectTables() mgr.inspectTables2() print 'Got connection'