jade的中文资料

本文介绍了多Agent系统的基本概念,强调了Agent的自治性、社会能力和反应能力等特性。文章指出JADE是一个用于开发多Agent系统的Java框架,符合FIPA标准,包括AMS、DF和ACC组件,并具备Agent移动性、行为模型、FIPA交互协议库等特性。JADE支持创建分布式Agent平台,提供图形用户界面管理和调试工具,便于Agent注册、注销和通信。此外,文章还讨论了JADE如何简化与DF和AMS服务的交互,以及Agent类的生命周期和行为执行模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 
 
 
第一章 绪论
1.1问题概述
多Agent系统是由多个可以相互交互的,称为Agent的计算单元所组成的系统.Agent作为计算机系统具有两种重要的能力.首先,每个Agent至少在某种程度上可以自治行动,由它们自己决定需要采取什么行动以实现其设计目标.其次,每个Agent可以与其他Agent进行交互,这种交互不是简单地交换数据,而是参与某种社会行为,就像我们在每天的生活中发生的那样:合作,协作和协商等.
多Agent系统是计算机科学中比较新的一个分支,从20世纪80年代才开始研究,而直到20世纪90年代中才得到广泛的认同.从此以后国际上对这个领域的兴趣大为增加.这种研究热情的快速增加至少部分的是由于认识到Agent是一种合适的软件范例,这种范例为研究大规模分布式开放系统(如Internet)提供了可能性.尽管多Agent系统在探索Internet的潜力方面能起到关键的作用,但是多Agent系统的作用远不止如此.对于理解和构造各种所谓的人工社会系统来说,多Agent系统似乎是一个自然的比喻.多Agent的思想并不局限在某个特定的领域,像在此前出现的对象一样,多Agent系统会在许多不同的应用领域中广泛出现.
1.2该领域技术发展现状
近年来,随着计算机技术的不断发展和应用的广泛普及,随着国际互联网络的出现和发展,计算机软件系统结构和计算机组织结构的复杂性不断增加,从而为软件系统的开发提出了更多,更复杂的要求,如可伸缩性,多功能性,可重用性,鲁棒性,一致性.传统的整体设计和集中控制的软件开发方法越来越显示出其固有的局限性.同时软件系统的设计越来越向个性化,智能化方向发展,一些大型软件系统纷纷采用了人工智能的技术.因此可以说智能化,分布式是未来软件设计的方向.
作为人工智能和分布式计算的结合,分布式人工智能正逐渐收到人们的重视.分布式人工智能研究的目标是要创建描述自然和社会系统精确的概念模型.在分布式人工智能中,由于智能本质上不是一个独立存在的概念,而智能在团体中实现,因此分布式人工智能研究感兴趣的主要是几个Agent之间的合作,交互等方面.分布式问题求解考虑怎样将一个特殊问题求解工作在多个合作的,知识共享的模块或节点之间划分;在多Agent系统中,主要研究一组自治的智能Agent之间智能行为的协调.知识,规划,不同技能和自身动作的协调是一个过程,在多Agent系统非常重要.
目前对Agent和多Agent系统的研究主要集中在以下几个方面:Agent和多Agent的理论,Agent的体系结构和组织,Agent语言,Agent之间的协作和协调,通信和交互技术,多Agent学习以及多Agent系统应用等.关于多Agent系统的应用已经有人做了许多工作,甚至应用于一些大型,复杂的系统,例如机场管理,自动驾驶,高级机器人系统,分布式电力管理,信息检索等.
现在,关于Agent的研究不仅得到了人工智能研究人员的关注,也吸引了数据通讯,人机界面设计,机器人,并行工程等各个领域的研究人员的兴趣.有人认为:"基于Agent的计算(Agent-based
Computing,简称ABC)将成为软件开发的下一个重要的突破."
1.3全文安排
本文首先简单的介绍了Agent特点,接着引出一个用于开发多Agent系统的平台-JADE.并结合一个"图书交易"系统,分析如何利用JADE平台创建多Agent系统,以及Agent是如何在平台上执行任务,进行通讯的.内容概要如下:
第二章 Agent简介
第三章 JADE平台介绍
第四章 基于JADE平台的"图书交易"系统
第五章 全文总结
最后是附录,参考书目以及致谢.
第二章 Agent简介
2.1Agent技术的起源与发展
进入20世纪90年代以来,在各种计算机文献和众多公司的技术发展规划中,Agent正日渐成为使用频率最高的词汇之一.下面就对Agent技术的发展做一个简要的阐述.
智能Agent技术的诞生和发展是人工智能 技术(AI)和网络技术发展的必然结果.从20世纪60年代起,传统的AI技术开始致力于对知识表达,推理,机器学习等技术的研究,其主要成果是专家系统.专家系统把专业领域知识与推理有机的组合在一起,为应用程序的智能化提供了一个低级而实用的解决办法.作为人工智能的一个分支,AI计划理论的研究成果使应用程序有了初步的面向目标和特征,即应用程序具有了某种意义上的主动性;而人工智能的另一个分支-决策理论和方法则使应用程序具有了自主判断和选择的行为的能力.人工智能围绕着知识所进行的广泛研究和应用正逐步形成一门新的学科,这就是知识工程,它涉及的知识的获取,存储和管理等许多课题.所有这些技术的发展加快了应用程序智能化的进程.
随着网络技术的发展,多个应用程序间相互作用的模式正从单一的集成式系统向分布式系统演化.一个在物理上和地理上分布的应用程序之间通信与合作的网络地层基础结构正逐渐建立起来.分布式对象技术(如CORBA或DCOM技术)则进一步使分布且异构的应用程序之间能以一种共同的方式提供和获得服务,实现了在分布式状态下的"软"集成.
智能化和网络化的发展促成了Agent技术的发展,Agent技术正是为解决复杂,动态,分布式智能应用而提供的一种新的计算手段.
2.2Agent定义
目前并不存在一个被普遍接受的Agent的定义,事实上,对这个问题尚有争论,并存在不同的看法.尽管把自治性作为Agent的核心概念已经达成了普遍的共识,但除此之外很少有一致的看法.
Wooldridge和Jennings在总结了前人在Agent领域的一些工作后认为,可以从狭义和广义两个方面去理解Agent的特性
(1)Agent弱概念
这是从广义的角度来规定Agent的特性.几乎所有被称为Agent的软件或硬件系统都具有以下的特性:
自治性(Autonomy):Agent运行时不直接由人或者其它东西控制,它对它们自己的行为和内部状态有一定的控制权.
社会能力(Social Ability)或称可通信性:Agent能够通过某种Agent通信语言(agent communication language)与其它Agent进行信息交换.
反应能力(Reactivity):即对环境的感知和影响.无论Agent生存在现实的世界中(如机器人,Internet上的通讯Agent,用户界面Agent等)还是虚拟的世界中(如虚拟商场中的Agent,交互式游戏中的Agent等),它们都应该可以感知它们所处的环境,并通过行为改变环境.一个不能对环境做出影响的物体不能被称作Agent.
自发行为(Pro-activeness):传统的应用程序是被动地由用户来运行的,而且机械地完成用户的指令;而Agent的行为应该是主动的,或者说自发的.Agent感知周围环境的变化,并作出基于目标的行为(goal-directed behaviour).
在这种定义下,最简单的Agent就是具有上述特性的一个计算机进程,这个进程可以简单到只是个具有某种智能的子程序,能够与别的Agent交换消息.Agent弱概念使Agent不仅仅只应用于人工智能领域,而且广泛地应用在诸如人机界面,通信,并行工程,软件工程,搜索引擎等.因此很多计算机软件都可以纳入Agent的范畴里来,例如处理Internet事务,帮助用户处理E-mail的助理Agent等.
Marvin Minsky从多Agent系统的社会智能的角度给出Agent的一个定义:"这些进程我们称之为Agent,每个Agent本身只会做一些简单的事情,但当我们用特定的方法将这些Agent组成一个Agent群(society),就产生了真正的智能."
Minsky的定义显然也是一种广义的定义.
(2)Agent强概念
对某些研究者,尤其是人工智能的研究者来说,Agent除了应具有上面这些特性以外,还应该具有某些通常人类具有的特性.例如知识,信念,意图,承诺等心智状态.有的学者甚至提出了有情感的Agent.
当前对强概念Agent的研究主要集中在理论方面.例如,Shoham提出的面向Agent编程(AOP Agent-Oriented Programming)使用的就是强概念的Agent定义:"一个Agent是这样一个实体,它的状态可以看作是由信念(belief),能力(capability),选择(choice),承诺(commitment)等心智构件(mental component)组成."
(3)Agent的其它属性
长寿性(Longevity):传统应用程序在用户需要时激活,不需要时或者运算结束后停止.Agent与之不同,它应该至少在"相当长"的时间内连续地运行.
移动性(Mobility):Agent可以从一个地方移动到另一个地方而保持其内部状态不变.Agent可以携带数据和能够在远处执行智能指令.
推理能力(Reasoning):Agent可以根据其当前的知识和经验,以理性的,可再生的方式推理或推测.
规划能力(Planning):根据目标,环境等的要求,Agent应该至少对自己的短期行为作出规划.虽然程序设计人员可以提供一些常见情况的处理策略,但这些策略不可能覆盖Agent将遇到的所有情况.所以,Agent应该有生成规划的能力.
学习和适应能力(Learning and Adaptability):Agent可以根据过去的经验积累知识,并且修改其行为以适应新的环境.另外,有些学者还提出Agent应该具有自适应性,个性等特性.
诚实(Veracity):假定Agent不会故意提供错误信息.
善意(Benevolence):假定在Agent之间不会存在相互冲突的目标,且Agent总是尽力去帮助其它Agent.
理性(Rationality):假定Agent总是尽力去实现自己的目标.
2.3Agent的适用领域
与用户有灵活的相互作用,在互相作用中智能地协助用户完成琐碎的工作.
在对海量分布式信息搜索中,建立快速智能的搜索机制.
在高度动态的环境下,要求应用程序能对多边的环境作出响应或自适应.
需要应用程序能自主处理失效或冲突,以进行在调度,再计划或资源再分配.
需要应用程序既能进行长期计划驱动的行为,又能从事短期试试响应行为.
在复杂的或安全性很重要的应用程序中,保证适宜的反应和应答时间.
在地理上或逻辑上分布,自主或异构的节点间提供应用服务或中间件服务.
在不完全信息下的复杂或分散的资源分配问题.
2.4agent技术的标准化
FIPA(Foundation for Intelligent Physical Agents)是一个由IBM,NHK,BT等公司和政府,学术机构组成的权威的Agent标准化组织(http://www.fipa.org),目前该组织正致力于以下三个主要领域的标准制定:
Agent管理需要认同和发现Agent(白,黄页服务),需要定义它们的各种状态以及哪些角色能与它们相互作用.
Agent相互作用覆盖最高层Agent间相互作用的标准,包括Agent间传递的信息的意义,命令,请求,义务等.
Agent与软件的接口.
此外FIPA还制定了4个参考应用领域的标准,包括个人旅行助手,个人助手,声/视娱乐广播,网络管理等.正在制定的标准包括人类Agent的相互作用,产品设计与制造Agent,Agent安全管理,支持移动性的Agent管理,Ontology(共享语汇)服务,Agent消息传送,Agent命名,内容语言库等.尽管FIPA标准仍在制定和发展之中,但是随着越来越多组织的加入,它必将称为促进Agent应用和发展的主要推动力.
第三章JADE平台介绍
3.1JADE平台简介
JADE(Java Agent Development Framework)是一个软件开发框架,用于开发多Agent系统和符合FIPA标准的智能Agent应用程序.它包含两个主要的产品:一个符合FIPA标准的Agent平台和一个开发JAVA
Agent的包.
JADE完全是由JAVA编写的,由各种JAVA包组成,它为应用程序员既提供现成的功能片断,同时也为自定义的应用程序任务提供抽象接口.由于JAVA的许多良好的特性,它是一种很特别的编程语言,特别是它在分布式的不同环境中的面向对象编程方法,例如对象序列化(Object Serialization),反映性API(Reflection API)和远程方法唤醒(Remote Method Invocation RMI).
JADE主要由下面的包组成:
jade.core实现系统的核心.它包含必须被应用程序员继承的Agent类,除此以外,jade.core.behaviours子包还包含一个Behaviour类层次结构.行为实现了一个Agent的任务或意图.它们是逻辑活动单元,并且可以以不同的方式组合,以获取不同的执行方式,当然,它们是可以并行执行的.应用程序员定义Agent的操作,编写行为以及Agent的执行路径.
jade.lang.acl子包用于依照FIPA标准规定处理Agent通讯语言(ACL).
jade.content包包含了一组类用于支持用户定义的概念和语言.
jade.domain包包含了所有那些由FIPA标准定义的,描述Agent管理实体的JAVA类,特别是AMS和DF
Agent,它们提供生命周期服务和白黄页服务.子包jade.domain.FIPAAgentManagement包含了FIPA Agent管理的概念和描述其概念的类.子包jade.domain.JADEAgentManagement则包含了JADE对Agent管理的扩展(例如,对消息的探测以及控制Agent的生命周期).子包jade.domain.introspection包含了用于描述在JADE工具和JADE内核之间沟通领域的概念.子包jade.domain.mobility包含了描述移动通信的概念.
子包Jade.gui包含了一组一般的类,用于建立用户图形界面,用来显示和编辑Agent标识符,Agent描述,ACL消息……
jade.mtp包包含了一个JAVA接口.为了容易用JADE框架集成,每个消息传送协议必须利用这个接口,它还包含了一组这些协议的执行.
jade.proto包包含了建模标准交互协议的类(如:fipa-request, fipa-query, fipa-contract-net, fipa-subscribe和其他一些被FIPA定义的类),同时也包含了帮助应用程序员建立自定义的协议的类.
3.2JADE的特点
下面是JADE提供给Agent编程人员的JADE特点列表:
-分布式Agent平台.Agent平台可以分散在几个主机上(假设它们可以通过RMI连接起来).
-从远方主机用图形用户界面来管理Agent和Agent容器.
-在开发基于JADE的多Agent应用程序时,可以利用调试工具.
-平台内的Agent移动性,包括传递Agent的状态和代码(当需要的时候).
-通过行为模型,对多个平行,并行的Agent活动的支持.JADE以无优先权的方式对Agent行为进行调度.
-FIPA标准的Agent平台,包括AMS
(Agent管理系统),DF(目录服务),和ACC(Agent通讯通道).这三个组成部分在Agent平台启动时被自动激活.
-为了多域的应用程序,许多FIPA标准的DF在运行时可以被启动.在程序中,每个域是一组逻辑Agent,它们提供的服务通过一个公共的设备被公布出来.每个DF继承了GUI和所有由FIPA定义的标准功能(即,注册,注销,修改,搜索Agent标识符的功能和在网内连接DF的功能).
-在同一个Agent平台内有效率的ACL消息传输.事实上,消息在传送时是以JAVA对象被编码,而不是字符串,这样是为了避开编组和未编组的程序.当消息跨越平台边界的时候,它们被自动转换为FIPA标准的语法,编码方式,传输协议或反之.这种转换对于Agent执行者来说是透明的,它们只需要处理JAVA对象.
-FIPA交互协议库是现成可用的.
-通过AMS,Agent可以自动进行注册和注销.
-符合FIPA标准的命名服务:在启动时,Agent从平台上获取它们的GUID(全球唯一标识).
-对应用程序定义的相关语言和概念的支持.
-程序内接口,它允许外部应用程序启动自治的Agent.
3.3用JADE创建多Agent系统
3.3.1Agent平台
由FIPA定义的标准的Agent平台模式由以下几部分组成:
Agent管理系统(AMS)是负责监督管理对Agent平台的访问和使用的Agent.在一个单独的平台上,只能有一个AMS.AMS提供白黄页服务,以及生命周期服务,它保留了一个Agent标识符目录(AID)和Agent状态信息.每个Agent必须在AMS注册,以获得一个有效的AID.
目录服务(DF)是在平台上提供默认的黄页服务的Agent.
消息传输系统,又叫做Agent通信通道(ACC),是控制平台内所有的信息交换,包括与远端平台进行信息交换的软件.
图3-1JADE完全参照这个标准体系结构.因此,当一个JADE平台启动的时候,AMS和DF就自动被建立了,同时ACC模块允许消息进行传输.Agent平台允许建立在几个主机上.在每个主机上只有一个JAVA应用程序,当然也只有一个JAVA虚拟机(JVM)被执行.每个JAVA虚拟机是一个基本的Agent容器,它为Agent的执行提供一个运行环境,同时它允许几个Agent在同一个主机上并行的执行.主容器(main-container)是Agent容器,它包括AMS和DF,在那里注册RMI(它由JADE在内部使用).与主容器相关的其它容器,为任何一组JADE Agent的执行提供一个完整的运行环境.
图3-2
3.3.1.1DF服务
jade.domain.DFService利用一组静态方法来实现与一个标准的FIPA DF服务进行交互.它包含了从DF请求注册,注销,修改,搜索行为的方法.每个方法都有一个带有所有所需参数的版本,以及一个所有省略参数都是默认值的版本.
注意,这些方法将会阻塞每个Agent活动直至行为被成功的执行或者掷出了一个jade.domain.FIPAException违例,也就是说直到会话的结束.在某些情况下,以不阻塞的方式执行这些方法可能会更方便.在这些情况下,jade.proto.AchieveREInitiator
或者jade.proto.SubscriptionInitiator将与createRequestMessage(),
createSubscriptionMessage(),decodeDone(), decodeResult()
decodeNotification()联合使用,这将简化向DF发送消息的准备,以及从DF接受消息时的解码.
3.3.1.2AMS服务
这个类与DFService类是成对的,它的服务是由一个标准的FIPA AMS
Agent提供的,并且它的界面是与DFService完全一致的.注意JADE在调用setup()前和takeDown()返回以后分别自动调用注册和注销方法,所以一般的程序员不用去调用它们.但是在某些特定的环境下,程序员可能需要调用它们.
3.3.2Agent类
Agent类是用户自定义Agent的公共基类.因此,从程序员的角度看,一个JADE Agent仅仅是用户自定义的继承了Agent类的一个实例.这表现了特性的继承性,这种继承行主要体现在Agent平台间交互(注册,配置,远程管理),以及用以实现自定义的Agent行为的一组基本方法(如收发消息,使用标准交互协议,注册域,...).Agent的计算模型是多任务的,任务(或是行为)是并行执行的.每个由Agent提供的功能/服务应该作为一个或者多个行为被执行(参考3.4行为的执行).Agent基类内的调度对程序员是透明的,它自动管理行为的调度.
3.3.2.1Agent生命周期
图3-3根据FIPA中的Agent平台生命周期,JADE Agent可以处于这几个状态之一,它们在Agent类中用几个常量来表示.这些状态分别是:
初始状态AP_INITIATED:Agent对象已经建立,但是还没有由AMS注册,既没有名字,也没有地址,而且不能与其它Agent进行通讯.
激活状态AP_ACTIVE:Agent对象已经由AMS注册,有正规的名字和地址,而且具有JADE的各种特性.
挂起状态AP_SUSPENDED:Agent对象当前被停止.内部的线程被挂起,没有Agent行为被执行.
等待状态AP_WAITING:Agent对象被阻塞,等待其它事件.内部的线程在JAVA 监控器上休眠,当条件满足时被唤醒(典型的情形是消息到达).
删除状态AP_DELETED:Agent死亡.内部的线程的执行被终结,Agent不再在AMS上有注册信息.
传送状态AP_TRANSIT:移动Agent移动至一个新的位置时进入这个状态.系统继续缓存将被送到这个新位置的消息.
拷贝状态AP_COPY:这是JADE在Agent克隆时的一个内部状态.
离开状态AP_GONE:这是JADE在移动Agent移至一个新的地点时的一个内部稳定状态.
注意Agent只有在激活状态时才允许执行行为(也就是任务).注意如果任何一个行为调用doWait()方法,那么整个Agent及其所有的活动都被阻塞,而不仅仅是调用这个方法的行为.block()方法是Behaviour类的一部分,这是为了挂起一个单独的Agent行为.
3.3.2.2Agent内的通讯
Agent类同样提供了一组用于Agent内通讯的方法.根据FIPA说明,Agent通过异步消息传输进行通讯,ACL消息的对象是交换的有效载荷.一些由FIPA定义的交互协议也是可由Agent活动调度的现成可用的行为,它们是jade.proto包的一部分.
Agent.send()方法可以发送ACL消息.接收槽保留了正在接收消息的Agent的ID.这种方法调用对于Agent的位置来说是透明的,也就是说无论是本地或是远程的Agent,是平台负责选择最合适的地址和传输机制.
3.3.2.3带有图形用户界面(GUI)的Agent
一个构造为多Agent系统的应用程序仍然需要与它的用户进行交互.因此,在应用程序中有必要至少在某些Agent上提供GUI.虽然这可能引起一些问题,这主要是因为Agent自治特性和普通用户图形界面的反映性间的不匹配造成的.使用JADE,JADE Agent采用的每个Agent一个线程的并发模式必须要与Swing并发机制配合使用.
3.3.3Agent任务.执行Agent行为
为了响应不同的外部事件,Agent必须能够执行几个并行的任务.为了使Agent管理更加有效率,每个JADE Agent都由一个单独的执行线程组成,并且它的任务都是模型化的,可以作为Behaviour的对象来执行.同样可以执行多线程的Agent,但是JADE并没有对此提供特别的支持.
想要执行一个基于Agent的任务的开发者应该定义一个或者更多Behaviours子类,实例化它们,并把任务对象添加到Agent任务列表中.类Agent是必须由Agent程序员继承的,提供了两个方法:addBehaviour(Behaviour)和removeBehaviour(Behaviour),它们允许用来管理一个具体任务的就绪队列.注意行为和子行为可以在需要的时候添加进来,而不仅仅是在Agent.setup()方法内部.添加一个行为应该被看做在Agent内产生一个新的(合作)执行线程的方式.
由Agent基类执行的调度程序对于程序员来说是透明的,对于就绪队列中所有有效的行为,它的调度策略是无优先权的时间片轮转法,执行Behaviour-derived类,直至释放控制权(这在action()方法返回时执行).如果任务没有放弃控制权,它将在下一次轮转是被重新调度.在等待消息到达时,行为同样可以被阻塞.具体的说,Agent调度程序执行就绪行为队列中每个行为的action()方法.当action()返回时,done()方法被调度,它用来检测行为是否完成.如果完成了,行为对象将从队列中删除.
行为像合作线程一样工作,但是,没有保存任何栈.因此,整个运行状态必须被保留在Behaviour和它相关的Agent的临时变量中.
为了防止在激活状态等待消息(这样会浪费CPU的时间),允许每个Behaviour阻塞它自己的运行.当action()方法返回时,block()方法就把行为放到阻塞行为队列中.注意,因此,阻塞的结果并不是在调用block()方法后立即体现出来,而是在action()方法返回后.
在新的消息到达后,所有被阻塞的行为将重新被调度,因此程序员必须考虑再次阻塞与到达的消息不相关的行为.此外,一个行为对象可以通过向block()方法传递一个时间域值把自己阻塞一端有限的时间.在JADE后来的版本中,考虑了更多的唤醒事件.
因为从Agent行为中进行选择时,采用的是无优先权的多任务模型,Agent程序员必须注意避免使用无限循环,以及在action()方法内部执行长的操作.记住,当某个行为的action()运行时,其它的行为都不能执行,直至action()结束(这当然只是考虑同一个Agent内的行为,其它Agent的行为是运行在不同的java线程内,当然可以继续独立的运行).
除此以外,既然没有保存任何堆栈,每次action()方法都是从头开始运行,action()方法不可以在中间打断,也不可以把CPU让给其它的行为,然后从行为离开的位置,启动最初的那个行为.
3.4交互协议
FIPA规定了一组标准的交互协议,可以以它们作为标准模板来建立Agent间的对话.对于Agent间的每一次对话,JADE都区分了发起者(发起会话的Agent)和回应者(在与其它Agent取得联系后参与到会话中的Agent).JADE依据大部分的FIPA交互协议,为会话中的两个角色都提供了行为类.正如在这节中所描述的,这些类都可以在jade.proto包中找到.它们通过一个同类的API提供了回叫方法来处理协议的各个状态.
所有的发起者行为一达到交互协议的某个最终状态,就会立即结束,并从Agent的任务队列中删除.为了不必重新建立新的java对象就能再次使用代表这些行为的java对象,所有的发起者都包含了一些带有合适参数的复位方法.此外,所有的发起者行为,不只是FipaRequestInitiatorBehaviour都可以进行一对多的会话,也就是说可以在同一时间处理几个回应者.
所有的回应者行为则是循环的,并且它们在达到交互协议的某个最终状态时将被重新调度.注意,这个特性允许程序员限制Agent应该并行执行的回应者的最大数量.
3.5对移动Agent的支持
使用JADE,应用程序的开发者能够建立移动Agent,它能够在多网络主机结见移动或复制自己.在JADE的这个版本中,只支持intra-platform移动性,这是一个能够在不同的Agent的container间移动的JADE移动Agent,但是它被限制于一个单独的JADE平台内.
移动或者克隆被视为Agent生命周期状态转换过程的一个状态.如同所有的其它生命周期的操作一样,Agent移动或是克隆可以由Agent自己或是AMS发起.Agent类提供了一个合适的API,而AMS
Agent能够通过FIPA ACL访问.
移动Agent为了能够决定什么时间以及向哪里移动,它们需要记住自己的位置.因此,JADE提供了一个所有者的概念,命名为jade-mobility-ontology,它保留了必要的概念和行动.
第四章 基于JADE平台上的"图书交易"系统
"图书交易"系统是一个利用JADE创建Agent的例子,利用这个例子来分析Agent是如何执行任务以及彼此间通讯的.
4.1"图书交易"系统要实现的功能
这个"图书交易"系统包括了一些代表个各自用户的"售书"Agent和"买书"Agent.
4.1.1买方Agent
买方Agent不带有GUI,用户将要购买的书目("target
book")以命令行参数的方式传递给买方Agent.买方Agent接着定期的向已知的卖方Agent发送购书请求.当有卖方Agent提供(offer)该书时,买方Agent接受该消息,并执行"买"的动作.如果不止一个卖方Agent提供这本书,买方Agent将接受最优(也就是最便宜)的一个.在交易完成后,买方Agent结束.
4.1.2卖方Agent
卖方Agent启动了一个简单的GUI,通过它,用户可以向本地的书目列表(catalogue)中添加新的书目.卖方Agent将一直运行,不断的等待来自买方Agent的购书请求.当收到买方Agent的请求时,它们先要检查请求的书目是否在本地的书目列表中.如果在,它们该书的价格作为回应发送给请求该书的买方Agent;如果不在,它们将发送拒绝(refuse)消息.当收到购买(purchase)命令时,卖方Agent将执行这个操作,并将请求的图书从本地的图书列表中删除.
4.2建立JADE Agent-Agent类
建立一个JADE Agent,最主要的是要定一个继承了jade.core.Agent类的类.并且该类还要执行setup()方法.代码如下:
import jade.core.Agent;
public class BookBuyerAgent extends Agent {
protected void setup() {
// 打印问候语
System.out.println("Hallo! Buyer-agent "+getAID().getName()+" is ready.");
}
}
setup()方法主要是用于Agent的初始化.而Agent实际上要完成的任务将在行为(behaviours)中执行.
4.2.1agent标识符
前面已经介绍了Agent标识符的表示方法.每个Agent标识符都是jade.core.AID的一个实例.Agent类的getAID()方法可以用来获取Agent的标识符.如果知道了Agent的昵称(nickname),可以通过下面的方式获取它的AID:
String nickname = "Peter";
AID id = new AID(nickname, AID.ISLOCALNAME);
ISLOCALNAME常量表明,方法的第一个参数代表的只是一个昵称,并不是一个全球唯一的标识.
4.2.2结束Agent
在上面给出的简单的代码中,Agent即使执行完了打印问候语的任务,Agent仍然是继续运行的.如果想结束这个Agent,必须调用这个Agent类的doDelete()方法.takeDown()在Agent结束前被调用,它的作用是进行一些Agent的清除工作,比如释放Agent占用的各种资源.
4.2.3向Agent中传递参数
在Agent启动时,我们可以通过命令行向Agent传递一些参数,参数在命令行要用小括号括起来.这些参数可以作为Object数组,通过Agent类的getArguments()方法获得.正如在前面提到的,我们希望把用户要买的书目以命令行参数的方式传递给买方Agent.为此,代码可以扩展如下:
import jade.core.Agent;
import jade.core.AID;
public class BookBuyerAgent extends Agent {
// 想要买的书目
private String targetBookTitle;
//已知卖方列表
private AID[] sellerAgents = {new AID("seller1", AID.ISLOCALNAME),
new AID("seller2", AID.ISLOCALNAME)};
//agent初始化
protected void setup() {
// 打印问候语
System.out.println("Hallo! Buyer-agent "+getAID().getName()+" is ready.");
// 获取启动参数,以便得到要买的书目名,
Object[] args = getArguments();
if (args != null && args.length > 0) {
targetBookTitle = (String) args[0];
System.out.println("Trying to buy "+targetBookTitle);
}
else {
//立即结束买方Agent
System.out.println("No book title specified");
doDelete();
}
}
// 把Agent的清除操作放在这里
protected void takeDown() {
//打印结束信息
System.out.println("Buyer-agent "+getAID().getName()+" terminating.");
}
}
4.3Agent执行的任务-Behaviour类
Agent实际上要完成的任务(task)应该在行为(behaviours)中被执行.每个行为都代表了Agent要执行的一个任务.每个行为都是一个继承了jade.core.behaviours.Behaviour.的类的对象.可以通过Agent类的addBehaviour方法把行为添加到Agent中.在任何地方都可以把行为添加到Agent中,比如在用来初始化Agent的setup()方法中,甚至在其它行为内部再添加一个行为.
每个继承了Behaviour的类,都必须执行action()方法,这个方法实际上定义了这个行为运行时执行的操作.done()方法的返回值是布尔型的.这个返回值表明了该行为是否已经结束,行为一旦结束,就必须从Agent的行为池中删除.
4.3.1行为调度和执行
Agent可以同时执行几个行为.行为一旦被调度执行了它的action()方法,那么它将一直运行下去知道该方法返回.因此什么时候从一个行为的执行切换到下一个行为的执行是由程序员来决定的.图4-1描述了Agent线程的执行流程:
图4-1
从上图可以看出来,下面示例的行为的action()方法是永远不会返回的:
public class OverbearingBehaviour extends Behaviour {
public void action() {
while (true) {
//执行某个任务
}
}
public boolean done() {
return true;
}
}
如果没有什么行为需要执行,那么Agent线程将要休眠,因为这样可以提高CPU的利用率.一旦有行为需要执行时,该线程将立即被唤醒.
4.3.2只执行一次的行为(One-shot behaviours),循环执行的行为(cyclic behaviours)和一般的行为(generic
behaviours)
这里主要讲讲三种主要类型的行为.
只执行一次的行为:这种行为的action()方法只执行一次,并且行为立即结束.jade.core.behaviours.OneShotBehaviour类已经把done()方法的返回值设为true,我们可以继承这个类,来完成我们自己定义的只执行一次的行为,举例如下:
public class MyOneShotBehaviour extends OneShotBehaviour {
public void action() {
//执行某个操作X
}
}
操作X只能执行一次
循环执行的行为:这种类型的行为从来不会结束,它的action()方法每次被调用时执行相同的操作,jade.core.behaviours.CyclicBehaviour类已经把done()方法的返回值设为false,我们可以通过继承这个类,来完成我们自己定义的循环执行的行为,举例如下:
public class MyCyclicBehaviour extends CyclicBehaviour {
public void action() {
// 执行某个操作Y
}
}
操作Y将永远被执行下去,知道执行这个行为的Agent结束.
一般的行为:这种类型的行为都包含了一个状态值,并依据这个状态值执行不同的操作.这种行为通常是一个大的switch语句,当满足某个条件时,这个行为就结束了.
举例如下:
public class MyThreeStepBehaviour extends Behaviour {
private int step = 0;
public void action() {
switch (step) {
case 0:
// 执行操作X
step++;
break;
case 1:
//执行操作Y
step++;,
break;
case 2:
// 执行操作Z
step++;
break;
}
}
public boolean done() {
return step == 3;
}
}
操作X,Y,Z将一次被执行,接着这个行为结束了.
JADE也提供了将这些简单的行为组合成更复杂的行为的功能.
4.3.2在特定的时间点执行某个操作
JADE提供了两个现成的类Wakerbehaviour和TickerBehaviour,通过这两个类,我们可以使行为在特定的时间点执行某个操作.
Wakerbehaviour:它的action()方法和done()方法在给定的一段时间后执行handleElapsedTimeout()抽象方法,在handleElapsedTimeout()方法结束后,行为也将结束.在下面的例子中,操作X在屏幕上打印"Adding
waker behaviour"后十秒钟被执行.
public class MyAgent extends Agent {
protected void setup() {
System.out.println("Adding waker behaviour");
addBehaviour(new WakerBehaviour(this, 10000) {
protected void handleElapsedTimeout() {
// 执行操作X
}
} );
}
}
TickerBehaviour:这个类的action()方法和done()方法在间隔给定的一段时间后重复地执行onTick()抽象方法.一个TickerBehaviour是永远不会结束的.在下面的例子中,操作Y每个十秒钟执行一次:
public class MyAgent extends Agent {
protected void setup() {
addBehaviour(new TickerBehaviour(this, 10000) {
protected void onTick() {
//执行操作Y
}
} );
}
}
4.4"图书交易"系统执行的行为
已经描述了行为的一些基本类型,现在分析一下"图书交易"系统执行了哪些行为.
4.4.1买方Agent的行为
前面已经讲过,买方Agent间歇的向卖方Agent请求要买的书目.为此,需要使用一个TickerBehaviour,每一次(tick)添加一个真正负责向卖方Agent发送请求的行为.因此可以如下修改BookBuyerAgent类的setup()方法:
protected void setup() {
//打印问候语
System.out.println("Hallo! Buyer-agent "+getAID().getName()+" is ready.");
//获取启动参数,以便得到要买的书目名
Object[] args = getArguments();
if (args != null && args.length > 0) {
targetBookTitle = (String) args[0];
System.out.println("Trying to buy "+targetBookTitle);
//添加一个TickerBehaviour负责每分钟调度一个向卖方Agent发送的请求
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
myAgent.addBehaviour(new RequestPerformer());
}
} );
}
else {
//结束Agent
System.out.println("No target book title specified");
doDelete();
}
}
注意:myAgent变量是在Behaviour类中定义的,它指向正在执行这个行为的Agent.事实上RequestPerformer行为是负责向卖方Agent发送购书请求,这将在下面进行讲述.
4.4.2卖方Agent的行为
前面已经讲过,每个卖方Agent都在等待卖方Agent发送来的购书请求,并尽可能的提供服务.买方Agent发送来的请求可以分为两种类型:一种是询问是否有想要购买的书;一种是请求购买图书.因此,可以这样来设计卖方Agent:卖方Agent执行两个循环执行的行为,分别用来处理买方Agent发送来的两种不同类型的请求
收到的请求消息是如何检测到,并被处理的将在下面进行讲述,这里主要是讲述Agent间的通讯问题.除此之外,我们还需要在卖方Agent中增加一个只执行一次的行为.当用户通过GUI向Agent中添加新的书目时,这个行为用来更新卖方Agent的书目列表.下面的代码讲述了BookSellerAgent类是如何执行的(OfferRequestsServer类和PurchaseOrdersServer类的代码将在下面进行讲述):
import jade.core.Agent;
import jade.core.behaviours.*;
import java.util.*;
public class BookSellerAgent extends Agent {
// 书目列表是一个哈希表,把书目名映射到价格
private Hashtable catalogue;
//一个GUI,通过它,用户可以向书目列表中添加新的书目
private BookSellerGui myGui;
// Agent初始化
protected void setup() {
//建立书目列表,它是一个哈希表
catalogue = new Hashtable();
// 建立并显示这个GUI
myGui = new BookSellerGui(this);
myGui.show();
//添加负责处理买方Agent发来的查询信息的行为
addBehaviour(new OfferRequestsServer());
// 添加负责处理买方Agent发来的购书请求的行为
addBehaviour(new PurchaseOrdersServer());
}
// Agent清除
protected void takeDown() {
// 关闭GUI
myGui.dispose();
// 打印Agent结束消息
System.out.println("Seller-agent "+getAID().getName()+" terminating.");
}
/**
当用户向书目向书目列表中添加新书时,将激活下面的方法
*/
public void updateCatalogue(final String title, final int price) {
addBehaviour(new OneShotBehaviour() {
public void action() {
catalogue.put(title, new Integer(price));
}
} );
}
}
BookSellerGUI类就是一个Swing GUI,代码在附录描述.
4.5Agent间通讯-ACLMessage类
JADE提供的最重要的特性就是Agent间的通讯能力,并采用异步通讯传输.每个Agent有一个信箱(mailbox),JADE把其它Agent发送来的信息发送到Agent的信箱中.只要有消息被发送到消息队列中,那么收到的Agent都会得到提示.但是,Agent是否以及合适处理队列中的消息对于程序员来说是透明的.
图4-2
4.5.1发送消息
向其它Agent发送消息,只要填好ACLMessage对象的各个域,然后调用Agent类的send方法即可.比如向一个昵称为"Peter"的Agent发送消息"Today
it's raining"代码如下所示:
ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
msg.addReceiver(new AID("Peter", AID.ISLOCALNAME));
msg.setLanguage("English");
msg.setOntology("Weather-forecast-ontology");
msg.setContent("Today it's raining");
send(msg);
4.5.2"图书交易"系统中的各类消息
在我们的这个"图书交易"实例中,当买方Agent向卖方Agent第一次提出购书请求,即询问是否出售想买的书目时,可以设定消息的类型为CFP(call for
proposal),如果卖方Agent有这本书的话,将发送带有PROPOSE的消息给买方Agent,接着,如果买方Agent决定买Agent
A的书,它将向Agent
A发送带有ACCEPT_PROPOSAL的消息.当然,如果卖方Agent的书目列表中没有买方Agent请求的书目,它将发送一个带有REFUSE的消息.
在买方Agent发送的两种类型的消息中,我们假设消息的内容都是书名.PROPOSE消息必须要带有请求书目的价格.下面是一个建立并发送CFP消息的例子:
// 查询书目的消息
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
for (int i = 0; i 0) {
targetBookTitle = (String) args[0];
System.out.println("Trying to buy "+targetBookTitle);
//添加一个TickerBehaviour,它每分钟调度向卖方Agent发送的请求
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
//更新卖方Agent列表
DFAgentDescription template = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType("book-selling");
template.addServices(sd);
try {
DFAgentDescription[] result = DFService.search(myAgent, template);
sellerAgents = new AID[result.length];
for (int i = 0; i 0) {
//取第一个参数作为书名,并将它强制转化为字符串类型
targetBookTitle = (String) args[0];
//打印"Target book is XX"
System.out.println("Target book is "+targetBookTitle);
//添加一个TickerBehaviour,每分钟调度向卖方主体发送的购书请求
addBehaviour(new TickerBehaviour(this, 60000) {
protected void onTick() {
System.out.println("Trying to buy "+targetBookTitle);
//更新卖方主体列表
//定义买方主体需要的服务类型
DFAgentDescription template = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType("book-selling");
template.addServices(sd);
//搜索买方主体需要的服务
try {
DFAgentDescription[] result = DFService.search(myAgent, template);
//搜索到需要的卖书服务
System.out.println("Found the following seller agents:");
//定义卖方主体列表
sellerAgents = new AID[result.length];
//打印买方主体列表
for (int i = 0; i < result.length; ++i) {
sellerAgents[i] = result[i].getName();
System.out.println(sellerAgents[i].getName());
}
}
catch (FIPAException fe) {
fe.printStackTrace();
}
//向卖方主体发送请求,通过添加RequestPerformer行为
myAgent.addBehaviour(new RequestPerformer());
}
} );
}
//如果参数为空,即没有想买的书目
else {
//结束主体
System.out.println("No target book title specified");
doDelete();
}
}
//执行一些主体清除工作
protected void takeDown() {
//打印主体已经结束的消息
System.out.println("Buyer-agent "+getAID().getName()+" terminating.");
}
 
/**内部类 RequestPerformer.这是买方主体用来向卖方主体请求购书的行为,这个行为要继承Behaviour类
*/
private class RequestPerformer extends Behaviour {
private AID bestSeller; //提供最低价格的主体
private int bestPrice; //最低价
private int repliesCnt = 0; //计数从卖方主体接收到的回应数目的计//数器
private MessageTemplate mt; //用来接收回应信息的模板
private int step = 0;//一个状态变量,用来控制SWITCH语句
public void action() {
switch (step) {
case 0:
//向所有的卖方主体发送带有CFP的消息,询问卖方主体是否有想买//的书目
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
for (int i = 0; i < sellerAgents.length; ++i) {
cfp.addReceiver(sellerAgents[i]);
}
cfp.setContent(targetBookTitle);
cfp.setConversationId("book-trade");
cfp.setReplyWith("cfp"+System.currentTimeMillis()); //一个//唯一值
myAgent.send(cfp);
//建立模板用来接收建议
mt = MessageTemplate.and(
MessageTemplate.MatchConversationId("book-trade"),
MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
step = 1;
break;
case 1:
//从所有的卖方主体接收建议或者拒绝消息
ACLMessage reply = myAgent.receive(mt);
if (reply != null) {
//收到符合模板的回应消息
if (reply.getPerformative() == ACLMessage.PROPOSE) {
//如果是建议,也就是说该主体有需要的书目
//取价格
int price = Integer.parseInt(reply.getContent());
if (bestSeller == null || price = sellerAgents.length) {
//如果已经收到所有的卖方主体发送的回应消息
step = 2;
}
}
//如果没有收到回应消息则阻塞
else {
block();
}
break;
case 2:
//向提供最低价格的卖方主体发送购书请求
//创建ACL消息
ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
order.addReceiver(bestSeller);
order.setContent(targetBookTitle);
order.setConversationId("book-trade");
order.setReplyWith("order"+System.currentTimeMillis());
myAgent.send(order);
//建立合适的模板用来接收卖方主体发送来的回应
mt = MessageTemplate.and(
MessageTemplate.MatchConversationId("book-trade"),
MessageTemplate.MatchInReplyTo(order.getReplyWith()));
step = 3;
break;
case 3:
//接收购书请求的回应
reply = myAgent.receive(mt);
if (reply != null) {
//收到购书请求的回应
if (reply.getPerformative() == ACLMessage.INFORM) {
//成功进行了交易,结束
System.out.println(targetBookTitle+" successfully purchased from agent
"+reply.getSender().getName());
System.out.println("Price = "+bestPrice);
//结束主体
myAgent.doDelete();
}
//如果收到的回应消息不是INFORM,则卖方主体已经把该书出售
else {
System.out.println("Attempt failed: requested book already sold.");
}
step = 4;
}//
//如果没有收到卖方主体发送来的回应消息,则阻塞
else {
block();
}
break;
}
}
//行为的done()方法
public boolean done() {
//收到所有的回应消息,但是没有一个卖方主体可以出售这本书,
if (step == 2 && bestSeller == null) {
//打印购书失败的消息
System.out.println("Attempt failed: "+targetBookTitle+" not available for
sale");
}
//没有任何主体出售该书或者交易成功,则done()方法返回真,//RequestPerformer行为结束
return ((step == 2 && bestSeller == null) || step == 4);
}
} // RequestPerformer类结束
}
(2)用来实现卖方主体GUI的BookSellerGui.java:
代码如下:
package jade.bookTrading;
import jade.core.AID;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class BookSellerGui extends JFrame {
private BookSellerAgent myAgent;
private JTextField titleField, priceField;
BookSellerGui(BookSellerAgent a) {
super(a.getLocalName());
myAgent = a;
JPanel p = new JPanel();
p.setLayout(new GridLayout(2, 2));
p.add(new JLabel("Book title:"));
titleField = new JTextField(15);
p.add(titleField);
p.add(new JLabel("Price:"));
priceField = new JTextField(15);
p.add(priceField);
getContentPane().add(p, BorderLayout.CENTER);
JButton addButton = new JButton("Add");
addButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
String title = titleField.getText().trim();
String price = priceField.getText().trim();
myAgent.updateCatalogue(title, Integer.parseInt(price));
titleField.setText("");
priceField.setText("");
}
catch (Exception e) {
JOptionPane.showMessageDialog(BookSellerGui.this, "Invalid values.
"+e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
} );
p = new JPanel();
p.add(addButton);
getContentPane().add(p, BorderLayout.SOUTH);
//当用户关闭时,结束主体
//用户使用右上角的按钮关闭主体的用户图形界面
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
myAgent.doDelete();
}
} );
setResizable(false);
}
 
public void show() {
pack();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int centerX = (int)screenSize.getWidth() / 2;
int centerY = (int)screenSize.getHeight() / 2;
setLocation(centerX - getWidth() / 2, centerY - getHeight() / 2);
super.show();
}
}
用来实现卖方主体的BookSellerAgent.java:
代码如下:
package jade.bookTrading;
import jade.core.Agent;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import java.util.*;/
public class BookSellerAgent extends Agent {
//代售书目列表,哈希表,把书目映射到价格上
private Hashtable catalogue;
//卖方主体的用户图形界面,通过它用户可以向书目列表添加新的书目
private BookSellerGui myGui;
//主体初始化
protected void setup() {
//创建书目列表
catalogue = new Hashtable();
//创建并显示GUI
myGui = new BookSellerGui(this);
myGui.show();
//在黄页上注册售书服务
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType("book-selling");
sd.setName("JADE-book-trading");
dfd.addServices(sd);
try {
DFService.register(this, dfd);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
 
//添加服务买方主体查询的行为
addBehaviour(new OfferRequestsServer());
//添加处理买方主体购书请求的行为,
addBehaviour(new PurchaseOrdersServer());
}
//主体清除工作
protected void takeDown() {
//从黄页上注销该服务
try {
DFService.deregister(this);
}
catch (FIPAException fe) {
fe.printStackTrace();
}
//关闭GUI
myGui.dispose();
//打印主体已经结束的消息
System.out.println("Seller-agent "+getAID().getName()+" terminating.");
}
/**
下面的函数是在用户想通过GUI向代售书目中添加新书时被激活的
*/
public void updateCatalogue(final String title, final int price) {
addBehaviour(new OneShotBehaviour() {
public void action() {
catalogue.put(title, new Integer(price));
System.out.println(title+" inserted into catalogue. Price = "+price);
}
} );
}
 
/**
内部类OfferRequestsServer.
这个行为是卖方主体用来处理买方主体发送来的查询消息的
如果查询的书目在本地的代售书目中,卖方主体回应一个PROPOSE消息,如果不在,则发送REFUSEIf
*/
private class OfferRequestsServer extends CyclicBehaviour {
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(
ACLMessage.CFP);
ACLMessage msg = myAgent.receive(mt);
if (msg != null) {
// 如果收到CFP消息,则处理
String title = msg.getContent();
ACLMessage reply = msg.createReply();
//读取价格
Integer price = (Integer) catalogue.get(title);
if (price != null) {
// 如果查询的书目在代售书目中,则读取它的价格
reply.setPerformative(ACLMessage.PROPOSE);
reply.setContent(String.valueOf(price.intValue()));
}
else {
//查询的书目不出售
reply.setPerformative(ACLMessage.REFUSE);
reply.setContent("not-available");
}
myAgent.send(reply);
}
else {
block();
}
}
} // OfferRequestsServer结束
 
/**
内部类PurchaseOrdersServer.
这个类用于处理买方主体发送来的购书请求,卖方主体从代售书目列表中删除该书目,并向买方主体发送一个INFORM消息,用于告诉买方主体,交易已经成功的进行了.
*/
private class PurchaseOrdersServer extends CyclicBehaviour {
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(
ACLMessage.ACCEPT_PROPOSAL);
ACLMessage msg = myAgent.receive(mt);
if (msg != null) {
//收到ACCEPT_PROPOSAL消息,并进行处理
String title = msg.getContent();
ACLMessage reply = msg.createReply();
 
Integer price = (Integer) catalogue.remove(title);
if (price != null) {
reply.setPerformative(ACLMessage.INFORM);
System.out.println(title+" sold to agent "+msg.getSender().getName());
}
else {
//请求的书目同时被卖出去了
reply.setPerformative(ACLMessage.FAILURE);
reply.setContent("not-available");
}
myAgent.send(reply);
}
else {
block();
}
}
} // OfferRequestsServer类结束
}
(4)
/**
内部类RequestPerformer.
这个行为是买方Agent用来向卖方Agent发送请求的.
*/
private class RequestPerformer extends Behaviour {
private AID bestSeller; // 提供最优选择(即书价最便宜)的卖方Agent
private int bestPrice; // 最低的价格
private int repliesCnt = 0; // 从卖方Agent收到的回应消息数
private MessageTemplate mt; // 接受消息的模板
private int step = 0; //这是一个状态变量,依据它采取不同的操作
public void action() {
switch (step) {
case 0:
//向所有的卖方Agent发送CFP消息
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
for (int i = 0; i < sellerAgents.length; ++i) {
cfp.addReceiver(sellerAgents[i]);
}
cfp.setContent(targetBookTitle);
cfp.setConversationId("book-trade");
cfp.setReplyWith("cfp"+System.currentTimeMillis());
// Unique value
myAgent.send(cfp);
// 定义消息的模板,以便收到PROPASE类型的消息
mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"),
MessageTemplate.MatchInReplyTo(cfp.getReplyWith()));
step = 1;
break;
case 1:
//接收所有的PROPOSE或REFUSDER类型的消息
ACLMessage reply = myAgent.receive(mt);
if (reply != null) {
// 收到回应消息
if (reply.getPerformative() == ACLMessage.PROPOSE) {
//这是一个供应者
int price = Integer.parseInt(reply.getContent());
//将其转化为整型
if (bestSeller == null || price = sellerAgents.length) {
// 已经收到所有回应信息
step = 2;
}
}
else {
block();
}
break;
case 2:
// 向出价最便宜的售书者发送购买请求
ACLMessage order = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
//以正确的值填充消息的各个域
order.addReceiver(bestSeller);
order.setContent(targetBookTitle);
order.setConversationId("book-trade");
order.setReplyWith("order"+System.currentTimeMillis());
myAgent.send(order);
// 定义合适的消息模板用来接受合适的回应消息
mt = MessageTemplate.and(
MessageTemplate.MatchConversationId("book-trade"),
MessageTemplate.MatchInReplyTo(order.getReplyWith()));
step = 3;
break;
case 3:
// 接受请求购买消息的回应
reply = myAgent.receive(mt);
if (reply != null) {
// 收到请求购买消息的回应
if (reply.getPerformative() == ACLMessage.INFORM) {
//成功购买,此时买方Agent可以结束了
System.out.println(targetBookTitle+" successfully purchased.");
System.out.println("Price = "+bestPrice);
myAgent.doDelete();
}
step = 4;
}
else {
block();
}
break;
}
}
public boolean done() {
return ((step == 2 && bestSeller == null) || step == 4);
}
} //结束
外文资料
1 INTRODUCTION
This programmer's guide is complemented by the administrator's guide and the
HTML documentation available in the directory jade/doc. If and where conflict
arises between what is reported in the HTML documentation and this guide,
preference should be given to the HTML documentation that is updated more
frequently.
JADE (Java Agent Development Framework) is a software development framework
aimed at developing multi-agent systems and applications conforming to FIPA
standards for intelligent agents. It includes two main products: a
FIPA-compliant agent platform and a package to develop Java agents. JADE has
been fully coded in Java and an agent programmer, in order to exploit the
framework, should code his/her agents in Java, following the implementation
guidelines described in this programmer's guide.
This guide supposes the reader to be familiar with the FIPA standards1, at least
with the Agent Management specifications (FIPA no. 23), the Agent Communication
Language, and the ACL Message Structure (FIPA no. 61).
JADE is written in Java language and is made of various Java packages, giving
application programmers both ready-made pieces of functionality and abstract
interfaces for custom, application dependent tasks. Java was the programming
language of choice because of its many attractive features, particularly geared
towards object-oriented programming in distributed heterogeneous environments;
some of these features are Object Serialization, Reflection API and Remote
Method Invocation (RMI).
JADE is composed of the following main packages.
jade.core implements the kernel of the system. It includes the Agent class that
must be extended by application programmers; besides, a Behaviour class
hierarchy is contained in jade.core.behaviours sub-package. Behaviours implement
the tasks, or intentions, of an agent. They are logical activity units that can
be composed in various ways to achieve complex execution patterns and that can
be concurrently executed. Application programmers define agent operations
writing behaviours and agent execution paths interconnecting them.
The jade.lang.acl sub-package is provided to process Agent Communication
Language according to FIPA standard specifications.
The jade.content package contains a set of classes to support user-defined
ontologies and content-languages. A separate tutorial describes how to use the
JADE support to message content. In particular jade.content.lang.sl contains the
SL codec2, both the parser and the encoder.
The jade.domain package contains all those Java classes that represent the Agent
Management entities defined by the FIPA standard, in particular the AMS and DF
agents, that provide life-cycle, white and yellow page services. The subpackage
jade.domain.FIPAAgentManagement contains the FIPA-Agent-Management Ontology and
all the classes representing its concepts. The subpackage
jade.domain.JADEAgentManagement contains, instead, the JADE extensions for
Agent- Management (e.g. for sniffing messages, controlling the life-cycle of
agents, …), including the Ontology and all the classes representing its
concepts. The subpackage jade.domain.introspection contains the concepts used
for the domain of discourse between the JADE tools (e.g. the Sniffer and the
Introspector) and the JADE kernel. The subpackage jade.domain.mobility contains
all concepts used to communicate about mobility.
The jade.gui package contains a set of generic classes useful to create GUIs to
display and edit Agent-Identifiers, Agent Descriptions, ACLMessages, …
The jade.mtp package contains a Java interface that every Message Transport
Protocol should implement in order to be readily integrated with the JADE
framework, and the implementation of a set of these protocols.
jade.proto is the package that contains classes to model standard interaction
protocols (i.e. fipa-request, fipa-query, fipa-contract-net, fipa-subscribe and
soon others defined by FIPA), as well as classes to help application programmers
to create protocols of their own.
The FIPA package contains the IDL module defined by FIPA for IIOP-based message
transport.
Finally, the jade.wrapper package provides wrappers of the JADE higher-level
functionalities that allows the usage of JADE as a library, where external Java
applications launch JADE agents and agent containers (see also section 3.8).
JADE comes bundled with some tools that simplify platform administration and
application development. Each tool is contained in a separate sub-package of
jade.tools. Currently, the following tools are available:
Remote Management Agent, RMA for short, acting as a graphical console for
platform management and control. A first instance of an RMA can be started with
a command line option ("-gui") , but then more than one GUI can be activated.
JADE maintains coherence among multiple RMAs by simply multicasting events to
all of them. Moreover, the RMA console is able to start other JADE tools.
The Dummy Agent is a monitoring and debugging tool, made of a graphical user
interface and an underlying JADE agent. Using the GUI it is possible to compose
ACL messages and send them to other agents; it is also possible to display the
list of all the ACL messages sent or received, completed with timestamp
information in order to allow agent conversation recording and rehearsal.
The Sniffer is an agent that can intercept ACL messages while they are in
flight, and displays them graphically using a notation similar to UML sequence
diagrams. It is useful for debugging your agent societies by observing how they
exchange ACL messages.
The IntrospectorAgent is a very useful tool that allows to monitor the life
cycle of an agent, its exchanged ACL messages and the behaviours in execution.
The SocketProxyAgent is a simple agent, acting as a bidirectional gateway
between a JADE platform and an ordinary TCP/IP connection. ACL messages,
travelling over JADE proprietary transport service, are converted to simple
ASCII strings and sent over a socket connection. Viceversa, ACL messages can be
tunnelled via this TCP/IP connection into the JADE platform. This agent is
useful, e.g. to handle network firewalls or to provide platform interactions
with Java applets within a web browser.
The DF GUI is a complete graphical user interface that is used by the default
Directory Facilitator (DF) of JADE and that can also be used by every other DF
that the user might need. In such a way, the user might create a complex network
of domains and sub-domains of yellow pages. This GUI allows in a simple and
intuitive way to control the knowledge base of a DF, to federate a DF with other
DF's, and to remotely control (register/deregister/modify/search) the knowledge
base of the parent DF's and also the children DF's (implementing the network of
domains and subdomains).
JADE. is a trade mark registered by CSELT3.
2 JADE FEATURES
The following is the list of features that JADE offers to the agent programmer:
- Distributed agent platform. The agent platform can be split among several
hosts (provided they can be connected via RMI). Only one Java application, and
therefore only one Java Virtual Machine, is executed on each host. Agents are
implemented as Java threads and live within Agent Containers that provide the
runtime support to the agent execution.
- Graphical user interface to manage several agents and agent containers from a
remote host.
- Debugging tools to help in developing multi agents applications based on JADE.
- Intra-platform agent mobility, including transfer of both the state and the
code (when necessary) of the agent.
- Support to the execution of multiple, parallel and concurrent agent activities
via the behaviour model. JADE schedules the agent behaviours in a non-preemptive
fashion.
- FIPA-compliant Agent Platform, which includes the AMS (Agent Management
System), the DF (Directory Facilitator), and the ACC (Agent Communication
Channel). All these three components are automatically activated at the agent
platform start-up.
- Many FIPA-compliant DFs can be started at run time in order to implement
multi-domain applications, where a domain is a logical set of agents, whose
services are advertised through a common facilitator. Each DF inherits a GUI and
all the standard capabilities defined by FIPA (i.e. capability of registering,
deregistering, modifying and searching for agent descriptions; and capability of
federating within a network of DF's).
- Efficient transport of ACL messages inside the same agent platform. Infact,
messages are transferred encoded as Java objects, rather than strings, in order
to avoid marshalling and unmarshalling procedures. When crossing platform
boundaries, the message is automatically converted to/from the FIPA compliant
syntax, encoding, and transport protocol. This conversion is transparent to the
agent implementers that only need to deal with Java objects.
- Library of FIPA interaction protocols ready to be used.
- Automatic registration and deregistration of agents with the AMS.
- FIPA-compliant naming service: at start-up agents obtain their GUID (Globally
Unique Identifier) from the platform.
- Support for application-defined content languages and ontologies.
- InProcess Interface to allow external applications to launch autonomous
agents.
3 CREATING MULTI-AGENT SYSTEMS WITH JADE
This chapter describes the JADE classes that support the development of
multi-agent systems. JADE warrants syntactical compliance and, where possible,
semantic compliance with FIPA specifications.
3.1 The Agent Platform
The standard model of an agent platform, as defined by FIPA, is represented in
the following figure.
The Agent Management System (AMS) is the agent who exerts supervisory control
over access to and use of the Agent Platform. Only one AMS will exist in a
single platform. The AMS provides white-page and life-cycle service, maintaining
a directory of agent identifiers (AID) and agent state. Each agent must register
with an AMS in order to get a valid AID.
The Directory Facilitator (DF) is the agent who provides the default yellow page
service in the platform.
The Message Transport System, also called Agent Communication Channel (ACC), is
the software component controlling all the exchange of messages within the
platform, including messages to/from remote platforms.
JADE fully complies with this reference architecture and when a JADE platform is
launched, the AMS and DF are immediately created and the ACC module is set to
allow message communication. The agent platform can be split on several hosts.
Only one Java application, and therefore only one Java Virtual Machine (JVM), is
executed on each host. Each JVM is a basic container of agents that provides a
complete run time environment for agent execution and allows several agents to
concurrently execute on the same host. The main-container, or front-end, is the
agent container where the AMS and DF lives and where the RMI registry, that is
used internally by JADE, is created. The other agent containers, instead,
connect to the main container and provide a complete run-time environment for
the execution of any set of JADE agents.
According to the FIPA specifications, DF and AMS agents communicate by using the
FIPA-SL0 content language, the fipa-agent-management ontology, and the
fiparequest interaction protocol. JADE provides compliant implementations for
all these components:
- the SL-0 content language is implemented by the class
jade.content.lang.sl.SLCodec. Automatic capability of using this language can be
added to any agent by using the method
getContentManager().registerLanguage(SL0Codec.NAME, new SLCodec(0));
- concepts of the ontology (apart from Agent Identifier, implemented by
jade.core.AID) are implemented by classes in the jade.domain.FIPAAgentManagement
package. The FIPAManagementOntology class defines the vocabulary with all the
constant symbols of the ontology. Automatic capability of using this ontology
can be added to any agent by using the fillowing code:
getContentManager().registerOntology(FIPAManagementOntology.NA ME,
FIPAManagementOntology.getInstance());
- finally, the fipa-request interaction protocol is implemented as ready-to-use
behaviours in the package jade.proto.
3.1.1 FIPA-Agent-Management ontology
Every class implementing a concept of the fipa-agent-management ontology is a
simple collection of attributes, with public methods to read and write them,
according to the frame based model that represents FIPA fipa-agent-management
ontology concepts. The following convention has been used. For each attribute of
the class, named attrName and of type attrType, two cases are possible:
1) The attribute type is a single value; then it can be read with attrType
getAttrName() and written with void setAttrName(attrType a), where every call to
setAttrName() overwrites any previous value of the attribute.
2) The attribute type is a set or a sequence of values; then there is an void
addAttrName(attrType a) method to insert a new value and a void
clearAllAttrName() method to remove all the values (the list becomes empty).
Reading is performed by a Iterator getAllAttrName() method that returns an
Iterator object that allows the programmer to walk through the List and cast its
elements to the appropriate type.
Refer to the HTML documentation for a complete list of these classes and their
interface.
3.1.1.1 Basic concepts of the ontology
The package jade.content.onto.basic includes a set of classes that are commonly
part of every ontology, such as Action, TrueProposition, Result, , … The
BasicOntology can be joined to any user-defined ontology as described in section
3.6.
Notice that the Action class should be used to represent actions. It has a
couple of methods to set/get the AID of the actor (i.e. the agent who should
perform the action) and the action itself (e.g. Register/Deregister/Modify).
3.1.2 Simplified API to access DF and AMS services
JADE features described so far allow complete interactions between FIPA system
agents and user defined agents, simply by sending and receiving messages as
defined by the standard.
However, because those interactions have been fully standardized and because
they are very common, the following classes allow to successfully accomplish
this task with a simplified interface.
Two methods are implemented by the class Agent to get the AID of the default DF
and AMS of the platform: getDefaultDF() and getAMS().
3.1.2.1 DFService
jade.domain.DFService implements a set of static methods to communicate with a
standard FIPA DF service (i.e. a yellow pages agent).
It includes methods to request register, deregister, modify and search actions
from a DF. Each of this method has a version with all the needed parameters, and
one with a subset of them where the omitted parameters are given default values.
Notice that these methods block every agent activity until the action is
successfully executed or a jade.domain.FIPAException exception is thrown (e.g.
because a failure message has been received by the DF), that is, until the end
of the conversation. In some cases, instead, it is more convenient to execute
these tasks in a non-blocking way. In these cases a
jade.proto.AchieveREInitiator or jade.proto.SubscriptionInitiator (see 3.5)
should be used in conjunction with the createRequestMessage(),
createSubscriptionMessage(), decodeDone(), decodeResult() and
decodeNotification() methods thatfacilitate the preparation and decoding of
messages to be sent/received to/from the DF. The following piece of code
exemplifies that in the case of an agent subscribing to the default DF.
DFAgentDescription template = // fill the template
AID df = getDefaultDF();
ACLMessage subs = DFService.createSubscriptionMessage(this, df, template, null))
Behaviour b = new SubscriptionInitiator(this, subs) {
protected void handleInform(ACLMessage inform) {
try {
DFAgentDescription[] dfds =
DFService.decodeNotification(inform.getContent());
// do something
}
catch (FIPAException fe) {
fe.printStackTrace();
}
}
};
addBehaviour(b);
3.1.2.2 AMSService
This class is dual of DFService class, accessing services provided by a standard
FIPA
AMS agent and its interface completely corresponds the the DFService one.
Notice that JADE calls automatically the register and deregister methods with
the default AMS respectively before calling setup() method and just after
takeDown() method returns; so there is no need for a normal programmer to call
them.
However, under certain circumstances, a programmer might need to call its
methods. To give some examples: when an agent wishes to register with the AMS of
a remote agent platform, or when an agent wishes to modify its description by
adding a private address to the set of its addresses, …
3.2 The Agent class
The Agent class represents a common base class for user defined agents.
Therefore, from the programmer's point of view, a JADE agent is simply an
instance of a user defined Java class that extends the base Agent class. This
implies the inheritance of features to accomplish basic interactions with the
agent platform (registration, configuration, remote management, …) and a basic
set of methods that can be called to implement the custom behaviour of the agent
(e.g. send/receive messages, use standard interaction protocols, register with
several domains, …).
The computational model of an agent is multitask, where tasks (or behaviours)
are executed concurrently. Each functionality/service provided by an agent
should be implemented as one or more behaviours (refer to section 3.4 for
implementation of behaviours). A scheduler, internal to the base Agent class and
hidden to the programmer, automatically manages the scheduling of behaviours.
3.2.1 Agent life cycle
A JADE agent can be in one of several states, according to Agent Platform Life
Cycle in FIPA specification; these are represented by some constants in Agent
class. The states are:
- AP_INITIATED : the Agent object is built, but hasn't registered itself yet
with the AMS, has neither a name nor an address and cannot communicate with
other agents.
- AP_ACTIVE : the Agent object is registered with the AMS, has a regular name
and address and can access all the various JADE features.
- AP_SUSPENDED : the Agent object is currently stopped. Its internal thread is
suspended and no agent behaviour is being executed.
- AP_WAITING : the Agent object is blocked, waiting for something. Its internal
thread is sleeping on a Java monitor and will wake up when some condition is met
(typically when a message arrives).
- AP_DELETED : the Agent is definitely dead. The internal thread has terminated
its execution and the Agent is no more registered with the AMS.
- AP_TRANSIT: a mobile agent enters this state while it is migrating to the new
location. The system continues to buffer messages that will then be sent to its
new location.
- AP_COPY: this state is internally used by JADE for agent being cloned.
- AP_GONE: this state is internally used by JADE when a mobile agent has
migrated to a new location and has a stable state.
The Agent class provides public methods to perform transitions between the
various states; these methods take their names from a suitable transition in the
Finite State Machine shown in FIPA specification Agent Management. For example,
doWait() method puts the agent into AP_WAITING state from AP_ACTIVE state,
doSuspend()method puts the agent into 12
AP_SUSPENDED state from AP_ACTIVE or AP_WAITING state, … Refer to the HTML
documentation of the Agent class for a complete list of these doXXX() methods.
Notice that an agent is allowed to execute its behaviours (i.e. its tasks) only
when it is in the AP_ACTIVE state. Take care that if any behaviours call the
doWait() method, then the whole agent and all its activities are blocked and not
just the calling behaviour. Instead, the block() method is part of the Behaviour
class in order to allow suspending a single agent behaviour (see section 3.4 for
details on the usage of behaviours).
3.2.1.1 Starting the agent execution
The JADE framework controls the birth of a new agent according to the following
steps: the agent constructor is executed, the agent is given an identifier (see
the HTML documentation for the jade.core.AID class), it is registered with the
AMS, it is put in the AP_ACTIVE state, and finally the setup() method is
executed. According to the FIPA specifications, an agent
identifier has the following attributes:
- a globally unique name. By default JADE composes this name as the
concatenation of the local name – i.e. the agent name provided on the command
line – plus the '@' symbol, plus the home agent platform identifier – i.e. ':'
'/' 'JADE'); Tough in the case that the name of the platform is specified on the
command line the agent name is constructed as a concatenation of the local name
plus the '@' symbol plus the specified platform name.
- a set of agent addresses. Each agent inherits the transport addresses of its
home agent platform;
- a set of resolvers, i.e. white page services with which the agent is
registered.
The setup() method is therefore the point where any application-defined agent
activity starts. The programmer has to implement the setup()method in order to
initialise the agent. When the setup() method is executed, the agent has been
already registered with the AMS and its Agent Platform state is AP_ACTIVE. The
programmer should use this initialisation procedure to:
- (optional) if necessary, modify the data registered with the AMS (see section
3.1.2);
- (optional) set the description of the agent and its provided services and, if
necessary, register the agent with one or more domains, i.e. DFs (see section
3.1.2);
- (necessary) add tasks to the queue of ready tasks using the method
addBehaviour(). These behaviours are scheduled as soon as the setup() method
ends;
The setup() method should add at least one behaviour to the agent. At the end of
the setup() method, JADE automatically executes the first behaviour in the queue
of ready tasks and then switches to the other behaviours in the queue by using a
round-robin non-preemptive scheduler. The addBehaviour(Behaviour) and
removeBehaviour(Behaviour) methods of the Agent class can be used to manage the
task queue.
3.2.1.2 Stopping agent execution
Any behaviour can call the Agent.doDelete() method in order to stop agent
execution.
The Agent.takeDown() method is executed when the agent is about to go to
AP_DELETED state, i.e. it is going to be destroyed. The takeDown() method can be
overridden by the programmers in order to implement any necessary cleanup. When
this method is executed the agent is still registered with the AMS and can
therefore send messages to other agents, but just after the takeDown()method is
completed, the agent will be de-registered and its thread destroyed. The
intended purpose of this method is to perform application specific cleanup
operations, such as de-registering with DF agents.
3.2.2 Inter-agent communication.
The Agent class also provides a set of methods for inter-agent communication.
According to the FIPA specification, agents communicate via asynchronous message
passing, where objects of the ACLMessage class are the exchanged payloads. See
also section 3.3 for a description of the ACLMessage class. Some of the
interaction protocols defined by FIPA are also available as ready-to-use
behaviours that can be scheduled for agent activities; they are part of the
jade.proto package.
The Agent.send() method allows to send an ACLMessage. The value of the receiver
slot holds the list of the receiving agent IDs. The method call is completely
transparent to where the agent resides, i.e. be it local or remote, it is the
platform that takes care of selecting the most appropriate address and transport
mechanism.
3.2.2.1 Accessing the private queue of messages.
The platform puts all the messages received by an agent into the agent's private
queue. By default (since JADE 2.5) the size of this queue is unlimited, however,
in case of limited resources, this default can be changed via the method
setQueueSize().
Several access modes have been implemented in order to get messages from this
private queue:
- The message queue can be accessed in a blocking (using blockingReceive()
method) or non-blocking way (using receive() method). The blocking version must
be used very carefully because it causes the suspension of all the agent
activities and in particular of all its Behaviours. The non-blocking version
returns immediately null when the requested message is not present in the queue;
- both methods can be augmented with a pattern-matching capability where a
parameter is passed that describes the pattern of the requested ACLMessage.
Section
3.3.4 describes the MessageTemplate class;
- the blocking access can have a timeout parameter. It is a long that describes
the maximum number of milliseconds that the agent activity should remain blocked
waiting for the requested message. If the timeout elapses before the message
arrives, the method returns null;
- the two behaviours ReceiverBehaviour and SenderBehaviour can be used to
schedule agent tasks that requires receiving or sending messages.
3.2.3 Agents with a graphical user interface (GUI).
An application, that is structured as a Multi Agent System, still needs to
interact with its users. So, it is often necessary to provide a GUI for at least
some agents in the application. This need raises some problems, though, stemming
from the mismatch between the autonomous nature of agents and the reactive
nature of ordinary graphical user interfaces. When JADE is used, the
thread-per-agent concurrency model of JADE agents must work together with the
Swing concurrency model.
3.2.3.1 Java GUI concurrency model
In a Java Virtual Machine there is a single thread, called Event Dispatcher
Thread, whose task is to continuously pick event objects (i.e. instances of
java.awt.AWTEvent class) from the System Event Queue (which is an instance of
java.awt.EventQueue class). Then the event dispatcher thread, among other
things, calls the various listeners registered with the event source. The
important observation is that all event listeners are executed within a single
thread of control (the event dispatcher); from this follows the well known rule
that the execution time of an event listener should be short (less than 0.1 s)
to ensure interface responsiveness. A very important Swing feature is the
Model/View system to manage GUI updates. When a Swing control has some state (a
JCheckBox has a checked flag, a JList holds elements, etc.), this state is kept
in a Model object (of class DefaultButtonModel, ListModel, etc.). The model
object provides commands to modify the state (e.g. to check or uncheck the
checkbox, to add and remove elements from the list, etc.) and the Swing built-in
notification mechanism updates the visual appearance of the GUI to reflect the
state change. So, a JCheckBox object can change its look in two cases:
An event from the user is received (e.g. a MouseClick event).
Some other part of the program modifies the model object associated with the
JCheckBox.
As stated in the Java Tutorial (JFC/Swing trail, Threads and Swing section), the
Swing framework is not thread-safe, so any code that updates the GUI elements
must be executed within the event dispatcher thread; since modifying a model
object triggers an update of the GUI, it follows from the above that model
objects also have to be manipulated just by the event dispatcher thread. The
Swing framework provides a simple but general way to pass some user defined code
to the Event Dispatcher thread: the SwingUtilities class exposes two static
methods that accept a Runnable object, wrap it with a RunnableEvent and push it
into the System Event Queue. The invokeLater() method puts the Runnable into the
System Event Queue and returns immediately (behaving like an asynchronous
inter-thread call), whereas the invokeAndWait() method puts the Runnable into
the System Event Queue and blocks until the Event Dispatcher thread has
processed the RunnableEvent (behaving like a synchronous inter-thread call).
Moreover, the invokeAndWait() method can catch exceptions thrown within the
Runnable object.
中文翻译
1 介 绍
这个程序员指导有管理员指导作为补充,并且HTML文档保存在jade/doc目录下.如果HTML文档中的内容和这个指导中的内容有冲突的话,应该参照HTML文档中的内容,因为这个文档的更新更频繁.
JADE(Java Agent Development
Framework)是一个软件开发框架,用于开发多agent系统和符合FIPA标准的智能主体应用程序.它包含两个主要的产品:一个符合FIPA标准的agent平台和一个开发JAVA
agent的包.JADE完全是由JAVA编写的.一个agent程序员要是想使用这个框架就必须用JAVA来给他的主体编码,并且,要遵照这个程序员指导中规定的执行方针.
这个指导假设读者熟悉FIPA标准,至少熟悉Agent Management规范(FIPA no.23),Agent通讯语言(ACL)和ACL消息的结构(FIPA
no. 61).
JADE使用JAVA语言编写的,由各种JAVA包组成,它为应用程序员既提供现成的功能片断,同时也为自定义的应用程序任务提供抽象接口.由于JAVA的许多良好的特性,它是一种很特别的编程语言,特别是它在分布式的不同环境中的面向对象编程方法,例如对象序列化(Object
Serialization),反映性API(Reflection API)和远程方法唤醒(Remote Method Invocation RMI).
JADE主要由下面的包组成:
jade.core实现系统的核心.它包含必须被应用程序员继承的Agent类,除此以外,jade.core.behaviours子包还包含一个Behaviour类层次结构.行为实现了一个主体的任务或意图.它们是逻辑活动单元,并且可以以不同的方式组合,以获取不同的执行方式,当然,它们是可以并行执行的.应用程序员定义主体的操作,编写行为以及主体的执行路径.
jade.lang.acl子包用于依照FIPA标准规定处理主体通讯语言(ACL).
jade.content包包含了一组类用于支持用户定义的概念和语言.一个单独的指南描述了JADE对消息内容的支持.特别的,jade.content.lang.sl包包含了SL
编码解码器,既有剖析器,也有编码器.
jade.domain包包含了所有那些由FIPA标准定义的,描述Agent管理实体的JAVA类,特别是AMS和DF主体,它们提供生命周期服务和白黄页服务.子包jade.domain.FIPAAgentManagement包含了FIPA主体管理的概念和描述其概念的类.子包jade.domain.JADEAgentManagement则包含了JADE对Agent管理的扩展(例如,对消息的探测以及控制主体的生命周期),包括概念和所有描述其概念的类.子包jade.domain.introspection包含了用于描述在JADE工具和JADE内核之间沟通领域的概念.子包jade.domain.mobility包含了描述移动通信的概念.
子包Jade.gui包含了一组一般的类,用于建立用户图形界面,用来显示和编辑Agent标识符,Agent描述,ACL消息……
jade.mtp包包含了一个JAVA接口.为了容易用JADE框架集成,每个消息传送协议必须利用这个接口,它还包含了一组这些协议的执行.
jade.proto包包含了建模标准交互协议的类(如:fipa-request, fipa-query, fipa-contract-net,
fipa-subscribe和其他一些被FIPA定义的类),同时也包含了帮助应用程序员建立自定义的协议的类.
FIPA包包含了由FIPA为基于IIOP的消息传送定义的IDL模块.
最后,jade.wrapper包包含了JADE高级功能的包装,这些功能允许把JADE当做一个库,在那里外部JAVA应用启动JADE主体和主体的容器(3.8也有讲述).
JADE还附带了一些用以简化平台管理和应用开发的工具.每个工具包含在jade.tools的单独的子包中.目前,下列工具是可用的:
*远程管理主体(Remote Management Agent,
RMA)简而言之,它起到了一个平台管理和控制的图形控制台的作用.RMA的第一个实例可以用命令行参数"-gui"来启动,但接下来可以激活更多的GUI界面.JADE通过向它们进行多点传送来维持一致性.此外,RMA控制台还能够启动其它的JADE工具.
*哑元主体(Dummy
Agent)是一个监视和调试的工具,由一个图形界面和一个潜在的JADE主体组成.使用用户图形界面,就可以组织ACL消息,把它们发送到其它的主体,还可以显示发送或收到的消息的列表,同时带有时间戳,这样可以允许对主体间对话进行记录和预演.
*嗅探器(Sniffer
Agent)是一个主体,它在ACL消息传递的是时候翻译它们,并用一个类似UML序列图表的符号图形化的显示它们.观察它们是如何交换ACL消息对于调试你的主体群是很有用的.
*内测主体(IntrospectorAgent)是一个非常有用的工具,它允许检测主体的生命周期,交换的ACL消息,以及主体正在执行的行为.
*套接字代理主体(SocketProxyAgent)是一个很简单的主体,它在JADE平台和普通的TCP/IP连接之间起到一个双向门的作用.当ACL消息在JADE传送装置传输的时候,它们被转换成简单的ASCII字符串,然后通过套接字连接传送出去.反之亦然,ACL消息可以通过这个TCP/IP连接传输到JADE平台.这个主体是很有用的,比如负责网络防火墙,或是在浏览器内通过JAVA小程序提供平台交互.
*目录服务用户图形界面(DF
GUI)就是一个用户图形界面,它是由JADE目录服务主体自带的,当然它也可以由用户可能需要的其它目录服务主体使用.通过这种方式,使用者可以建立一个域和子域网络的黄页.这个用户图形界面用一种简单直观的方式来控制一个目录服务的信息,把一个目录服务同其它的目录服务联系起来,并远程控制(注册/注销/修改/搜索)其父目录服务和子目录服务(负责域和子域网络)的信息内容.
2 JADE 特点
下面是JADE提供给agent编程人员的JADE特点列表:
-分布式主体平台.主体平台可以分散在几个主机上(假设它们可以通过RMI连接起来).这样,在每个主机上只有一个JAVA应用程序,当然也只有一个JAVA虚拟机被执行.Agent作为JAVA线程存在于Agent容器中,这个容器对于主体的执行提供了运行时的支持.
-从远方主机用图形用户界面来管理主体和主体容器.
-在开发基于JADE的多agent应用程序时,可以利用调试工具.
-平台内的agent移动性,包括传递agent的状态和代码(当需要的时候).
-通过行为模型,对多个平行,并行的agent活动的支持.JADE以无优先权的方式对agent行为进行调度.
-FIPA标准的Agent平台,包括AMS (主体管理系统),DF (目录服务), 和ACC (主体通讯通道).这三个组成部分在agent平台启动时被自动激活.
-为了多域的应用程序,许多FIPA标准的DF在运行时可以被启动.在程序中,每个域是一组逻辑主体,它们提供的服务通过一个公共的设备被公布出来.每个DF继承了GUI和所有由FIPA定义的标准功能(即,注册,注销,修改,搜索主体标识符的功能和在网内连接DF的功能).
-在同一个主体平台内有效率的ACL消息传输.事实上,消息在传送时是以JAVA对象被编码,而不是字符串,这样是为了避开编组和未编组的程序.当消息跨越平台边界的时候,它们被自动转换为FIPA标准的语法,编码方式,传输协议或反之.这种转换对于主体执行者来说是透明的,它们只需要处理JAVA对象.
-FIPA交互协议库是现成可用的.
-通过AMS,主体可以自动进行注册和注销.
-符合FIPA标准的命名服务:在启动时,主体从平台上获取它们的GUID(全球唯一标识).
-对应用程序定义的相关语言和概念的支持.
-程序内接口,它允许外部应用程序启动自治的主体.
3 用JADE创建多agent系统
这一章描述了用以支持多agent系统开发的JADE类.JADE遵守FIPA标准规定的语法,可能地方也会遵守规定的语义.
3.1 Agent平台
由FIPA定义的标准的主体平台模式由以下几部分组成:
Agent管理系统(AMS)是负责监督管理对Agent平台的访问和使用的主体.在一个单独的平台上,只能有一个AMS.AMS提供白黄页服务,以及生命周期服务,它保留了一个主体标识符目录(AID)和主体状态信息.每个主体必须在AMS注册,以获得一个有效的AID.
目录服务(DF)是在平台上提供默认的黄页服务的主体.
消息传输系统,又叫做Agent通信通道(ACC),是控制平台内所有的信息交换,包括与远端平台进行信息交换的软件.
JADE完全参照这个标准体系结构.因此,当一个JADE平台启动的时候,AMS和DF就自动被建立了,同时ACC模块允许消息进行传输.Agent平台允许建立在几个主机上.在每个主机上只有一个JAVA应用程序,当然也只有一个JAVA虚拟机(JVM)被执行.每个JAVA虚拟机是一个基本的主体容器,它为主体的执行提供一个运行环境,同时它允许几个主体在同一个主机上并行的执行.主容器(main-container)是主体容器,它包括AMS和DF,在那里注册RMI(它由JADE在内部使用).与主容器相关的其它容器,为任何一组JADE主体的执行提供一个完整的运行环境.
根据FIPA的规定,DF和AMS主体必须使用FIPA-SL0语言,FIPA主体管理概念和FIPA请求交互协议进行通讯,JADE对以下组成部分提供符合FIIPA标准的执行方式:
-SL-0语言是由类jade.content.lang.sl.SLCODE执行的.通过下面的方式,可以向任何一个主体添加自动使用这种语言的能力:
getContentManager().registerLanguage(SL0Codec.NAME, newSLCodec(0)).
-定义的概念(除了由jade.core.AID使用的主体标示符)由jade.domain.FIPAAgentManagement包中的类执行.FIPAManagementOntology类定义了存在的词汇以及所有常用的符号.可以通过下面的方法把自动使用它的能力添加到任何一个主体中:getContentManager().registerOntology(FIPAManagementOntology.NAME,FIPAManagementOntology.getInstance())
-最后,FIPA请求交互协议在jade.proto包中作为现成的行为被执行.
3.1.1 FIPA标准的主体管理概念
每个执行fipa-agent-management概念的类都是一个简单的属性的集合,根据基于体现FIPA标准的fipa-agent-management概念的框架模式,可以用公共的方法对它们进行读写.通常使用下面的约定.对类的每个属性,要有属性名和属性类型,可能有两种情况是:
1)属性类型是单值的.那么可以通过attrType getAttrName()方法得到,并通过
void setAttrName(attrType a)来写,每一次对void setAttrName(attrType a)的调用都将覆盖前面的属性值.
2)属性的类型上一组或者一系列值,void addAttrName(attrType a)方法可以用来插入一个新的值,void
clearAllAttrName()方法可以用来删除所有的值.读是通过Iterator类的getAllAttrName()方法实现的,它将返回一个Iterator对象,这个对象允许程序员在List类之间移动,并为它的元素设置合适的类型.
参考HTML文档来获得这些类的列表以及它们的接口.
3.1.1.1定义的基本概念
jade.content.onto.basic包包含了一组类,它们通常是每个定义概念的一部分,比如Action,TrueProposition, Result,
, …BasicOntology可以被添加到任何用户定义的概念中,正如在3.6中所述的.
注意Action类应该可以用来实现行为.它有一对用来设置和获取行动者AID的方法.
3.1.2简化了的,用来访问DF和AMS服务的API
目前定义的JADE特性允许通过发送和接收由标准定义的消息来实现简单的在FIPA系统主体和用户定义的主体间的交互.
但是,因为那些交互已经是标准化的,通用的,下面的类可以成功的通过一个简化的接口完成这个任务.
这两个方法是通过Agent类实现的,它可以获取平台默认的DF和AMS的AID,这两个方法是:getDefaultDF() 和getAMS().
3.1.2.1DF服务
jade.domain.DFService利用一组静态方法来实现与一个标准的FIPA
DF服务进行交互.它包含了从DF请求注册,注销,修改,搜索行为的方法.每个方法都有一个带有所有所需参数的版本,以及一个所有省略参数都是默认值的版本.
注意,这些方法将会阻塞每个主体活动直至行为被成功的执行或者掷出了一个jade.domain.FIPAException违例,也就是说直到会话的结束.在某些情况下,以不阻塞的方式执行这些方法可能会更方便.在这些情况下,jade.proto.AchieveREInitiator
或者jade.proto.SubscriptionInitiator将createRequestMessage(),createSubscriptionMessage(),decodeDone(),
decodeResult()
和decodeNotification()联合使用,这将简化向DF发送消息的准备,以及从DF接受消息时的解码.下面的代码片断示例了主体到默认DF的情况.
DFAgentDescription template = // fill the template
AID df = getDefaultDF();
ACLMessage subs = DFService.createSubscriptionMessage(this, df, template, null))
Behaviour b = new SubscriptionInitiator(this, subs) {
protected void handleInform(ACLMessage inform) {
try {
DFAgentDescription[] dfds =DFService.decodeNotification(inform.getContent());
// do something
}
catch (FIPAException fe) {
fe.printStackTrace();
}
}
};
addBehaviour(b);
 
