当前位置:文档之家› 学习agent必备!最全的JADE程序员指南

学习agent必备!最全的JADE程序员指南

学习agent必备!最全的JADE程序员指南
学习agent必备!最全的JADE程序员指南

JADE程序员指导

Jade集成开发环境是一个入门级的产品,但是它仍然拥有强大的功能。它提供的用户图形界面包含了大部分SUN SDK工具,可以方便的编辑源代码,生成一个类,执行一个java程序或java applet. Jade提供的高效率的功能可以让你为每个project生成单独的类模板,这个功能包括生成使用AWT或Swing APIs对话窗口。Jade可以使用Sure shot的Jive Lint支持静态代码检查,同时也提供了入门级的调试功能。新版本提供了如下功能:允许用户在XML 编辑器中调用用户提供的函数;方法定位(method location)采用了树形视图。

1简介

程序员指南由管理员指南作为补充,在jade/doc目录下可以找到可用的HTML文档。如果本指南和HTML文档之间哪里出现了冲突,以经常更新的HTML文档为准。

JADE(Java Agent Development Framework)是一个软件开发框架,它可以为智能AGENT 开发多AGENT系统和遵守FIAP协议的应用程序。它包含两个主要的产品:一个是与FIPA 相适应的agent平台,另一个是开发Java agents的包。JADE是完全用JA V A编码的,如果agent程序员想探索本框架,他/她的agents就应该按照这个程序员指南中描述的大纲用Java 编码。

这个指南是在假设读者熟悉FIPA标准,至少是熟悉Agent Management specifications(FIPA no.23),Agent Communication Language和ACL Message Structure(FIPA no.61)的基础上编写的

JADE是用JA V A写的由各种JA V A包构成,给程序设计者以完备的功能接口和规范的抽象性界面,具体应用取决与任务。选择JA V A语言是因为它有许多独特的特点,尤其是在分布式异质环境下的面向对象的编程连接方式;这些特点还包括Object Serialization,Reflection API和Remote Method Invocation(RMI)。

JADE由如下的包构成:

Jade.core-执行系统核心问题,包括必须由软件程序员扩展的Agent类,除此之外一个行为类包含在jade.core.behaviours子包内。行为执行agent的任务或目的。它们是可以完成不同复杂任务或并行任务的逻辑行为单元。程序员编写行为定义agent的操作,并相互连接他们定义agent执行路径。

https://www.doczj.com/doc/5c7387067.html,ng.acl子包用来根据FIAP标准规范处理ACL的。

jade.content子包包含了一系列支持用户定义的本体和内容语言的类。单独有一个指南描述如何使用JADE支持消息内容。尤其是https://www.doczj.com/doc/5c7387067.html,ng.sl包含了SL编码解码器,包含有皮剖析器和解码器。

jade.domainb包:包含了FIPA标准定义的表示Agent管理实体的所有Java类,特别是AMS agents和DF agents,提供生命周期服务,白页和黄页服务。子包jade.domain.FIPAAgentManagemnt包含FIPA-Agent-Management Ontology和所有表示它的概念的类。而子包jade.domain.JADEAgentManagemnt包含JADE的Agent管理的扩展名(比如,为sniffing messages,controlling the life-cycle of agents,…),包括本体和表示它的概念所有类。子包jade.domain.introspection包含用于JADE工具(比如,sniffer和Introspector)间引用域和JADE核心的概念。子包jade.domain.mobility包含用于移动通信的概念。jade.gui包:包含了一系列有助于创建GUIs的普通类,用于显示和编辑Agent-Identifiers,Agent Descriptions,ACLMessages,…

jade.mtp包:包含一个为容易地与JADE框架整合,每一个MTP都应该执行的Java接口,

和一系列这些协议的实现。

jade.proto包:包含模拟标准交互协议(例如:fipa-request, fipa-query, fipa-contract-net, fipa-subscribe和由FIPA定义的其它一些协议)的类,和帮助程序员创建他们自己的协议的类。

FIPA包包含由FIPA为基于IIOP的消息传输定义的IDL模块。

最后,jade.wrapper包提供JADE高层次封装功能,这可以将JADE的用法作为库,从而使外部的Java程序启动JADE agents和agent容器(见3.8节)。

JADE还包括一些工具,用来简化平添管理和应用开发。每个工具包含在jade.tools的一个单独的包内。目前,以下工具是可用的:

Remote Management Agent(RMA):作为平台管理和控制的图形控制台。第一个RMA实例可以通过命令行选项(“-gui”)来启动,但是以后可以激活多个GUI。通过简单的用多台调频发射机向所有RMAs播送一个事件,JADE在多RMAs保持一致性。而且,RMA控制台能启动其它JADE工具。

Dummy Agent:是一个监控和调试工具,由图形用户界面和潜在的JADE agent构成。用GUI 可能写出ACL消息,并将消息发送给其他agents;也可能显示所有发送或接收到的ACL消息,以及为了便于agent通话记录和复述的时间戳信息。

