| Trees | Indices | Help |
|
|---|
|
|
1 ##############################################################################
2 #
3 # Copyright (C) Zenoss, Inc. 2007, all rights reserved.
4 #
5 # This content is made available according to terms specified in
6 # License.zenoss under the directory where your Zenoss product is installed.
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
28 implements(IUpdateEvent)
29
30
32 implements(IDeletionEvent)
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 # Create a mutable to store the handler name between the call to
51 # decorator and the call to advisor (simple assignment won't work for
52 # scope reasons)
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 # Log that we've called this listener
62 fname = '.'.join((self.__class__.__name__, f.__name__))
63 log.debug('%s is interested in %r for %r' % (fname, event, obj))
64
65 # Call the original function
66 return f(self, obj, event)
67
68 # Push the name of the function outside the decorator scope so the
69 # class advisor has access when it needs to register handlers.
70 _f[f.__name__] = 1
71
72 # Return the closure to replace the original function.
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 # Set one flag per fname on the class so we don't double-register
82 # when we override in a subclass (once for super, once for sub)
83 fname = _f.keys()[0]
84 cls.__registered = getattr(cls, '__registered', {})
85
86 # Check our flag
87 if fname not in cls.__registered or not issubclass(cls, tuple(cls.__registered[fname])):
88 # Decorator for __init__
89 def registerHandlers(f):
90 def __init__(self, *args, **kwargs):
91 # Call the original constructor; we'll register handlers
92 # afterwards
93 f(self, *args, **kwargs)
94 handler = getattr(self, fname)
95 for t in types:
96 # Register the handler. Here's where we use
97 # eventtype, which was passed in to the outermost
98 # function in this behemoth.
99 provideHandler(handler, (t, eventtype))
100
101 # Return the closure to replace the decorated method
102 return __init__
103
104 # Decorate __init__ so it will register the handlers on
105 # instantiation
106 cls.__init__ = registerHandlers(cls.__init__)
107 # Set the flag for this fname
108 cls.__registered.setdefault(fname, []).append(cls)
109
110
111 # Return the class, which will replace the original class.
112 return cls
113
114 # Add the advisor to the class.
115 addClassAdvisor(advisor)
116
117 # Return the decorator so we get the log message when called
118 return decorator
119
120 return factory
121
122
123 # Create two decorator factories for the two kinds of events.
124 onUpdate = _listener_decorator_factory(IUpdateEvent)
125 onDelete = _listener_decorator_factory(IDeletionEvent)
126
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1.1812 on Mon Jul 30 17:11:35 2012 | http://epydoc.sourceforge.net |