26 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
26 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
27 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
27 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
28 """ |
28 """ |
29 __docformat__ = "restructuredtext en" |
29 __docformat__ = "restructuredtext en" |
30 |
30 |
31 ENTITIES_HOOKS = ('before_add_entity', 'after_add_entity', |
31 ENTITIES_HOOKS = ('before_add_entity', 'after_add_entity', |
32 'before_update_entity', 'after_update_entity', |
32 'before_update_entity', 'after_update_entity', |
33 'before_delete_entity', 'after_delete_entity') |
33 'before_delete_entity', 'after_delete_entity') |
34 RELATIONS_HOOKS = ('before_add_relation', 'after_add_relation' , |
34 RELATIONS_HOOKS = ('before_add_relation', 'after_add_relation' , |
35 'before_delete_relation','after_delete_relation') |
35 'before_delete_relation','after_delete_relation') |
36 SYSTEM_HOOKS = ('server_startup', 'server_shutdown', |
36 SYSTEM_HOOKS = ('server_startup', 'server_shutdown', |
40 |
40 |
41 class HooksManager(object): |
41 class HooksManager(object): |
42 """handle hooks registration and calls |
42 """handle hooks registration and calls |
43 """ |
43 """ |
44 verification_hooks_activated = True |
44 verification_hooks_activated = True |
45 |
45 |
46 def __init__(self, schema): |
46 def __init__(self, schema): |
47 self.set_schema(schema) |
47 self.set_schema(schema) |
48 |
48 |
49 def set_schema(self, schema): |
49 def set_schema(self, schema): |
50 self._hooks = {} |
50 self._hooks = {} |
51 self.schema = schema |
51 self.schema = schema |
52 self._init_hooks(schema) |
52 self._init_hooks(schema) |
53 |
53 |
54 def register_hooks(self, hooks): |
54 def register_hooks(self, hooks): |
55 """register a dictionary of hooks : |
55 """register a dictionary of hooks : |
56 |
56 |
57 {'event': {'entity or relation type': [callbacks list]}} |
57 {'event': {'entity or relation type': [callbacks list]}} |
58 """ |
58 """ |
59 for event, subevents in hooks.items(): |
59 for event, subevents in hooks.items(): |
60 for subevent, callbacks in subevents.items(): |
60 for subevent, callbacks in subevents.items(): |
61 for callback in callbacks: |
61 for callback in callbacks: |
62 self.register_hook(callback, event, subevent) |
62 self.register_hook(callback, event, subevent) |
63 |
63 |
64 def register_hook(self, function, event, etype=''): |
64 def register_hook(self, function, event, etype=''): |
65 """register a function to call when <event> occurs |
65 """register a function to call when <event> occurs |
66 |
66 |
67 <etype> is an entity/relation type or an empty string. |
67 <etype> is an entity/relation type or an empty string. |
68 If etype is the empty string, the function will be called at each |
68 If etype is the empty string, the function will be called at each |
69 event, else the function will be called only when event occurs on an |
69 event, else the function will be called only when event occurs on an |
70 entity/relation of the given type. |
70 entity/relation of the given type. |
71 """ |
71 """ |
74 etype = etype or '' |
74 etype = etype or '' |
75 try: |
75 try: |
76 self._hooks[event][etype].append(function) |
76 self._hooks[event][etype].append(function) |
77 self.debug('registered hook %s on %s (%s)', event, etype or 'any', |
77 self.debug('registered hook %s on %s (%s)', event, etype or 'any', |
78 function.func_name) |
78 function.func_name) |
79 |
79 |
80 except KeyError: |
80 except KeyError: |
81 self.error('can\'t register hook %s on %s (%s)', |
81 self.error('can\'t register hook %s on %s (%s)', |
82 event, etype or 'any', function.func_name) |
82 event, etype or 'any', function.func_name) |
83 |
83 |
84 def unregister_hook(self, function, event, etype=''): |
84 def unregister_hook(self, function, event, etype=''): |
85 """register a function to call when <event> occurs |
85 """register a function to call when <event> occurs |
86 |
86 |
87 <etype> is an entity/relation type or an empty string. |
87 <etype> is an entity/relation type or an empty string. |
88 If etype is the empty string, the function will be called at each |
88 If etype is the empty string, the function will be called at each |
89 event, else the function will be called only when event occurs on an |
89 event, else the function will be called only when event occurs on an |
90 entity/relation of the given type. |
90 entity/relation of the given type. |
91 """ |
91 """ |
107 hook(*args, **kwargs) |
107 hook(*args, **kwargs) |
108 if __type: |
108 if __type: |
109 for hook in self._hooks[__event][__type]: |
109 for hook in self._hooks[__event][__type]: |
110 #print '[%s]'%__type, hook.__name__ |
110 #print '[%s]'%__type, hook.__name__ |
111 hook(*args, **kwargs) |
111 hook(*args, **kwargs) |
112 |
112 |
113 def _init_hooks(self, schema): |
113 def _init_hooks(self, schema): |
114 """initialize the hooks map""" |
114 """initialize the hooks map""" |
115 for hook_event in ENTITIES_HOOKS: |
115 for hook_event in ENTITIES_HOOKS: |
116 self._hooks[hook_event] = {'': []} |
116 self._hooks[hook_event] = {'': []} |
117 for etype in schema.entities(): |
117 for etype in schema.entities(): |
162 self.unregister_hook(cstrcheck_after_add_relation, 'after_add_relation', '') |
162 self.unregister_hook(cstrcheck_after_add_relation, 'after_add_relation', '') |
163 self.unregister_hook(uniquecstrcheck_before_modification, 'before_add_entity', '') |
163 self.unregister_hook(uniquecstrcheck_before_modification, 'before_add_entity', '') |
164 self.unregister_hook(uniquecstrcheck_before_modification, 'before_update_entity', '') |
164 self.unregister_hook(uniquecstrcheck_before_modification, 'before_update_entity', '') |
165 # self.unregister_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '') |
165 # self.unregister_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '') |
166 # self.unregister_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '') |
166 # self.unregister_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '') |
167 |
167 |
168 def reactivate_verification_hooks(self): |
168 def reactivate_verification_hooks(self): |
169 from cubicweb.server.hooks import (cardinalitycheck_after_add_entity, |
169 from cubicweb.server.hooks import (cardinalitycheck_after_add_entity, |
170 cardinalitycheck_before_del_relation, |
170 cardinalitycheck_before_del_relation, |
171 cstrcheck_after_add_relation, |
171 cstrcheck_after_add_relation, |
172 uniquecstrcheck_before_modification) |
172 uniquecstrcheck_before_modification) |
177 self.register_hook(cstrcheck_after_add_relation, 'after_add_relation', '') |
177 self.register_hook(cstrcheck_after_add_relation, 'after_add_relation', '') |
178 self.register_hook(uniquecstrcheck_before_modification, 'before_add_entity', '') |
178 self.register_hook(uniquecstrcheck_before_modification, 'before_add_entity', '') |
179 self.register_hook(uniquecstrcheck_before_modification, 'before_update_entity', '') |
179 self.register_hook(uniquecstrcheck_before_modification, 'before_update_entity', '') |
180 # self.register_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '') |
180 # self.register_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '') |
181 # self.register_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '') |
181 # self.register_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '') |
182 |
182 |
183 from cubicweb.selectors import yes |
183 from cubicweb.selectors import yes |
184 from cubicweb.appobject import AppObject |
184 from cubicweb.appobject import AppObject |
185 |
185 |
186 class autoid(type): |
186 class autoid(type): |
187 """metaclass to create an unique 'id' attribute on the class using it""" |
187 """metaclass to create an unique 'id' attribute on the class using it""" |
197 __select__ = yes() |
197 __select__ = yes() |
198 # set this in derivated classes |
198 # set this in derivated classes |
199 events = None |
199 events = None |
200 accepts = None |
200 accepts = None |
201 enabled = True |
201 enabled = True |
202 |
202 |
203 def __init__(self, event=None): |
203 def __init__(self, event=None): |
204 super(Hook, self).__init__() |
204 super(Hook, self).__init__() |
205 self.event = event |
205 self.event = event |
206 |
206 |
207 @classmethod |
207 @classmethod |
208 def registered(cls, vreg): |
208 def registered(cls, vreg): |
209 super(Hook, cls).registered(vreg) |
209 super(Hook, cls).registered(vreg) |
210 return cls() |
210 return cls() |
211 |
211 |
212 @classmethod |
212 @classmethod |
213 def register_to(cls): |
213 def register_to(cls): |
214 if not cls.enabled: |
214 if not cls.enabled: |
215 cls.warning('%s hook has been disabled', cls) |
215 cls.warning('%s hook has been disabled', cls) |
216 return |
216 return |
230 for eetype in eschema.specialized_by(): |
230 for eetype in eschema.specialized_by(): |
231 if (event, eetype) in done: |
231 if (event, eetype) in done: |
232 continue |
232 continue |
233 yield event, str(eetype) |
233 yield event, str(eetype) |
234 done.add((event, eetype)) |
234 done.add((event, eetype)) |
235 |
235 |
236 |
236 |
237 def make_callback(self, event): |
237 def make_callback(self, event): |
238 if len(self.events) == 1: |
238 if len(self.events) == 1: |
239 return self.call |
239 return self.call |
240 return self.__class__(event=event).call |
240 return self.__class__(event=event).call |
241 |
241 |
242 def call(self): |
242 def call(self): |
243 raise NotImplementedError |
243 raise NotImplementedError |
244 |
244 |
245 class SystemHook(Hook): |
245 class SystemHook(Hook): |
246 accepts = ('',) |
246 accepts = ('',) |
247 |
247 |
248 from logging import getLogger |
248 from logging import getLogger |
249 from cubicweb import set_log_methods |
249 from cubicweb import set_log_methods |