Sniffer:是一个在ACL消息传输时可以截取ACL消息,并用类似与UML程序表的符号将消息图形式显示的agent。它有助于通过观察agents如何交换ACL消息来调试你的agent社会。

Introspector:可以监控agent生命周期,它交换的ACL消息和执行的行为的agent。

DF GUI:是一个完全的图形用户界面,被默认的JADE DF使用,也可以被其它每一个用户可能需要的DF使用。以这种方式,用户可能创黄页域和子域的复杂网络。GUI可以用简单直觉的方式控制DF的知识库,使DF和其它DF联合,和远程控制(注册/注销/修改/搜索)DF父亲DF和孩子DF的知识库(执行域和子域网络)。

LogManagerAgent:允许在运行时设置日志信息,如日志水平,对于用Java日志的JADE和程序应用的特殊类来说。

SocketProxyAgent:是一个普通的agent,作为JADE平台和普通TCP/IP连接间的双向通道。仔细考虑JADE所有的传输服务,ACL消息被转换成简单的ASCII字符串并通过套接字连接传输。反过来,ACL消息可以通过TCP/IP连接到JADE平台传送。这个agent是有用的,例如,处理网络防火墙或在Web浏览器中提供与Java applets交互的平台。

JADE TM是一个由CSELT3注册的商标。

JADE由五部分组成:混淆器、加密器、封装器、类编辑器和输出工具。

混淆器能够保护软件使之不被反编译。它通过混淆类文件使得反编译无效,并把敏感的名字指代变成另一个名字空间,这样可以使反编译的结果毫无疑义。混淆器有“完全”和“快速”两种选项,能处理任何Java产品包括API,应用程序和小程序。它遵从Java虚拟机规范。

加密器隐藏和加密用户产品的主类,处理的结果是一个类文件。它为编码和反编码提供了一个界面。JADE有一些类用DES完成这个界面。加密和解密的过程对于用户来说是透明的。用户感觉不到使用原始的主类和使用处理后的结果类有什么不同。当然,用户也可以不加密地处理这些主类和产品。

封装器不仅仅处理类文件,它还隐藏和加密在产品根目录下的其它文件。它封装产品并只产生一个类。软件厂商把这个类销售给用户,用户将运行这个类文件,安装买来的软件。封装

器使用和加密器相同的安全类。

对于高级Java开发人员,JADE还提供了一个叫做“类编辑器”的工具。它能够直接修改类的代码字节。类编辑器也是一个独立的应用程序,它将把所有的结果生成到jar格式的的文件里。

输出工具把所有的结果生成到一个jar格式的文件中,这个文件能够被其它的压缩工具如Unzip, Winzip和Jar处理。

JADE是由上面的工具集成起来的应用程序,它由纯Java语言编写。这些应用既能够在命令行下运行,也可以在图形界面环境下交互使用。用户可以分别使用这些功能,也可以按下图中的序列运行一组特征。JADE允许用户把配置参数存到一个文本文件里,并可以编辑它。这样,下一次只要装入该配置文件就可以在相同的参数下运行了。

2 JADE的特征

下面是JADE为agent程序员提供的特征列表:

●分布式的agent平台:agent平台可以分布在许多主机之中(假设他们通过RMI连接)。

在每台主机上只有一个Java应用程序,因此也就只有一个Java虚拟机运行。Agents 以Java的思路执行,存在于Agent容器中,agent容易为在运行时为agent执行提供支持。

●图形用户界面:从远程主机来管理若干agents和agents容器。

●调试工具:帮助开发基于JADE的多agents软件程序。

●通过行为模型支持agent活动的多重、平行和并行执行。JADE以非优先权的方式安排

agent的行为。

●遵循FIPA的agent平台:它包括AMS、DF和ACC。所有这三个组成都在agent平台

启动时自动激活。

●许多遵循FIPA的DFs可以在运行时启动以执行多域程序,一个域是指一系列逻辑

agents,它们的服务通过一个共同的facilitator发布。每个DF继承一个GUI和所有由FIPA定义的标准能力(例如,注册,注销,修改和搜索agent描述的能力,DF网络内联盟的能力)。

●在同一个agent平台内有效传输ACL消息。事实上,消息被编译成Java对象而不是字

符串的形式进行传输,以避免集结或未编组的程序。当跨越平台边界时,消息自动转换成/自基于FIPA语法、编码和传输协议。这种转换对只需要处理Java对象的agent的执行者是很明显的。

●备用的FIPA交互协议库。

●Agent在AMS上的自动注册和注销。

●遵循FIPA的命名服务:在启动agents时从平台上获取它们的GUID(Globally Unique

Identifier)。

●支持程序定义的内容语言和本体。

●InProcess接口允许外部程序启动自治agents。

3 用JADE创建多agent系统

本章描述支持多agent系统开发的JADE类。JADE遵循句法规则,有写地方遵循FIPA规范的语法

3.1代理平台

FIPA定义的一个agent平台的标准模型,如下图所示:

