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

Source Code for Module spade.Agent

   1  # -*- coding: cp1252 -*- 
   2   
   3  try: 
   4      import psyco 
   5      psyco.full() 
   6  except ImportError: 
   7      pass #self.DEBUG("Psyco optimizing compiler not found","warn") 
   8   
   9  import sys 
  10  import xml.dom.minidom 
  11  import traceback 
  12  import xmpp 
  13  import threading 
  14  import thread 
  15  import Queue 
  16  import time 
  17  import MessageReceiver 
  18  import AID 
  19  import XMLCodec 
  20  import ACLParser 
  21  import Envelope 
  22  import ACLMessage 
  23  import BasicFipaDateTime 
  24  import Behaviour 
  25  import SL0Parser 
  26  import fipa 
  27  import peer2peer as P2P 
  28  import socialnetwork 
  29  import RPC 
  30  import pubsub 
  31  import bdi 
  32  from logic import * 
  33  from kb import * 
  34   
  35  import mutex 
  36  import types 
  37  import random 
  38  import string 
  39  import copy 
  40  import socket 
  41  import SocketServer 
  42  import colors 
  43  import cPickle as pickle 
  44  import uuid 
  45  import json 
  46   
  47   
  48  import DF 
  49  from content import ContentObject 
  50  from wui import * 
  51   
  52  from xmpp import * 
  53   
  54  # Taken from xmpp debug 
  55  color_none         = chr(27) + "[0m" 
  56  color_black        = chr(27) + "[30m" 
  57  color_red          = chr(27) + "[31m" 
  58  color_green        = chr(27) + "[32m" 
  59  color_brown        = chr(27) + "[33m" 
  60  color_blue         = chr(27) + "[34m" 
  61  color_magenta      = chr(27) + "[35m" 
  62  color_cyan         = chr(27) + "[36m" 
  63  color_light_gray   = chr(27) + "[37m" 
  64  color_dark_gray    = chr(27) + "[30;1m" 
  65  color_bright_red   = chr(27) + "[31;1m" 
  66  color_bright_green = chr(27) + "[32;1m" 
  67  color_yellow       = chr(27) + "[33;1m" 
  68  color_bright_blue  = chr(27) + "[34;1m" 
  69  color_purple       = chr(27) + "[35;1m" 
  70  color_bright_cyan  = chr(27) + "[36;1m" 
  71  color_white        = chr(27) + "[37;1m" 
  72   
  73  try: 
  74      threading.stack_size(64 * 1024)  # 64k compo 
  75  except: pass 
