############################################################################## # # Copyright (c) 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """DBTab and DatabaseFactory classes. $Id: DBTab.py 24763 2004-05-17 05:59:28Z philikon $ """ import sys from thread import allocate_lock from ZODB.ActivityMonitor import ActivityMonitor import Globals from Exceptions import DBTabConfigurationError class DBTab: """A Zope database configuration, similar in purpose to /etc/fstab. """ def __init__(self, db_factories, mount_paths): self._started = 0 self.opened = {} # { name -> Database instance } self.lock = allocate_lock() self.db_factories = db_factories # { name -> DatabaseFactory } self.mount_paths = mount_paths # { virtual path -> name } def startup(self): """Opens the databases set to open_at_startup.""" if self._started: return self._started = 1 for name, factory in self.db_factories.items(): if factory.getOpenAtStartup(): self.getDatabase(name=name) def listMountPaths(self): """Returns a sequence of (virtual_mount_path, database_name). """ return self.mount_paths.items() def listDatabaseNames(self): """Returns a sequence of names. """ return self.db_factories.keys() def hasDatabase(self, name): """Returns true if name is the name of a configured database.""" return self.db_factories.has_key(name) def _mountPathError(self, mount_path): if mount_path == '/': raise DBTabConfigurationError( "No root database configured") else: raise DBTabConfigurationError( "No database configured for mount point at %s" % mount_path) def getDatabase(self, mount_path=None, name=None, is_root=0): """Returns an opened database. Requires either mount_path or name. """ self.startup() if name is None: if mount_path is None: raise ValueError('Either mount_path or name is required') name = self.mount_paths.get(mount_path) if name is None: self._mountPathError(mount_path) db = self.opened.get(name) if db is None: if not self.db_factories.has_key(name): raise KeyError('%s is not a configured database' % repr(name)) self.lock.acquire() try: # Check again, since the database may have been created # by another thread before the lock was acquired. db = self.opened.get(name) if db is None: db = self._createDatabase(name, is_root) finally: self.lock.release() return db def getDatabaseFactory(self, mount_path=None, name=None): if name is None: if mount_path is None: raise ValueError('Either mount_path or name is required') name = self.mount_paths.get(mount_path) if name is None: self._mountPathError(mount_path) return self.db_factories[name] def _createDatabase(self, name, is_root): factory = self.db_factories[name] db = factory.open() self.opened[name] = db if not is_root: Globals.opened.append(db) # If it is the root database, Zope will add the database to # Globals.opened. A database should not be listed twice. return db