AMS是管理控制进出和使用AP的agent。一个平台上只能有一个AMS。它提供百页和生命周期服务,维护AID目录和agent状态。为了获得有效的AID,每个agent都必须在AMS 上注册。

DF是平台上提供默认黄页服务的agent。

消息传输系统也叫agent通信通道(ACC),由软件构成在平台内负责所有的消息交换,包括来自或发送到远程平台的消息。

JADE完全遵守这个参考架构,当一个JADE平台被启动,AMS和DF立刻被创建,ACC 模块也设置为允许消息通信。Agent平台可以分布在不同的主机上。但一台主机上只能有一个应用程序即一个JA V A虚拟机运行。每个JVM是一个基本的agents容器,它为agent的执行提供完全运行时环境,并允许若干agents在同一台主机上并行执行。创建主容器或front-end,它是AMS和DF存在以及RMI注册的agent容器,被JADE内部使用。其它agent 容器与主容器相连,为任何JADE agents的执行提供完全运行时环境。

根据FIPA规范,DF和AMS agents通信使用FIPA-SL0内容语言,fipa-agent-management 本体,fipa-request交互协议。JADE为所有这些部分提供编译执行:

●SL0内容语言是由https://www.doczj.com/doc/5c7387067.html,ng.sl.SLCodec类执行的,使用此语言的自动功能可以

用getContentManager().registerLanguage(new SLCodec(0))方法添加到任何agent。

●本体概念(除了jade.core.AID执行的AID)被jade.domain.FIPAAgentManagement包中

类执行。FIPAManagementOntology类定义了与本体符号一致的词汇。用下面的代码使用本体的自动能力可以添加到任何agent:

●最后,fipa-request交互协议作为ready-to-use行为执行,存在于jade.proto包内。

3.1.1FIPA-Agent-Management本体

每一个使用fipa-agent-management本体的类都是一个简单的属性集合,根据基于表示FIPA 的fipa-agent-management本体概念的模型框架,用公共方法读写它们。使用下面的规定:为类的每个属性的attrName命名和attrType指明类型,有两种可能的情况:

1)属性类型是一个单一值,则它们由attrType getAttrName()读取,由void setAttrName (attrType a)写入,每次调用setAttrName()后的执行结果将重写以前的属性值。

2)属性类型是一系列的值,则用void addAttrName(attrType a)方法插入一个新值,

void clearAllAttrName()方法移除所有的值(列表变为空)。读取则用返回Iterator对象的Iterator getAllAttrName()方法,允许程序员查看列表并将列表元素设置合适的类型。

参考HTML文档查看这些类和它们的接口的完整列表。

3.1.1.1本体的基本概念

包jade.content.onto.basic之中包含一系列类,它们是每个本体的通用部分,如Action, TrueProposition, Result, , …正如3.6节所讲的BasicOntology可以加入任何用户定义的本体。

注意:Action类被用于表示行为。它有一对方法来set/get行为者的AID(如应该表现行为的agent)和行为本身(如注册/注销/修改)。

3.1.2 简化API以访问DF和AMS服务

目前为止描述的JADE特征允许FIPA系统agents和用户定义agents之间通过简单的发送和接收由标准定义的消息进行交互。

然而,因为那些交互被充分的标准化,因为它们非常一般,下面的类可以用简化的接口成功完成这一任务。

Agent类用两种方法得到平台默认DF和AMS的AID:getDefaultDF()和getAMS()。

3.1.2.1DF服务

jade.domain.DFService执行了一系列与标准FIPA DF服务通信的静态方法(如黄页agent)。它包括的方法有:从DF请求注册,注销,修改和搜索行为。这种方法的每个版本带有所有需要的参数,以及它们的子集,省略的参数以缺省值填充。

注意:这些方法block每一个agent活动直到该活动成功执行或抛出一个jade.domain.FIPAException异常(如因为DF接收到一个failure消息),即直到对话结束。另外,有一些情况,以non-blocking方式执行这些任务更方便。在这些情况下,应该用jade.proto.AchieveREInitiator或jade.proto.SubscriptionInitiator(见 3.4.12节)关联createRequestMessage(), createSubscriptionMessage(), decodeDone(), decodeResult()和DecodeNotification()方法,以方便到/从DF发送/接收的消息的准备和解码。下面这段代码解释了agent与默认的DF协商的情况:

基本的DF语句:

3.1.2.2AMS服务

这个类是DFService的二重类,访问由标准的FIPA AMSagent提供的服务,它的接口完全相当于一个DFService接口。

注意:在分别调用setup()方法前和takeDown()方法后,JADE用默认的AMS自动调用注册和注消方法,所以对一般程序员来说不需要调用它们。

然而,在某些情况下,程序员可能需要调用它的方法。例如:当一个agent想在远程agent 平台的AMS上注册时,或者当一个agent想通过添加私有地址到它的地址序列从而修改它的描述时,…

3.2 agent类

Agent类对用户定义的agents来说表示一个通用的基本类。因此,从程序员观点来说,JADE agent简单地说就是一个从基本Agent类扩展来的用户定义的Java类的实例。这就意味着对

