Package proton :: Module _events
[frames] | no frames]

Source Code for Module proton._events

  1  # 
  2  # Licensed to the Apache Software Foundation (ASF) under one 
  3  # or more contributor license agreements.  See the NOTICE file 
  4  # distributed with this work for additional information 
  5  # regarding copyright ownership.  The ASF licenses this file 
  6  # to you under the Apache License, Version 2.0 (the 
  7  # "License"); you may not use this file except in compliance 
  8  # with the License.  You may obtain a copy of the License at 
  9  # 
 10  #   http://www.apache.org/licenses/LICENSE-2.0 
 11  # 
 12  # Unless required by applicable law or agreed to in writing, 
 13  # software distributed under the License is distributed on an 
 14  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
 15  # KIND, either express or implied.  See the License for the 
 16  # specific language governing permissions and limitations 
 17  # under the License. 
 18  # 
 19   
 20  from __future__ import absolute_import 
 21   
 22  import threading 
 23   
 24  from cproton import PN_SESSION_REMOTE_CLOSE, PN_SESSION_FINAL, pn_event_context, pn_collector_put, \ 
 25      PN_SELECTABLE_UPDATED, pn_collector, PN_CONNECTION_REMOTE_OPEN, pn_event_attachments, pn_event_type, \ 
 26      pn_collector_free, pn_handler_dispatch, PN_SELECTABLE_WRITABLE, PN_SELECTABLE_INIT, PN_SESSION_REMOTE_OPEN, \ 
 27      pn_collector_peek, PN_CONNECTION_BOUND, PN_LINK_FLOW, pn_event_connection, PN_LINK_LOCAL_CLOSE, \ 
 28      PN_TRANSPORT_ERROR, PN_CONNECTION_LOCAL_OPEN, PN_CONNECTION_LOCAL_CLOSE, pn_event_delivery, \ 
 29      PN_LINK_REMOTE_OPEN, PN_TRANSPORT_CLOSED, PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT, pn_event_reactor, \ 
 30      PN_CONNECTION_REMOTE_CLOSE, pn_collector_pop, PN_LINK_INIT, pn_event_link, PN_CONNECTION_UNBOUND, \ 
 31      pn_event_type_name, pn_event_session, PN_LINK_FINAL, pn_py2void, PN_REACTOR_INIT, PN_REACTOR_QUIESCED, \ 
 32      PN_LINK_LOCAL_DETACH, PN_SESSION_INIT, PN_CONNECTION_FINAL, PN_TIMER_TASK, pn_class_name, PN_SELECTABLE_READABLE, \ 
 33      pn_event_transport, PN_TRANSPORT_TAIL_CLOSED, PN_SELECTABLE_FINAL, PN_SESSION_LOCAL_OPEN, PN_DELIVERY, \ 
 34      PN_SESSION_LOCAL_CLOSE, pn_event_copy, PN_REACTOR_FINAL, PN_LINK_LOCAL_OPEN, PN_SELECTABLE_EXPIRED, \ 
 35      PN_LINK_REMOTE_DETACH, PN_PYREF, PN_LINK_REMOTE_CLOSE, pn_event_root, PN_SELECTABLE_ERROR, \ 
 36      PN_CONNECTION_INIT, pn_event_class, pn_void2py, pn_cast_pn_session, pn_cast_pn_link, pn_cast_pn_delivery, \ 
 37      pn_cast_pn_transport, pn_cast_pn_connection, pn_cast_pn_selectable 
 38   
 39  from ._common import Constant 
 40  from ._delivery import Delivery 
 41  from ._endpoints import Connection, Session, Link 
 42  from ._reactor_impl import Selectable, WrappedHandler 
 43  from ._transport import Transport 
 44  from ._wrapper import Wrapper 
