server/hooksmanager.py
changeset 2835 04034421b072
parent 2822 f26578339214
child 2968 0e3460341023
--- a/server/hooksmanager.py	Fri Aug 14 09:20:33 2009 +0200
+++ b/server/hooksmanager.py	Fri Aug 14 09:26:41 2009 +0200
@@ -1,270 +1,4 @@
-"""Hooks management
-
-Hooks are called before / after any individual update of entities / relations
-in the repository.
-
-Here is the prototype of the different hooks:
-
-* filtered on the entity's type:
-
-  before_add_entity    (session, entity)
-  after_add_entity     (session, entity)
-  before_update_entity (session, entity)
-  after_update_entity  (session, entity)
-  before_delete_entity (session, eid)
-  after_delete_entity  (session, eid)
-
-* filtered on the relation's type:
-
-  before_add_relation    (session, fromeid, rtype, toeid)
-  after_add_relation     (session, fromeid, rtype, toeid)
-  before_delete_relation (session, fromeid, rtype, toeid)
-  after_delete_relation  (session, fromeid, rtype, toeid)
-
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-__docformat__ = "restructuredtext en"
-
-ENTITIES_HOOKS = ('before_add_entity',    'after_add_entity',
-                  'before_update_entity', 'after_update_entity',
-                  'before_delete_entity', 'after_delete_entity')
-RELATIONS_HOOKS = ('before_add_relation',   'after_add_relation' ,
-                   'before_delete_relation','after_delete_relation')
-SYSTEM_HOOKS = ('server_backup', 'server_restore',
-                'server_startup', 'server_shutdown',
-                'session_open', 'session_close')
-
-ALL_HOOKS = frozenset(ENTITIES_HOOKS + RELATIONS_HOOKS + SYSTEM_HOOKS)
-
-class HooksManager(object):
-    """handle hooks registration and calls
-    """
-    verification_hooks_activated = True
-
-    def __init__(self, schema):
-        self.set_schema(schema)
-
-    def set_schema(self, schema):
-        self._hooks = {}
-        self.schema = schema
-        self._init_hooks(schema)
-
-    def register_hooks(self, hooks):
-        """register a dictionary of hooks :
-
-             {'event': {'entity or relation type': [callbacks list]}}
-        """
-        for event, subevents in hooks.items():
-            for subevent, callbacks in subevents.items():
-                for callback in callbacks:
-                    self.register_hook(callback, event, subevent)
-
-    def register_hook(self, function, event, etype=''):
-        """register a function to call when <event> occurs
-
-        <etype> is an entity/relation type or an empty string.
-
-        If etype is the empty string, the function will be called at each event,
-        else the function will be called only when event occurs on an entity or
-        relation of the given type.
-        """
-        assert event in ALL_HOOKS, '%r NOT IN %r' % (event, ALL_HOOKS)
-        assert (not event in SYSTEM_HOOKS or not etype), (event, etype)
-        etype = etype or ''
-        try:
-            self._hooks[event][etype].append(function)
-            self.debug('registered hook %s on %s (%s)', event, etype or 'any',
-                       function.func_name)
-
-        except KeyError:
-            self.error('can\'t register hook %s on %s (%s)',
-                       event, etype or 'any', function.func_name)
-
-    def unregister_hook(self, function_or_cls, event=None, etype=''):
-        """unregister a function to call when <event> occurs, or a Hook subclass.
-        In the later case, event/type information are extracted from the given
-        class.
-        """
-        if isinstance(function_or_cls, type) and issubclass(function_or_cls, Hook):
-            for event, ertype in function_or_cls.register_to(self.schema):
-                for hook in self._hooks[event][ertype]:
-                    if getattr(hook, 'im_self', None).__class__ is function_or_cls:
-                        self._hooks[event][ertype].remove(hook)
-                        self.info('unregister hook %s on %s (%s)', event, etype,
-                                  function_or_cls.__name__)
-                        break
-                else:
-                    self.warning("can't unregister hook %s on %s (%s), not found",
-                                 event, etype, function_or_cls.__name__)
-        else:
-            assert event in ALL_HOOKS, event
-            etype = etype or ''
-            self.info('unregister hook %s on %s (%s)', event, etype,
-                      function_or_cls.func_name)
-            self._hooks[event][etype].remove(function_or_cls)
-
-    def call_hooks(self, __event, __type='', *args, **kwargs):
-        """call hook matching event and optional type"""
-        if __type:
-            self.info('calling hooks for event %s (%s)', __event, __type)
-        else:
-            self.info('calling hooks for event %s', __event)
-        # call generic hooks first
-        for hook in self._hooks[__event]['']:
-            #print '[generic]', hook.__name__
-            hook(*args, **kwargs)
-        if __type:
-            for hook in self._hooks[__event][__type]:
-                #print '[%s]'%__type, hook.__name__
-                hook(*args, **kwargs)
-
-    def _init_hooks(self, schema):
-        """initialize the hooks map"""
-        for hook_event in ENTITIES_HOOKS:
-            self._hooks[hook_event] = {'': []}
-            for etype in schema.entities():
-                self._hooks[hook_event][etype] = []
-        for hook_event in RELATIONS_HOOKS:
-            self._hooks[hook_event] = {'': []}
-            for r_type in schema.relations():
-                self._hooks[hook_event][r_type] = []
-        for hook_event in SYSTEM_HOOKS:
-            self._hooks[hook_event] = {'': []}
-
-    def register_system_hooks(self, config):
-        """register system hooks according to the configuration"""
-        self.info('register core hooks')
-        from cubicweb.server.hooks import _register_metadata_hooks, _register_wf_hooks
-        _register_metadata_hooks(self)
-        self.info('register workflow hooks')
-        _register_wf_hooks(self)
-        if config.core_hooks:
-            from cubicweb.server.hooks import _register_core_hooks
-            _register_core_hooks(self)
-        if config.schema_hooks:
-            from cubicweb.server.schemahooks import _register_schema_hooks
-            self.info('register schema hooks')
-            _register_schema_hooks(self)
-        if config.usergroup_hooks:
-            from cubicweb.server.hooks import _register_usergroup_hooks
-            from cubicweb.server.hooks import _register_eproperty_hooks
-            self.info('register user/group hooks')
-            _register_usergroup_hooks(self)
-            _register_eproperty_hooks(self)
-        if config.security_hooks:
-            from cubicweb.server.securityhooks import register_security_hooks
-            self.info('register security hooks')
-            register_security_hooks(self)
-        if not self.verification_hooks_activated:
-            self.deactivate_verification_hooks()
-
-    def deactivate_verification_hooks(self):
-        from cubicweb.server.hooks import (cardinalitycheck_after_add_entity,
-                                        cardinalitycheck_before_del_relation,
-                                        cstrcheck_after_add_relation,
-                                        uniquecstrcheck_before_modification)
-        self.warning('deactivating verification hooks')
-        self.verification_hooks_activated = False
-        self.unregister_hook(cardinalitycheck_after_add_entity, 'after_add_entity', '')
-        self.unregister_hook(cardinalitycheck_before_del_relation, 'before_delete_relation', '')
-        self.unregister_hook(cstrcheck_after_add_relation, 'after_add_relation', '')
-        self.unregister_hook(uniquecstrcheck_before_modification, 'before_add_entity', '')
-        self.unregister_hook(uniquecstrcheck_before_modification, 'before_update_entity', '')
-#         self.unregister_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '')
-#         self.unregister_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '')
-
-    def reactivate_verification_hooks(self):
-        from cubicweb.server.hooks import (cardinalitycheck_after_add_entity,
-                                        cardinalitycheck_before_del_relation,
-                                        cstrcheck_after_add_relation,
-                                        uniquecstrcheck_before_modification)
-        self.warning('reactivating verification hooks')
-        self.verification_hooks_activated = True
-        self.register_hook(cardinalitycheck_after_add_entity, 'after_add_entity', '')
-        self.register_hook(cardinalitycheck_before_del_relation, 'before_delete_relation', '')
-        self.register_hook(cstrcheck_after_add_relation, 'after_add_relation', '')
-        self.register_hook(uniquecstrcheck_before_modification, 'before_add_entity', '')
-        self.register_hook(uniquecstrcheck_before_modification, 'before_update_entity', '')
-#         self.register_hook(tidy_html_fields('before_add_entity'), 'before_add_entity', '')
-#         self.register_hook(tidy_html_fields('before_update_entity'), 'before_update_entity', '')
-
-from cubicweb.selectors import yes
-from cubicweb.appobject import AppObject
-
-class autoid(type):
-    """metaclass to create an unique 'id' attribute on the class using it"""
-    # XXX is this metaclass really necessary ?
-    def __new__(mcs, name, bases, classdict):
-        cls = super(autoid, mcs).__new__(mcs, name, bases, classdict)
-        cls.id = str(id(cls))
-        return cls
-
-class Hook(AppObject):
-    __metaclass__ = autoid
-    __registry__ = 'hooks'
-    __select__ = yes()
-    # set this in derivated classes
-    events = None
-    accepts = None
-    enabled = True
-
-    def __init__(self, event=None):
-        super(Hook, self).__init__(None)
-        self.event = event
-
-    @classmethod
-    def __registered__(cls, vreg):
-        super(Hook, cls).__registered__(vreg)
-        return cls()
-
-    @classmethod
-    def register_to(cls, schema):
-        if not cls.enabled:
-            cls.warning('%s hook has been disabled', cls)
-            return
-        done = set()
-        assert isinstance(cls.events, (tuple, list)), \
-               '%s: events is expected to be a tuple, not %s' % (
-            cls, type(cls.events))
-        for event in cls.events:
-            if event in SYSTEM_HOOKS:
-                assert not cls.accepts or cls.accepts == ('Any',), \
-                       '%s doesnt make sense on %s' % (cls.accepts, event)
-                cls.accepts = ('Any',)
-            for ertype in cls.accepts:
-                if (event, ertype) in done:
-                    continue
-                yield event, ertype
-                done.add((event, ertype))
-                try:
-                    eschema = schema.eschema(ertype)
-                except KeyError:
-                    # relation schema
-                    pass
-                else:
-                    for eetype in eschema.specialized_by():
-                        if (event, eetype) in done:
-                            continue
-                        yield event, str(eetype)
-                        done.add((event, eetype))
-
-
-    def make_callback(self, event):
-        if len(self.events) == 1:
-            return self.call
-        return self.__class__(event=event).call
-
-    def call(self):
-        raise NotImplementedError
-
-class SystemHook(Hook):
-    accepts = ()
-
-from logging import getLogger
-from cubicweb import set_log_methods
-set_log_methods(HooksManager, getLogger('cubicweb.hooksmanager'))
-set_log_methods(Hook, getLogger('cubicweb.hooks'))
+from logilab.common.deprecation import class_renamed, class_moved
+from cubicweb.server.hook import Hook
+SystemHook = class_renamed('SystemHook', Hook)
+Hook = class_moved(Hook)