| Home | Trees | Indices | Help |
|
|---|
|
|
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
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
93 """
94 Abstract Agent
95 only for heritance
96 Child classes: PlatformAgent, Agent
97 """
98
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
188 self.wui.passwd = str(passwd)
189
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
207 if hasattr(self.session, "user_authenticated"):
208 delattr(self.session,"user_authenticated")
209 raise HTTP_REDIRECTION, "index"
210
211 @require_login
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
234
235 @require_login
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(">",">")
265 strm = strm.replace("<","<")
266 strm = strm.replace(""",'"')"""
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(">", ">")
272 strm = strm.replace("<", "<")
273 strm = strm.replace('"', """)
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
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
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
474
476 # Record at log
477 t = time.ctime()
478 dmsg = dmsg.replace(">",">")
479 dmsg = dmsg.replace("<","<")
480 dmsg = dmsg.replace(""",'"')
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
512
515
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
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
546
550
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
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
705
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
721
727
729 self._aid.addAddress(addr)
730
732 return self._aid.getName()
733
735 """
736 returns the AMS aid
737 """
738 return AID.aid(name="ams." + self._serverplatform, addresses=[ "xmpp://ams."+self._serverplatform ])
739
741 """
742 returns the DF aid
743 """
744 return AID.aid(name="df." + self._serverplatform, addresses=[ "xmpp://df."+self._serverplatform ])
745
751
757
763
766
767
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
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
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
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
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
1119
1125
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
1147
1154
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
1164 """
1165 stops the agent
1166 must be overridden
1167 (kind of a "onEnd" for the agent)
1168 """
1169 pass
1170
1171
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
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
1253
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
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
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
1311
1317
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
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
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
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
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
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
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
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 ####################
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 ####################
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
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
1620
1621
1622 ########################
1623 #Knowledge Base services
1624 ########################
1625
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
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
1651
1654
1657
1660
1661 ##################################
1662
1663 # Changed to be a 'daemonic' python Thread
1664 -class jabberProcess(threading.Thread):
1665
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
1681
1684
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
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
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
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
1773 """
1774 This is the main class which may be inherited to build a SPADE agent
1775 """
1776
1777
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
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
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
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
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
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
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
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
2028 self.bdiBehav = bdi.BDIBehaviour(period=1)
2029 self.addBehaviour(self.bdiBehav,None)
2030 self.DEBUG("BDI behaviour added.",'info')
2031
2033 self.bdiBehav.setPeriod(period)
2034
2036 return self.bdiBehav.getPeriod()
2037
2040
2042 self.bdiBehav.addGoal(goal)
2043
2047
2051
2053 '''func MUST have as input parameter a DF.Service'''
2054 self.bdiBehav.serviceCompletedCB = func
2055
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed Aug 1 18:45:02 2012 | http://epydoc.sourceforge.net |