在agent平台上完成基本交互的特征(注册、配置、远程管理、…)和可以被调用执行agent 规定的行为的一系列基本方法(如send/receive message, use standard interaction protocols, register with several domains,…)的继承。

Agent的计算模型是多任务的,任务(或行为)是并发执行的。Agent提供的每项功能/服务应该作为一个或多个行为执行(参考3.4节行为执行)。调度程序对基本agent类是内部的,而对程序员来说是隐藏的,自动管理行为的调度。

3.2.1agent的生命周期

根据FIAP规范中的AP生命周期理论,JADE agent可以处于若干状态中的一种,如图3所示,下面将详细介绍:

●创建:创建agent对象,但没有在AMS上注册,也没有名字和地址,不能其它agents

通信。

●活动:agent对象在AMS上注册,有一个合格的名字和地址,可以访问所有JADE特征。

●挂起:agent对象当前被停止。它的内部线程被暂停,没有agent行为被执行。

●等待:agent对象被阻塞,等待什么。它的内部线程处于睡眠状态,当一些条件满足时

被唤醒(典型地是消息到达)。

●删除:agent明确地死亡。内部线程终止它的执行,agents不再注册在AMS上。

●转移:当移动agent向新的地址迁移时进入这个状态。系统连续缓存消息,之后将发往

它的新的地址。

Agent类提供公共方法使其在各种状态间转换,这些方法从FIPA规范agent管理中的有限状态机(the Finite State Machine)内的适当的转换中获取它们的名字。

例如,doWait()方法把agent从活动的状态转变为等待状态,doSuspend()方法把agent 从活动或等待状态转变为挂起状态,…参考agent类的HTML文档,它提供这些doXXX()方法的完整列表。

注意:只有在活动状态下,代理才能执行它的行为(即它的任务)。小心:如果任何一个行为调用doWait()方法,那么整个agent和它的所有活动都将被阻塞,而不仅仅是调用该方法的行为。block()方法是Behaviour类的一部分,它允许单个agent行为挂起(详见3.4节的行为用法)。

3.2.1.1启动agent执行

JADE框架根据一下步骤控制新的agent的诞生:执行agent构造器,给agent赋一个标识符(见jade.core.AID类的HTML文档),在AMS上注册,进入活动状态,最后执行setup()方法。根据FIPA规范,agent标识符有一下属性:

●一个全局唯一的名字。默认情况下由JADE用本地名字串联组成——例如,命令行提供

的agent名字加上“@”,再加上本地AP标识符——例如’:’ ’/’ ‘JADE’);还有一种情况在命令行说明平台名字,本地名字加上‘@’加上规定的平台名字串联组成agent名字。

●一系列agent地址。每个agent继承本地agent平台的传输地址。

●一系列解释器,例如agent注册用的白页服务。

setup()方法是应用程序定义的agent活动开始的点。程序员要想初始化agent,必须执行setup()方法。setup()方法执行后,agent就已在AMS上注册,它的AP状态处于活动状态。程序员应该用以下初始化程序:

—(可选的)如果需要,修改AMS注册数据(见3.1.2)

—(可选的)如果需要,设置agent的描述和它提供的服务,以及在一个或多个域注册agent,比如DFs(见3.1.2)

—(必选的)用addBehaviour()方法添加任务到准备好的任务队列。

一旦setup()方法结束,就安排这些行为。

setup()方法给agent至少添加一个行为。setup()方法结束后,JADE自动执行准备好的任务队列中的第一个行为,然后用无优先的循环调度方法切换到队列中的其它行为。Agent类的addBehaviour(Behaviour)和removeBehaviour(Behaviour)方法可以用于管理任务队列。

3.2.1.2停止agent执行

任何行为都可以调用Agent.doDelete()方法来停止agent运行。

当agent将要进入DELETED状态时,运行Agent.takeDown()方法,例如agent被销毁的时候。takeDown()方法可以被程序员重写以执行任何必要的清理。当这个方法执行的时候,agent仍然注册在AMS上,从而可以给其它agents发送消息,但是takeDown()方法完成后,agent将注销,它的线程也将被销毁。这个方法想要的目的的执行程序指定的清除操作,如DF agents上的注销。

3.2.2 agents间通信

Agent类也提供一系列agents间通信的方法。根据FIPA规范,agents通过异步消息传输通信,ACLMessage类的对象是交换的有效载荷。也可以参见3.3节对ACLMessage类的描述。FIPA定义的一些交互协议如ready-to-use行为一样可以为agent活动指定;它们是jade.proto 包的一部分。

Agent.send()方法允许发送ACLMessage。receiver字段的值表明接收anget的IDs列表。该方法在agent所在的地方是完全透明的,比如作为本地的或远程的agent,平台认真选择的最合适的地址和传输机制。

3.2.2.1访问私有消息队列

平台通过一个agent将所有收到的消息加入agent私有队列。(从JADE2.5开始)队列的默认

规模是无限制的,但是,有限资源的事情下,可以通过setQueueSize()方法改变缺省值。

