Package Products :: Package ZenHub :: Module zodb |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenHub.zodb

      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
     21 -class InvalidationEvent(ObjectEvent):
     22 -    def __init__(self, object, oid):
     23          super(InvalidationEvent, self).__init__(object)
     24          self.oid = oid
     25
     26
     27 -class UpdateEvent(InvalidationEvent):
     28      implements(IUpdateEvent)
     29
     30
     31 -class DeletionEvent(InvalidationEvent):
     32      implements(IDeletionEvent)
     33
     34
     35 -def _listener_decorator_factory(eventtype):
     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