76 77 78 -def require_login(func):
79 '''decorator for requiring login in wui controllers''' 80 self = func.__class__ 81 def wrap(self, *args, **kwargs): 82 if (not hasattr(self.session,"user_authenticated") or getattr(self.session,"user_authenticated")==False) and self.wui.passwd!=None: 83 name = self.getName().split(".")[0].upper() 84 if name=="ACC": name="SPADE" 85 return "login.pyra", {"name":name,'message':"Authentication is required.", "forward_url":self.session.url} 86 return func(self,*args,**kwargs)
87 wrap.__doc__=func.__doc__ 88 wrap.__name__=func.__name__ 89 return wrap 90
91 92 -class AbstractAgent(MessageReceiver.MessageReceiver):
93 """ 94 Abstract Agent 95 only for heritance 96 Child classes: PlatformAgent, Agent 97 """ 98
99 - def __init__(self, agentjid, serverplatform, p2p=False):
100 """ 101 inits an agent with a JID (user@server) and a platform JID (acc.platformserver) 102 """ 103 MessageReceiver.MessageReceiver.__init__(self) 104 self._agent_log = [] # Log system 105 self._aid = AID.aid(name=agentjid, addresses=["xmpp://"+agentjid]) 106 self._jabber = None 107 self._serverplatform = serverplatform 108 self.server = serverplatform 109 self._defaultbehaviour = None 110 self._behaviourList = dict() 111 self._alive = True 112 self._alivemutex = mutex.mutex() 113 self._forceKill = threading.Event() 114 self._forceKill.clear() 115 self.JID=agentjid 116 self.setName(str(agentjid)) 117 118 self._debug = False 119 self._debug_filename = "" 120 self._debug_file = None 121 self._debug_mutex = thread.allocate_lock() 122 123 self._messages=[] 124 self._messages_mutex = thread.allocate_lock() 125 126 self.wui = WUI(self) 127 self.wui.registerController("index",self.WUIController_admin) 128 self.wui.registerController("login",self.WUIController_login) 129 self.wui.registerController("logout",self.WUIController_logout) 130 self.wui.registerController("admin", self.WUIController_admin) 131 self.wui.registerController("log", self.WUIController_log) 132 self.wui.registerController("messages",self.WUIController_messages) 133 self.wui.registerController("search",self.WUIController_search) 134 self.wui.registerController("send",self.WUIController_sendmsg) 135 self.wui.registerController("sent",self.WUIController_sent) 136 self.wui.passwd = None 137 138 self._aclparser = ACLParser.ACLxmlParser() 139 140 #self._friend_list = [] # Legacy 141 #self._muc_list= {} 142 self._roster = {} 143 self._socialnetwork = {} 144 self._subscribeHandler = lambda frm,typ,stat,show: False 145 self._unsubscribeHandler = lambda frm,typ,stat,show: False 146 147 #PubSub 148 self._pubsub = pubsub.PubSub(self) 149 self._events = {} 150 151 #Knowledge base 152 self.kb = KB() # knowledge base 153 154 155 self._waitingForRoster = False # Indicates that a request for the roster is in progress 156 157 self.behavioursGo = threading.Condition() # Condition to synchronise behaviours 158 self._running = False 159 160 # Add Disco Behaviour 161 self.addBehaviour(P2P.DiscoBehaviour(), Behaviour.MessageTemplate(Iq(queryNS=NS_DISCO_INFO))) 162 163 # Add Stream Initiation Behaviour 164 iqsi = Iq() 165 si = iqsi.addChild("si") 166 si.setNamespace("http://jabber.org/protocol/si") 167 self.addBehaviour(P2P.StreamInitiationBehaviour(), Behaviour.MessageTemplate(iqsi)) 168 169 # Add P2P Behaviour 170 self.p2p_ready = False # Actually ready for P2P communication 171 self.p2p = p2p 172 self.p2p_routes = {} 173 self.p2p_lock = thread.allocate_lock() 174 self.p2p_send_lock = thread.allocate_lock() 175 self._p2p_failures = 0 # Counter for failed attempts to send p2p messages 176 if p2p: 177 self.registerLogComponent("p2p") 178 self.P2PPORT = random.randint(1025,65535) # Random P2P port number 179 p2pb = P2P.P2PBehaviour() 180 self.addBehaviour(p2pb) 181 182 #Remote Procedure Calls support 183 self.RPC = {} 184 self.addBehaviour(RPC.RPCServerBehaviour(), Behaviour.MessageTemplate(Iq(typ='set',queryNS=NS_RPC)))
185 186
187 - def setAdminPasswd(self, passwd):
188 self.wui.passwd = str(passwd)
189
190 - def WUIController_login(self, password=None, forward_url="index"):
191 if hasattr(self.session, "user_authenticated") and getattr(self.session,"user_authenticated")==True: 192 raise HTTP_REDIRECTION, 'index' 193 194 name = self.getName().split(".")[0].upper() 195 if name=="ACC": name="SPADE" 196 197 if password==None: 198 return "login.pyra", {"name":name, "message":"Authentication is required.","forward_url":forward_url} 199 if password!=self.wui.passwd: 200 return "login.pyra", {"name":name, "message":"Password is incorrect. Try again.","forward_url":forward_url} 201 202 else: 203 setattr(self.session,"user_authenticated",True) 204 raise HTTP_REDIRECTION, forward_url
205
206 - def WUIController_logout(self):
207 if hasattr(self.session, "user_authenticated"): 208 delattr(self.session,"user_authenticated") 209 raise HTTP_REDIRECTION, "index"
210 211 @require_login
212 - def WUIController_admin(self):
213 import types 214 behavs = {} 215 attrs = {} 216 sorted_attrs = [] 217 for k in self._behaviourList.keys(): 218 behavs[id(k)]=k 219 for attribute in self.__dict__: 220 if eval( "type(self."+attribute+") not in [types.MethodType, types.BuiltinFunctionType, types.BuiltinMethodType, types.FunctionType]" ): 221 if attribute not in ["_agent_log"]: 222 attrs[attribute] = eval( "str(self."+attribute+")" ) 223 sorted_attrs = attrs.keys() 224 sorted_attrs.sort() 225 import pygooglechart 226 chart=pygooglechart.QRChart(125,125) 227 chart.add_data(self.getAID().asXML()) 228 chart.set_ec('H',0) 229 return "admin.pyra", {"name":self.getName(),"aid":self.getAID(), "qrcode":chart.get_url(), "defbehav":(id(self._defaultbehaviour),self._defaultbehaviour), "behavs":behavs, "p2pready":self.p2p_ready, "p2proutes":self.p2p_routes, "attrs":attrs, "sorted_attrs":sorted_attrs}
230 231 @require_login
232 - def WUIController_log(self):
233 return "log.pyra", {"name":self.getName(), "log":self.getLog()}
234 235 @require_login
236 - def WUIController_messages(self,agents=None):
237 index=0 238 mess = {} 239 msc = "" 240 agentslist=[] 241 for ts,m in self._messages: 242 if isinstance(m,ACLMessage.ACLMessage): 243 strm=self._aclparser.encodeXML(m) 244 x = xml.dom.minidom.parseString(strm) 245 #strm = x.toprettyxml() 246 strm = m.asHTML() 247 frm = m.getSender() 248 if frm!=None: frm = str(frm.getName()) 249 else: frm = "Unknown" 250 if "/" in frm: frm=frm.split("/")[0] 251 r = m.getReceivers() 252 if len(r)>=1: 253 to = r[0].getName() 254 else: 255 to = "Unknown" 256 if "/" in to: to=to.split("/")[0] 257 if agents: 258 if to in agents or frm in agents: 259 msc += frm+"->"+to+':'+str(index)+" "+str(m.getPerformative())+'\n' 260 else: 261 msc += frm+"->"+to+':'+str(index)+" "+str(m.getPerformative())+'\n' 262 else: 263 strm=str(m) 264 """strm = strm.replace("&gt;",">") 265 strm = strm.replace("&lt;","<") 266 strm = strm.replace("&quot;",'"')""" 267 x = xml.dom.minidom.parseString(strm) 268 strm = x.toprettyxml() 269 # Quick'n dirty hack to display jabber messages on the WUI 270 # Will fix with a proper display 271 strm = strm.replace(">", "&gt;") 272 strm = strm.replace("<", "&lt;") 273 strm = strm.replace('"', "&quot;") 274 frm = m.getFrom() 275 if frm==None: frm = "Unknown" 276 else: frm = str(frm) 277 if "/" in frm: frm=frm.split("/")[0] 278 to = m.getTo() 279 if to==None: to = "Unknown" 280 else: to = str(to) 281 if "/" in to: to=to.split("/")[0] 282 if agents: 283 if to in agents or frm in agents: 284 msc += frm+"-->"+to+':'+str(index)+' '+str(m.getName()) 285 if m.getType(): msc+=" " + str(m.getType())+'\n' 286 elif m.getName()=="message": 287 if m.getAttr("performative"): msc+=" " + str(m.getAttr("performative"))+'\n' 288 else: msc+='\n' 289 else: msc+='\n' 290 else: 291 msc += frm+"-->"+to+':'+str(index)+' '+str(m.getName()) 292 if m.getType(): msc+=" " + str(m.getType())+'\n' 293 elif m.getName()=="message": 294 if m.getAttr("performative"): msc+=" " + str(m.getAttr("performative"))+'\n' 295 else: msc+='\n' 296 else: msc+='\n' 297 298 if frm not in agentslist: agentslist.append(frm) 299 if to not in agentslist: agentslist.append(to) 300 301 mess[index]=(ts,strm) 302 index+=1 303 304 return "messages.pyra", {"name":self.getName(), "messages":mess, "diagram": msc, "agentslist":agentslist}
305 306 @require_login
307 - def WUIController_search(self, query):
308 309 #FIRST SEARCH AGENTS 310 from AMS import AmsAgentDescription 311 agentslist = [] 312 313 #search by name 314 aad = AmsAgentDescription() 315 aad.setAID(AID.aid(name=query)) 316 res = self.searchAgent(aad) 317 if res: 318 agentslist += res 319 320 #search by address 321 aad = AmsAgentDescription() 322 aad.setAID(AID.aid(addresses=[query])) 323 res = self.searchAgent(aad) 324 if res: 325 for a in res: 326 if not a in agentslist: 327 agentslist.append(a) 328 329 #search by ownership 330 aad = AmsAgentDescription() 331 aad.setOwnership(query) 332 res = self.searchAgent(aad) 333 if res: 334 for a in res: 335 if not a in agentslist: 336 agentslist.append(a) 337 338 #search by state 339 aad = AmsAgentDescription() 340 aad.setState(query) 341 res = self.searchAgent(aad) 342 if res: 343 for a in res: 344 if not a in agentslist: 345 agentslist.append(a) 346 347 # Build AWUIs dict 348 awuis = {} 349 if agentslist: 350 aw = "" 351 for agent in agentslist: 352 if agent.getAID(): 353 aw = "#" 354 for addr in agent.getAID().getAddresses(): 355 if "awui://" in addr: 356 aw = addr.replace("awui://", "http://") 357 break 358 awuis[agent.getAID().getName()] = aw 359 self.DEBUG("AWUIs: "+str(awuis)) 360 361 #NOW SEARCH SERVICES 362 from DF import Service,DfAgentDescription, ServiceDescription 363 servs = {} 364 365 #search by name 366 s = Service(name=query) 367 search = self.searchService(s) 368 369 for service in search: 370 if service.getDAD().getServices()[0].getType() not in servs.keys(): 371 servs[service.getDAD().getServices()[0].getType()] = [] 372 if service not in servs[service.getDAD().getServices()[0].getType()]: 373 servs[service.getDAD().getServices()[0].getType()].append(service) 374 375 #search by type 376 s = Service() 377 sd = ServiceDescription() 378 sd.setType(query) 379 dad = DfAgentDescription() 380 dad.addService(sd) 381 s.setDAD(dad) 382 search = self.searchService(s) 383 384 for service in search: 385 if service.getDAD().getServices()[0].getType() not in servs.keys(): 386 servs[service.getDAD().getServices()[0].getType()] = [] 387 if service not in servs[service.getDAD().getServices()[0].getType()]: 388 servs[service.getDAD().getServices()[0].getType()].append(service) 389 390 #search by owner 391 s = Service(owner=AID.aid(name=query)) 392 search = self.searchService(s) 393 394 for service in search: 395 if service.getDAD().getServices()[0].getType() not in servs.keys(): 396 servs[service.getDAD().getServices()[0].getType()] = [] 397 if service not in servs[service.getDAD().getServices()[0].getType()]: 398 servs[service.getDAD().getServices()[0].getType()].append(service) 399 400 #search by ontology 401 s = Service() 402 dad = DfAgentDescription() 403 dad.addOntologies(query) 404 dad.addService(sd) 405 s.setDAD(dad) 406 search = self.searchService(s) 407 408 for service in search: 409 if service.getDAD().getServices()[0].getType() not in servs.keys(): 410 servs[service.getDAD().getServices()[0].getType()] = [] 411 if service not in servs[service.getDAD().getServices()[0].getType()]: 412 servs[service.getDAD().getServices()[0].getType()].append(service) 413 414 #search by description 415 '''s = Service() 416 s.setDescription(query) 417 search = self.searchService(s) 418 419 for service in search: 420 if service.getDAD().getServices()[0].getType() not in servs.keys(): 421 servs[service.getDAD().getServices()[0].getType()] = [] 422 if service not in servs[service.getDAD().getServices()[0].getType()]: 423 print "found by description:" +str(service) 424 servs[service.getDAD().getServices()[0].getType()].append(service)''' 425 426 427 return "search.pyra", {"name":self.getName(), "agentslist": agentslist, "awuis":awuis, "services":servs}
428 429 @require_login
430 - def WUIController_sendmsg(self, to=None):
431 from AMS import AmsAgentDescription 432 agentslist = [] 433 aad = AmsAgentDescription() 434 res = self.searchAgent(aad) 435 if res==None: res=[self] 436 for a in res: 437 agentslist.append(a.getAID().getName()) 438 return "message.pyra", {"name":self.getName(), "keys":agentslist, "to":to}
439 440 @require_login
441 - def WUIController_sent(self, receivers=[],performative=None,sender=None,reply_with=None,reply_by=None,reply_to=None,in_reply_to=None,encoding=None,language=None,ontology=None,protocol=None,conversation_id=None,content=""):
442 msg = ACLMessage.ACLMessage() 443 import types 444 if type(receivers)==types.StringType: 445 a = AID.aid(name=receivers,addresses=["xmpp://"+receivers]) 446 msg.addReceiver(a) 447 elif type(receivers)==types.ListType: 448 for r in receivers: 449 a = AID.aid(name=r,addresses=["xmpp://"+r]) 450 msg.addReceiver(a) 451 if performative: msg.setPerformative(performative) 452 if sender: 453 a = AID.aid(name=sender,addresses=["xmpp://"+sender]) 454 msg.setSender(a) 455 if reply_to: msg.setReplyTo(reply_to) 456 if reply_with: msg.setReplyWith(reply_with) 457 if reply_by: msg.setReplyBy(reply_by) 458 if in_reply_to: msg.setInReplyTo(in_reply_to) 459 if encoding: msg.setEncoding(encoding) 460 if language: msg.setLanguage(language) 461 if ontology: msg.setOntology(ontology) 462 if conversation_id: msg.setConversationId(conversation_id) 463 if content: msg.setContent(content) 464 465 self.send(msg) 466 467 return "sentmsg.pyra", {"name":self.getName(), "msg":msg}
468 469 470
471 - def registerLogComponent(self, component):
472 #self._agent_log[component] = {} 473 pass
474
475 - def DEBUG(self, dmsg, typ="info", component="spade"):
476 # Record at log 477 t = time.ctime() 478 dmsg = dmsg.replace("&gt;",">") 479 dmsg = dmsg.replace("&lt;","<") 480 dmsg = dmsg.replace("&quot;",'"') 481 482 self._debug_mutex.acquire() 483 self._agent_log.append((typ,dmsg,component,t)) 484 self._debug_mutex.release() 485 486 if self._debug: 487 # Print on screen 488 if typ == "info": 489 print colors.color_none + "DEBUG:[" + component + "] " + dmsg + " , info" + colors.color_none 490 elif typ == "err": 491 print colors.color_none + "DEBUG:[" + component + "] " + color_red + dmsg + " , error" + colors.color_none 492 elif typ == "ok": 493 print colors.color_none + "DEBUG:[" + component + "] " + colors.color_green + dmsg + " , ok" + colors.color_none 494 elif typ == "warn": 495 print colors.color_none + "DEBUG:[" + component + "] " + colors.color_yellow + dmsg + " , warn" + colors.color_none 496 497 # Log to file 498 if self._debug_file: 499 if typ == "info": 500 self._debug_file.write( t + ": [" + component + "] " + dmsg + " , info\n") 501 elif typ == "err": 502 self._debug_file.write( t + ": [" + component + "] " + dmsg + " , error\n") 503 elif typ == "ok": 504 self._debug_file.write( t + ": [" + component + "] " + dmsg + " , ok\n") 505 elif typ == "warn": 506 self._debug_file.write( t + ": [" + component + "] " + dmsg + " , warn\n") 507 self._debug_file.flush()
508
509 - def setDebug(self, activate = True):
510 self.setDebugToScreen(activate) 511 self.setDebugToFile(activate)
512
513 - def setDebugToScreen(self, activate = True):
514 self._debug = activate
515
516 - def setDebugToFile(self, activate = True, fname = "" ):
517 if not fname: 518 self._debug_filename = self.getName() + ".log" 519 else: 520 self._debug_filename = fname 521 522 try: 523 if self._debug_file: 524 self._debug_file.close() 525 self._debug_file = open(self._debug_filename, "a+") 526 except: 527 self.DEBUG("Could not open file " + self._debug_filename + " as log file", "err")
528
529 - def getLog(self):
530 l = copy.copy(self._agent_log) 531 l.reverse() 532 return l 533 ''' 534 keys = self._agent_log.keys() 535 keys.sort() 536 keys.reverse() 537 l = list() 538 for k in keys: 539 l.append(self._agent_log[k]) 540 return l 541 '''
542
543 - def newMessage(self):
544 """Creates and returns an empty ACL message""" 545 return ACLMessage.ACLMessage()
546
547 - def newContentObject(self):
548 """Creates and returns an empty Content Object""" 549 return ContentObject()
550
551 - def _jabber_presenceCB(self, conn, mess):
552 """ 553 presence callback 554 manages jabber stanzas of the 'presence' protocol 555 """ 556 557 frm = mess.getFrom() 558 typ = str(mess.getType()) 559 status = str(mess.getStatus()) 560 show = str(mess.getShow()) 561 role = None 562 affiliation = None 563 564 children = mess.getTags(name='x',namespace='http://jabber.org/protocol/muc#user') 565 for x in children: 566 for item in x.getTags(name='item'): 567 role = item.getAttr('role') 568 affiliation = item.getAttr('affiliation') 569 570 try: 571 # Pass the FIPA-message to the behaviours 572 for b in self._behaviourList.keys(): 573 b.managePresence(frm, typ, status, show, role, affiliation) 574 575 self._defaultbehaviour.managePresence(frm, typ, status, show, role, affiliation) 576 except Exception, e: 577 #There is not a default behaviour yet 578 self.DEBUG(str(e),"err")
579
580 - def _jabber_messageCB(self, conn, mess, raiseFlag=True):
581 """ 582 message callback 583 read the message envelope and post the message to the agent 584 """ 585 586 for child in mess.getChildren(): 587 if (child.getNamespace() == "jabber:x:fipa") or (child.getNamespace() == u"jabber:x:fipa"): 588 # It is a jabber-fipa message 589 ACLmsg = ACLMessage.ACLMessage() 590 ACLmsg._attrs.update(mess.attrs) 591 try: 592 # Clean 593 del ACLmsg._attrs["from"] 594 except: 595 pass 596 try: 597 # Clean 598 del ACLmsg._attrs["to"] 599 except: 600 pass 601 ACLmsg.setContent(mess.getBody()) 602 # Rebuild sender and receiver 603 604 # Check wether there is an envelope 605 if child.getTag("envelope"): 606 # There is an envelope; use it to build sender and receivers 607 xc = XMLCodec.XMLCodec() 608 envelope = xc.parse(str(child.getTag("envelope"))) 609 if envelope.getFrom(): 610 try: 611 ACLmsg.setSender(envelope.getFrom().getStripped()) 612 except: 613 ACLmsg.setSender(envelope.getFrom()) 614 else: 615 ACLmsg.setSender(AID.aid(str(mess.getFrom().getStripped()), ["xmpp://"+str(mess.getFrom().getStripped())])) 616 if envelope.getIntendedReceiver(): 617 for ir in envelope.getIntendedReceiver(): 618 ACLmsg.addReceiver(ir) 619 else: 620 ACLmsg.addReceiver(AID.aid(str(mess.getTo().getStripped()), ["xmpp://"+str(mess.getTo())])) 621 else: 622 ACLmsg.setSender(AID.aid(str(mess.getFrom().getStripped()), ["xmpp://"+str(mess.getFrom().getStripped())])) 623 ACLmsg.addReceiver(AID.aid(str(mess.getTo().getStripped()), ["xmpp://"+str(mess.getTo().getStripped())])) 624 625 self._messages_mutex.acquire() 626 timestamp = time.time() 627 self._messages.append((timestamp,ACLmsg)) 628 self._messages_mutex.release() 629 self.postMessage(ACLmsg) 630 if raiseFlag: raise xmpp.NodeProcessed # Forced by xmpp.py for not returning an error stanza 631 return True 632 633 # Not a jabber-fipa message 634 self._messages_mutex.acquire() 635 timestamp = time.time() 636 self._messages.append((timestamp,mess)) 637 self._messages_mutex.release() 638 639 # Check wether is an offline action 640 if not self._running: 641 if mess.getName() == "iq": 642 # Check if it's an offline disco info request 643 if mess.getAttr("type") == "get": 644 q = mess.getTag("query") 645 if q and q.getNamespace() == NS_DISCO_INFO: 646 self.DEBUG("DISCO Behaviour called (offline)","info") 647 # Inform of services 648 reply = mess.buildReply("result") 649 if self.p2p_ready: 650 reply.getTag("query").addChild("feature", {"var":"http://jabber.org/protocol/si"}) 651 reply.getTag("query").addChild("feature", {"var":"http://jabber.org/protocol/si/profile/spade-p2p-messaging"}) 652 self.send(reply) 653 if raiseFlag: raise xmpp.NodeProcessed 654 return True 655 # Check if it's an offline stream initiation request 656 if mess.getAttr("type") == "set": 657 q = mess.getTag("si") 658 if q: 659 if mess.getType() == "set": 660 if mess.getTag("si").getAttr("profile") == "http://jabber.org/protocol/si/profile/spade-p2p-messaging": 661 # P2P Messaging Offer 662 if self.p2p_ready: 663 # Take note of sender's p2p address if any 664 if mess.getTag("si").getTag("p2p"): 665 remote_address = str(mess.getTag("si").getTag("p2p").getData()) 666 d = {"url":remote_address, "p2p":True} 667 self.p2p_lock.acquire() 668 if self.p2p_routes.has_key(str(mess.getFrom().getStripped())): 669 self.p2p_routes[str(mess.getFrom().getStripped())].update(d) 670 if self.p2p_routes[str(mess.getFrom().getStripped())].has_key("socket"): 671 self.p2p_routes[str(mess.getFrom().getStripped())]["socket"].close() 672 else: 673 self.p2p_routes[str(mess.getFrom().getStripped())] = d 674 self.p2p_lock.release() 675 676 # Accept offer 677 reply = mess.buildReply("result") 678 si = reply.addChild("si") 679 si.setNamespace("http://jabber.org/protocol/si") 680 p2p = si.addChild("p2p") 681 p2p.setNamespace('http://jabber.org/protocol/si/profile/spade-p2p-messaging') 682 value = p2p.addChild("value") 683 value.setData(self.getP2PUrl()) 684 else: 685 # Refuse offer 686 reply = mess.buildReply("error") 687 err = reply.addChild("error", attrs={"code":"403","type":"cancel"}) 688 err.addChild("forbidden") 689 err.setNamespace("urn:ietf:params:xml:ns:xmpp-stanzas") 690 self.send(reply) 691 if raiseFlag: raise xmpp.NodeProcessed 692 return True 693 694 self.DEBUG("Posting message " + str(mess), "info", "msg") 695 self.postMessage(mess) 696 if raiseFlag: raise xmpp.NodeProcessed # Forced by xmpp.py for not returning an error stanza 697 return True
698 699
700 - def _other_messageCB(self, conn, mess):
701 """ 702 non jabber:x:fipa chat messages callback 703 """ 704 pass
705
706 - def _jabber_iqCB(self, conn, mess):
707 """ 708 IQ callback 709 manages jabber stanzas of the 'iq' protocol 710 """ 711 # We post every jabber iq 712 self.postMessage(mess) 713 self.DEBUG("Jabber Iq posted to agent " + str(self.getAID().getName()),"info")
714 715
716 - def getAID(self):
717 """ 718 returns AID 719 """ 720 return self._aid
721
722 - def setAID(self, aid):
723 """ 724 sets a new AID 725 """ 726 self._aid = aid
727
728 - def addAddress(self, addr):
729 self._aid.addAddress(addr)
730
731 - def getName(self):
732 return self._aid.getName()
733
734 - def getAMS(self):
735 """ 736 returns the AMS aid 737 """ 738 return AID.aid(name="ams." + self._serverplatform, addresses=[ "xmpp://ams."+self._serverplatform ])
739
740 - def getDF(self):
741 """ 742 returns the DF aid 743 """ 744 return AID.aid(name="df." + self._serverplatform, addresses=[ "xmpp://df."+self._serverplatform ])
745
746 - def getMUC(self):
747 """ 748 returns the MUC JID 749 """ 750 return "muc." + self._serverplatform
751
752 - def getSpadePlatformJID(self):
753 """ 754 returns the SPADE JID (string) 755 """ 756 return "acc." + self._serverplatform
757
758 - def getDomain(self):
759 """ 760 returns the SPADE server domain 761 """ 762 return self._serverplatform
763
764 - def getP2PUrl(self):
765 return str("spade://"+socket.gethostbyname(socket.gethostname())+":"+str(self.P2PPORT))
766 767
768 - def requestDiscoInfo(self, to):
769 770 self.DEBUG("Request Disco Info called by " + str(self.getName())) 771 rdif = P2P.RequestDiscoInfoBehav(to) 772 t = Behaviour.MessageTemplate(rdif.temp_iq) 773 if self._running: 774 # Online way 775 self.DEBUG("Request Disco Info ONLINE", "info") 776 self.addBehaviour(rdif, t) 777 rdif.join() 778 return rdif.result 779 else: 780 # Offline way 781 self.DEBUG("Request Disco Info OFFLINE", "info") 782 self.runBehaviourOnce(rdif, t) 783 return rdif.result
784 785
786 - def initiateStream(self, to):
787 """ 788 Perform a Stream Initiation with another agent 789 in order to stablish a P2P communication channel 790 """ 791 792 793 self.DEBUG("Initiate Stream called by " + str(self.getName())) 794 # First deal with Disco Info request 795 services = self.requestDiscoInfo(to) 796 if "http://jabber.org/protocol/si/profile/spade-p2p-messaging" in services: 797 798 sib = P2P.SendStreamInitiationBehav(to) 799 t = Behaviour.MessageTemplate(sib.temp_iq) 800 801 if self._running: 802 # Online way 803 self.addBehaviour(sib, t) 804 sib.join() 805 return sib.result 806 else: 807 # Offline way 808 self.DEBUG("Initiate Stream OFFLINE","warn") 809 self.runBehaviourOnce(sib,t) 810 return sib.result
811 812
813 - def send(self, ACLmsg, method="jabber"):
814 """ 815 sends an ACLMessage 816 """ 817 self._messages_mutex.acquire() 818 timestamp = time.time() 819 self._messages.append((timestamp,ACLmsg)) 820 self._messages_mutex.release() 821 822 #if it is a jabber Iq or Presence message just send it 823 if isinstance(ACLmsg,xmpp.Iq) or isinstance(ACLmsg,xmpp.Presence) or isinstance(ACLmsg,xmpp.Message): 824 self.jabber.send(ACLmsg) 825 return 826 827 ACLmsg._attrs.update({"method":method}) 828 # Check for the sender field!!! (mistake #1) 829 if not ACLmsg.getSender(): 830 ACLmsg.setSender(self.getAID()) 831 832 self._sendTo(ACLmsg, ACLmsg.getReceivers(), method=method.strip())
833
834 - def _sendTo(self, ACLmsg, tojid, method):
835 """ 836 sends an ACLMessage to a specific JabberID 837 """ 838 839 #First, try Ultra-Fast(tm) python cPickle way of things 840 try: 841 if method in ["auto", "p2ppy"]: 842 remaining = copy.copy(tojid) 843 for receiver in tojid: 844 to = None 845 for address in receiver.getAddresses(): 846 #Get a jabber address 847 if "xmpp://" in address: 848 to = address.split("://")[1] 849 break 850 if to and self.send_p2p(None, to, method="p2ppy", ACLmsg=ACLmsg): 851 #The Ultra-Fast(tm) way worked. Remove this receiver from the remaining receivers 852 remaining.remove(receiver) 853 854 tojid = remaining 855 if not tojid: 856 #There is no one left to send the message to 857 return 858 except Exception, e: 859 self.DEBUG("Could not send through P2PPY: "+str(e), "warn") 860 method = "jabber" 861 862 # Second, try it the old way 863 xenv = xmpp.protocol.Node('jabber:x:fipa x') 864 envelope = Envelope.Envelope() 865 generate_envelope = False 866 #If there is more than one address in the sender or 867 #the only address is not an xmpp address, 868 #we need the fill sender AID field 869 try: 870 if method=="xmppfipa" or len(ACLmsg.getSender().getAddresses()) > 1 or \ 871 "xmpp" not in ACLmsg.getSender().getAddresses()[0]: 872 envelope.setFrom(ACLmsg.getSender()) 873 generate_envelope = True 874 except Exception, e: 875 self.DEBUG("Error setting sender: "+ str(e), "err") 876 877 try: 878 for i in ACLmsg.getReceivers(): 879 #For every receiver, 880 #if there is more than one address in the receiver or 881 #the only address is not an xmpp address, 882 #we need the full receiver AID field 883 if len(i.getAddresses()) > 1 or \ 884 "xmpp" not in i.getAddresses()[0]: 885 envelope.addTo(i) 886 generate_envelope = True 887 except Exception, e: 888 self.DEBUG("Error setting receivers: " + str(e),"err") 889 890 891 try: 892 #The same for 'reply_to' 893 for i in ACLmsg.getReplyTo(): 894 #For every receiver, 895 #if there is more than one address in the receiver or 896 #the only address is not an xmpp address, 897 #we need the full receiver AID field 898 if len(i.getAddresses()) > 1 or \ 899 "xmpp" not in i.getAddresses()[0]: 900 envelope.addIntendedReceiver(i) 901 generate_envelope = True 902 except Exception, e: 903 self.DEBUG("Error setting reply-to: " + str(e),"err") 904 905 #Generate the envelope ONLY if it is needed 906 if generate_envelope: 907 xc = XMLCodec.XMLCodec() 908 envxml = xc.encodeXML(envelope) 909 xenv['content-type']='fipa.mts.env.rep.xml.std' 910 xenv.addChild(node=simplexml.NodeBuilder(envxml).getDom()) 911 912 #For each of the receivers, try to send the message 913 for to in tojid: 914 isjabber = False 915 for address in to.getAddresses(): 916 if "xmpp://" in address: 917 #If there is a jabber address for this receiver, send the message directly to it 918 jabber_id = address.split("://")[1] 919 isjabber = True 920 break 921 if isjabber and str(self.getDomain()) in jabber_id: 922 jabber_msg = xmpp.protocol.Message(jabber_id, xmlns="") 923 jabber_msg.attrs.update(ACLmsg._attrs) 924 jabber_msg.addChild(node=xenv) 925 jabber_msg["from"]=self.getAID().getName() 926 jabber_msg.setBody(ACLmsg.getContent()) 927 else: 928 #I don't understand this address, relay the message to the platform 929 jabber_msg = xmpp.protocol.Message(self.getSpadePlatformJID(), xmlns="") 930 jabber_id = self.getSpadePlatformJID() 931 jabber_msg.attrs.update(ACLmsg._attrs) 932 jabber_msg.addChild(node=xenv) 933 jabber_msg["from"]=self.getAID().getName() 934 jabber_msg.setBody(ACLmsg.getContent()) 935 936 if (not self._running and method=="auto") or method=="jabber": 937 self.jabber.send(jabber_msg) 938 continue 939 940 #If the receiver is one of our p2p contacts, send the message through p2p. 941 #If it's not or it fails, send it through the jabber server 942 #We suppose method in ['p2p'] 943 jabber_id = xmpp.JID(jabber_id).getStripped() 944 945 if self.p2p_ready: 946 sent = False 947 self.p2p_send_lock.acquire() 948 try: 949 sent = self.send_p2p(jabber_msg, jabber_id, method=method, ACLmsg=ACLmsg) 950 except Exception, e: 951 self.DEBUG("P2P Connection to "+str(self.p2p_routes)+jabber_id+" prevented. Falling back. "+str(e), "warn") 952 sent = False 953 self.p2p_send_lock.release() 954 if not sent: 955 #P2P failed, try to send it through jabber 956 self.DEBUG("P2P failed, try to send it through jabber","warn") 957 jabber_msg.attrs.update({"method":"jabber"}) 958 if method in ["auto","p2p","p2ppy"]: self.jabber.send(jabber_msg) 959 960 else: 961 #P2P is not available / not supported 962 #Try to send it through jabber 963 self.DEBUG("P2P is not available/supported, try to send it through jabber","warn") 964 jabber_msg.attrs.update({"method":"jabber"}) 965 if method in ["auto","p2p","p2ppy"]: self.jabber.send(jabber_msg)
966 967
968 - def send_p2p(self, jabber_msg=None, to="", method="p2ppy", ACLmsg=None):
969 970 #If this agent supports P2P, wait for P2PBEhaviour to properly start 971 if self.p2p: 972 while not self.p2p_ready: 973 time.sleep(0.1) 974 else: 975 # send_p2p should not be called in a P2P-disabled agent ! 976 self.DEBUG("This agent does not support sending p2p messages", "warn") 977 return False 978 979 #Get the address 980 if not to: 981 if not jabber_msg: 982 return False 983 else: 984 to = str(jabber_msg.getTo()) 985 if jabber_msg: 986 self.DEBUG("Trying to send Jabber msg through P2P") 987 elif ACLmsg: 988 self.DEBUG("Trying to send ACL msg through P2P") 989 990 991 try: 992 #Try to get the contact's url 993 url = self.p2p_routes[to]["url"] 994 except: 995 #The contact is not in our routes 996 self.DEBUG("P2P: The contact " + str(to) + " is not in our routes. Starting negotiation","warn") 997 self.initiateStream(to) 998 if self.p2p_routes.has_key(to) and self.p2p_routes[to].has_key('p2p'): 999 #If this p2p connection is marked as faulty, 1000 #check if enough time has passed to try again a possible p2p connection 1001 if self.p2p_routes[to]['p2p'] == False: 1002 try: 1003 t1 = time.time() 1004 t = t1 - self.p2p_routes[to]['failed_time'] 1005 #If more than 10 seconds have passed . . . 1006 if t > 10.0: 1007 self.p2p_lock.acquire() 1008 self.p2p_routes[to]['p2p'] = True 1009 self.p2p_routes[to]['failed_time'] = 0.0 1010 self.p2p_lock.release() 1011 except: 1012 #The p2p connection is really faulty 1013 self.DEBUG("P2P: The p2p connection is really faulty","warn") 1014 return False 1015 url = self.p2p_routes[to]["url"] 1016 else: 1017 #There is no p2p for this contact 1018 self.DEBUG("P2P: There is no p2p support for this contact","warn") 1019 return False 1020 1021 1022 #Check if there is already an open socket 1023 s = None 1024 if self.p2p_routes[to].has_key("socket"): 1025 s = self.p2p_routes[to]["socket"] 1026 if not s: 1027 #Parse url 1028 scheme, address = url.split("://",1) 1029 if scheme == "spade": 1030 #Check for address and port number 1031 l = address.split(":",1) 1032 if len(l) > 1: 1033 address = l[0] 1034 port = int(l[1]) 1035 1036 #Create a socket connection to the destination url 1037 connected = False 1038 tries = 2 1039 while not connected and tries > 0: 1040 try: 1041 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1042 s.connect((address, port)) 1043 self.p2p_lock.acquire() 1044 self.p2p_routes[to]["socket"] = s 1045 self.p2p_lock.release() 1046 connected = True 1047 except: 1048 tries -= 1 1049 _exception = sys.exc_info() 1050 if _exception[0]: 1051 self.DEBUG("Error opening p2p socket " +'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip(),"err") 1052 1053 if not connected: 1054 self.DEBUG("Socket creation failed","warn") 1055 return False 1056 1057 #Send length + message 1058 sent = False 1059 tries = 2 1060 while not sent and tries > 0: 1061 try: 1062 if method in ["p2p","auto"]: 1063 jabber_msg.attrs.update({"method":"p2p"}) 1064 length = "%08d"%(len(str(jabber_msg))) 1065 #Send message through socket 1066 s.send(length+str(jabber_msg)) 1067 self.DEBUG("P2P message sent through p2p","ok") 1068 elif method in ["p2ppy"]: 1069 ACLmsg._attrs.update({"method":"p2ppy"}) 1070 ser = pickle.dumps(ACLmsg) 1071 length = "%08d"%(len(str(ser))) 1072 s.send(length+ser) 1073 self.DEBUG("P2P message sent through p2ppy","ok") 1074 sent = True 1075 1076 except Exception, e: 1077 self.DEBUG("Socket: send failed, threw an exception: " +str(e), "err") 1078 self._p2p_failures += 1 1079 # Dispose of old socket 1080 self.p2p_lock.acquire() 1081 s.close() 1082 try: 1083 del s 1084 del self.p2p_routes[to]["socket"] 1085 except: pass 1086 self.p2p_lock.release() 1087 #Get address and port AGAIN 1088 scheme, address = url.split("://",1) 1089 if scheme == "spade": 1090 #Check for address and port number 1091 l = address.split(":",1) 1092 if len(l) > 1: 1093 address = l[0] 1094 port = int(l[1]) 1095 #Try again 1096 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1097 s.connect((address, port)) 1098 self.p2p_lock.acquire() 1099 self.p2p_routes[to]["socket"] = s 1100 self.p2p_lock.release() 1101 else: 1102 return False 1103 tries -= 1 1104 if not sent: 1105 self.DEBUG("Socket send failed","warn") 1106 self.p2p_lock.acquire() 1107 self.p2p_routes[to]["p2p"] = False 1108 self.p2p_routes[to]["failed_time"] = time.time() 1109 self.p2p_lock.release() 1110 return False 1111 else: 1112 return True
1113
1114 - def _kill(self):
1115 """ 1116 kills the agent 1117 """ 1118 self._forceKill.set()
1119
1120 - def isRunning(self):
1121 """ 1122 returns wether an agent is running or not 1123 """ 1124 return self._alive
1125
1126 - def stop(self, timeout=0):
1127 """ 1128 Stops the agent execution and blocks until the agent dies 1129 """ 1130 1131 self.wui.stop() 1132 1133 self._kill() 1134 if timeout > 0: 1135 to = time.now() + timeout 1136 while self._alive and time.now() < to: 1137 time.sleep(0.1) 1138 #No timeout (true blocking) 1139 else: 1140 while self._alive: 1141 time.sleep(0.1) 1142 return True
1143 1144
1145 - def forceKill(self):
1146 return self._forceKill.isSet()
1147
1148 - def _setup(self):
1149 """ 1150 setup agent method. configures the agent 1151 must be overridden 1152 """ 1153 pass
1154
1155 - def _initBdiBehav(self):
1156 """ 1157 starts the BDI behaviour ONLY 1158 if self is a subclass of bdi.BDIAgent 1159 """ 1160 if issubclass(self.__class__, BDIAgent): 1161 self._startBdiBehav()
1162
1163 - def takeDown(self):
1164 """ 1165 stops the agent 1166 must be overridden 1167 (kind of a "onEnd" for the agent) 1168 """ 1169 pass
1170 1171
1172 - def run(self):
1173 """ 1174 periodic agent execution 1175 """ 1176 #Init The agent 1177 self._setup() 1178 self.behavioursGo.acquire() 1179 self._running = True 1180 self.behavioursGo.notifyAll() 1181 self.behavioursGo.release() 1182 1183 #Start the Behaviours 1184 if (self._defaultbehaviour != None): 1185 self._defaultbehaviour.start() 1186 1187 #If this agent supports P2P, wait for P2PBEhaviour to properly start 1188 if self.p2p: 1189 while not self.p2p_ready: 1190 time.sleep(0.1) 1191 1192 ############# 1193 # Main Loop # 1194 ############# 1195 while not self.forceKill(): 1196 try: 1197 #Check for queued messages 1198 proc = False 1199 toRemove = [] # List of EventBehaviours to remove after this pass 1200 msg = self._receive(block=True, timeout=0.01) 1201 if msg != None: 1202 bL = copy.copy(self._behaviourList) 1203 for b in bL: 1204 t = bL[b] 1205 if (t != None): 1206 if (t.match(msg) == True): 1207 if ((b == types.ClassType or type(b) == types.TypeType) and issubclass(b, Behaviour.EventBehaviour)): 1208 ib = b() 1209 if ib.onetime: 1210 toRemove.append(b) 1211 ib.setAgent(self) 1212 ib.postMessage(msg) 1213 ib.start() 1214 else: 1215 b.postMessage(msg) 1216 proc = True 1217 1218 if (proc == False): 1219 #If no template matches, post the message to the Default behaviour 1220 self.DEBUG("Message was not reclaimed by any behaviour. Posting to default behaviour: " + str(msg) + str(bL), "info", "msg") 1221 if (self._defaultbehaviour != None): 1222 self._defaultbehaviour.postMessage(msg) 1223 for beh in toRemove: 1224 self.removeBehaviour(beh) 1225 1226 except Exception, e: 1227 self.DEBUG("Agent " + self.getName() + "Exception in run:" + str(e), "err") 1228 self._kill() 1229 1230 self._shutdown()
1231
1232 - def setDefaultBehaviour(self, behaviour):
1233 """ 1234 sets a Behavior as Default 1235 """ 1236 class NotAllowed(Exception): 1237 """ 1238 Not Allowed Exception: an EventBehaviour cannot be a default behaviour 1239 """ 1240 def __init__(self): pass 1241 def __str__(self): return "an EventBehaviour cannot be a default behaviour"
1242 1243 if behaviour.__class__ == Behaviour.EventBehaviour: 1244 raise NotAllowed 1245 self._defaultbehaviour = behaviour 1246 behaviour.setAgent(self)
1247
1248 - def getDefaultBehaviour(self):
1249 """ 1250 returns the default behavior 1251 """ 1252 return self._defaultbehaviour
1253
1254 - def addBehaviour(self, behaviour, template=None):
1255 """ 1256 adds a new behavior to the agent 1257 """ 1258 if not issubclass(behaviour.__class__, Behaviour.EventBehaviour): #and type(behaviour) != types.TypeType: 1259 #Event behaviour do not start inmediately 1260 self._behaviourList[behaviour] = copy.copy(template) 1261 behaviour.setAgent(self) 1262 behaviour.start() 1263 else: 1264 self.DEBUG("Adding Event Behaviour "+str(behaviour.__class__)) 1265 self._behaviourList[behaviour.__class__] = copy.copy(template)
1266
1267 - def runBehaviourOnce(self, behaviour,template=None):
1268 """ 1269 Runs the behaviour offline 1270 Executes its process once 1271 @warning Only for OneShotBehaviour 1272 """ 1273 if not issubclass(behaviour.__class__, Behaviour.OneShotBehaviour): 1274 self.DEBUG("Only OneShotBehaviour execution is allowed offline","err") 1275 return False 1276 1277 if not self._running: 1278 try: 1279 behaviour._receive = self._receive 1280 behaviour.myAgent = self 1281 behaviour.onStart() 1282 behaviour._process() 1283 behaviour.onEnd() 1284 del behaviour 1285 return True 1286 except Exception,e: 1287 self.DEBUG("Failed the execution of the OFFLINE behaviour "+str(behaviour)+": "+str(e),"err") 1288 return False 1289 else: 1290 self.addBehaviour(behaviour,template)
1291 1292
1293 - def removeBehaviour(self, behaviour):
1294 """ 1295 removes a behavior from the agent 1296 """ 1297 if (type(behaviour) not in [types.ClassType,types.TypeType]) and (not issubclass(behaviour.__class__, Behaviour.EventBehaviour)): 1298 behaviour.kill() 1299 try: 1300 self._behaviourList.pop(behaviour) 1301 self.DEBUG("Behaviour removed: " + str(behaviour), "info", "behaviour") 1302 except KeyError: 1303 self.DEBUG("removeBehaviour: Behaviour " + str(behaviour) +"with type " +str(type(behaviour))+ " is not registered in "+str(self._behaviourList),"warn")
1304 1305
1306 - def subscribeToFriend(self, aid):
1307 """ 1308 presence subscription to another agent 1309 """ 1310 pass
1311
1312 - def unsubscribeToFriend(self, aid):
1313 """ 1314 presence unsubscription to another agent 1315 """ 1316 pass
1317
1318 - def getSocialNetwork(self, nowait=False):
1319 """ 1320 get list of social agents which have some relation with the agent 1321 """ 1322 self._waitingForRoster = True 1323 iq = Iq("get", NS_ROSTER) 1324 self.send(iq) 1325 if not nowait: 1326 while self._waitingForRoster: 1327 time.sleep(0.3) 1328 return self._roster
1329 1330 1331 ################## 1332 # FIPA procedures # 1333 ################## 1334
1335 - def searchAgent(self, AAD):
1336 """ 1337 searches an agent in the AMS 1338 the search template is an AmsAgentDescription class 1339 """ 1340 msg = ACLMessage.ACLMessage() 1341 template = Behaviour.ACLTemplate() 1342 template.setConversationId(msg.getConversationId()) 1343 r = str(uuid.uuid4()).replace("-","") 1344 msg.setReplyWith(r) 1345 template.setInReplyTo(r) 1346 t = Behaviour.MessageTemplate(template) 1347 b = fipa.SearchAgentBehaviour(msg, AAD) 1348 1349 self.addBehaviour(b,t) 1350 b.join() 1351 return b.result
1352 1353 1354
1355 - def modifyAgent(self, AAD):
1356 """ 1357 modifies the AmsAgentDescription of an agent in the AMS 1358 """ 1359 msg = ACLMessage.ACLMessage() 1360 template = Behaviour.ACLTemplate() 1361 template.setConversationId(msg.getConversationId()) 1362 r = str(uuid.uuid4()).replace("-","") 1363 msg.setReplyWith(r) 1364 template.setInReplyTo(r) 1365 t = Behaviour.MessageTemplate(template) 1366 b = fipa.ModifyAgentBehaviour(msg, AAD) 1367 1368 self.addBehaviour(b,t) 1369 b.join() 1370 return b.result
1371 1372 1373
1374 - def getPlatformInfo(self):
1375 """ 1376 returns the Plarform Info 1377 """ 1378 msg = ACLMessage.ACLMessage() 1379 template = Behaviour.ACLTemplate() 1380 template.setConversationId(msg.getConversationId()) 1381 r = str(uuid.uuid4()).replace("-","") 1382 msg.setReplyWith(r) 1383 template.setInReplyTo(r) 1384 t = Behaviour.MessageTemplate(template) 1385 b = fipa.getPlatformInfoBehaviour(msg) 1386 1387 self.addBehaviour(b,t) 1388 b.join() 1389 return b.result
1390 1391 1392
1393 - def registerService(self, service, methodCall=None, otherdf=None):
1394 """ 1395 registers a service in the DF 1396 the service template is a DfAgentDescriptor 1397 """ 1398 1399 if isinstance(service,DF.Service): DAD=service.getDAD() 1400 else: DAD = service 1401 1402 msg = ACLMessage.ACLMessage() 1403 template = Behaviour.ACLTemplate() 1404 if otherdf and isinstance(otherdf, AID.aid): 1405 template.setSender(otherdf) 1406 else: 1407 template.setSender(self.getDF()) 1408 template.setConversationId(msg.getConversationId()) 1409 r = str(uuid.uuid4()).replace("-","") 1410 msg.setReplyWith(r) 1411 template.setInReplyTo(r) 1412 t = Behaviour.MessageTemplate(template) 1413 b = fipa.registerServiceBehaviour(msg=msg, DAD=DAD, otherdf=otherdf) 1414 if self._running: 1415 # Online 1416 self.addBehaviour(b,t) 1417 b.join() 1418 else: 1419 self.runBehaviourOnce(b,t) 1420 1421 if methodCall and b.result==True: 1422 if not isinstance(service,DF.Service): 1423 self.DEBUG("Could not register RPC Service. It's not a DF.Service class","error") 1424 return False 1425 1426 name = service.getName() 1427 self.DEBUG("Registering RPC service "+ name) 1428 self.RPC[name.lower()] = (service, methodCall) 1429 1430 return b.result
1431 1432
1433 - def deregisterService(self, DAD, otherdf=None):
1434 """ 1435 deregisters a service in the DF 1436 the service template is a DfAgentDescriptor 1437 """ 1438 1439 if self.RPC.has_key(DAD.getName()): 1440 del self.RPC[DAD.getName()] 1441 1442 if isinstance(DAD,DF.Service): 1443 DAD=DAD.getDAD() 1444 1445 msg = ACLMessage.ACLMessage() 1446 template = Behaviour.ACLTemplate() 1447 if otherdf and isinstance(otherdf, AID.aid): 1448 template.setSender(otherdf) 1449 else: 1450 template.setSender(self.getDF()) 1451 1452 template.setConversationId(msg.getConversationId()) 1453 r = str(uuid.uuid4()).replace("-","") 1454 msg.setReplyWith(r) 1455 template.setInReplyTo(r) 1456 t = Behaviour.MessageTemplate(template) 1457 b = fipa.deregisterServiceBehaviour(msg=msg, DAD=DAD, otherdf=otherdf) 1458 if self._running: 1459 # Online 1460 self.addBehaviour(b,t) 1461 b.join() 1462 return b.result 1463 else: 1464 self.runBehaviourOnce(b,t) 1465 return b.result
1466 1467
1468 - def searchService(self, DAD):
1469 """ 1470 search a service in the DF 1471 the service template is a DfAgentDescriptor 1472 1473 """ 1474 if isinstance(DAD,DF.Service): 1475 DAD=DAD.getDAD() 1476 returnDAD=False 1477 else: returnDAD=True 1478 1479 msg = ACLMessage.ACLMessage() 1480 template = Behaviour.ACLTemplate() 1481 template.setConversationId(msg.getConversationId()) 1482 r = str(uuid.uuid4()).replace("-","") 1483 msg.setReplyWith(r) 1484 template.setInReplyTo(r) 1485 t = Behaviour.MessageTemplate(template) 1486 b = fipa.searchServiceBehaviour(msg, DAD) 1487 if self._running: 1488 self.addBehaviour(b,t) 1489 b.join() 1490 else: 1491 self.runBehaviourOnce(b,t) 1492 1493 1494 if b.result==None: return None 1495 if returnDAD: return b.result 1496 else: 1497 r = [] 1498 for dad in b.result: 1499 for sd in dad.getServices(): 1500 s=DF.Service() 1501 if sd.getName(): s.setName(sd.getName()) 1502 if dad.getAID(): s.setOwner(dad.getAID()) 1503 for o in sd.getOntologies(): s.setOntology(o) 1504 if sd.getProperty("description"): s.setDescription(sd.getProperty("description")) 1505 if sd.getProperty("inputs"): s.setInputs(sd.getProperty("inputs")) 1506 if sd.getProperty("outputs"): s.setOutputs(sd.getProperty("outputs")) 1507 if sd.getProperty("P"): 1508 for p in sd.getProperty("P"): s.addP(p) 1509 if sd.getProperty("Q"): 1510 for q in sd.getProperty("Q"): s.addQ(q) 1511 s.getDAD().getServices()[0].setType(sd.getType()) 1512 for o in sd.getOntologies(): s.setOntology(o) 1513 r.append(s) 1514 return r
1515 1516 1517
1518 - def modifyService(self, DAD, methodCall=None):
1519 """ 1520 modifies a service in the DF 1521 the service template is a DfAgentDescriptor 1522 """ 1523 1524 if methodCall: 1525 if not isinstance(DAD,DF.Service): 1526 self.DEBUG("Could not modify RPC Service. It's not a DF.Service class","error") 1527 return False 1528 1529 self.RPC[DAD.getName()] = (DAD, methodCall) 1530 1531 if isinstance(DAD,DF.Service): 1532 DAD=DAD.getDAD() 1533 1534 msg = ACLMessage.ACLMessage() 1535 template = Behaviour.ACLTemplate() 1536 template.setConversationId(msg.getConversationId()) 1537 r = str(uuid.uuid4()).replace("-","") 1538 msg.setReplyWith(r) 1539 template.setInReplyTo(r) 1540 t = Behaviour.MessageTemplate(template) 1541 b = fipa.modifyServiceBehaviour(msg, DAD) 1542 1543 if self._running: 1544 # Online 1545 self.addBehaviour(b,t) 1546 b.join() 1547 return b.result 1548 else: 1549 self.runBehaviourOnce(b,t) 1550 return b.result
1551 1552 #################### 1553 #RPC invokation 1554 ####################
1555 - def invokeService(self, service, inputs=None):
1556 """ 1557 invokes a service using jabber-rpc (XML-RPC) 1558 the service template is a DF.Service 1559 if inputs is None, they are extracted from the agent's KB 1560 """ 1561 1562 if not isinstance(service,DF.Service): 1563 self.DEBUG("Service MUST be a DF.Service instance",'error') 1564 return False 1565 1566 num = str(uuid.uuid4()).replace("-","") 1567 1568 if inputs==None: #inputs = self.KB 1569 inputs={} 1570 for i in service.getInputs(): 1571 r = self.kb.get(str(i)) 1572 if r==None: 1573 self.DEBUG("Can not invoke Service, input not found: " + str(i),'error') 1574 return False 1575 self.DEBUG("Adding input: "+str(i)+" = "+str(r)) 1576 inputs[i] = r 1577 1578 self.DEBUG("Invoking service " + str(service.getName()) + " with inputs = "+ str(inputs)) 1579 b = RPC.RPCClientBehaviour(service,inputs,num) 1580 t = Behaviour.MessageTemplate(Iq(typ="result",attrs={'id':num})) 1581 1582 if self._running: 1583 # Online 1584 self.addBehaviour(b,t) 1585 b.join() 1586 return b.result 1587 else: 1588 self.runBehaviourOnce(b,t) 1589 return b.result
1590 1591 1592 1593 #################### 1594 #PubSub services 1595 ####################
1596 - def publishEvent(self, name, event):
1597 return self._pubsub.publish(name,event)
1598 - def subscribeToEvent(self, name, behaviour=None, server=None,jid=None):
1599 r = self._pubsub.subscribe(name,server,jid) 1600 if r[0]=='ok' and behaviour!=None: 1601 if not issubclass(behaviour.__class__, Behaviour.EventBehaviour): 1602 self.DEBUG("Behaviour MUST be an EventBehaviour to subscribe to events.","error","pubsub") 1603 return ("error",["not-event-behaviour"]) 1604 self._events[name]=behaviour 1605 n = xmpp.Node(node='<message xmlns="jabber:client"><event xmlns="http://jabber.org/protocol/pubsub#events"><items node="'+name+'" /></event></message>') 1606 template = xmpp.Message(node=n) 1607 mt = Behaviour.MessageTemplate(template) 1608 self.addBehaviour(behaviour,mt) 1609 return r
1610 - def unsubscribeFromEvent(self, name,server=None,jid=None):
1611 r = self._pubsub.unsubscribe(name,server,jid) 1612 if name in self._events.keys(): 1613 self.removeBehaviour(self._events[name]) 1614 del self._events[name] 1615 return r
1616 - def createEvent(self, name, server=None, type='leaf', parent=None, access=None):
1617 return self._pubsub.createNode(name, server=None, type='leaf', parent=None, access=None)
1618 - def deleteEvent(self, name, server=None):
1619 return self._pubsub.deleteNode(name, server=None)
1620 1621 1622 ######################## 1623 #Knowledge Base services 1624 ######################## 1625
1626 - def addBelieve(self, sentence, type="insert"):
1627 if isinstance(sentence,types.StringType): 1628 try: 1629 if issubclass(Flora2KB.Flora2KB,self.kb.__class__): 1630 self.kb.tell(sentence,type) 1631 except: 1632 self.kb.tell(sentence) 1633 else: 1634 self.kb.tell(sentence) 1635 self._needDeliberate = True
1636 ###self.newBelieveCB(sentence) #TODO 1637
1638 - def removeBelieve(self, sentence, type="delete"):
1639 if isinstance(sentence,types.StringType): 1640 try: 1641 if issubclass(Flora2KB.Flora2KB,self.kb.__class__): 1642 self.kb.retract(sentence,type) 1643 except: 1644 self.kb.retract(sentence) 1645 else: 1646 self.kb.retract(sentence) 1647 self._needDeliberate = True
1648
1649 - def askBelieve(self, sentence):
1650 return self.kb.ask(sentence)
1651
1652 - def configureKB(self, typ, sentence=None, path=None):
1653 self.kb.configure(typ,sentence,path)
1654
1655 - def saveFact(self, name, sentence):
1656 self.kb.set(name, sentence)
1657
1658 - def getFact(self, name):
1659 return self.kb.get(name)
1660
1661 ################################## 1662 1663 # Changed to be a 'daemonic' python Thread 1664 -class jabberProcess(threading.Thread):
1665
1666 - def __init__(self, socket, owner):
1667 self.jabber = socket 1668 #self._alive = True 1669 self._forceKill = threading.Event() 1670 self._forceKill.clear() 1671 threading.Thread.__init__(self) 1672 self.setDaemon(False) 1673 self._owner = owner
1674
1675 - def _kill(self):
1676 try: 1677 self._forceKill.set() 1678 except: 1679 #Agent is already dead 1680 pass
1681
1682 - def forceKill(self):
1683 return self._forceKill.isSet()
1684
1685 - def run(self):
1686 """ 1687 periodic jabber update 1688 """ 1689 while not self.forceKill(): 1690 try: 1691 err = self.jabber.Process(0.4) 1692 except Exception, e: 1693 _exception = sys.exc_info() 1694 if _exception[0]: 1695 self._owner.DEBUG( '\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip(),"err") 1696 self._owner.DEBUG("Exception in jabber process: "+ str(e),"err") 1697 self._owner.DEBUG("Jabber connection failed: "+self._owner.getAID().getName()+" (dying)","err") 1698 self._kill() 1699 self._owner.stop() 1700 err = None 1701 1702 if err == None or err == 0: # None or zero the integer, socket closed 1703 self._owner.DEBUG("Agent disconnected: "+self._owner.getAID().getName()+" (dying)","err") 1704 self._kill() 1705 self._owner.stop()
1706
1707 1708 1709 -class PlatformAgent(AbstractAgent):
1710 """ 1711 A PlatformAgent is a SPADE component. 1712 Examples: AMS, DF, ACC, ... 1713 """
1714 - def __init__(self, node, password, server="localhost", port=5347, config=None ,debug = [], p2p=False):
1715 AbstractAgent.__init__(self, node, server, p2p=p2p) 1716 self.config = config 1717 if config.has_key('adminpasswd'): self.wui.passwd = config['adminpasswd'] 1718 self.debug = debug 1719 self.jabber = xmpp.Component(server=server, port=port, debug=self.debug) 1720 if not self._register(password): 1721 self._shutdown()
1722
1723 - def _register(self, password, autoregister=True):
1724 """ 1725 registers the agent in the Jabber server 1726 """ 1727 1728 jid = xmpp.protocol.JID(self._aid.getName()) 1729 name = jid.getNode() 1730 1731 tries = 5 1732 while not self.jabber.connect() and tries >0: 1733 time.sleep(0.005) 1734 tries -=1 1735 if tries <= 0: 1736 self.DEBUG("The agent could not connect to the platform "+ str(self.getDomain()),"err") 1737 return False 1738 1739 1740 if (self.jabber.auth(name=name,password=password) == None): 1741 raise NotImplementedError 1742 1743 self.jabber.RegisterHandler('message',self._jabber_messageCB) 1744 self.jabber.RegisterHandler('presence',self._jabber_messageCB) 1745 self.jabber.RegisterHandler('iq',self._jabber_messageCB) 1746 #self.jabber.RegisterHandler('presence',self._jabber_presenceCB) 1747 #self.jabber.RegisterHandler('iq',self._jabber_iqCB) 1748 1749 self.jabber_process = jabberProcess(self.jabber, owner=self) 1750 self.jabber_process.start() 1751 return True
1752
1753 - def _shutdown(self):
1754 1755 self._kill() # Doublecheck death 1756 self.jabber_process._kill() 1757 1758 #Stop the Behaviours 1759 for b in self._behaviourList: 1760 try: 1761 b.kill() 1762 except: 1763 pass 1764 1765 if (self._defaultbehaviour != None): 1766 self._defaultbehaviour.kill() 1767 #DeInit the Agent 1768 self.takeDown() 1769 1770 self._alive = False
1771
1772 -class Agent(AbstractAgent):
1773 """ 1774 This is the main class which may be inherited to build a SPADE agent 1775 """ 1776 1777
1778 - def __init__(self, agentjid, password, port=5222, debug=[], p2p=False):
1779 jid = xmpp.protocol.JID(agentjid) 1780 self.server = jid.getDomain() 1781 self.port = port 1782 self.debug = debug 1783 AbstractAgent.__init__(self, agentjid, jid.getDomain(),p2p=p2p) 1784 1785 self.jabber = xmpp.Client(jid.getDomain(), port, debug) 1786 1787 # Try to register 1788 try: 1789 self.DEBUG("Trying to register agent " + agentjid) 1790 if not self._register(password): 1791 self.stop() 1792 except NotImplementedError: 1793 self.DEBUG("NotImplementedError: Could not register agent %s"%(agentjid),"err") 1794 self.stop() 1795 return 1796 except: 1797 self.DEBUG("Could not register agent %s"%(agentjid),"err") 1798 self.stop() 1799 return 1800 1801 # Add Presence Control Behaviour 1802 self.addBehaviour(socialnetwork.PresenceBehaviour(), Behaviour.MessageTemplate(Presence())) 1803 1804 # Add Roster Behaviour 1805 self.addBehaviour(socialnetwork.RosterBehaviour(), Behaviour.MessageTemplate(Iq(queryNS=NS_ROSTER))) 1806 1807 # Add BDI Behaviour #only for BDI agents 1808 self._initBdiBehav() 1809 1810 self.DEBUG("Agent %s registered"%(agentjid),"ok") 1811 1812 if not self.__register_in_AMS(): 1813 self.DEBUG("Agent " + str(self.getAID().getName()) + " dying ...","err") 1814 self.stop()
1815 1816 # Ask for roster 1817 ##self.getSocialNetwork(nowait=True) 1818
1819 - def setSocialItem(self, jid, presence=""):
1820 if self._socialnetwork.has_key(jid): 1821 if not self._socialnetwork[jid].getPresence(): 1822 # If we have no previous presence information, update it 1823 self._socialnetwork[jid].setPresence(presence) 1824 else: 1825 self._socialnetwork[jid] = socialnetwork.SocialItem(self, jid, presence)
1826 1827
1828 - def _register(self, password, autoregister=True):
1829 """ 1830 registers the agent in the Jabber server 1831 """ 1832 1833 jid = xmpp.protocol.JID(self._aid.getName()) 1834 name = jid.getNode() 1835 1836 1837 tries = 5 1838 while not self.jabber.connect(use_srv=None) and tries >0: 1839 time.sleep(0.005) 1840 tries -=1 1841 if tries <=0 : 1842 self.setDebugToScreen() 1843 self.DEBUG("There is no SPADE platform at " + self.server + " . Agent dying...","err") 1844 return False 1845 1846 1847 if (self.jabber.auth(name,password,"spade") == None): 1848 1849 self.DEBUG("First auth attempt failed. Trying to register","warn") 1850 1851 if (autoregister == True): 1852 xmpp.features.getRegInfo(self.jabber,jid.getDomain()) 1853 xmpp.features.register(self.jabber,jid.getDomain(),\ 1854 {'username':name, 'password':str(password), 'name':name}) 1855 1856 1857 if not self.jabber.reconnectAndReauth(): 1858 self.DEBUG("Second auth attempt failed (username="+str(name)+")", "err") 1859 return False 1860 else: 1861 return False 1862 1863 self.DEBUG("Agent %s got authed"%(self._aid.getName()),"ok") 1864 1865 self.jabber.RegisterHandler('message',self._jabber_messageCB) 1866 self.jabber.RegisterHandler('presence',self._jabber_messageCB) 1867 self.jabber.RegisterHandler('iq',self._jabber_messageCB) 1868 #self.jabber.RegisterHandler('presence',self._jabber_presenceCB) 1869 1870 self.jabber_process = jabberProcess(self.jabber, owner=self) 1871 self.jabber_process.start() 1872 1873 # Request roster and send initial presence 1874 #self.getSocialNetwork() 1875 1876 self.jabber.sendInitPresence() 1877 1878 return True
1879 1880
1881 - def _shutdown(self):
1882 #Stop the Behaviours 1883 for b in copy.copy(self._behaviourList): 1884 try: 1885 b.kill() 1886 if "P2PBehaviour" in str(b.__class__): 1887 b.onEnd() 1888 except: 1889 pass 1890 1891 if (self._defaultbehaviour != None): 1892 self._defaultbehaviour.kill() 1893 1894 #DeInit the Agent 1895 self.takeDown() 1896 1897 if self._alivemutex.testandset(): 1898 if not self.jabber_process.forceKill(): 1899 if not self.__deregister_from_AMS(): 1900 self.DEBUG("Agent " + str(self.getAID().getName()) + " dying without deregistering itself ...","err") 1901 self.jabber_process._kill() # Kill jabber thread 1902 self._alive = False 1903 self._alivemutex.unlock() 1904 1905 self._kill() # Doublecheck death
1906 1907 1908
1909 - def __register_in_AMS(self, state='active', ownership=None, debug=False):
1910 # Let's change it to "subscribe" 1911 presence = xmpp.Presence(to=self.getAMS().getName(),frm=self.getName(),typ='subscribe') 1912 1913 self.send(presence) 1914 1915 self.DEBUG("Agent: " + str(self.getAID().getName()) + " registered correctly (inform)","ok") 1916 return True
1917
1918 - def __register_in_AMS_with_ACL(self, state='active', ownership=None, debug=False):
1919 1920 self._msg = ACLMessage.ACLMessage() 1921 self._msg.addReceiver( self.getAMS() ) 1922 self._msg.setPerformative('request') 1923 self._msg.setLanguage('fipa-sl0') 1924 self._msg.setProtocol('fipa-request') 1925 self._msg.setOntology('FIPA-Agent-Management') 1926 1927 content = "((action " 1928 content += str(self.getAID()) 1929 content += "(register (ams-agent-description " 1930 content += ":name " + str(self.getAID()) 1931 content += ":state "+state 1932 if ownership: 1933 content += ":ownership " + ownership 1934 content +=" ) ) ))" 1935 1936 self._msg.setContent(content) 1937 1938 self.send(self._msg) 1939 1940 # We expect the initial answer from the AMS 1941 msg = self._receive(True,20) 1942 if (msg != None) and (str(msg.getPerformative()) == 'refuse'): 1943 self.DEBUG("There was an error initiating the register of agent: " + str(self.getAID().getName()) + " (refuse)","err") 1944 return False 1945 elif (msg != None) and (str(msg.getPerformative()) == 'agree'): 1946 self.DEBUG("Agent: " + str(self.getAID().getName()) + " initiating registering process (agree)") 1947 else: 1948 # There was no answer from the AMS or it answered something weird, so error 1949 self.DEBUG("There was an error initiating the register of agent: " + str(self.getAID().getName()),"err") 1950 return False 1951 1952 # Now we expect the real informative answer from the AMS 1953 msg = self._receive(True,20) 1954 if (msg != None) and (msg.getPerformative() == 'failure'): 1955 self.DEBUG("There was an error with the register of agent: " + str(self.getAID().getName()) + " (failure)","err") 1956 return False 1957 elif (msg != None) and (str(msg.getPerformative()) == 'inform'): 1958 self.DEBUG("Agent: " + str(self.getAID().getName()) + " registered correctly (inform)","ok") 1959 else: 1960 # There was no real answer from the AMS or it answered something weird, so error 1961 self.DEBUG("There was an error with the register of agent: " + str(self.getAID().getName()),"err") 1962 return False 1963 1964 return True
1965 1966
1967 - def __deregister_from_AMS(self, state=None, ownership=None, debug=False):
1968 1969 presence = xmpp.Presence(to=self.getAMS().getName(),frm=self.getName(),typ='unsubscribe') 1970 1971 self.send(presence) 1972 self.DEBUG("Agent: " + str(self.getAID().getName()) + " deregistered correctly (inform)","ok") 1973 1974 return True
1975 1976
1977 - def __deregister_from_AMS_with_ACL(self, state=None, ownership=None, debug=False):
1978 1979 _msg = ACLMessage.ACLMessage() 1980 _msg.addReceiver( self.getAMS() ) 1981 _msg.setPerformative('request') 1982 _msg.setLanguage('fipa-sl0') 1983 _msg.setProtocol('fipa-request') 1984 _msg.setOntology('FIPA-Agent-Management') 1985 1986 content = "((action " 1987 content += str(self.getAID()) 1988 content += "(deregister (ams-agent-description " 1989 content += " :name " + str(self.getAID()) 1990 if state: 1991 content += " :state "+state 1992 if ownership: 1993 content += " :ownership " + ownership 1994 content +=" ) ) ))" 1995 1996 _msg.setContent(content) 1997 1998 self.send(_msg) 1999 2000 # We expect the initial answer from the AMS 2001 msg = self._receive(True,20) 2002 if (msg != None) and (str(msg.getPerformative()) == 'refuse'): 2003 self.DEBUG("There was an error initiating the deregister of agent: " + str(self.getAID().getName()) + " (refuse)","err") 2004 return False 2005 elif (msg != None) and (str(msg.getPerformative()) == 'agree'): 2006 self.DEBUG("Agent: " + str(self.getAID().getName()) + " initiating deregistering process (agree)") 2007 else: 2008 # There was no answer from the AMS or it answered something weird, so error 2009 self.DEBUG("There was an error deregistering of agent: " + str(self.getAID().getName()),"err") 2010 return False 2011 2012 # Now we expect the real informative answer from the AMS 2013 msg = self._receive(True,20) 2014 if (msg != None) and (msg.getPerformative() == 'failure'): 2015 self.DEBUG("There was an error with the deregister of agent: " + str(self.getAID().getName()) + " (failure)","err") 2016 return False 2017 elif (msg != None) and (str(msg.getPerformative()) == 'inform'): 2018 self.DEBUG("Agent: " + str(self.getAID().getName()) + " deregistered correctly (inform)","ok") 2019 else: 2020 # There was no real answer from the AMS or it answered something weird, so error 2021 self.DEBUG("There was an error with the deregister of agent: " + str(self.getAID().getName()),"err") 2022 return False 2023 2024 return True
2025
2026 -class BDIAgent(Agent):
2027 - def _startBdiBehav(self):
2028 self.bdiBehav = bdi.BDIBehaviour(period=1) 2029 self.addBehaviour(self.bdiBehav,None) 2030 self.DEBUG("BDI behaviour added.",'info')
2031
2032 - def setPeriod(self, period):
2033 self.bdiBehav.setPeriod(period)
2034
2035 - def getPeriod(self):
2036 return self.bdiBehav.getPeriod()
2037
2038 - def addPlan(self, inputs=[], outputs=[],P=[],Q=[],services=[]):
2039 return self.bdiBehav.addPlan(inputs,outputs,P,Q,services)
2040
2041 - def addGoal(self, goal):
2042 self.bdiBehav.addGoal(goal)
2043
2044 - def setPlanSelectedCB(self, func):
2045 '''func MUST have as input parameter a plan''' 2046 self.bdiBehav.planSelectedCB = func
2047
2048 - def setGoalCompletedCB(self, func):
2049 '''func MUST have as input parameter a goal''' 2050 self.bdiBehav.goalCompletedCB = func
2051
2052 - def setServiceCompletedCB(self, func):
2053 '''func MUST have as input parameter a DF.Service''' 2054 self.bdiBehav.serviceCompletedCB = func
2055