可以通过若干中访问模式从这个私有队列中得到消息:

—可以以控制(使用blockingReceive()方法)或非控制方式(用receive()方法)访问消息队列。必须慎用控制方式,因为它会引起所有agent活动挂起,尤其是它所有的行为。当队列中没有请求消息时,非控制方式立刻返回null。

—两种方法都可以通过pattern-matching能力扩展,传入一个描述请求的ACLMessage的方式的参数。3.3.4描述的MessageTemplate类。

—控制访问可以有一个时间间隔参数。它是长整型的,用来描述为请求消息agent活动应该保持控制等待状态的最大毫秒数。如果消息到达前超过了间隔时间,该方法返回null。—两个行为ReceiverBehaviour和SenderBehaviour可以用来安排请求接收或发送消息的agent 任务。

3.2.3 图形交互界面agent

一个构建多agent系统的应用程序仍然需要与用户交互。所以,有必要提供GUI,至少是为程序中的一些agents提供。这一需要仍引发了一些问题,是由agent的自治属性和普通GUI 的反作用属性之间的不匹配引发的。这些是JADE需要提高一些问题。当JADE被使用,JADE agents的thread-per-agent并行模型必须和Swing并行模型一起工作。

3.2.3.1 Java GUI并行模型

在一个JA V A虚拟机上有一个单一线程,成为Event Dispatcher Thread,它的任务是从System Event Queue(它是java.awt.EventQueue类的一个实例)中连续选择事件对象(比如:java.awt.AWTEvent类的实例)。然后其它事情中的事件调度线程,调用各种注册到事件资源的监听者。重要观察的是所有的事件监听者都在一个单一的控制线程(the event dispatcher)中执行;因为这遵循已知的规则,所以每个事件监听者的执行时间应该缩短(小于0.1s)以确保界面响应。一个重要的Swing特征是Model/View系统来管理GUI更新。Swing控制器有某种状态(JCheckBox有checked标识,JList持有元素,等等),这状态保存在Model对象(DefaultButtonModel类,ListModel类,等)中。model类提供修改状态的命令(比如,检测或不检测checkbox,list中添加或去除元素,等),并且Swing建立了告知机制,更新可见的GUI的外观以反映状态的改变。所以JCheckBox对象可以在两种情况下改变它的外观:

●从用户接收到事件(如,一个MouseClick事件)

●程序中的其它部分改变了和JChecBox相关的model对象

正如在JA V A指南(JFC/Swing trail、Threads和Swing部分)里指出的一样,Swing框架不是线程安全的,因此任何更新GUI元素的代码必须在事件调度线程之内执行;因为改变一个model对象会引发GUI的更新,所以按照上面所说的,model对象也必须由事件调度线程来控制。Swing框架提供了一个简单但通用的方式将一些用户定义的代码传给Event Dispatcher thread:SwingUtilities类包含了两个静态方法,接受Runnable对象,用RunnableEvent将其封装,并把它放到System Event Queue中。invokeLater()方法把Runnable 放入System Event Queue中,并立即返回(此行为类似于异步交互线程调用),而invokeAndWait()方法把Runnable放入System Event Queue中,就休眠直到Event Dispatcher thread处理了RunnableEvent(此行为类似于同步交互线程调用)。而且,invokeAndWait()方法可以捕获由Runnable对象抛出的异常。

3.2.3.2为响应一个GUI事件做一次ACL信息交换

当一个agent被给一个GUI时,则因为用户的动作,要求该agent发送一个消息(例如,用

户点击了pushbutton)。ActionListener按钮将在事件调度线程之内运行,而Agent.send()方法应当在agent线程之内调用。

所以:

在事件监听者中,给agent添加一个新的行为,以执行必须的通信。

如果做的通讯是一个简单的信息传送操作,可以使用SenderBehaviour类,事件管理者将包括一行代码如下:

myAgent.addBehaviour(new SenderBehaviour(msgToSend ));

如果通讯操作是一个信息接收操作,同样地可以用ReceiverBehaviour类:

myAgent.addBehaviour(new ReceiverBehaviour(msgToRecv ));

更一般地说,当用户在GUI上操作时,一些复杂的会话(例如,遵循交互协议的整个交互过程)就会启动。在一次,这个方法给agent添加一个新的行为;这个行为将为交互协议扩展预先定义的JADE behaviours类,或将是一个定制的复杂行为。

下面的代码是从JADE RMA management agent中抽取出来的。当用户要创建一个新的agent 的时候,他/她就在RMA GUI上操作(通过菜单栏,工具栏或弹出菜单)执行StartNewAgentAction对象,该对象调用rma类的newAgent()方法。这一方法代码如下:

AMSClientBehaviour类是ram类的一个私有内部类,它扩展自FipaRequestInitiatorBehaviour,与AMS agent间使用fipa-request交互协议。在这种情况下,addBehaviour()调用和特定行为类的添加都被完全封装到rma类内。RMA GUI(主要是action类)的各种类都参考RMA agent,并用它来调用方法,如newAgent()。注意:像newAgent()之类的方法并不是真正属于该agent 的,因为它们不以任何方式访问该agent。所以,它们是为了从外部(不同的执行线程)调用而设计的:接下来,这些方法将称为external methods。