45 46 47 -class Collector:
48
49 - def __init__(self):
50 self._impl = pn_collector()
51
52 - def put(self, obj, etype):
53 pn_collector_put(self._impl, PN_PYREF, pn_py2void(obj), etype.number)
54
55 - def peek(self):
56 return Event.wrap(pn_collector_peek(self._impl))
57
58 - def pop(self):
59 ev = self.peek() 60 pn_collector_pop(self._impl)
61
62 - def __del__(self):
63 pn_collector_free(self._impl) 64 del self._impl
65 66 67 if "TypeExtender" not in globals():
68 - class TypeExtender:
69 - def __init__(self, number):
70 self.number = number
71
72 - def next(self):
73 try: 74 return self.number 75 finally: 76 self.number += 1
77
78 79 -class EventType(object):
80 _lock = threading.Lock() 81 _extended = TypeExtender(10000) 82 TYPES = {} 83
84 - def __init__(self, name=None, number=None, method=None):
85 if name is None and number is None: 86 raise TypeError("extended events require a name") 87 try: 88 self._lock.acquire() 89 if name is None: 90 name = pn_event_type_name(number) 91 92 if number is None: 93 number = self._extended.next() 94 95 if method is None: 96 method = "on_%s" % name 97 98 self.name = name 99 self.number = number 100 self.method = method 101 102 self.TYPES[number] = self 103 finally: 104 self._lock.release()
105
106 - def __repr__(self):
107 return self.name
108
109 110 -def dispatch(handler, method, *args):
111 m = getattr(handler, method, None) 112 if m: 113 return m(*args) 114 elif hasattr(handler, "on_unhandled"): 115 return handler.on_unhandled(method, *args)
116
117 118 -class EventBase(object):
119
120 - def __init__(self, clazz, context, type):
121 self.clazz = clazz 122 self.context = context 123 self.type = type
124
125 - def dispatch(self, handler):
126 return dispatch(handler, self.type.method, self)
127
128 129 -def _none(x): return None
130 131 132 DELEGATED = Constant("DELEGATED")
133 134 135 -def _core(number, method):
136 return EventType(number=number, method=method)
137 138 139 wrappers = { 140 "pn_void": lambda x: pn_void2py(x), 141 "pn_pyref": lambda x: pn_void2py(x), 142 "pn_connection": lambda x: Connection.wrap(pn_cast_pn_connection(x)), 143 "pn_session": lambda x: Session.wrap(pn_cast_pn_session(x)), 144 "pn_link": lambda x: Link.wrap(pn_cast_pn_link(x)), 145 "pn_delivery": lambda x: Delivery.wrap(pn_cast_pn_delivery(x)), 146 "pn_transport": lambda x: Transport.wrap(pn_cast_pn_transport(x)), 147 "pn_selectable": lambda x: Selectable.wrap(pn_cast_pn_selectable(x)) 148 }
149 150 151 -class Event(Wrapper, EventBase):
152 REACTOR_INIT = _core(PN_REACTOR_INIT, "on_reactor_init") 153 REACTOR_QUIESCED = _core(PN_REACTOR_QUIESCED, "on_reactor_quiesced") 154 REACTOR_FINAL = _core(PN_REACTOR_FINAL, "on_reactor_final") 155 156 TIMER_TASK = _core(PN_TIMER_TASK, "on_timer_task") 157 158 CONNECTION_INIT = _core(PN_CONNECTION_INIT, "on_connection_init") 159 CONNECTION_BOUND = _core(PN_CONNECTION_BOUND, "on_connection_bound") 160 CONNECTION_UNBOUND = _core(PN_CONNECTION_UNBOUND, "on_connection_unbound") 161 CONNECTION_LOCAL_OPEN = _core(PN_CONNECTION_LOCAL_OPEN, "on_connection_local_open") 162 CONNECTION_LOCAL_CLOSE = _core(PN_CONNECTION_LOCAL_CLOSE, "on_connection_local_close") 163 CONNECTION_REMOTE_OPEN = _core(PN_CONNECTION_REMOTE_OPEN, "on_connection_remote_open") 164 CONNECTION_REMOTE_CLOSE = _core(PN_CONNECTION_REMOTE_CLOSE, "on_connection_remote_close") 165 CONNECTION_FINAL = _core(PN_CONNECTION_FINAL, "on_connection_final") 166 167 SESSION_INIT = _core(PN_SESSION_INIT, "on_session_init") 168 SESSION_LOCAL_OPEN = _core(PN_SESSION_LOCAL_OPEN, "on_session_local_open") 169 SESSION_LOCAL_CLOSE = _core(PN_SESSION_LOCAL_CLOSE, "on_session_local_close") 170 SESSION_REMOTE_OPEN = _core(PN_SESSION_REMOTE_OPEN, "on_session_remote_open") 171 SESSION_REMOTE_CLOSE = _core(PN_SESSION_REMOTE_CLOSE, "on_session_remote_close") 172 SESSION_FINAL = _core(PN_SESSION_FINAL, "on_session_final") 173 174 LINK_INIT = _core(PN_LINK_INIT, "on_link_init") 175 LINK_LOCAL_OPEN = _core(PN_LINK_LOCAL_OPEN, "on_link_local_open") 176 LINK_LOCAL_CLOSE = _core(PN_LINK_LOCAL_CLOSE, "on_link_local_close") 177 LINK_LOCAL_DETACH = _core(PN_LINK_LOCAL_DETACH, "on_link_local_detach") 178 LINK_REMOTE_OPEN = _core(PN_LINK_REMOTE_OPEN, "on_link_remote_open") 179 LINK_REMOTE_CLOSE = _core(PN_LINK_REMOTE_CLOSE, "on_link_remote_close") 180 LINK_REMOTE_DETACH = _core(PN_LINK_REMOTE_DETACH, "on_link_remote_detach") 181 LINK_FLOW = _core(PN_LINK_FLOW, "on_link_flow") 182 LINK_FINAL = _core(PN_LINK_FINAL, "on_link_final") 183 184 DELIVERY = _core(PN_DELIVERY, "on_delivery") 185 186 TRANSPORT = _core(PN_TRANSPORT, "on_transport") 187 TRANSPORT_ERROR = _core(PN_TRANSPORT_ERROR, "on_transport_error") 188 TRANSPORT_HEAD_CLOSED = _core(PN_TRANSPORT_HEAD_CLOSED, "on_transport_head_closed") 189 TRANSPORT_TAIL_CLOSED = _core(PN_TRANSPORT_TAIL_CLOSED, "on_transport_tail_closed") 190 TRANSPORT_CLOSED = _core(PN_TRANSPORT_CLOSED, "on_transport_closed") 191 192 SELECTABLE_INIT = _core(PN_SELECTABLE_INIT, "on_selectable_init") 193 SELECTABLE_UPDATED = _core(PN_SELECTABLE_UPDATED, "on_selectable_updated") 194 SELECTABLE_READABLE = _core(PN_SELECTABLE_READABLE, "on_selectable_readable") 195 SELECTABLE_WRITABLE = _core(PN_SELECTABLE_WRITABLE, "on_selectable_writable") 196 SELECTABLE_EXPIRED = _core(PN_SELECTABLE_EXPIRED, "on_selectable_expired") 197 SELECTABLE_ERROR = _core(PN_SELECTABLE_ERROR, "on_selectable_error") 198 SELECTABLE_FINAL = _core(PN_SELECTABLE_FINAL, "on_selectable_final") 199 200 @staticmethod
201 - def wrap(impl, number=None):
202 if impl is None: 203 return None 204 205 if number is None: 206 number = pn_event_type(impl) 207 208 event = Event(impl, number) 209 210 # check for an application defined ApplicationEvent and return that. This 211 # avoids an expensive wrap operation invoked by event.context 212 if pn_event_class(impl) == PN_PYREF and \ 213 isinstance(event.context, EventBase): 214 return event.context 215 else: 216 return event
217
218 - def __init__(self, impl, number):
219 Wrapper.__init__(self, impl, pn_event_attachments) 220 self.__dict__["type"] = EventType.TYPES[number]
221
222 - def _init(self):
223 pass
224
225 - def copy(self):
226 copy = pn_event_copy(self._impl) 227 return Event.wrap(copy)
228 229 @property
230 - def clazz(self):
231 cls = pn_event_class(self._impl) 232 if cls: 233 return pn_class_name(cls) 234 else: 235 return None
236 237 @property
238 - def root(self):
239 return WrappedHandler.wrap(pn_event_root(self._impl))
240 241 @property
242 - def context(self):
243 """Returns the context object associated with the event. The type of this depend on the type of event.""" 244 return wrappers[self.clazz](pn_event_context(self._impl))
245
246 - def dispatch(self, handler, type=None):
247 type = type or self.type 248 if isinstance(handler, WrappedHandler): 249 pn_handler_dispatch(handler._impl, self._impl, type.number) 250 else: 251 result = dispatch(handler, type.method, self) 252 if result != DELEGATED and hasattr(handler, "handlers"): 253 for h in handler.handlers: 254 self.dispatch(h, type)
255 256 @property
257 - def reactor(self):
258 """Returns the reactor associated with the event.""" 259 return wrappers.get("pn_reactor", _none)(pn_event_reactor(self._impl))
260
261 - def __getattr__(self, name):
262 r = self.reactor 263 if r and hasattr(r, 'subclass') and r.subclass.__name__.lower() == name: 264 return r 265 else: 266 return super(Event, self).__getattr__(name)
267 268 @property
269 - def transport(self):
270 """Returns the transport associated with the event, or null if none is associated with it.""" 271 return Transport.wrap(pn_event_transport(self._impl))
272 273 @property
274 - def connection(self):
275 """Returns the connection associated with the event, or null if none is associated with it.""" 276 return Connection.wrap(pn_event_connection(self._impl))
277 278 @property
279 - def session(self):
280 """Returns the session associated with the event, or null if none is associated with it.""" 281 return Session.wrap(pn_event_session(self._impl))
282 283 @property 287 288 @property
289 - def sender(self):
290 """Returns the sender link associated with the event, or null if 291 none is associated with it. This is essentially an alias for 292 link(), that does an additional checkon the type of the 293 link.""" 294 l = self.link 295 if l and l.is_sender: 296 return l 297 else: 298 return None
299 300 @property
301 - def receiver(self):
302 """Returns the receiver link associated with the event, or null if 303 none is associated with it. This is essentially an alias for 304 link(), that does an additional checkon the type of the link.""" 305 l = self.link 306 if l and l.is_receiver: 307 return l 308 else: 309 return None
310 311 @property
312 - def delivery(self):
313 """Returns the delivery associated with the event, or null if none is associated with it.""" 314 return Delivery.wrap(pn_event_delivery(self._impl))
315
316 - def __repr__(self):
317 return "%s(%s)" % (self.type, self.context)
318
319 320 -class LazyHandlers(object):
321 - def __get__(self, obj, clazz):
322 if obj is None: 323 return self 324 ret = [] 325 obj.__dict__['handlers'] = ret 326 return ret
327
328 329 -class Handler(object):
330 handlers = LazyHandlers() 331
332 - def on_unhandled(self, method, *args):
333 pass
334