以下如果未特殊声明,都在JADE管理器中运行,然后再Eclipse控制台中查看!
JADE行为类
在前面的例子中,Agent所作的工作都定义在了setup方法中,实际上它具有的行为和执行的动作都应该定义在Behavious类中,我们可以对Behavior类生成实例,然后将任务或者动作代码放在对Behavious类中的action方法中,action方法是必须要有的。Behavious类还有很多子类,分别对应着不同类型的Behaviour,包括SimpleBehaviour,SequencesBehaviour, ParallelBehavior, CyclicBehavior等。
一个Agent的行为表示它能够执行的任务,通过继承jade.core.behaviours.Behaviour来实现。然后在Agent类中通过addBehaviour()方法将行为加入进来。当一个Agent启动(通过setup()方法后,行为可以在任何时间加入进来。
要定义Behaviour必须实现其action()方法,它定义了Agent的执行时的实际动作,而done()方法指名了一个行为是否已执行完毕,是否要从行为池中删除。
一个Agent可以并发执行多个behaviour。每个Agent线程启动后执行的过程如下:
SimpleBehaviour简单行为
下面的例子中我们不在setup()中打印信息,而是把它放在一个简单行为中:
在jadetest包里面新建一个java类命名为HelloWorldBehaviour,输入下面代码。配置中把变量改为-gui sb:jadetest.SimpleBehaviour,运行
packagejadetest;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午5:20:11*/
importjade.core.Agent;importjade.core.Location;importjade.core.behaviours.SimpleBehaviour;public class HelloWorldBehaviours extendsAgent {public voidsetup() {
SimpleBehaviour hello_behaviour= new SimpleBehaviour(this) {boolean finished = false;//覆盖 Behaviour 类的action这一抽象方法
public voidaction() {
System.out.println("HelloWorldBehaviour run: Hello World!");
System.out.println("-----About Me:-----");
System.out.println("My local name is:" +getLocalName());
System.out.println("My globally unique name is:" +getName());
System.out.println("-----About Here:-----");
Location l=here();
System.out.println("I am running in a location called:" +l.getName());
System.out.println("Which is identified uniquely as:" +l.getID());
System.out.println("And is contactable at:" +l.getAddress());
System.out.println("Using the protocol:" +l.getProtocol());
finished= true;
}//done()在父类中也是一个抽象方法
public booleandone() {returnfinished;
}
};
addBehaviour(hello_behaviour);
}//setup()
}
然后使用智能体管理器添加智能体并运行:
输出结果为:
HelloWorldBehaviour run: Hello World!
-----About Me:-----
My local name is:hwb
My globally unique name is:hwb@172.17.98.217:1099/JADE
-----About Here:-----
I am running in a location called:Main-Container
Which is identified uniquely as:Main-Container@172.17.98.217
And is contactable at:172.17.98.217
Using the protocol:jicp
这个程序相较于前面的例子多了action, done两个函数,它们分别执行自己的操作。HelloWorldBehaviours类加载时定义一个简单行为,这个简单行为执行的操作由action,done来实现。然后,再通过加载语句(addBehaviour(hello_behaviour))执行这个简单行为
简单行为和循环行为(CyclicBehaviour)组合的例子
一个Agent中可以加入各种Behaviour构成CompositeBehaviour。
在Eclipse的jade工程中编写下列程序,过程如前所描述。
packagejadetest;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午8:46:29*/
importjade.core.Agent;importjade.core.behaviours.Behaviour;importjade.core.behaviours.CyclicBehaviour;importjade.core.behaviours.OneShotBehaviour;public class SimpleAgent extendsAgent {private class FourStepBehaviour extendsBehaviour {//SimpleBehaviour hello_behaviour = new SimpleBehaviour(this){//这两条语句有很大不同吗?上面的定义一个新的类,下面的修改了标准行为的执行内容
private int step = 1;public voidaction() {switch(step) {case 1:
System.out.println("Operation 1");break;case 2:
System.out.println("Operation 2. Adding one-shot behaviour");
myAgent.addBehaviour(newOneShotBehaviour(myAgent) {//增加了一个新的动作,即快照
public voidaction() {
System.out.println("One-shot");
}
});//myAgent.addbehaviour
break;case 3:
System.out.println("Operation 3");break;case 4:
System.out.println("Operation 4");break;
}//switch
step++;
}//action
public booleandone() {return step == 5; //判断语句
}public intonEnd() {
myAgent.doDelete();
System.out.println("Finished!");return super.onEnd();
}
}//class FourStepBehaviour
/**Creates a new instance of SimpleAgent*/
protected voidsetup() {
System.out.println("Agent " + getLocalName() + " started.");
addBehaviour(new CyclicBehaviour(this) { //增加了一个循环行为
public voidaction() {
System.out.println("Cycling");
}
});// //增加的循环行为//Add the generic behaviour
addBehaviour(newFourStepBehaviour());
}// //setup()
}
输出结果:
Agent sa started.
Cycling
Operation 1
Cycling
Operation 2. Adding one-shot behaviour
Cycling
Operation 3
One-shot
Cycling
Operation 4
Finished!
注意每个Agent内部都有一个ParallelBehaviour,我们如果加入多个behaviour到Agent中,他们会并行执行。behaviours加入到队列的顺序就是他们执行的次序。最后,behaviours可以动态的加入到Agent以及CompositeBehaviour。
总结:每个主体的执行都是从setup() 开始顺序执行的。主体可以执行自定义的行为,如上例中的hello_behaviour ,FourStepBehaviour,也可以执行标准化的行为如OneShotBehaviour。Agent通讯:ACL(Agent communication language)
JADE的Agent之间进行通信使用的acl语言遵循fipa acl规范。一个acl消息通常包含这些参数:sender:消息的发送者,用Agent标志AID表示; receivers,接受Agent消息的Agent可以是多个;Reply-to,应收到回应的接受者;Performative:标志发送消息的目的,即发送者想要通过发送消息干什么,通常有这样一些常值:REQUEST, INFORM, ACCEPT_PROPOSAL, REJECT_PROPOSAL, PROPOSE;Content,消息的内容;内容语言,比如内容的编码格式;ontology,双方都能够理解的消息内容的概念说明和语义描述。
简单实例
发送者:
packagejadetest;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:00:25*/
importjade.core.AID;importjade.core.Agent;importjade.core.behaviours.Behaviour;importjade.lang.acl.ACLMessage;public class SimpleSender extendsAgent {protected voidsetup() {
addBehaviour(new Behaviour(this) {private boolean finished = false;public voidaction() {
System.out.println(getLocalName()+ ": about to inform bob hello");//we sleep here to give bob a chance to start.
doWait(5000);
AID r= new AID();//作用是什么?表示消息的发送者
r.setLocalName("bob");
ACLMessage msg= newACLMessage(ACLMessage.INFORM);//set performative
msg.setSender(getAID());
msg.addReceiver(r);
msg.setContent("Hello_BOB");
send(msg);
System.out.println(getLocalName()+ ": Send hello to bob");
System.out.println("the content is:" + msg.getContent()); //finished = true;
doWait(5000);
doDelete();
}//action
public booleandone() {returnfinished;
}
});//addbehavior
}//setup
}//Agent
这段代码的主要执行过程为:构建一个AID,以此来指出该消息的目的Agent。这里我们指定目的为一个本地的Agent,名字为bob。建立一个ACL消息标志其performative为INFORM。设定Sender为自身,指定接收者为bob。然后发送消息内容。打印相关信息。
接收者:他的名字必须为bob
packagejadetest;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:01:36*/
importjade.core.Agent;importjade.core.behaviours.SimpleBehaviour;importjade.lang.acl.ACLMessage;public class SimpleReceiver extendsAgent {class DoSimpleReceiveBehaviour extendsSimpleBehaviour {private boolean finished = false;publicDoSimpleReceiveBehaviour(Agent Agent) {super(Agent);
}public voidaction() {
ACLMessage msg=receive();if (msg != null) {
System.out.println(getLocalName()+ ": received the following message : ");
System.out.println(msg.toString());
finished= true;
myAgent.doDelete();
}else{
System.out.println(getLocalName()+ ":No message received, Blocking the behaviour till one is");
block();
}
}//action
public booleandone() {returnfinished;
}
}//DoSimpleReceiveBehaviour
protected voidsetup() {
DoSimpleReceiveBehaviour behaviour= new DoSimpleReceiveBehaviour(this);
addBehaviour(behaviour);
}
}//Agent
接收者的代码流程为:添加一个简单行为,这一行为检查现在是否有受到消息,若没有,则执行block()方法组织目前的behaviour执行,直到有新的消息到达。
复杂实例
FIPA定义了一组交互协议,包括FIPA-request, FIPA-query, FIPA-request-when, FIPA-contract-net, FIPA-Iterater-net, FIPA-Auction-English, FIPA-Auction-Dutch.其中:
REQUEST-INFORM:A请求B做一些工作,B可以同意或拒绝。如果B同意,则会去完成并告诉A该工作已经完成。等等。
Query:A想知道一些事情,B可以同意或不同意,并将B的回应告诉A。
Propose:在给定一些precondition的条件下,提出一个proposal去执行某些动作。
在Eclipse中创建文件夹ips:其代码文件有两个,分别为
packageips;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:03:05*/
importjade.core.AID;importjade.core.Agent;importjade.domain.FIPANames.InteractionProtocol;importjade.lang.acl.ACLMessage;importjade.proto.SimpleAchieveREInitiator;public class SimpleRequestInitiator extendsAgent {static class MarriageProposer extendsSimpleAchieveREInitiator {protectedMarriageProposer(Agent Agent, ACLMessage msg) {super(Agent, msg);
}protected voidhandleAgree(ACLMessage msg) {
System.out.println(myAgent.getLocalName()+ ": 吼吼! " +msg.getSender().getLocalName()+ " 已经同意嫁给我了, I'm so excited!");
}protected voidhandleRefuse(ACLMessage msg) {
System.out.println(myAgent.getLocalName()+ ": Oh no! "
+ msg.getSender().getLocalName() + " 拒绝了我, i feel sad.");
}protected voidhandleInform(ACLMessage msg) {
System.out.println(myAgent.getLocalName()+ ":" +msg.getSender().getLocalName()+ " has informed me of the status of my request." + " They said : "
+msg.getContent());
}protected voidhandleNotUnderstood(ACLMessage msg) {
System.out.println(myAgent.getLocalName()+ ":" +msg.getSender().getLocalName()+ " has indicated that they didn't understand.");
}protected voidhandleOutOfSequence(ACLMessage msg) {
System.out.println(myAgent.getLocalName()+ ":" +msg.getSender().getLocalName()+ "has sent me a message which I wasn't" + " expecting in this conversation");
}
}protected voidsetup() {
System.out.println(getLocalName()+ ": about to propose marriage to bob ");
doWait(5000); //wait for bob to be started.
ACLMessage msg = newACLMessage(ACLMessage.REQUEST);
AID to= newAID();
to.setLocalName("bob");
msg.setSender(getAID());
msg.addReceiver(to);
msg.setContent("Marry Me!");
msg.setProtocol(InteractionProtocol.FIPA_REQUEST);
addBehaviour(new MarriageProposer(this, msg));
}
}
还有:
packageips;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:03:57*/
importjade.core.AID;importjade.core.Agent;importjade.domain.FIPANames.InteractionProtocol;importjade.lang.acl.ACLMessage;importjade.proto.SimpleAchieveREResponder;public class SimpleRequestResponder extendsAgent {static class MarriageResponder extendsSimpleAchieveREResponder {publicMarriageResponder(Agent Agent) {super(Agent, createMessageTemplate(InteractionProtocol.FIPA_REQUEST));
}protectedACLMessage prepareResponse(ACLMessage msg) {
ACLMessage response=msg.createReply();if (msg.getContent() != null && msg.getContent().equals("Marry Me!")) {
System.out.println(myAgent.getLocalName()+ ":" +msg.getSender().getLocalName()+ " has asked me to marry him!");
AID sender;
sender=msg.getSender();if (sender.getLocalName().equals("baz")) {
response.setPerformative(ACLMessage.AGREE);
System.out.println(myAgent.getLocalName()+ ":I'm going to agree.");
}else{
response.setPerformative(ACLMessage.REFUSE);
System.out.println(myAgent.getLocalName()+ ":I'm going to turn him down.");
}
}else{
response.setPerformative(ACLMessage.NOT_UNDERSTOOD);
System.out.println(myAgent.getLocalName()+ ":I didn't understand what "
+ msg.getSender().getLocalName() + " just said to me.");
}returnresponse;
}protectedACLMessage prepareResultNotification(ACLMessage inmsg, ACLMessage outmsg) {//what they have asked is now complete (or if it failed)
ACLMessage msg =inmsg.createReply();
msg.setPerformative(ACLMessage.INFORM);
msg.setContent("I Do!");returnmsg;
}
}protected voidsetup() {
System.out.println(getLocalName()+ ": I wonder if anybody wants to marry me?");
addBehaviour(new MarriageResponder(this));
}//}
按照以前记载,先打开GUI管理器,主类依然为jade.Boot,参数为-gui,GUI管理打开之后先建立一个名为bob的Agent,对应的类为ips.SimpleRequestResponder,然后再建立一个名为baz的Agent,对应的类为ips.SimpleRequestInitiator,记住顺序不能变,以下是输出结果:
bob: I wonder if anybody wants to marry me?
baz: about to propose marriage to bob
bob:baz has asked me to marry him!
bob:I'm going to agree.
baz: 吼吼! bob 已经同意嫁给我了, I'm so excited!
baz:bob has informed me of the status of my request. They said : I Do!
上例中,应用了SimpleAchieveREInitiator和SimpleAchieveREResponder两个基类,适用于两个Agent之间的交互。可以看出发起者对于不同的回应有不同的执行动作。
技巧:从AMS中获取所有Agent的AID。
packageips;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月16日 下午1:52:33*/
importjade.core.Agent;importjade.domain.AMSService;importjade.domain.FIPAAgentManagement.AMSAgentDescription;importjade.domain.FIPAAgentManagement.SearchConstraints;importjade.lang.acl.ACLMessage;public class AMSDump extendsAgent {protected voidsetup() {
AMSAgentDescription[] Agents= null;try{
SearchConstraints c= newSearchConstraints();
c.setMaxResults(new Long(-1));
Agents= AMSService.search(this, newAMSAgentDescription(), c);
}catch(Exception e) {
System.out.println("Problem searching AMS: " +e);
e.printStackTrace();
}
ACLMessage msg= newACLMessage(ACLMessage.INFORM);
msg.setContent("Ping");for (int i = 0; i < Agents.length; i++) {if(Agents[i].getName().equals(getAID())) {//如果不是自己则加入到接收者数组中
continue;
}
msg.addReceiver(Agents[i].getName());
}
}
}
ACL高级特性之消息模板:
MessageTemplate class 利用MessageTemplate可以针对ACLMessage的每个属性设置模式,以达到过滤消息的目的。为了可以构建更复杂的匹配规则,多个模式也可以进行and,or,not运算。最有用的一些规则或方法包括:通信行为匹配,发送者匹配,会话ID匹配。
比如MatchPerformative( performative ) 是通信行为的匹配。
这里 performative 可能是:
ACLMessage.INFORM
ACLMessage.PROPOSE
ACLMessage.AGREE
还有发送者匹配MatchSender( AID ),会话匹配MatchConversationID( String ),通信协议匹配MatchProtocol( String ) ,本体匹配MatchOntology( String)。
比如:MessageTemplate mt = MessageTemplate.and(
MessageTemplate.MatchPerformative( ACLMessage.INFORM ),
MessageTemplate.MatchSender( new AID( "a1", AID.ISLOCALNAME))) ;
相当于建立了一个模板,表示消息规则为INFORM行为并且发送者为“a1”。
接收过程如下:ACLMessage msg = receive( mt );
if (msg != null) { ... handle message }
block();
示例:
packagejadePrime.acl;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:07:11*/
importjade.core.AID;importjade.core.Agent;importjade.core.behaviours.CyclicBehaviour;importjade.lang.acl.ACLMessage;importjade.lang.acl.MessageTemplate;public class Template extendsAgent {
MessageTemplate mt1=MessageTemplate.and(MessageTemplate.MatchPerformative(ACLMessage.INFORM),
MessageTemplate.MatchSender(new AID("a1", AID.ISLOCALNAME)));protected voidsetup() {//Send messages to "a1" and "a2"
ACLMessage msg= newACLMessage(ACLMessage.INFORM);
msg.setContent("Ping");for (int i = 1; i <= 2; i++)
msg.addReceiver(new AID("a" +i, AID.ISLOCALNAME));
send(msg);//Set-up Behaviour 1
addBehaviour(new CyclicBehaviour(this) {public voidaction() {
System.out.print("Behaviour ONE: ");
ACLMessage msg=receive(mt1);if (msg != null)
System.out.println("gets " + msg.getPerformative() + " from "
+ msg.getSender().getLocalName() + "=" +msg.getContent());elseSystem.out.println("gets NULL");
block();
}
});//Set-up Behaviour 2
addBehaviour(new CyclicBehaviour(this) {public voidaction() {
System.out.print("Behaviour TWO: ");
ACLMessage msg=receive();if (msg != null)
System.out.println("gets " + msg.getPerformative() + " from "
+ msg.getSender().getLocalName() + "=" +msg.getContent());elseSystem.out.println("gets NULL");
block();
}
});
}
}
packagejadePrime.acl;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月14日 下午9:10:07*/
importjade.core.Agent;importjade.core.behaviours.CyclicBehaviour;importjade.lang.acl.ACLMessage;public class Responder extendsAgent {protected voidsetup() {
addBehaviour(new CyclicBehaviour(this) {public voidaction() {
ACLMessage msg=receive();if (msg != null) {
ACLMessage reply=msg.createReply();
reply.setPerformative(ACLMessage.INFORM);
reply.setContent(" Gossip.....");
send(reply);
reply.setPerformative(ACLMessage.PROPOSE);
reply.setContent(" Really sexy stuff... cheap! ");
send(reply);
}
block();
}
});
}
}
输出结果:
Behaviour ONE: gets NULL
Behaviour TWO: gets 6 from ams=( (action ( agent-identifier :name template@192.168.23.1:1099/JADE :addresses (sequence http://jacksile:7778/acc )) (ACLMessage) ) (MTS-error ( agent-identifier :name a1@192.168.23.1:1099/JADE ) (internal-error "Agent not found: getContainerID() failed to find agent a1@192.168.23.1:1099/JADE")) )
Behaviour ONE: gets NULL
Base64:发送消息为java序列化对象
在JADE中,支持Agents之间通信的消息内容使用序列化的java对象,对本地应用,特别是所有Agent都用java实现的情况下也是很有用的.
看实例:一个ObjectSender负责发送一个Person对象,ObjectReceiver负责接收后打印出接收到的内容。
源文件:Person.java
packageexamples.Base64;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:34:47*/
importjava.io.Serializable;importjava.util.Date;public class Person implementsSerializable {
String name;
String surname;
Date birthdate;intage;
Person(String n, String s, Date d,inta) {
name=n;
surname=s;
birthdate=d;
age=a;
}publicString toString() {return (name + " " + surname + " born on " + birthdate.toString() + " age = " +age);
}
}
文件2:ObjectSender.java
packageexamples.Base64;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:35:47*/
importjade.core.AID;importjade.core.Agent;importjade.lang.acl.ACLMessage;importjava.io.IOException;importjava.util.Date;public class ObjectSender extendsAgent {protected voidsetup() {try{
ACLMessage msg= newACLMessage(ACLMessage.INFORM);
msg.setContent("Ping");
AID personR= new AID("personR", AID.ISLOCALNAME);
msg.addReceiver(personR);
Person p= new Person("Name1", "Surname1", new Date(), 1);
msg.setContentObject(p);
msg.setLanguage("JavaSerialization");
send(msg);
System.out.println(getLocalName()+ " sent 1st msg " +msg);
send(msg);
}catch(IOException e) {
e.printStackTrace();
}
doDelete();//kill itself because it has completed its task.
}
}
文件三:ObjectReceiver.java
packageexamples.Base64;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:37:17*/
importjade.core.Agent;importjade.core.behaviours.CyclicBehaviour;importjade.lang.acl.ACLMessage;importjade.lang.acl.UnreadableException;public class ObjectReceiver extendsAgent {protected voidsetup() {
addBehaviour(new CyclicBehaviour(this) {public voidaction() {try{
ACLMessage msg=blockingReceive();
System.out.println(getLocalName()+ " rx msg" +msg);if ("JavaSerialization".equals(msg.getLanguage())) {
Person p=(Person) msg.getContentObject();
System.out.println(getLocalName()+ " 获取Java对象: ");
System.out.println(p.getClass().getName());
System.out.println(p.toString());
}
}catch(UnreadableException e3) {
System.err.println(getLocalName()+ " catched exception " +e3.getMessage());
}
block();
}
});
}
}
外部应用程序调用Agent
JADE2.3以后的版本都提供了in-process接口来实现外部应用程序对Agent的调用。
我们可以通过jade.core.Runtime.instance()来获得jade运行时的一个单独得实例。有两种方法可以用来创建一个jade主容器和一个jade远程容器。主要调用过程如下:
先看简单的例子:
packageinprocess;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:48:37*/
importjade.core.Agent;importjade.core.behaviours.SimpleBehaviour;/***
*@authorAdministrator*/
public class CustomAgent extendsAgent {public voidsetup() {
SimpleBehaviour helloBehaviour= new SimpleBehaviour(this) {boolean finished = false;public voidaction() {
System.out.println("Hello World Behaviour run: 你好,世界!");
System.out.println("-----我是:-----");
System.out.println("我的本地名称是:" +getLocalName());
System.out.println("我全局唯一的标志名称为:" +getName());
finished= true;
}public booleandone() {returnfinished;
}
};
addBehaviour(helloBehaviour);
}
}
以上是要调用的Agent类
packageinprocess;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:49:43*/
importjade.core.Profile;importjade.core.ProfileImpl;importjade.core.Runtime;importjade.wrapper.AgentContainer;importjade.wrapper.AgentController;public classInprocessTest {public static voidmain(String args[]) {try{
Runtime rt=Runtime.instance();
rt.setCloseVM(true);
Profile pMain= new ProfileImpl(null, 8888, null);
System.out.println("Launching a whole in-process platform..." +pMain);
AgentContainer mc=rt.createMainContainer(pMain);//set now the default Profile to start a container
ProfileImpl pContainer = new ProfileImpl(null, 8888, null);
System.out.println("Launching the Agent container ..." +pContainer);
AgentController custom= mc.createNewAgent("custom", "inprocess.CustomAgent", null);
custom.start();
}catch(Exception e) {
e.printStackTrace();
}
}
}//以上是调用者,在Eclipse中调试通过。
再看一个例子,也是main函数中动态创建Agent的例子。可以通过先创建另一个容器,然后再这个容器中创建Aent。比如:
public static voidmain(String[] args) {//TODO code application logic here
Runtime rt =Runtime.instance();
rt.setCloseVM(true);
ContainerController cc= rt.createAgentContainer(new ProfileImpl(false));
AgentController pingAgent= null;try{//create Agent and start it
(cc.createNewAgent("hello", "jadeclient.HelloWorldAgent", new Object[0])).start();
}catch(Exception e){}
}
可以写如下测试程序,这里用Eclipse平台,一个HelloWorldAgent,他将被动态创建并向主容器中的server发送一个消息:
packagejadeclient;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:50:50*/
importjade.core.AID;importjade.core.Agent;importjade.core.behaviours.SimpleBehaviour;importjade.lang.acl.ACLMessage;public class HelloWorldAgent extendsAgent {public voidsetup() {
addBehaviour(new SimpleBehaviour(this) {boolean finished = false;
AID server= new AID("server", AID.ISLOCALNAME);public voidaction() {
System.out.println("我的本地名称是:" +getLocalName());
ACLMessage msg= newACLMessage(ACLMessage.INFORM);
msg.setContent("消息内容");
msg.addReceiver(server);
send(msg);
System.out.println("已经往主容器中的server发送信息#");
block(1000);
finished= true;
}public booleandone() {returnfinished;
}
});
};
}
而server角色是收到消息后打印出来。
/** ReceiverAgent.java
* To change this template, choose Tools | Template Manager
* and open the template in the editor.*/
packagejadeclient;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:51:57*/
importjade.core.Agent;importjade.core.behaviours.CyclicBehaviour;importjade.lang.acl.ACLMessage;/***
*@authoradmin*/
public class ReceiverAgent extendsAgent {/**Creates a new instance of ReceiverAgent*/
//把接收到的信息打印出来
protected voidsetup() {
addBehaviour(new CyclicBehaviour(this) {public voidaction() {
ACLMessage msg=receive();if (msg != null)
System.out
.println("收到信息 " + myAgent.getLocalName() + "
block();
}
});
}
}
所有类写完之后,这里运行的时候先打开GUI管理器,然后GUI界面下创建一个名叫server的Agent,其类为jadeclient. ReceiverAgent,然后再创建一个名叫hello的Agent,其类为jadeclient.HelloWorldAgent.,记住,顺序不能变
在GUI界面管理器显示如下,在Eclipse平台中下面显示的是打印出的信息,可见在同一主机的不同容器中Agent通信与在同一容器中通信并无二样。
看一个稍微复杂的例子:
packageexamples.inprocess;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:53:06*/
importjade.core.Profile;importjade.core.ProfileImpl;importjade.core.Runtime;importjade.core.behaviours.CyclicBehaviour;importjade.wrapper.AgentContainer;importjade.wrapper.AgentController;public classInProcessTest {//Simple class behaving as a Condition Variable
public static classCondVar {private boolean value = false;synchronized void waitOn() throwsInterruptedException {while (!value) {
wait();
}
}synchronized voidsignal() {
value= true;
notifyAll();
}
}//End of CondVar class//This class is a custom Agent, accepting an Object through the//object-to-Agent communication channel, and displying it on the//standard output.
public static class CustomAgent extendsjade.core.Agent {public voidsetup() {//Accept objects through the object-to-Agent communication//channel, with a maximum size of 10 queued objects
setEnabledO2ACommunication(true, 10);//Notify blocked threads that the Agent is ready and that//object-to-Agent communication is enabled
Object[] args =getArguments();if (args.length > 0) {
CondVar latch= (CondVar) args[0];
latch.signal();
}//Add a suitable cyclic behaviour...
addBehaviour(newCyclicBehaviour() {public voidaction() {//Retrieve the first object in the queue and print it on//the standard output
Object obj =getO2AObject();if (obj != null) {
System.out.println("Got an object from the queue: [" + obj + "]");
}elseblock();
}
});
}public voidtakeDown() {//Disables the object-to-Agent communication channel, thus//waking up all waiting threads
setEnabledO2ACommunication(false, 0);
}
}//End of CustomAgent class
public static voidmain(String args[]) {try{
Runtime rt= Runtime.instance();//获取jade运行时//Exit the JVM when there are no more containers around
rt.setCloseVM(true);//看运行参数中是否有-container
if (args.length > 0) {if (args[0].equalsIgnoreCase("-container")) {//创建一个默认的profile
Profile p = new ProfileImpl(false);//p.setParameter(Profile.MAIN, "false");//Create a new non-main container, connecting to the default//main container (i.e. on this host, port 1099)
System.out.println("Launching the Agent container ..." +p);
AgentContainer ac=rt.createAgentContainer(p);//创建一个新的Agent
AgentController dummy = ac.createNewAgent("inProcess","jade.tools.DummyAgent.DummyAgent", new Object[0]);//启动它
System.out.println("Starting up a DummyAgent...");
dummy.start();//等10秒
Thread.sleep(10000);//杀死这个Agent
System.out.println("Killing DummyAgent...");
dummy.kill();//在同一虚拟机上创建另一个容器,NB,//NB. 两个容器不能共享同一个 Profile对象!!! -->//所以需再创建一个profile对象
p = new ProfileImpl(false);//p.putProperty(Profile.MAIN, "false");
AgentContainer another =rt.createAgentContainer(p);//用两个参数创建一个移动agnet
Object[] arguments = new Object[2];
arguments[0] = "Hello World!";
arguments[1] =dummy;
AgentController mobile= another.createNewAgent("Johnny","examples.mobile.MobileAgent", arguments);
mobile.start();return;
}
}//在8888端口运行一个完整的平台t//create a default Profile
Profile pMain = new ProfileImpl(null, 8888, null);
System.out.println("Launching a whole in-process platform..." +pMain);
AgentContainer mc=rt.createMainContainer(pMain);//使用默认的profile启动一个容器
ProfileImpl pContainer = new ProfileImpl(null, 8888, null);
System.out.println("Launching the Agent container ..." +pContainer);
AgentContainer cont=rt.createAgentContainer(pContainer);
System.out.println("Launching the Agent container after ..." +pContainer);
System.out.println("Launching the rma Agent on the main container ...");
AgentController rma= mc.createNewAgent("rma", "jade.tools.rma.rma", new Object[0]);
rma.start();//Launch a custom Agent, taking an object via the//object-to-Agent communication channel. Notice how an Object//is passed to the Agent, to achieve a startup synchronization://this Object is used as a POSIX 'condvar' or a Win32//'EventSemaphore' object...
CondVar startUpLatch= newCondVar();
AgentController custom= mc.createNewAgent("customAgent", CustomAgent.class.getName(),newObject[] { startUpLatch });
custom.start();//Wait until the Agent starts up and notifies the Object
try{
startUpLatch.waitOn();
}catch(InterruptedException ie) {
ie.printStackTrace();
}//Put an object in the queue, asynchronously
System.out.println("Inserting an object, asynchronously...");
custom.putO2AObject("Message 1", AgentController.ASYNC);
System.out.println("Inserted.");//Put an object in the queue, synchronously
System.out.println("Inserting an object, synchronously...");
custom.putO2AObject(mc, AgentController.SYNC);
System.out.println("Inserted.");
}catch(Exception e) {
e.printStackTrace();
}
}
}
现在看看servlet能不能调用这个,在Eclipse中建立一个web工程,添加jade库,建立一个servlet在servlet中进行调用Agent,看能不能输出结果。
其中主要文件如下
文件名:StartServlet.java:
packageexamples;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午12:57:37*/
importjade.core.Profile;importjade.core.ProfileImpl;importjade.core.Runtime;importjade.wrapper.AgentContainer;importjade.wrapper.AgentController;importjava.io.IOException;importjava.io.PrintWriter;importjavax.servlet.ServletException;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;public class StartServlet extendsHttpServlet {protected voidprocessRequest(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
out.println("");
out.println("
");out.println("
Servlet StartServlet");out.println("");
out.println("
");out.println("
Servlet StartServlet at " + request.getContextPath() + "
");out.println("你好");try{
Runtime rt=Runtime.instance();
rt.setCloseVM(true);
Profile pMain= new ProfileImpl(null, 8888, null);
AgentContainer mc=rt.createMainContainer(pMain);//set now the default Profile to start a container
ProfileImpl pContainer = new ProfileImpl(null, 8888, null);
out.println("运行Agent容器 ..." +pContainer);
AgentController rma= mc.createNewAgent("rma", "jade.tools.rma.rma", null);
rma.start();
AgentController custom= mc.createNewAgent("custom", "examples.CustomAgent", null);
custom.start();
out.println("我已经启动了一个小Agent");
}catch(Exception e) {
e.printStackTrace();
}
out.println("");
out.println("");
out.close();
}protected voiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
processRequest(request, response);
}protected voiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException {
processRequest(request, response);
}publicString getServletInfo() {return "Short description";
}
}
CustomAgent.java:
packageexamples;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午1:03:40*/
importjade.core.Agent;importjade.core.behaviours.SimpleBehaviour;public class CustomAgent extendsAgent {public voidsetup() {
SimpleBehaviour helloBehaviour= new SimpleBehaviour(this) {boolean finished = false;public voidaction() {
System.out.println("Hello World Behaviour run: 你好,世界!");
System.out.println("-----我是:-----");
System.out.println("我的本地名称是:" +getLocalName());
System.out.println("我全局唯一的标志名称为:" +getName());
finished= true;try{
Thread.sleep(40000);
}catch(java.lang.InterruptedException e) {
e.printStackTrace();
}
System.out.println("已经过了40秒钟");//这里是为了测试关掉IE之后控制台上还会不会输出信息。
}public booleandone() {returnfinished;
}
};
addBehaviour(helloBehaviour);
}
}
web.xml:
jade
StartServlet
examples.StartServlet
StartServlet
/StartServlet
30
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
Servlet StartServlet at /jade
你好 运行Agent容器 ...(Profile main=true local-host=59.73.87.114 port=8888 services=jade.core.mobility.AgentMobilityService;jade.core.event.NotificationService host=59.73.87.114 local-port=8888 mtps=[jade.mtp.http.MessageTransportProtocol] jvm=j2se) 我已经启动了一个小Agent
在Tomcat控制台上输出信息:
Hello World Behaviour run: 你好,世界!
-----我是:-----
我的本地名称是:custom
我全局唯一的标志名称为:custom@deepin-84e2a07b:8888/JADE
已经过了40秒钟
同时图形化JADE容器运行,其中“已经过了40秒钟”是在浏览器关闭之后显示,说明Agent容器及Agent启动后一直运行着。
奇怪的是,我每次退出主容器,总显示
Exception while removing reference: java.lang.InterruptedException
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
at sun.java2d.Disposer.run(Disposer.java:107)
at java.lang.Thread.run(Thread.java:595)
AWT blocker activation interrupted: //后面这个是JADE GUI的bug么?
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:474)
at sun.awt.AWTAutoShutdown.activateBlockerThread(AWTAutoShutdown.java:309)
at sun.awt.AWTAutoShutdown.setToolkitBusy(AWTAutoShutdown.java:226)
at sun.awt.AWTAutoShutdown.notifyToolkitThreadBusy(AWTAutoShutdown.java:118)
at sun.awt.windows.WToolkit.eventLoop(Native Method)
at sun.awt.windows.WToolkit.run(WToolkit.java:269)
at java.lang.Thread.run(Thread.java:595)
不知道什么问题?
一个Agent如何以程序的方式生成另一个Agent:
可以通过以下方式进行创建:
String name = "Alice";
AgentContainer c=getContainerController();try{
AgentController a= c.createNewAgent( name, "Pong", null);
a.start();
}catch (Exception e){}
其中,createNewAgent方法的第一个参数是要创建的Agent的名称,第二个是Agent的类名,实际使用时要包括他所在的命名空间(包名),第三个参数是要传入的参数的名称。
例子:
packagejadePrime.acl;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午1:08:17*/
/*** Program which creates another Agent and sends
------------ it some messages
comm2.java
**/
importjade.core.AID;importjade.core.Agent;importjade.core.behaviours.SimpleBehaviour;importjade.lang.acl.ACLMessage;importjade.wrapper.AgentContainer;importjade.wrapper.AgentController;public class Comm2 extendsAgent {
String name= "Alice";
AID alice= newAID(name, AID.ISLOCALNAME);protected voidsetup() {
AgentContainer c=getContainerController();
System.out.println("find container!");try{
AgentController a= c.createNewAgent(name, "jadePrime.acl.Pong", null);
a.start();
System.out.println("++++pong has created:" +alice);
}catch(Exception e) {
System.out.println("Create Agent Error!");
addBehaviour(new SimpleBehaviour(this) {int n = 0;public voidaction() {
ACLMessage msg= newACLMessage(ACLMessage.INFORM);
msg.setContent("Message #" +n);
msg.addReceiver(alice);
System.out.println("+++ Sending: " +n);
send(msg);
block(1000);
}public booleandone() {return ++n > 3;
}
});
}
}
}
当我们创建一个Comm2的Agent时,在控制台上会打印出创建alice成功的消息。
如何收集当前AMS中Agent列表
packagejadePrime.manage;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午1:09:53*/
importjade.core.AID;importjade.core.Agent;importjade.domain.AMSService;importjade.domain.FIPAAgentManagement.AMSAgentDescription;importjade.domain.FIPAAgentManagement.SearchConstraints;public class AMSDump extendsAgent {protected voidsetup() {
AMSAgentDescription[] Agents= null;try{
SearchConstraints c= newSearchConstraints();
c.setMaxResults(new Long(-1));
Agents= AMSService.search(this, newAMSAgentDescription(), c);
}catch(Exception e) {
System.out.println("Problem searching AMS: " +e);
e.printStackTrace();
}
AID myID=getAID();for (int i = 0; i < Agents.length; i++) {
AID AgentID=Agents[i].getName();
System.out.println((AgentID.equals(myID)? "*** " : " ") + i + ": "
+AgentID.getName());
}
doDelete();//System.exit(0);
}
}//end class AMSDump
JADE中如何使用DF(Directory Facilitator)Agent提供的黄页服务。
这个比较好理解,DF相当于一个目录服务器,每个提供服务的Agent可以向DF注册其服务,然后,其他的Agent可以从DF中查询该类服务,也可以订阅这类服务,如果是后者,那么一旦这类服务被注册到DF中,则订阅方就可以收到。例程如下:
文件一, DFRegisterAgent.java 服务提供方
packageyellowpages;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午1:11:14*/
importjade.core.Agent;importjade.domain.DFService;importjade.domain.FIPAException;importjade.domain.FIPANames;importjade.domain.FIPAAgentManagement.DFAgentDescription;importjade.domain.FIPAAgentManagement.Property;importjade.domain.FIPAAgentManagement.ServiceDescription;public class DFRegisterAgent extendsAgent {protected voidsetup() {
String serviceName= "unknown";//从命令行的参数中读取服务的名称,默认为unknown
Object[] args =getArguments();if (args != null && args.length > 0) {
serviceName= (String) args[0];
}//注册服务
System.out.println("Agent " + getLocalName() + " registering service \"" +serviceName+ "\" of type \"weather-forecast\"");try{//必要的几个步骤
DFAgentDescription dfd = newDFAgentDescription();
dfd.setName(getAID());
ServiceDescription sd= newServiceDescription();
sd.setName(serviceName);
sd.setType("weather-forecast");//设置服务类型为天气预报
sd.addOntologies("weather-forecast-ontology");
sd.addLanguages(FIPANames.ContentLanguage.FIPA_SL);//使用服务的一方必须遵循的规范,和具有的本体知识
sd.addProperties(new Property("country", "Italy"));
dfd.addServices(sd);
DFService.register(this, dfd);
}catch(FIPAException fe) {
fe.printStackTrace();
}
}
}
文件二.
DFSubscribeAgent.java订阅方
packageyellowpages;/*** @function
*@authorJacksile E-mail:tufujietec@foxmail.com
* @date 2016年1月15日 下午1:12:26*/
importjade.core.AID;importjade.core.Agent;importjade.domain.DFService;importjade.domain.FIPAException;importjade.domain.FIPAAgentManagement.DFAgentDescription;importjade.domain.FIPAAgentManagement.Property;importjade.domain.FIPAAgentManagement.SearchConstraints;importjade.domain.FIPAAgentManagement.ServiceDescription;importjade.lang.acl.ACLMessage;importjade.proto.SubscriptionInitiator;importjade.util.leap.Iterator;public class DFSubscribeAgent extendsAgent {protected voidsetup() {//Build the description used as template for the subscription
DFAgentDescription template = newDFAgentDescription();
ServiceDescription templateSd= newServiceDescription();
templateSd.setType("weather-forecast");
templateSd.addProperties(new Property("country", "Italy"));
template.addServices(templateSd);
SearchConstraints sc= newSearchConstraints();//最多能接受10个结果
sc.setMaxResults(new Long(10));
addBehaviour(new SubscriptionInitiator(this, DFService.createSubscriptionMessage(this,
getDefaultDF(), template, sc)) {protected voidhandleInform(ACLMessage inform) {
System.out.println("Agent " + getLocalName() + ": Notification received from DF");try{
DFAgentDescription[] results=DFService
.decodeNotification(inform.getContent());if (results.length > 0) {for (int i = 0; i < results.length; ++i) {
DFAgentDescription dfd=results[i];
AID provider=dfd.getName();//同一个Agent可能提供很多服务,我们只对天气预报感兴趣
Iterator it =dfd.getAllServices();while(it.hasNext()) {
ServiceDescription sd=(ServiceDescription) it.next();if (sd.getType().equals("weather-forecast")) {
System.out.println("Weather-forecast service for Italy found:");
System.out.println("- Service \"" +sd.getName()+ "\" provided by Agent " +provider.getName());
}
}
}
}
System.out.println();
}catch(FIPAException fe) {
fe.printStackTrace();
}
}
});
}
}
这样,编译后,我们为了体现发布服务和订阅服务时间上的一致关系,我们从命令行来运行这些类。假设已编译成功,文件标志在某目录下yellowpages\ DFSubscribeAgent.class 和yellowpages\ DFRegisterAgent.class,我们在yellowpages目录下运行命令
java jade.Boot –gui service1: yellowpages.DFRegisterAgent
系统运行主容器,同时控制台上显示Agent service1 registering service “noname” of type "weather-forecast"
然后我们在图形界面下,start new Agent,AgentName:subscriber ClassName:yellowpages.DFSubscribeAgent 添加后,控制台上会显示相关启动后的信息,但不会显示收到服务的消息。然后再start new Agent,AgentName:service2 ClassName:yellowpages.DFRegisterAgent 参数设为:rainny,这是控制台上显示注册服务成功的消息和订阅到服务的消息。显示如下:
JADE中使用本体:
Agent之间进行通信要有相同的语言,词汇和协议。在JADE中,Agents之间通信的方式可以有三种:1.使用字符串表达信息的内容,是最基本的方式.当消息内容是原子数据时,这种方式非常便利.2.消息内容使用序列化的java对象,对本地应用,特别是所有Agent都用java实现的情况下也是很有用的.3.为了jade能够以FIPA格式队消息进行编码和解码,扩展预先定义好的类,亦即使用本体的方式。这种方式允许jade的Agent可以同其他异质Agent系统进行互操作。这三种方式下对应设置和获取内容的方法对应如下:
现在有一些已经存在的language来描述ontologies,如DAML+OIL和OWL,JADE并不直接支持这些ontologies,而是将ontologies编码为java类(比如protégé可以将本体直接导出为java类)。
本体提供了Agent交互的语义支持,但必须与内容语言结合使用,后者是Agent交互的语法支持。JADE支持的三种内容语言包括:FIPA-SL类似lisp的语言族;Leap-encoding应用于嵌入式开发;JavaCodec,JADE特定的内容语言。