src/pyams_utils/zodb.py
changeset 10 e87103c49c8a
parent 1 3f89629b9e54
child 17 c5a19fddac05
equal deleted inserted replaced
9:6a55c8cbced0 10:e87103c49c8a
    15 
    15 
    16 # import standard library
    16 # import standard library
    17 
    17 
    18 # import interfaces
    18 # import interfaces
    19 from persistent.interfaces import IPersistent
    19 from persistent.interfaces import IPersistent
       
    20 from pyams_utils.interfaces.site import IOptionalUtility
       
    21 from pyams_utils.interfaces.zeo import IZEOConnection
    20 from transaction.interfaces import ITransactionManager
    22 from transaction.interfaces import ITransactionManager
    21 from ZODB.interfaces import IConnection
    23 from ZODB.interfaces import IConnection
       
    24 from zope.annotation.interfaces import IAttributeAnnotatable
       
    25 from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent
       
    26 from zope.schema.interfaces import IVocabularyFactory
    22 
    27 
    23 # import packages
    28 # import packages
       
    29 from persistent import Persistent
    24 from pyams_utils.adapter import adapter_config
    30 from pyams_utils.adapter import adapter_config
       
    31 from pyramid.events import subscriber
       
    32 from ZEO import ClientStorage
       
    33 from ZODB import DB
       
    34 from zope.componentvocabulary.vocabulary import UtilityVocabulary
       
    35 from zope.container.contained import Contained
       
    36 from zope.interface import implementer, provider
       
    37 from zope.schema import getFieldNames
       
    38 from zope.schema.fieldproperty import FieldProperty
       
    39 from zope.schema.vocabulary import getVocabularyRegistry
    25 
    40 
    26 
    41 
    27 @adapter_config(context=IPersistent, provides=IConnection)
    42 @adapter_config(context=IPersistent, provides=IConnection)
    28 def get_connection(obj):
    43 def get_connection(obj):
    29     """An adapter which gets a ZODB connection of a persistent object.
    44     """An adapter which gets a ZODB connection of a persistent object.
    44 # IPersistent adapters copied from zc.twist package
    59 # IPersistent adapters copied from zc.twist package
    45 # also register this for adapting from IConnection
    60 # also register this for adapting from IConnection
    46 @adapter_config(context=IPersistent, provides=ITransactionManager)
    61 @adapter_config(context=IPersistent, provides=ITransactionManager)
    47 def get_transaction_manager(obj):
    62 def get_transaction_manager(obj):
    48     conn = IConnection(obj)  # typically this will be
    63     conn = IConnection(obj)  # typically this will be
    49                              # zope.app.keyreference.persistent.connectionOfPersistent
    64                              # zope.keyreference.persistent.connectionOfPersistent
    50     try:
    65     try:
    51         return conn.transaction_manager
    66         return conn.transaction_manager
    52     except AttributeError:
    67     except AttributeError:
    53         return conn._txn_mgr
    68         return conn._txn_mgr
    54         # or else we give up; who knows.  transaction_manager is the more
    69         # or else we give up; who knows.  transaction_manager is the more
    55         # recent spelling.
    70         # recent spelling.
       
    71 
       
    72 
       
    73 @implementer(IZEOConnection)
       
    74 class ZEOConnection(object):
       
    75     """ZEO connection object"""
       
    76 
       
    77     _storage = None
       
    78     _db = None
       
    79     _connection = None
       
    80 
       
    81     name = FieldProperty(IZEOConnection['name'])
       
    82     server_name = FieldProperty(IZEOConnection['server_name'])
       
    83     server_port = FieldProperty(IZEOConnection['server_port'])
       
    84     storage = FieldProperty(IZEOConnection['storage'])
       
    85     username = FieldProperty(IZEOConnection['username'])
       
    86     password = FieldProperty(IZEOConnection['password'])
       
    87     server_realm = FieldProperty(IZEOConnection['server_realm'])
       
    88     blob_dir = FieldProperty(IZEOConnection['blob_dir'])
       
    89     shared_blob_dir = FieldProperty(IZEOConnection['shared_blob_dir'])
       
    90 
       
    91     def get_settings(self):
       
    92         result = {}
       
    93         for name in getFieldNames(IZEOConnection):
       
    94             result[name] = getattr(self, name)
       
    95         return result
       
    96 
       
    97     def update(self, settings):
       
    98         names = getFieldNames(IZEOConnection)
       
    99         for key, value in settings.items():
       
   100             if key in names:
       
   101                 setattr(self, key, value)
       
   102 
       
   103     def get_connection(self, wait=False, get_storage=False):
       
   104         storage = ClientStorage.ClientStorage((self.server_name, self.server_port),
       
   105                                               storage=self.storage,
       
   106                                               username=self.username or '',
       
   107                                               password=self.password or '',
       
   108                                               realm=self.server_realm,
       
   109                                               blob_dir=self.blob_dir,
       
   110                                               shared_blob_dir=self.shared_blob_dir,
       
   111                                               wait=wait)
       
   112         db = DB(storage)
       
   113         return (storage, db) if get_storage else db
       
   114 
       
   115     @property
       
   116     def connection(self):
       
   117         return self._connection
       
   118 
       
   119     # Context manager methods
       
   120     def __enter__(self):
       
   121         self._storage, self._db = self.get_connection(get_storage=True)
       
   122         self._connection = self._db.open()
       
   123         return self._connection.root()
       
   124 
       
   125     def __exit__(self, exc_type, exc_val, exc_tb):
       
   126         if self._connection is not None:
       
   127             self._connection.close()
       
   128         if self._storage is not None:
       
   129             self._storage.close()
       
   130 
       
   131 
       
   132 @implementer(IOptionalUtility, IAttributeAnnotatable)
       
   133 class ZEOConnectionUtility(ZEOConnection, Persistent, Contained):
       
   134     """Persistent ZEO connection utility"""
       
   135 
       
   136 
       
   137 @subscriber(IObjectAddedEvent, context_selector=IZEOConnection)
       
   138 def handle_added_connection(event):
       
   139     """Register new ZEO connection when added"""
       
   140     manager = event.newParent
       
   141     manager.registerUtility(event.object, IZEOConnection, name=event.object.name)
       
   142 
       
   143 
       
   144 @subscriber(IObjectRemovedEvent, context_selector=IZEOConnection)
       
   145 def handle_removed_connection(event):
       
   146     """Un-register ZEO connection when deleted"""
       
   147     manager = event.oldParent
       
   148     manager.unregisterUtility(event.object, IZEOConnection, name=event.object.name)
       
   149 
       
   150 
       
   151 @provider(IVocabularyFactory)
       
   152 class ZEOConnectionVocabulary(UtilityVocabulary):
       
   153     """ZEO connections vocabulary"""
       
   154 
       
   155     interface = IZEOConnection
       
   156     nameOnly = True
       
   157 
       
   158 getVocabularyRegistry().register('PyAMS ZEO connections', ZEOConnectionVocabulary)