我试着回答自己。我不确定这是最好的解决方案,但肯定有效。
请注意,在使用此解决方案之前,我已详细记录了找到的指南和教程(在http://jade.tilab.com/上),并与其他 JADE 开发人员面对面(在邮件列表中http://jade.tilab. com/pipermail/jade-develop/ )
答案很复杂,所以我会尽量详尽。
在我的项目中,我必须处理两种不同类型的代理。
- ShipperAgent代表一个托运人:它跟踪托运人拥有的车辆、可用的车辆以及从其“保留”的货物。

- 代表客户(或买家)的BuyerAgent:每个客户都有一份想要从 A 点移动到 B 点的货物清单。

这两个代理都注册到黄页服务。
在 ShipperAgent 中,单击“搜索”按钮开始搜索:启动Contract Net Interaction Protocol。
解释合约网络交互协议和我的案例
在标准 FIPA 中:http ://www.fipa.org/specs/fipa00029/SC00029H.html

可以在此处找到 JADE 指南:http: //jade.tilab.com/doc/programmersguide.pdf(第 35 页)
进一步你会注意到我必须采取的改变。
ShipperAgent 向每个BuyerAgent 发送CFP。
每个买方代理:
2.1 如果他有货,发送PROPOSE给ShipperAgent。
2.2 如无货,向ShipperAgent 发送REFUSE。对于买方,协议结束。
因为这里很容易。使用嗅探器,我们可以观察到:

现在:
托运人代理:
3.1 收到买家的一个或多个提案,并展示(见下图)。
3.2 如果收到REFUSE(或在一定时间后没有收到任何东西),则终止与该买家的沟通。
以下是托运人以图形方式显示提案的方式:

现在由用户来选择想要哪些商品,哪些不想要。
为了实现这一点,我必须为代理自己创建某种“内部通信”:GUI(在 3.1 中)一旦单击执行,就会向代理发送一条消息。它可能看起来不优雅,但它似乎是不使协议端 ShipperAgent 崩溃的唯一方法。

托运人代理:
4.1 如果用户选择了一个或多个商品提案(并点击执行),则向相应的BuyerAgent 发送一个ACCEPT_PROPOSAL,其中具体的商品想要(上一个提案的子集)。
4.2 如果用户没有选择任何商品(或点击取消),则向相应的BuyerAgent 发送REJECT_PROPOSAL。结束与该买家的通信。
买方代理:
5.1 如果收到 ACCEPT_PROPOSAL,请检查货物是否仍然可用(同时任何其他托运人都可以“保留”它们),如果是,则发送 INFORM。
5.2 如果收到 ACCEPT_PROPOSAL ma 一件或多件商品不再可用,则发送 FAILURE。
5.3 如果收到REJECT_PROPOSAL,则结束与ShipperAgent 的通信。

简而言之(例如):

编码
BuyerAgent.java
我创建了一个随时准备接收 CFP 的调度程序。一旦收到并启动协议,买方:启动 SearchJobResponder。
/*
* ...
*/
final MessageTemplate template = MessageTemplate.and(
MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_CONTRACT_NET),
MessageTemplate.MatchPerformative(ACLMessage.CFP) );
// SSResponderDispatcher:
SSResponderDispatcher dispatcher = new SSResponderDispatcher(this, template) {
BuyerAgent b = (BuyerAgent) this.myAgent;
protected Behaviour createResponder(ACLMessage initiationMsg) {
// SearchJobResponder for single cfp:
return new SearchJobResponder(b, initiationMsg);
}
};
addBehaviour(dispatcher);
/*
* ...
*/
ShipperAgent.java
搜索所有买家,创建 CFP 并启动协议,发货方:启动 SearchJobInitiator。
/*
* ...
*/
ACLMessage cfp = new ACLMessage(ACLMessage.CFP);
AID[] buyerAgents = searchBuyers(); // search all buyerAgents
for (AID buyer : buyerAgents)
cfp.addReceiver(buyer);
addBehaviour(new SearchJobInitiator(this, cfp));
/*
* ...
*/
SearchJobInitiator.java
这是最难的部分......
/*
* ...
*/
public class SearchJobInitiator extends ContractNetInitiator {
ShipperAgent shipperAgent;
public SearchJobInitiator(ShipperAgent a, ACLMessage cfp) {
super(a, cfp);
shipperAgent=a;
// Very important:
registerHandleAllResponses(new HandleProposes());
}
@Override
protected Vector<?> prepareCfps(ACLMessage cfp) {
long now = System.currentTimeMillis();
cfp.setConversationId("contractNet-by-"
+shipperAgent.getAID().getLocalName()+now);
cfp.setContent("Fammi delle proposte di lavoro");
/*
* filtering...
*/
cfp.setProtocol(FIPANames.InteractionProtocol.FIPA_CONTRACT_NET);
cfp.setReplyByDate(new Date(now+10000));
//cfp.setReplyWith("cfp"+System.currentTimeMillis()) //useless, is overwrited at the end
return super.prepareCfps(cfp);
}
//inner class for handling a single proposal
public class HandleProposes extends Behaviour {
private static final long serialVersionUID = 1L;
private Vector<ACLMessage> proposes;
private Vector<ACLMessage> acceptances;
private int numberOfProposes;
public void onStart() {
proposes = (Vector<ACLMessage>) getDataStore().get(ALL_RESPONSES_KEY);
acceptances = (Vector<ACLMessage>) getDataStore().get(ALL_ACCEPTANCES_KEY);
numberOfProposes=proposes.size();
for (Iterator I=proposes.iterator(); I.hasNext();) {
ACLMessage propose = (ACLMessage) I.next();
// Very important:
if (propose.getPerformative()==ACLMessage.PROPOSE)
myAgent.addBehaviour(new HandleSinglePropose(propose, acceptances));
else
numberOfProposes--;
}
}
public void action() {
if (!done())
block();
}
public boolean done() {
return (acceptances.size()==numberOfProposes);
}
/*
* Inner class for handle a single proposal and display it:
*/
public class HandleSinglePropose extends Behaviour {
private ACLMessage propose;
private Vector<ACLMessage> acceptances;
private boolean finish=false;
public HandleSinglePropose (ACLMessage propose, Vector<ACLMessage> acceptances) {
this.propose=propose;
this.acceptances=acceptances;
// This is GUI in 3.1 point
GoodsChoiceBox gcb = new GoodsChoiceBox(shipperAgent, this, propose); // fill the JTable
gcb.setVisible(true);
}
@Override
public void action() {
MessageTemplate mt = MessageTemplate.and(
MessageTemplate.MatchSender(shipperAgent.getAID()),
MessageTemplate.and(
MessageTemplate.MatchReplyWith("response"+propose.getReplyWith()),
MessageTemplate.or(
MessageTemplate.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL),
MessageTemplate.MatchPerformative(ACLMessage.REJECT_PROPOSAL)
) ) ) ;
// Read data from GUI. The user accept or reject:
ACLMessage decisionFromGUI = shipperAgent.receive(mt);
if (decisionFromGUI != null) {
ACLMessage reply = propose.createReply();
// bla bla...
finish=true;
HandleProposes.this.restart();
} else {
block();
}
}
public boolean done() {
return finish;
}
public void handleChoice(ACLMessage propose, boolean bool, Vector<Goods> selectedGoods) {
ACLMessage reply;
if (bool){
reply = new ACLMessage(ACLMessage.ACCEPT_PROPOSAL);
//...
} else {
reply = new ACLMessage(ACLMessage.REJECT_PROPOSAL);
//...
}
reply.addReceiver(shipperAgent.getAID());
reply.setReplyWith("response"+propose.getReplyWith());
shipperAgent.send(reply);
}
} // closes HandleSinglePropose
} // closes HandleProposes
}
SearchJobResponder.java
响应者很简单。唯一需要注意的是:我扩展了 SSContractNetResponder,没有扩展 ContractNetResponder。
public class SearchJobResponder extends SSContractNetResponder {
BuyerAgent buyerAgent;
public SearchJobResponder(BuyerAgent a, ACLMessage cfp) {
super(a, cfp);
buyerAgent = a;
}
/*
* override methods...
*/
}
GoodsChoiceBox.java
显示建议的 GUI...
public GoodsChoiceBox(final Agent agent, final HandleSinglePropose behaviour, final ACLMessage propose){
/*
* graphics stuff
*/
// if goods selected and press Execute
behaviour.handleChoice(propose,true,selectedGoods);
//else
behaviour.handleChoice(propose,false,null);
/*
* bla bla
*/
}
我知道,我住了很多,但我不知道该怎么解释。但是,现在我的项目工作了。但我愿意接受任何建议。