一般来说,一个外部软件组件维持关于agent的直接对象不是件好事,因为这个组件可以直接调用该agent的任何公共方法(而不仅仅是外部的方法),跳过异步消息传输层,把自治agent转换为服务对象,从属于它的调用者。更好的方法是将所有的外部方法集中到一个接口,再由agent类使用。这样涉及到该接口的对象将被传送到GUI,这样只有外部方法可以从事件管理者那里调用。下面的代码将解释这个方法;

上面的例子,GUI智能调用RMA agent的外部方法。

3.2.3.3收到ACL消息时修改GUI

Anget可以通过ACL消息从其它agents获取消息:FIPA通信原语inform就是用于此目的。如果该gent有一个GUI,它会想经常通过改变可视的GUI外观和它的用户交流新的信息。根据Model/View模式,新消息应该用于修改一些model对象,Swing会自动更新GUI。用于读取消息的Agent.receive()操作在agent线程中执行,但是对Swing model对象的修改必须从Event Dispathcer线程中执行。

所以:

在agent行为中,将所有对GUI model对象的访问封装成一个Runnable对象,用SwingUtilities.invokeXXX()将Runnable提交给Event Dispathcer线程。

例如,当一个新的agent在JADE平台诞生,AMS就会发送inform消息给所有的活动的RMA agents;它们当中的每个agent都要更新它的AgentTree,添加代表新agent的节点。rma类掌管着(内部的和私有的)AMSListerner类的行为,它不断从AMS接收inform消息,并将消息发送给合适的内部事件管理者(它基本上是一个简单地分布式的ACL消息上的事件系统)。与agent-born事件相对应的管理者有下面的代码:

正如从上面代码中看到的,对agent树的所有访问都被封装到Runnable中,用SwingUtilities.invokeLater()方法提交到Event Dispatcher线程执行。整个Runnable创建和提交过程都包含在MainWindow类的addAgent()方法中,这样rma agent不直接处理Swing调用(它甚至不必引用Swing相关类)。

如果我们将整个MainWindow作为一个活动对象,它的线程是Event Dispatcher线程,addAgent()方法明显的是一个外部方法,这个方法准确反映了上面部分中用到的技术。但是,因为GUI没有被看做自治软件组件,所以是否选择使用外部方法只是一个软件结构问题,没有特殊的概念意义。

3.2.3.4在JADE上构建GUI可用的agents

使agents拥有GUI是件很普通的事情,JADE包含jade.gui.GuiAgent类以达到这个目的。这个类是jade.core.Agent类的简单扩展:在启动(setup()方法执行的时候)的时候,它建立ad-hoc behaviour的实例,管理jade.gui.GuiEvent事件对象的队,该队列可以被其它线程接收。当然,这个行为对程序员是隐藏的,他们只需要实现和每个事件相关的应用程序代码。详细地说,必须执行下面的操作。

一个线程(尤其是GUI)希望通知一个事件给一个agent,它就应该创建一个新的jade.gui.GuiEvent类型的对象,并将它作为参数传给jade.gui.GuiAgent对象的postGuieEvent 方法的调用。postGuiEvent()方法调用后,agent通过唤醒所有它的活动行为作为反应,尤其是上面提到使agent线程执行onGuiEvent()方法的行为。注意:GuiEvent对象有两个必须的属性(the source of the event和an integer identifying the type of event)和一个可以添加到event 对象的可选参数列表。

作为结果,希望从另一线程(尤其是它的GUI)接收事件的agent应该定义它想接收的事件的类型,然后执行onGuiEvent()方法。一般来说,这个方法是一个大的循环,每种情况对应一种事件类型。JADE发布的mobile例子就是一个很好的例子。

为了进一步解释前面的概念,下面给出一些关于MobileAgent例子的有趣的代码段:

3.2.4带参数的agent和启动代理

参数列表可以传给agent,也可以通过调用方法Object[] getArguments()进行检索。注意:参数是瞬时的,不能与agent一起迁移,也不能随agent克隆。

有三种方式启动agent:

●使用管理者指南中描述的语法,在命令行输入一张agent列表,括号中的参数可以传给

每个agent。这是最普通的选择,这个选择也是与agent自治的理论要求最匹配的。

●如管理员指南中描述的,用户可以通过使用RMA(Remote Monitoring Agent)GUI启

动agent。括号中的参数可以传给每一个agent。

●最后,任何外部Java程序可以用3.8节中描述的InProcess接口启动agent。

3.3 agent通信语言(ACL)

类ACLMessage代表可以在agents间交换的ACL消息。它包含一系列FIPA规范定义的属性。

希望发送消息的agent应该创建一个新的ACLMessage对象,然后用恰当的值填充属性,最后调用方法Agent.send()。同样地,希望接收消息的agent应该调用receive()或blockingReceive()方法,Agent类使用的两种方法在3.2.2节中都介绍了。

