1
2
3
4
5
6
7
8
9
10
11 import logging
12 log = logging.getLogger('zen.ZenHub')
13
14 from zope.interface import implements
15 from zope.interface.advice import addClassAdvisor
16 from zope.component import provideHandler
17 from zope.component.interfaces import ObjectEvent
18 from Products.ZenHub.interfaces import IUpdateEvent, IDeletionEvent
19
20
25
26
29
30
33
34
36 """
37 Given a particular event interface, returns a decorator factory that may be
38 used to create decorators for methods causing those methods, when bound, to
39 be registered as object event subscribers.
40
41 @param eventtype: The event interface to which the subscribers should
42 listen.
43 """
44 def factory(*types):
45 """
46 The eventtype-specific decorator factory. Calling this factory both
47 produces a decorator and wraps the __init__ of the class of the
48 decorated method with a function that registers the handlers.
49 """
50
51
52
53 _f = {}
54
55 def decorator(f):
56 """
57 The decorator. All it does is print a log message, then call the
58 original function.
59 """
60 def inner(self, obj, event):
61
62 fname = '.'.join((self.__class__.__name__, f.__name__))
63 log.debug('%s is interested in %r for %r' % (fname, event, obj))
64
65
66 return f(self, obj, event)
67
68
69
70 _f[f.__name__] = 1
71
72
73 return inner
74
75 def advisor(cls):
76 """
77 A class advisor that is called after the class is created. We use
78 this to wrap __init__ in a function that registers any handlers
79 created via this factory, which are stored on the class.
80 """
81
82
83 fname = _f.keys()[0]
84 cls.__registered = getattr(cls, '__registered', {})
85
86
87 if fname not in cls.__registered or not issubclass(cls, tuple(cls.__registered[fname])):
88
89 def registerHandlers(f):
90 def __init__(self, *args, **kwargs):
91
92
93 f(self, *args, **kwargs)
94 handler = getattr(self, fname)
95 for t in types:
96
97
98
99 provideHandler(handler, (t, eventtype))
100
101
102 return __init__
103
104
105
106 cls.__init__ = registerHandlers(cls.__init__)
107
108 cls.__registered.setdefault(fname, []).append(cls)
109
110
111
112 return cls
113
114
115 addClassAdvisor(advisor)
116
117
118 return decorator
119
120 return factory
121
122
123
124 onUpdate = _listener_decorator_factory(IUpdateEvent)
125 onDelete = _listener_decorator_factory(IDeletionEvent)
126