1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Registered event listener."""
17
18 import inspect
19 import logging
20
21 from muntjac.util import IEventListener
22 from muntjac.util import getSuperClass
23
24
25 logger = logging.getLogger(__name__)
29 """One registered event listener. This class contains the listener object
30 reference, listened event type, the trigger method to call when the event
31 fires, and the optional argument list to pass to the method and the index
32 of the argument to replace with the event object.
33
34 This Class provides several constructors that allow omission of the
35 optional arguments, and giving the listener method directly, or having the
36 constructor to reflect it using merely the name of the method.
37
38 It should be pointed out that the method L{receiveEvent} is the one that
39 filters out the events that do not match with the given event type and thus
40 do not result in calling of the trigger method.
41
42 @author: Vaadin Ltd.
43 @author: Richard Lincoln
44 @version: 1.1.2
45 """
46
48 raise NotImplementedError
49
50
51 try:
52 out.defaultWriteObject()
53 name = self._method.__name__
54 paramTypes = self._method.getParameterTypes()
55 out.writeObject(name)
56 out.writeObject(paramTypes)
57 except Exception, e:
58 logger.warning(('Error in serialization of the application: Class '
59 + self._target.__class__.__name__
60 + ' must implement serialization.'))
61 raise e
62
63
65 raise NotImplementedError
66
67
68 in_.defaultReadObject()
69 try:
70 name = in_.readObject()
71 paramTypes = in_.readObject()
72
73
74 self._method = self.findHighestMethod(self._target.__class__,
75 name, paramTypes)
76 except Exception:
77 logger.critical('Internal deserialization error')
78
79
80 @classmethod
82 ifaces = klass.getInterfaces()
83 for i in range(len(ifaces)):
84 ifaceMethod = cls.findHighestMethod(ifaces[i], method, paramTypes)
85 if ifaceMethod is not None:
86 return ifaceMethod
87
88 if getSuperClass(klass) is not None:
89 parentMethod = cls.findHighestMethod(getSuperClass(klass), method, paramTypes)
90 if parentMethod is not None:
91 return parentMethod
92
93 methods = klass.getMethods()
94 for i in range(len(methods)):
95
96 if methods[i].getName() == method:
97 return methods[i]
98
99 return None
100
101
102 - def __init__(self, eventType, target, method, arguments=None,
103 eventArgumentIndex=None):
104 """Constructs a new event listener from a trigger method, it's
105 arguments and the argument index specifying which one is replaced with
106 the event object when the trigger method is called.
107
108 This constructor gets the trigger method as a parameter so it does not
109 need to reflect to find it out.
110
111 @param eventType:
112 the event type that is listener listens to. All events of
113 this kind (or its subclasses) result in calling the trigger
114 method.
115 @param target:
116 the object instance that contains the trigger method
117 @param method:
118 the trigger method or the name of the trigger method. If
119 the object does not contain the method a C{ValueError} is
120 thrown.
121 @param arguments:
122 the arguments to be passed to the trigger method
123 @param eventArgumentIndex:
124 An index to the argument list. This index points out the
125 argument that is replaced with the event object before the
126 argument set is passed to the trigger method. If the
127 eventArgumentIndex is negative, the triggering event object
128 will not be passed to the trigger method, though it is still
129 called.
130 @raise ValueError:
131 if C{method} is not a member of C{target}
132 """
133
134
135 self._eventType = None
136
137
138 self._target = None
139
140
141
142 self._method = None
143
144
145 self._arguments = None
146
147
148
149
150 self._eventArgumentIndex = None
151
152
153
154 if arguments is None:
155 if isinstance(method, basestring):
156 methodName = method
157
158
159 method = getattr(target, methodName)
160
161 self._eventType = eventType
162 self._target = target
163 self._method = methodName
164 self._eventArgumentIndex = -1
165
166 params, _, _, _ = inspect.getargspec(method)
167
168 if len(params) == 1:
169 self._arguments = []
170 elif len(params) == 2:
171 self._arguments = [None]
172 self._eventArgumentIndex = 0
173 else:
174 raise ValueError
175 else:
176 if ((target is not None) and
177 not issubclass(target.__class__, method.im_class)):
178 raise ValueError, ('%s : %s' % (target.__class__,
179 method.im_class))
180
181 self._eventType = eventType
182 self._target = target
183
184 if target is None:
185 self._method = method
186 else:
187
188 self._method = method.im_func.func_name
189
190 self._eventArgumentIndex = -1
191
192 params, _, _, _ = inspect.getargspec(method)
193 nparam = len(params)
194
195 if self._target is not None:
196
197 nparam = nparam - 1
198
199 if nparam == 0:
200 self._arguments = []
201 elif nparam == 1:
202 self._arguments = [None]
203 self._eventArgumentIndex = 0
204 else:
205 raise ValueError, 'listener takes too many arguments'
206
207 elif eventArgumentIndex is None:
208
209 if isinstance(method, basestring):
210 methodName = method
211 method = getattr(target, methodName)
212
213 self._eventType = eventType
214 self._target = target
215 self._method = method
216 self._arguments = arguments
217 self._eventArgumentIndex = -1
218 else:
219 if ((target is not None) and
220 not issubclass(target.__class__, method.im_class)):
221 raise ValueError, ('%s : %s' % (target.__class__,
222 method.im_class))
223
224 self._eventType = eventType
225 self._target = target
226 self._method = method
227 self._arguments = arguments
228 self._eventArgumentIndex = -1
229 else:
230 if isinstance(method, basestring):
231 methodName = method
232 method = getattr(target, methodName)
233
234
235 if (eventArgumentIndex >= 0
236 and arguments[eventArgumentIndex] is not None):
237 raise ValueError, 'event argument not None'
238
239 self._eventType = eventType
240 self._target = target
241 self._method = method
242 self._arguments = arguments
243 self._eventArgumentIndex = eventArgumentIndex
244 else:
245 if ((target is not None) and
246 not issubclass(target.__class__, method.im_class)):
247 raise ValueError, ('%s : %s' % (target.__class__,
248 method.im_class))
249
250
251 if (eventArgumentIndex >= 0
252 and arguments[eventArgumentIndex] is not None):
253 raise ValueError, 'event argument not None'
254
255 self._eventType = eventType
256 self._target = target
257 self._method = method
258 self._arguments = arguments
259 self._eventArgumentIndex = eventArgumentIndex
260
261
263 """Receives one event from the C{EventRouter} and calls the trigger
264 method if it matches with the criteria defined for the listener. Only
265 the events of the same or subclass of the specified event class result
266 in the trigger method to be called.
267
268 @param event:
269 the fired event. Unless the trigger method's argument list
270 and the index to the to be replaced argument is specified,
271 this event will not be passed to the trigger method.
272 """
273
274 if issubclass(event.__class__, self._eventType):
275
276 if self._target is None:
277 m = self._method
278 else:
279 m_name = self._method
280 m = getattr(self._target, m_name)
281
282 if self._eventArgumentIndex >= 0:
283 if (self._eventArgumentIndex == 0
284 and len(self._arguments) == 1):
285 m(event)
286 else:
287 arg = list(self._arguments)
288 arg[self._eventArgumentIndex] = event
289 m(*arg)
290 else:
291 m(*self._arguments)
292
293
294
295
296
297
298
299
300 - def matches(self, eventType, target, method=None):
301 """Checks if the given object and event match with the ones stored in
302 this listener.
303
304 @param target:
305 the object to be matched against the object stored by this
306 listener.
307 @param eventType:
308 the type to be tested for equality against the type stored
309 by this listener.
310 @param method:
311 the method to be tested for equality against the method
312 stored by this listener.
313 @return: C{True} if C{target} is the same object as
314 the one stored in this object, C{eventType} equals
315 with the event type stored in this object and
316 C{method} equals with the method stored in this
317 object
318 """
319 if method is None:
320 return self._target == target and eventType == self._eventType
321 else:
322 if target is None:
323 return (self._target == target and eventType == self._eventType
324 and method == self._method)
325 else:
326 return (self._target == target and eventType == self._eventType
327 and method.im_func.func_name == self._method)
328
329
331 hsh = 7
332 hsh = (31 * hsh) + self._eventArgumentIndex
333 hsh = (31 * hsh) + (0 if self._eventType is None else hash(self._eventType))
334 hsh = (31 * hsh) + (0 if self._target is None else hash(self._target))
335 hsh = (31 * hsh) + (0 if self._method is None else hash(self._method))
336 return hsh
337
338
340
341
342 if (obj is None) or (obj.__class__ != self.__class__):
343 return False
344
345
346 return (self._eventArgumentIndex == obj._eventArgumentIndex
347 and (self._eventType == obj._eventType)
348 and (self._target == obj._target)
349 and (self._method == obj._method)
350 and (self._arguments == obj._arguments))
351
352
354 """Compares the type of this ListenerMethod to the given type
355
356 @param eventType:
357 The type to compare with
358 @return: true if this type of this ListenerMethod matches the given
359 type, false otherwise
360 """
361 return self._eventType == eventType
362
363
365 """Compares the type of this ListenerMethod to the given type
366
367 @param eventType:
368 The type to compare with
369 @return: true if this event type can be assigned to the given type,
370 false otherwise
371 """
372 return issubclass(self._eventType, eventType)
373
374
376 """Returns the target object which contains the trigger method.
377
378 @return: The target object
379 """
380 return self._target
381
384 """Exception that wraps an exception thrown by an invoked method. When
385 C{ListenerMethod} invokes the target method, it may throw arbitrary
386 exception. The original exception is wrapped into MethodException instance
387 and rethrown by the C{ListenerMethod}.
388
389 @author: Vaadin Ltd.
390 @author: Richard Lincoln
391 @version: 1.1.2
392 """
393
397
398
400 """Retrieves the cause of this throwable or C{None} if the
401 cause does not exist or not known.
402
403 @return: the cause of this throwable or C{None} if the cause
404 is nonexistent or unknown.
405 """
406 return self._cause
407
408
410 """Returns the error message string of this throwable object.
411
412 @return: the error message.
413 @see: Exception.message
414 """
415 return self._message
416
417
419 msg = super(MethodException, self).__str__()
420
421 if self._cause is not None:
422 msg += '\nCause: ' + str(self._cause)
423
424 return msg
425