通过在agent任务队列加入ReceiverBehaviour和SenderBehaviour行为,发送或接收消息也可以作为独立的agent活动。

所有ACLMessage对象的属性都可以通过set/get()访问方法进行访问。所有属性按FIPA规范定义的参数名字命名。那些参数类型是一个值的集合(如receiver)的参数可以通过方法add/getAll()访问,第一个方法添加值到结合中,第二个方法根据集合内所有的值返回Iterator。注意:当没有设置属性的时候,所有的get()方法返回null。

此外,这个类也定义了一个常量集合,用于说明FIPA原语,如REQUEST, INFORM,等。当创建一个新的ACLMessage对象的时候,这些常量中的一个必须传递给ACLMessage类构造器,以选择消息原语。reset()方法重置所有消息字段的值。

toString()方法返回代表消息的字符串。这个方法应该只用作调试目的。

3.3.1支持消息回复

根据FIAP标准,必须按照一系列成熟的规则进行消息回复。如,为in-reply-to属性设置恰当的值,使用同样的conversation-id,等。在这项任务中,JADE ACLMessage类的createReply()方法帮助程序员。这个方法返回一个新的ACLMessage对象,该对象是对当前消息的有效回复。程序员只需要设置程序指定通信动作和消息内容。

3.3.2支持JA V A传送字节

有些程序可能从传送ACLMessage消息之外的字节序列获益。典型的用法就是通过使用Java 序列化在两个agents之间传送Java对象。在这个任务中,ACLMessage类通过setContentObject()和getContentObject()方法支持程序员,这两个方法自动激活Base64编码用

法。参考JADE API的HEML文档,在examples/Base64目录下找到关于这一用法的例子。从JADE2.5开始,增加了两个方法允许到/从ACLMessage的内容设置/获取字节序列:get/setByteSequenceContent()。在某些情况下(尤其是当ACLMessage编码成字符串格式),字节序列可能创建不兼容的和不可回复的消息内容,使用这两个方法的时候一定要格外小心。

3.3.3ACL编码解码器

在一般情况下,agent从来不需要显式调用ACL消息的编码解码器,因为它由平台自动调用。然而,对一些特殊情况,需要显式调用的时候,程序员应该用StringACLCodec类提供的方法以字符创格式对ACL消息进行解析和编码。

3.3.4 MessageTemplate类

JADE行为模型允许agent执行若干并行任务。然而也应该提供任何agent执行多个并发会话的能力。因为所有引入的消息队列由所有的agent行为共享,所以必须使用基于模式匹配的访问模式访问该队列(见3.2.2.1)。

MessageTemplate类允许建立模式以匹配ACL消息。用这个类的方法,程序员可以为每个ACLMessage属性创建模式。基本模式可以用AND, OR和NOT进行合并操作,以建立更复杂的匹配规则。以这样的方式,引入ACL消息队列可以通过模式匹配而不是FIFO访问。用户可以定义程序特定的模式,扩展MatchExpression接口以提供新的match()方法用于模式匹配阶段。

在examples包的MessageTemplate目录下的WaitAgent例子,说明了创建程序特定MessageTemplate的创建方法:

3.3.5基于主题的通信

从JADE3.5版也支持基于主题的通信,除了给一个或多个接收者(addressed by name)发送消息,它还可以发送关于某一给定主体的消息。这种消息将被发给所有在该主题下注册它们的兴趣的agent。如果没有agent在一个主题下注册它的兴趣,给该主题发送消息怎没有任何影响(例如,收不到FAILURE回复)。应该注意一点,发送者agent不需要知道任何关于有哪个agent注册到该主题的信息。

基于主题的通信由jade.core.messaging.TopicManagementService实现,因此必须激活平台上所有的容器(见JADE管理员指南上的JADE Kernel services)。

为了有一个完全一致的API使得既能发送消息给既定的接收者又能发送关于给定的主题消息,主题由AID对象表示。TopicManagementHelper接口包含在jade.core.messaging包内,提供创建主题AIDs的便利方法,如果给出一个AID表示一个主题(isTopic()),也负责进行检查。给一个既定的主题发送消息,只要把主题AID添加到消息接收者中就可以了。因此一个关于“JADE”主题的消息可以通过下面这段代码来发送:

注册关于一个既定主题的接收消息通过TopicManagementHelper接口的register()方法来实现,例子如下:

典型地,当注册接收关于某一主题的消息时,处理这些消息的适当的行为要添加到agent中。MatchTopic()库方法已被添加到MessageTemplate类以便于关于某一给定主题的模板匹配消息的创建,例子如下:

3.4 agent任务,执行agent行为

一个agent必须能够执行若干个并行任务以相应不同的外部事件。为了有效管理agent,每个JADE agent由一个单独的执行线程组成,将所有任务建模,用Behaviour对象执行。多线程agent也可以执行,但JADE没有提供特殊的支持(除了同步的ACL消息队列)。

