Package spade :: Module Behaviour
[hide private]
[frames] | no frames]

Source Code for Module spade.Behaviour

  1  # -*- coding: UTF8 -*- 
  2  import time 
  3  import ACLMessage 
  4  import MessageReceiver 
  5  import threading 
  6  import types 
  7  import copy 
  8  import colors 
  9  import sys 
 10  import traceback 
 11   
 12  from xmpp import Node, Message, Presence, Iq 
 13  import xmpp 
 14  import re 
 15   
 16   
17 -class BehaviourTemplate:
18 """ 19 Template operators 20 """ 21
22 - def __init__(self, regex=False):
23 self.regex=regex
24
25 - def match(self, message):
26 return False
27
28 - def __and__(self, other):
29 """Implementation of & operator""" 30 return ANDTemplate(self, other)
31 - def __rand__(self, other):
32 """Implementation of &= operator""" 33 return (self & other)
34
35 - def __or__(self, other):
36 """Implementation of | operator""" 37 return ORTemplate(self, other)
38 - def __ror__(self, other):
39 """Implementation of |= operator""" 40 return (self | other)
41
42 - def __xor__(self, other):
43 """Implementation of ^ operator""" 44 return XORTemplate(self, other)
45 - def __rxor__(self, other):
46 """Implementation of ^= operator""" 47 return (self ^ other)
48 - def __invert__(self):
49 """Implementation of ~ operator""" 50 return NOTTemplate(self)
51 52
53 -class ACLTemplate(BehaviourTemplate):
54 """ 55 Template for message matching 56 """
57 - def __init__(self, performative=None):
58 self.performative = performative 59 self.sender = None 60 self.receivers = [] 61 self.reply_to = [] 62 self.content = None 63 self.reply_with = None 64 self.reply_by = None 65 self.in_reply_to = None 66 self.encoding = None 67 self.language = None 68 self.ontology = None 69 self.protocol = None 70 self.conversation_id = None
71 #self.userDefProps = None 72
73 - def __str__(self):
74 return str({"performative":self.performative,"sender":str(self.sender),"receivers":str(self.receivers),"reply_to":self.reply_to, "content":self.content,"reply_with":self.reply_with, "reply_by":self.reply_by, "in_reply_to":self.in_reply_to,"encoding":self.encoding, "language":self.language, "ontology":self.ontology,"protocol":self.protocol, "conversation_id":self.conversation_id})
75
76 - def reset(self):
77 self.__init__()
78
79 - def setSender(self, sender):
80 self.sender = sender
81
82 - def getSender(self):
83 return self.sender
84
85 - def addReceiver(self, recv):
86 self.receivers.append(recv)
87
88 - def removeReceiver(self, recv):
89 if recv in self.receivers: 90 self.receivers.remove(recv)
91
92 - def getReceivers(self):
93 return self.receivers
94 95
96 - def addReplyTo(self, re):
97 if isinstance(re,AID.aid): 98 self.reply_to.append(re)
99
100 - def removeReplyTo(self, re):
101 if re in self.reply_to: 102 self.reply_to.remove(re)
103
104 - def getReplyTo(self):
105 return self.reply_to
106
107 - def setPerformative(self, p):
108 self.performative = p
109
110 - def getPerformative(self):
111 return self.performative
112
113 - def setContent(self,c):
114 self.content = c
115
116 - def getContent(self):
117 return self.content
118
119 - def setReplyWith(self,rw):
120 self.reply_with = rw
121
122 - def getReplyWith(self):
123 return self.reply_with
124
125 - def setInReplyTo(self, reply):
126 self.in_reply_to = reply
127
128 - def getInReplyTo(self):
129 return self.in_reply_to
130
131 - def setEncoding(self,e):
132 self.encoding = e
133
134 - def getEncoding(self):
135 return self.encoding
136
137 - def setLanguage(self,e):
138 self.language = e
139
140 - def getLanguage(self):
141 return self.language
142 - def setOntology(self,e):
143 self.ontology = e
144
145 - def getOntology(self):
146 return self.ontology
147 - def setReplyBy(self,e):
148 self.reply_by = e
149
150 - def getReplyBy(self):
151 return self.reply_by
152
153 - def setProtocol(self,e):
154 self.protocol = e
155
156 - def getProtocol(self):
157 return self.protocol
158 - def setConversationId(self,e):
159 self.conversation_id = e
160
161 - def getConversationId(self):
162 return self.conversation_id
163 164
165 -class NOTTemplate(BehaviourTemplate):
166 - def __init__(self, expr):
167 self.expr = expr
168 - def match(self, message):
169 return (not(self.expr.match(message)))
170
171 -class ORTemplate(BehaviourTemplate):
172 - def __init__(self, expr1, expr2):
173 self.expr1 = expr1 174 self.expr2 = expr2
175 - def match(self, message):
176 return (self.expr1.match(message) | self.expr2.match(message))
177
178 -class ANDTemplate(BehaviourTemplate):
179 - def __init__(self, expr1, expr2):
180 self.expr1 = expr1 181 self.expr2 = expr2
182 - def match(self, message):
183 return (self.expr1.match(message) & self.expr2.match(message))
184
185 -class XORTemplate(BehaviourTemplate):
186 - def __init__(self, expr1, expr2):
187 self.expr1 = expr1 188 self.expr2 = expr2
189 - def match(self, message):
190 return (self.expr1.match(message) ^ self.expr2.match(message))
191 192 193 ''' 194 class PresenceTemplate(BehaviourTemplate): 195 """ 196 Template for presence notifications 197 """ 198 def __init__(self, frm=None, type=None, status=None, show=None, role=None, affiliation=None): 199 self._frm, self._type, self._status, self._show, self._role, self._affiliation = frm,type,status,show,role,affiliation 200 ''' 201 202
203 -class MessageTemplate(BehaviourTemplate):
204 - def __init__(self, Template, regex=False):
205 # Discriminate Template class 206 BehaviourTemplate.__init__(self, regex) 207 if type(Template) == types.InstanceType: 208 if Template.__class__ == ACLTemplate: 209 self.match = self.acl_match 210 else: 211 # Default template option 212 self.match = self.node_match 213 214 self.template = copy.copy(Template)
215 216
217 - def acl_match(self, message):
218 # print "acl_match called with \n +Template:" + str(self.template) + "\n +Messange: " + str(message) 219 if message.__class__ != ACLMessage.ACLMessage: return False 220 if (self.template.getPerformative() != None): 221 if (self.template.getPerformative() != message.getPerformative()): return False 222 if (self.template.getConversationId() != None): 223 if (str(self.template.getConversationId()) != str(message.getConversationId())): 224 return False 225 if (self.template.sender != None): 226 if not message.sender.match(self.template.sender): return False 227 if (self.template.receivers != []): 228 for tr in self.template.receivers: 229 found=False 230 for mr in message.receivers: 231 if mr.match(tr): found=True 232 break 233 if not found: return False 234 if (self.template.getReplyTo() != []): 235 if (self.template.getReplyTo() != message.getReplyTo()): return False 236 if (self.template.content != None): 237 if (self.template.content != message.content): return False 238 if (self.template.getReplyWith() != None): 239 if (self.template.getReplyWith() != message.getReplyWith()): return False 240 if (self.template.getReplyBy() != None): 241 if (self.template.getReplyBy() != message.getReplyBy()): return False 242 if (self.template.getInReplyTo() != None): 243 if (self.template.getInReplyTo() != message.getInReplyTo()): return False 244 if (self.template.getEncoding() != None): 245 if (self.template.getEncoding() != message.getEncoding()): return False 246 if (self.template.getLanguage() != None): 247 if (self.template.getLanguage() != message.getLanguage()): return False 248 if (self.template.getOntology() != None): 249 if (self.template.getOntology() != message.getOntology()): return False 250 if (self.template.getProtocol() != None): 251 if (self.template.getProtocol() != message.getProtocol()): return False 252 return True
253 254
255 - def node_match(self, other):
256 """ 257 Function that matches a xmpp Node with another one 258 """ 259 # print "node_match called with \n %s \n AND\n %s" % (str(self.template), str(other)) 260 try: 261 # Check types and classes 262 if type(self.template) != types.InstanceType: 263 # print "node_match: First node not an instance" 264 return False 265 #if not issubclass(self.template.__class__, Node) and not issubclass(self.template.__class__, Protocol) and : 266 if "Message" not in str(self.template.__class__) and "Presence" not in str(self.template.__class__) and "Iq" not in str(self.template.__class__) and "Node" not in str(self.template.__class__): 267 # print "node_match: First node not a node:", str(self.template.__class__) 268 return False 269 270 if type(other) != types.InstanceType: 271 # print "node_match: Second node not an instance" 272 return False 273 #if not issubclass(other.__class__ , Node): 274 if "Message" not in str(other.__class__) and "Presence" not in str(other.__class__) and "Iq" not in str(other.__class__) and "Node" not in str(self.template.__class__): 275 # print "node_match: Second node not a node" 276 return False 277 278 if self.template.name != None: 279 if self.template.name != other.name: 280 # print "node_match: Different names: ", str(self.template.name), str(other.name) 281 return False 282 if self.template.attrs != None and self.template.attrs != {}: 283 # for i in self.template.attrs.items(): 284 # if i not in other.attrs.items(): 285 for i,j in self.template.attrs.items(): 286 # print "****Comparing: i=%s (%s),%s (%s),other=%s (%s)" % (i,type(i),j,type(j),other.attrs[i],type(other.attrs[i])) 287 if (i,j) not in (other.attrs.items()): # not in other.attrs.items(): 288 # print "node_match: Different attrs:", str(self.template.attrs), str(other.attrs) 289 if not self.regex: 290 return False 291 if not re.match(str(j),str(other.attrs[i])): 292 return False 293 if self.template.data != None and self.template.data != []: 294 if self.template.data != other.data: 295 # print "node_match: Different data:", str(self.template.data), str(other.data), re.match(str(self.template.data),str(other.data)) 296 if not self.regex: 297 return False 298 if not re.match(str(self.template.data[0]),str(other.data[0])): 299 return False 300 # print "node_match: Matched regex:", str(self.template.data), str(other.data), re.match(str(self.template.data),str(other.data)) 301 302 if self.template.namespace: 303 if self.template.namespace != other.namespace: 304 # print "node_match: Different namespace:", str(self.template.namespace), str(other.namespace) 305 return False 306 307 for kid in self.template.kids: 308 # Assemble a list of similar kids from the other node 309 suspects = other.getTags(kid.getName()) 310 if not suspects: return False 311 value = False 312 for s in suspects: 313 value = MessageTemplate(kid,regex=self.regex).node_match(s) 314 #value = self.node_match(kid, s) 315 if value == True: 316 # There is a match among the supects 317 break 318 if not value: 319 # If we reach this point, there is no hope left . . . (no match among the suspects) 320 return False 321 322 except Exception, e: 323 # print "Exception in node_match:", e 324 return False 325 # Arriving here means this is a perfect match 326 return True
327
328 - def presence_match(self, message): #frm=None, type=None, status=None, show=None):
329 330 frm,type,status,show,role,affiliation = message.frm,message.type,message.status,message.show,message.role,message.affiliation 331 332 #if self._frm !=None and frm != self._frm: return False 333 if self._type !=None and type != self._type: return False 334 if self._status !=None and status != self._status: return False 335 if self._show !=None and show != self._show: return False 336 if self._role !=None and role != self._role: return False 337 if self._affiliation != None and affiliation != self._affiliation: return False 338 339 if self._frm: 340 if not JID(self._frm).getResource(): 341 if self._frm != JID(frm).getBareJID(): 342 return False 343 else: 344 if self._frm != frm: return False 345 346 return True
347
348 - def message_match(self, msg):
349 return self.node_match(msg)
350
351 - def iq_match(self, iq):
352 return self.node_match(iq)
353 354 355 356 357
358 -class Behaviour(MessageReceiver.MessageReceiver):
359 - def __init__(self):
360 MessageReceiver.MessageReceiver.__init__(self) 361 #self._running = False # Not needed for now 362 self.myParent = None 363 self._forceKill = threading.Event() 364 self._presenceHandlers = dict() 365 366 self._exitcode = 0
367 368 """ 369 def __getattr__(self, aname): 370 return self.myAgent.__dict__[aname] 371 372 def __setattr__(self, aname, value): 373 # Base case: aname is defined locally 374 if aname in self.__dict__: 375 self.__dict__[aname] = value 376 # Second case: aname is defined in "myAgent" 377 elif "myAgent" in self.__dict__ and self.__dict__["myAgent"] and aname in self.myAgent.__dict__: 378 setattr(self.myAgent, aname, value) 379 # Third case: new local declaration 380 else: 381 self.__dict__[aname] = value 382 """ 383
384 - def setParent(self, parent):
385 self.myParent = parent
386 - def getParent(self):
387 return self.myParent
388 - def setAgent(self, agent):
389 """ 390 sets the agent which controls the behavior 391 """ 392 self.myAgent = agent 393 self.DEBUG = self.myAgent.DEBUG 394 try: 395 self.setName(str(self.myAgent.getName()) + " Behaviour") 396 except: 397 pass
398
399 - def getAgent(self):
400 """ 401 returns the agent which controls the behavior 402 """ 403 return self.myAgent
404 - def root(self):
405 if (self.myParent != None): 406 return self.myParent.root() 407 else: 408 return self
409
410 - def done(self):
411 """ 412 returns True if the behavior has finished 413 else returns False 414 """ 415 return False
416
417 - def _process(self):
418 """ 419 main loop 420 must be overridden 421 """ 422 raise NotImplementedError
423
424 - def kill(self):
425 """ 426 stops the behavior 427 """ 428 try: 429 self._forceKill.set() 430 except: 431 #Behavior is already dead 432 self.myAgent.DEBUG("Behavior " +str(self)+ " is already dead","warn/")
433
434 - def onStart(self):
435 """ 436 this method runs when the behavior starts 437 """ 438 pass
439 - def onEnd(self):
440 """ 441 this method runs when the behavior stops 442 """ 443 pass
444 - def exitCode(self):
445 """ 446 returns the default exit code for the behavior 447 """ 448 return self._exitcode
449
450 - def run(self):
451 if not self.myAgent._running: 452 # Get condition and wait for the other behaviours 453 self.myAgent.behavioursGo.acquire() 454 self.myAgent.behavioursGo.wait() 455 self.myAgent.behavioursGo.release() 456 457 """ 458 # Check wether this behaviour has already started 459 if not self._running: 460 self._running = True 461 else: 462 # The behaviour was already running, no need to run run (he he) twice 463 return 464 """ 465 self.onStart() 466 try: 467 while (not self.done()) and (not self._forceKill.isSet()): 468 self._exitcode = self._process() 469 except Exception,e: 470 self.myAgent.DEBUG("Exception in Behaviour "+str(self)+": "+str(e), "err") 471 self.onEnd() 472 #if issubclass(self.__class__, EventBehaviour): 473 # self.myAgent.removeBehaviour(self.__class__) 474 #else: 475 if not issubclass(self.__class__, EventBehaviour): 476 self.myAgent.removeBehaviour(self)
477
478 - def registerPresenceHandler(self, template, handler):
479 """ 480 DEPRECATED 481 register a handler that will manage all incoming presence notifications matching the given presence template 482 """ 483 self._presenceHandlers[handler] = template
484
485 - def managePresence(self, frm=None, type=None, status=None, show=None, role=None, affiliation=None):
486 """ 487 DEPRECATED 488 manage a FIPA-formed presence message 489 """ 490 class struct: 491 def __init__(self,frm,type,status,show,role,affiliation): 492 self.frm,self.type,self.status,self.show,self.role,self.affiliation=frm,type,status,show,role,affiliation
493 # Check every handler template to see which ones match 494 for handler in self._presenceHandlers: 495 t = self._presenceHandlers[handler] 496 if t: 497 if t.match(struct(frm,type,status,show,role,affiliation)): 498 handler(frm,type,status,show,role,affiliation) 499
500 - def setTemplate(self, template):
501 """ 502 Set the message template for this behaviour 503 """ 504 if self.myAgent: 505 self.myAgent._behaviourList[self] = template
506 507
508 -class OneShotBehaviour(Behaviour):
509 """ 510 this behavior is only executed once 511 """
512 - def __init__(self):
513 Behaviour.__init__(self) 514 self._firsttime = True
515 - def done(self):
516 if (self._firsttime == True): 517 self._firsttime = False 518 return False 519 return True
520 521 522 523
524 -class PeriodicBehaviour(Behaviour):
525 """ 526 this behavior runs periodically with a period 527 """
528 - def __init__(self, period, timestart = None):
529 Behaviour.__init__(self) 530 self._period = period 531 if (timestart == None): 532 self._nextActivation = time.time() 533 else: 534 self._nextActivation = timestart
535
536 - def getPeriod(self):
537 return self._period
538 - def setPeriod(self, period):
539 self._period = period
540
541 - def _process(self):
542 if time.time() >= self._nextActivation: 543 self._exitcode = self._onTick() 544 while self._nextActivation <= time.time(): 545 self._nextActivation += self._period 546 else: 547 t = self._nextActivation - time.time() 548 if t > 0: 549 time.sleep(t) 550 return self._exitcode
551
552 - def _onTick(self):
553 """ 554 this method is executed every period 555 must be overridden 556 """ 557 raise NotImplementedError
558 559
560 -class TimeOutBehaviour(PeriodicBehaviour):
561 """ 562 this behavior is executed only once after a timeout 563 """
564 - def __init__(self, timeout):
565 PeriodicBehaviour.__init__(self, timeout, time.time()+timeout) 566 self._stop = False
567
568 - def getTimeOut(self):
569 return self.getPeriod()
570 - def stop(self):
571 """ 572 cancels the programmed execution 573 """ 574 self._stop = True
575 - def done(self):
576 return self._stop
577
578 - def _onTick(self):
579 if (self._stop == False): 580 self.timeOut() 581 self.stop()
582
583 - def timeOut(self):
584 """ 585 this method is executed after the timeout 586 must be overridden 587 """ 588 raise NotImplementedError
589 590 591 592 593
594 -class FSMBehaviour(Behaviour):
595 """ 596 this behavior is executed according to a Finite State Machine 597 """
598 - def __init__(self):
599 Behaviour.__init__(self) 600 self._firstStateName = None 601 self._lastStatesNames = [] 602 self._states = dict() 603 self._transitions = dict() 604 self._actualState = None 605 self._lastexitcode = None 606 self._destroy = False 607 self._firsttime = True
608
609 - def setAgent(self, agent):
610 """ 611 sets the parent agent 612 """ 613 #self.setAgent(agent) 614 Behaviour.setAgent(self, agent) 615 for b in self._states: 616 self._states[b].setAgent(agent)
617
618 - def registerState(self, behaviour, name):
619 """ 620 registers a state with a behavior 621 """ 622 if not issubclass(behaviour.__class__, OneShotBehaviour): 623 print "WARNING! Registering not-OneShot as FSM state" 624 behaviour.setParent(self) 625 self._states[name]=behaviour 626 self._transitions[name]=dict() 627 behaviour._receive = self._receive 628 behaviour.setTemplate = self.setTemplate 629 behaviour._stateName = name
630
631 - def registerFirstState(self, behaviour, name):
632 """ 633 sets the first state of the fsm 634 """ 635 self.registerState(behaviour, name) 636 self._firstStateName = name
637
638 - def registerLastState(self, behaviour, name):
639 """ 640 sets the final state of the fsm 641 """ 642 self.registerState(behaviour, name) 643 self._lastStatesNames.append(name)
644
645 - def registerTransition(self, fromname, toname, event):
646 """ 647 registers a transition between two states 648 """ 649 self._transitions[fromname][event] = toname
650
651 - def getState(self, name):
652 return self._states[name]
653 654 #def onStart(self): 655 # self._actualState = self._firstStateName 656 # self._actualState.start() 657 # for b in self._states: 658 # self._states[b].start() 659 #def onEnd(self): 660 # for b in self._states: 661 # self._states[b].kill() 662
663 - def exitCode(self):
664 return self._lastexitcode
665
666 - def done(self):
667 if self._actualState in self._lastStatesNames: 668 if self._firsttime == True: 669 # The first time "done" is called while in a final state, return False 670 # The next time, return True 671 self._firsttime = False 672 return False 673 else: 674 return True 675 else: return False
676
677 - def _transitionTo(self,newState):
678 try: 679 b = self._states[self._actualState] 680 b.onEnd() 681 except KeyError: 682 pass 683 self._actualState = newState 684 try: 685 b = self._states[self._actualState] 686 b.onStart() 687 except KeyError: 688 pass
689
690 - def _process(self):
691 if (self._actualState == None): 692 self._transitionTo(self._firstStateName) 693 #msg = self._receive(False) 694 b = self._states[self._actualState] 695 #if msg: buede .postMessage(msg) 696 self._lastexitcode = b._process() 697 if (b.done() or b._forceKill.isSet()): 698 if not self._lastexitcode: self._lastexitcode = b.exitCode() 699 self._transitionTo(self._transitions[b._stateName][self._lastexitcode]) 700 self._lastexitcode = None
701 702
703 - def getCurrentState(self):
704 return self._states[self._actualState]
705 706 707 708
709 -class EventBehaviour(OneShotBehaviour):
710 """ 711 A behaviour that is executed in response to a certain event. 712 The 'onetime' parameter in the constructor represents the 713 re-usability of the behaviour. By default, an Event behaviour is 714 re-instanced (and re-launched) every time a new event that matches 715 the template arrives. This can be changed by setting 'onetime' 716 to True, which renders the behaviour for one use only 717 """ 718 #onetime = False
719 - def __init__(self, onetime=False):
720 OneShotBehaviour.__init__(self) 721 self.onetime = onetime
722 723 #def run(self): 724 725 726 727 728 if __name__ == "__main__":
729 - class TestBehaviour(PeriodicBehaviour):
730 - def __init__(self, time):
731 PeriodicBehaviour.__init__(self, time)
732 - def _onTick(self):
733 print "Tick: " + str(time.time())
734 735 a = TestBehaviour(5) 736 a.start() 737