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

Source Code for Module Products.ZenHub.zodb

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 or (at your 
  8  # option) any later version as published by the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13  import logging 
 14  log = logging.getLogger('zen.ZenHub') 
 15   
 16  from zope.component.event import objectEventNotify 
 17  from zope.interface import implements 
 18  from zope.interface.advice import addClassAdvisor 
 19  from zope.component import provideHandler 
 20  from zope.component.interfaces import ObjectEvent 
 21  from ZODB.utils import u64 
 22  from twisted.internet import defer, reactor 
 23   
 24  from Products.ZenModel.Device import Device 
 25  from Products.ZenModel.DeviceComponent import DeviceComponent 
 26  from time import time 
 27  from Products.ZenRelations.PrimaryPathObjectManager import PrimaryPathObjectManager 
 28  from Products.ZenHub.interfaces import IUpdateEvent, IDeletionEvent 
29 30 31 -class InvalidationEvent(ObjectEvent):
32 - def __init__(self, object, oid):
33 super(InvalidationEvent, self).__init__(object) 34 self.oid = oid
35
36 37 -class UpdateEvent(InvalidationEvent):
38 implements(IUpdateEvent)
39
40 41 -class DeletionEvent(InvalidationEvent):
42 implements(IDeletionEvent)
43
44 45 -def _remove(_ignored, oid, queue):
46 """ 47 We don't want bad oids hanging around forever. 48 """ 49 queue.remove(oid)
50
51 52 -def _dispatch(dmd, oid, ioid, queue):
53 """ 54 Send to all the services that care by firing events. 55 """ 56 d = defer.Deferred() 57 # Closure to use as a callback 58 def inner(_ignored): 59 try: 60 if dmd.pauseHubNotifications: 61 log.debug('notifications are currently paused') 62 return 63 64 # Go pull the object out of the database 65 obj = dmd._p_jar[oid] 66 # Don't bother with all the catalog stuff; we're depending on primaryAq 67 # existing anyway, so only deal with it if it actually has primaryAq. 68 if (isinstance(obj, PrimaryPathObjectManager) 69 or isinstance(obj, DeviceComponent)): 70 try: 71 # Try to get the object 72 obj = obj.__of__(dmd).primaryAq() 73 except (AttributeError, KeyError), ex: 74 # Object has been removed from its primary path (i.e. was 75 # deleted), so make a DeletionEvent 76 log.debug("Notifying services that %r has been deleted" % obj) 77 event = DeletionEvent(obj, oid) 78 else: 79 # Object was updated, so make an UpdateEvent 80 log.debug("Notifying services that %r has been updated" % obj) 81 event = UpdateEvent(obj, oid) 82 # Fire the event for all interested services to pick up 83 objectEventNotify(event) 84 # Return the oid, although we don't currently use it 85 return oid 86 finally: 87 queue.remove(ioid)
88 d.addCallback(inner) 89 # Call the deferred in the reactor so we give time to other things 90 reactor.callLater(0, d.callback, True) 91 return d 92
93 94 @defer.inlineCallbacks 95 -def processInvalidations(dmd, queue, oids):
96 i = 0 97 for i, oid in enumerate(oids): 98 ioid = u64(oid) 99 # Try pushing it into the queue, which is an IITreeSet. If it inserted 100 # successfully it returns 1, else 0. 101 if queue.insert(ioid): 102 # Get the deferred that does the notification 103 d = _dispatch(dmd, oid, ioid, queue) 104 yield d 105 defer.returnValue(i)
106
107 108 -def _listener_decorator_factory(eventtype):
109 """ 110 Given a particular event interface, returns a decorator factory that may be 111 used to create decorators for methods causing those methods, when bound, to 112 be registered as object event subscribers. 113 114 @param eventtype: The event interface to which the subscribers should 115 listen. 116 """ 117 def factory(*types): 118 """ 119 The eventtype-specific decorator factory. Calling this factory both 120 produces a decorator and wraps the __init__ of the class of the 121 decorated method with a function that registers the handlers. 122 """ 123 # Create a mutable to store the handler name between the call to 124 # decorator and the call to advisor (simple assignment won't work for 125 # scope reasons) 126 _f = {} 127 128 def decorator(f): 129 """ 130 The decorator. All it does is print a log message, then call the 131 original function. 132 """ 133 def inner(self, obj, event): 134 # Log that we've called this listener 135 fname = '.'.join((self.__class__.__name__, f.__name__)) 136 log.debug('%s is interested in %r for %r' % (fname, event, obj)) 137 138 # Call the original function 139 return f(self, obj, event)
140 141 # Push the name of the function outside the decorator scope so the 142 # class advisor has access when it needs to register handlers. 143 _f[f.__name__] = 1 144 145 # Return the closure to replace the original function. 146 return inner 147 148 def advisor(cls): 149 """ 150 A class advisor that is called after the class is created. We use 151 this to wrap __init__ in a function that registers any handlers 152 created via this factory, which are stored on the class. 153 """ 154 # Set one flag per fname on the class so we don't double-register 155 # when we override in a subclass (once for super, once for sub) 156 fname = _f.keys()[0] 157 cls.__registered = getattr(cls, '__registered', {}) 158 159 # Check our flag 160 if fname not in cls.__registered or not issubclass(cls, tuple(cls.__registered[fname])): 161 # Decorator for __init__ 162 def registerHandlers(f): 163 def __init__(self, *args, **kwargs): 164 # Call the original constructor; we'll register handlers 165 # afterwards 166 f(self, *args, **kwargs) 167 handler = getattr(self, fname) 168 for t in types: 169 # Register the handler. Here's where we use 170 # eventtype, which was passed in to the outermost 171 # function in this behemoth. 172 provideHandler(handler, (t, eventtype)) 173 174 # Return the closure to replace the decorated method 175 return __init__ 176 177 # Decorate __init__ so it will register the handlers on 178 # instantiation 179 cls.__init__ = registerHandlers(cls.__init__) 180 # Set the flag for this fname 181 cls.__registered.setdefault(fname, []).append(cls) 182 183 184 # Return the class, which will replace the original class. 185 return cls 186 187 # Add the advisor to the class. 188 addClassAdvisor(advisor) 189 190 # Return the decorator so we get the log message when called 191 return decorator 192 193 return factory 194 195 196 # Create two decorator factories for the two kinds of events. 197 onUpdate = _listener_decorator_factory(IUpdateEvent) 198 onDelete = _listener_decorator_factory(IDeletionEvent) 199