希望执行明确agent任务的开发者应该定义一个或多个Behaviour子类,实例化它们,并将它们添加到agent任务列表。Agent类必须由agent程序员进行扩展,方法有两种:addBehaviour(Behaviour)和removeBehaviour(Behaviour),可以用来管理特殊的agent的准备好的任务队列。注意:行为和子行为可以在需要的时候随时添加,而不是只在Agent.setup()方法中。添加行为应该被视为在agent内产生新的(合作的)执行线程。

由基础Agent类执行的,对程序员隐藏的安排程序,在准备好的队列中有效的所有行为之间按照一个循环的没有优先权的排序策略执行。执行一个Behaviour驱动的类直到它释放控制权(当action()方法返回时发生)。如果放弃控制权的任务仍然没有完成,将把它安排在下一轮。一个行为也可以进入休眠,等待一个消息的到达。详细地说,agent调度程序执行出现在准备好的行为队列中的每个行为的action()方法;当action()方法返回时,调用done()方法来检查该行为是否完成了它的任务。如果完成了,该行为对象从队列中移除。

行为就像合作的线程一样工作,但是没有堆栈保存。因此,整个计算状态必须维持例如各种Behaviour和它的相关Agent。

为了避免一个活动等待消息(浪费CPU时间),允许每个单独Behaviour休眠它自己的计算。一旦action()方法返回,block()方法就将行为放入休眠行为队列中。注意:调用block()方法后休眠效果并不能马上达到,但是只要action()方法返回后。一旦一个新的消息到底,所有休眠的行为就要从新安排,因此,程序员必须注意,如果一个行为对到达的消息没有兴趣,就要再次休眠该行为。而且,一个行为对象可以通过传递间隔时间值给block()方法使自己休眠有限的时间。未来JADE的释放,可能要考虑更多唤醒事件。

由于为agent行为选择了无优先权的多任务模型,agent程序员必须避免使用无端回线,甚至是action()方法内执行太长的操作。记住:当一些行为的action()正在执行的时候,其它行

为不能继续直到该方法结束(当然,这只是相对于同一个agent的行为来说的:其它agents 的行为在不同的Java线程中运行,仍然可以独立执行)。

除此之外,因为没有堆栈竞争存在,每次action()方法都从开始执行:没有方法能在行为的action()方法中间打断它,分配CUP给其它行为,从原始行为开始的地方启动它。

例如,假设一个特定的操作op()一步完成太长,所以就分成三个子操作,命名为op1(),op2()和op3()。为了达到期望的功能,行为运行时必须第一次调用op1(),第二次调用op2(),第三次调用op3(),然后该行为必须被标记为结束。代码如下:

按照这个方法,agent行为可以描述为有限状态机,维持整个状态在不同的实例变量中。

当处理复杂的agent行为(作agent交互协议)时,用外部状态变量可能比较繁琐;所以JADE 也支持合成技术,由各个简单的行为来建立更复杂的行为。

该框架准备好提供使用Behaviour子类,从而可以包含子行为并按照某些策略执行它们。例如:提供的SequentialBehaviour类,由每个action()引导,它一个接一个的执行它的子行为。下面的图用UML类图示JADE行为:

从基础类Behaviour开始,类的层次在JADE框架的jade.core.behaviours包中定义。

下面完整地介绍所有这些类。

3.4.1 Behaviour类

这个抽象类为模拟agent任务提供了一个抽象基础类,为行为调度创建了基础,因为它允许状态转换(如:starting,blocking,restarting a Java behaviour object)。

block()方法允许暂停一个行为对象直到某个事件发生(典型地,直到消息到达)。这个方法不影响agent的其它行为,从而能够更好的控制agent的多任务处理。这个方法把行为放入暂停的行为队列中,一旦action()返回就执行。一旦新的消息到达,所有暂停的行为就重新排序。而且,行为对象可以通过传递时间间隔值(你毫秒为单位)给block()方法,使自己暂停有限的时间。在将来的JADE版本,将考虑更多的唤醒事件。一个行为可以通过调用它的restart()方法显式启动。

总之,当下列三个条件之一发生时,一个休眠的行为可以重新执行:

1.这个行为所属的agent收到一条ACL消息。

2.和这个行为相关的时间间隔由先前block()调用到期。

3.这个方法的restart()方法显式调用。

该Behaviour类也提供了两个占位符方法,命名为onStart()和onEnd()。当有些行为在运行时行为执行之前或之后执行时,用户可以通过定义子类重写这些方法。

onEnd()返回一个int代表行为结束值。

应该注意:onEnd()在行为完成和并从agent行为池中移除之后调用。因此在onEnd()内调用reset()是不能循环重复由该行为代表的任务的;除此之外,该行为应该再次添加到agent,例子如下:

这个类也提供了一对方法来为行为获取和设置DataStore。DataStore是对行为间交换数据非常有用的仓库,例如,jade.proto.AchieveREInitiator/Responder类所做的。注意:当行为重置时,DataStore清空,所有包含的数据丢失。

相关主题
文本预览
相关文档 最新文档