3.1.2.2 AMS服务
这个类与DFService类是成对的,它的服务是由一个标准的FIPA
AMS主体提供的,并且它的界面是与DFService完全一致的.注意JADE在调用setup()前和takeDown()返回以后分别自动调用注册和注销方法,所以一般的程序员不用去调用它们.但是在某些特定的环境下,程序员可能需要调用它们.举个例子,当一个主体想到远方主体t平台的AMS注册的时候,或这当一个主体希望通过向它的地址组中加入一个私人地址来修改它的描述时……
3.2 Agent类
Agent类是用户自定义主体的公共基类.因此,从程序员的角度看,一个JADE主体仅仅是用户自定义的继承了Agent类的一个实例.这表现了特性的继承性,这种继承行主要体现在主体平台间交互(注册,配置,远程管理),以及用以实现自定义的主体行为的一组基本方法(如收发消息,使用标准交互协议,注册域,...).主体的计算模型是多任务的,任务(或是行为)是并行执行的.每个由主体提供的功能/服务应该作为一个或者多个行为被执行(参考3.4行为的执行).Agent基类内的调度对程序员是透明的,它自动管理行为的调度
3.2.1 Agent生命周期
根据FIPA中的Agent平台生命周期,JADE主体可以处于这几个状态之一,它们在Agent类中用几个常量来表示.这些状态分别是:
-初始状态AP_INITIATED:Agent对象已经建立,但是还没有由AMS注册,既没有名字,也没有地址,而且不能与其它主体进行通讯.
-激活状态AP_ACTIVE:Agent对象已经由AMS注册,有正规的名字和地址,而且具有JADE的各种特性.
-挂起状态AP_SUSPENDED:Agent对象当前被停止.内部的线程被挂起,没有主体行为被执行.
-等待状态AP_WAITING:Agent对象被阻塞,等待其它事件.内部的线程在JAVA 监控器上休眠,当条件满足时被唤醒(典型的情形是消息到达).
-删除状态AP_DELETED:Agent死亡.内部的线程的执行被终结,Agent不再在AMS上有注册信息.
-传送状态AP_TRANSIT:移动主体移动至一个新的位置时进入这个状态.系统继续缓存将被送到这个新位置的消息.
-拷贝状态AP_COPY:这是JADE在主体克隆时的一个内部状态.
-离开状态AP_GONE:这是JADE在移动主体t移至一个新的地点时的一个内部稳定状态.
Agent类提供了公共方法用于这些状态间的转换.FIPA说明"Agent
管理"中定义了一个有穷自动机,而这些方法就是从这个自动机的转换状态中命名的.如,doWait()把主体从激活状态转变为等待状态.doSuspend()把主体从激活状态或等待状态转变为挂起状态...
doXXX()方法的全部列表可以参见Agent类的HTML文档.
注意agent只有在激活状态时才允许执行行为(也就是任务).注意如果任何一个行为调用doWait()方法,那么整个主体及其所有的活动都被阻塞,而不仅仅是调用这个方法的行为.而block()方法是Behaviour类的一部分,这是为了挂起一个单独的主体行为(详见3.4).
3.2.1.1启动主体执行
JADE框架遵循以下步骤控制一个新的主体的产生:运行主体构造器,给主体一个标识符(参见jade.core.AID的HTML文档),它由AMS注册,置为激活状态,最后执行setup().根据FIPA说明,主体标识符有如下属性:
- 一个全球唯一的名字.JADE默认的方式是:本地名字,即命令行上提供的主体名,加上"@"符号,再加上主体平台标识符(即 ':' '/'
'JADE').虽然有时平台名在命令行列出,但是主体名仍然是本地名加上"@",再加上具体的平台名.
- 一组主体地址.每个主体继承了它本地主体平台的传输地址.
- 一组解析器,也就是主体进行注册的白页服务.
因此setup()方法是任何应用程序定义的主体活动启动的起始点.程序员为了初始化一个主体必须执行setup()方法.当setup()方法执行时,主体已经由AMS注册,并且Agent平台的状态是激活状态.程序员应该使用这个初始化过程来:
-(可选)必要时,修改AMS注册的信息(见3.1.2节);
-(可选)设置主体的描述信息和它所提供的服务.必要时向一个或者更多的域,即DF,注册该主体.(参见3.1.2节).
-(必须)使用addBehavior()方法把任务添加到就绪任务队列.setup()方法运行一结束,这些行为就会被调度.
Setup()方法应该至少添加一个行为到主体中.在setup()方法结束时,JADE自动执行就绪任务队列中的第一个行为,然后按照无优先权的时间片轮转法切换到队列中的其它任务.Agent类的addBehavior(行为)方法和removeBehavior(行为)方法用于管理任务队列.
3.2.1.2停止agent执行
任何行为都可以调用Agent.doDelete()方法来停止一个主体的执行.
当主体将要转变为删除状态时,也就是将被删除时,执行Agent.takeDown()方法.程序员在执行必要的清除时,可以重载takeDown()方法.当takeDown()方法执行时,主体仍然是在AMS注册过的,因此能够向其它主体发送消息,但是在takeDown()方法执行完毕的时候,主体将不再是注册过的,并且它的线程将被撤销.这个方法的主要作用是执行程序特定的清除操作,比如在DF主体注销某个主体.
3.2.2 主体内的通讯
Agent类同样提供了一组用于主体内通讯的方法.根据FIPA说明,主体通过异步消息传输进行通讯,ACL消息的对象是交换的有效载荷.ACLmessage类的描述详间3.3节.一些由FIPA定义的交互协议也是可由主体活动调度的现成可用的行为,它们是jade.proto包的一部分.
Agent.send()方法可以发送ACL消息.接收槽保留了正在接收消息的主体的ID.这种方法调用对于主体的位置来说是透明的,也就是说无论是本地或是远程的主体,是平台负责选择最合适的地址和传输机制.
3.2.2.1访问私有消息队列
平台把主体接收到的所有消息放到主体的私有消息队列.(从JADE2.5起)消息队列的默认长度是无限的,但是在资源有限的情况下,可以通过setQueueSize()方法来改变这个默认值.有几种访问模式用以从这个消息队列获取消息:
-消息队列可以以阻塞(调用blockingReceive()方法)和非阻塞方式(调用receive()方法)进行访问.必须小心的使用阻塞方式
,因为它回引起所有主体活动的挂起,特别是它所有的任务将会被挂起.在非阻塞方式,当请求的消息不在队列时,将立即返回空.
-这两种方式都可以扩展成具有模式匹配的能力,此时,必须传递一个描述了请求的ACLMessage的模式的参数.3.3.4节描述了MessageTemplate类.
-阻塞方式的访问可以有一个时间域值作为参数,它是长型的整数,它描述了主体在等待请求的消息时保持阻塞状态的最大毫秒数.如果在消息到达前时间域值到了,该方法将自动返回空值.
-可以通过ReceiverBehaviour和SenderBehaviour两种方法来调度主体用来请求接收或发送消息的行为.
3.2.3带有图形用户界面(GUI)的主体
一个构造为多Agent系统的应用程序仍然需要与它的用户进行交互.因此,在应用程序中有必要至少在某些主体上提供GUI.虽然这可能引起一些问题,这主要是因为主体自治特性和普通用户图形界面的反映性间的不匹配造成的.使用JADE时,JADE主体采用的每个主体一个线程的并发模式必须要与Swing并发机制配合使用.
3.2.3.1 Java GUI并发模式
在Java虚拟机中有一个单独的线程,叫做事件发报线程(Event Dispatcher
Thread),它的任务就是不断地从系统事件队列(它是java.awt.EventQueue类的一个实例)中选出事件对象(也就是java.awt.AWTEvent类的实例).接着事件发报线程调用在事件源注册过的各个收听者.一个重要的观察结果是所有的事件收听者都是在一个单独的控制线程内执行的,还有一个明显的规则是事件收听者的执行时间应该较短,这样可以保证界面的响应.一个很重要的Swing特性是管理GUI更新的模型/视图系统.当一个Swing控制处于某个状态时(jCheckBox有一个检测标记,jList持有元素,等),这个状态保存在Model对象中.Model对象提供修改状态(如,检查或是反检查checkbox,或是从列表中添加或删除元素等)的命令,并且Swing固定的通告机制能够更新GUI的可视化界面来反映状态的改变.因此,一个JCheckBox对象能够在下面两种情况下改变它的外观:
*接收到用户的事件(如,点击鼠标)
*程序的其它部分修改了与jCheckBox相关的模型对象.
正如在Java
Tutorial中所述,Swing结构不是线程安全的,因此任何更新GUI元素的代码都必须在事件发报线程内执行.既然修改一个模型对象将触发GUI的一次更新,由上面可以得知,模型对象也只能由事件发报线程操控.Swing结构提供了一个简单但是通用的方法向事件发报线程传递某些用户定义的代码:SwingUtilities类提供两个接收Runnable对象的静态方法,这两个静态方法把类封装在可运行事件(RunnableEvent)中并把他们放入系统事件队列.invokeLater()方法把Runnable放至系统事件队列中并立即返回(如同一次异步线程内调用),然而
invokeAndWait()方法把Runnable放入系统事件队列并阻塞直至事件发报线程处理(如同一次同步线程内调用
 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值