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) |