2015年6月3日星期三

Multi-agent platform 之 Jade 学习笔记 2

这篇是学习完Jade文档JADEProgramming-Tutorial-for-beginners.pdf后的总结。

1. Jade平台
   Jade是用来开发Multi-Agent System的中间件,包括3部分:
   a. 一个运行环境,
   b. 一个Java库
   c. 一套开发图形界面的工具。

一个Jade Multi-Agent系统是由容器(container)和平台(platform)构成的。一个Jade runtime environment的运行实例叫做一个容器。一般来说,一台电脑运行Jade runtime environment后可以视为一个container。因为agent的后缀名字如“@172.18.23.255:1099/JADE”是和电脑地址和端口相关的,所以要想在一台电脑上创建多个container需要其他办法。

多个激活的container就组成了一个平台(platform)。一个平台只有一个Main container,默认情况下,第一个container就自动成为Main container。其他container要加入这个平台,需要知道Main container的地址和端口(host and port),如
java -cp <classpath> jade.Boot -container -host avalon.tilab.com -agents john:myPackage.myClass
就是把当前计算机上的container注册到host为avalon.tilab.com(port默认为1099)的main container上去,并在本地container上创建一个叫做john的myPackage.myClass agent。

Main container区别于其他容器地方,是因为它有两个特殊的agent,一个是AMS(Agent Management System),另一个是DF(Directory Facilitator)。AMS用于提供agent的命名服务和管理agent,DF就像一个黄页本,agent可以通过它查找发现其他agent提供的服务。

Agent间的通讯是灵活的,包括同一个容器内agent间通讯(A2和A3),同一个平台不同容器内agent间通讯(A1和A2),不同平台上agent间通讯(A4和A5)。



2.Agent创建和运行

当一个Agent实例创建后,它首先会调用setup()方法,这个方法一般用来添加agent之后要执行的动作(behaviour),这些添加的动作会按添加顺序排入队列(queue)中(在下图队列被称作pool)。当setup()完成后,agent进入Active状态,也就是循环查看并运行队列中的动作。

当一个队列中的动作b被选出后,就会调用它的b.action()来执行,然后用b.done()来检查这个动作是否完成。

动作种类有多种,如One-shot behaviours, cyclic behaviours 和 generic behaviours,以及定时动作,如WakerBehaviour和TickerBehaviour。

当队列中没有任何动作后,agent还是回持续不断的查看。只有调用了doDelete()方法,agent才会结束。在结束前,agent会调用takeDown(),用来做一些清理工作。


3.Agent间通讯

Agent A1 准备好message,然后发送给agent A2,这时message会压入message队列中,然后通过获取操作,A2从message队列中提取message。

一般来说,接收端的agent要用循环动作CyclicBehaviour来循环检查信箱
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
ACLMessage msg = myAgent.receive(mt);
if (msg != null) {
System.out.println("Received Message: " + msg.getContent() + " --- from " + msg.getSender().getName());
}
else {
block();
}
}

当没有message时,block()方法就会让接收agent的线程休眠,当新的message被压入message队列后,线程重新激活。

package test;

import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.OneShotBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class MySender extends Agent {
protected void setup() {
addBehaviour(new SendMessage());
}

protected void takeDown() {
System.out.println("MySender-agent "+getAID().getName()+" terminating.");
}

private class SendMessage extends OneShotBehaviour {
public void action() {
ACLMessage info = new ACLMessage(ACLMessage.INFORM);
AID receiver = new AID("receiver",AID.ISLOCALNAME);
info.addReceiver(receiver);
info.setContent("Hello World!");
info.setConversationId("conmmunication");
myAgent.send(info);
myAgent.send(info);
myAgent.send(info);

try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

myAgent.send(info);
}
}
}




package test;

import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;

public class MyReceiver extends Agent {
protected void setup() {
addBehaviour(new ReceiveMessage());
}

protected void takeDown() {
System.out.println("MyReceiver-agent "+getAID().getName()+" terminating.");
}

private class ReceiveMessage extends CyclicBehaviour {
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
ACLMessage msg = myAgent.receive(mt);
if (msg != null) {
System.out.println("Received Message: " + msg.getContent() + " --- from " + msg.getSender().getName());
}
else {
block();
}
}
}
}