package jadelab2; import jade.core.Agent; import jade.core.AID; 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; public class BookBuyerAgent extends Agent { private BookBuyerGui myGui; private String targetBookTitle; private int budget = 128; //list of found sellers private AID[] sellerAgents; protected void setup() { targetBookTitle = ""; System.out.println("Hello! " + getAID().getLocalName() + " is ready for the purchase order."); myGui = new BookBuyerGui(this); myGui.display(); //time interval for buyer for sending subsequent CFP //as a CLI argument int interval = 20000; Object[] args = getArguments(); if (args != null && args.length > 0) interval = Integer.parseInt(args[0].toString()); addBehaviour(new TickerBehaviour(this, interval) { protected void onTick() { //search only if the purchase task was ordered if (!targetBookTitle.equals("")) { System.out.println(getAID().getLocalName() + ": I'm looking for " + targetBookTitle); //update a list of known sellers (DF) 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(getAID().getLocalName() + ": the following sellers have been found"); sellerAgents = new AID[result.length]; for (int i = 0; i < result.length; ++i) { sellerAgents[i] = result[i].getName(); System.out.println(sellerAgents[i].getLocalName()); } } catch (FIPAException fe) { fe.printStackTrace(); } myAgent.addBehaviour(new RequestPerformer()); } } }); } //invoked from GUI, when purchase was ordered public void lookForTitle(final String title) { addBehaviour(new OneShotBehaviour() { public void action() { targetBookTitle = title; System.out.println(getAID().getLocalName() + ": purchase order for " + targetBookTitle + " accepted"); } }); } protected void takeDown() { myGui.dispose(); System.out.println("Buyer agent " + getAID().getLocalName() + " terminated."); } private class RequestPerformer extends Behaviour { private AID bestSeller; private int bestPrice; private int repliesCnt = 0; private MessageTemplate mt; private int step = 0; public void action() { switch (step) { case 0: //call for proposal (CFP) to found sellers 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); mt = MessageTemplate.and(MessageTemplate.MatchConversationId("book-trade"), MessageTemplate.MatchInReplyTo(cfp.getReplyWith())); step = 1; break; case 1: //collect proposals ACLMessage reply = myAgent.receive(mt); if (reply != null) { if (reply.getPerformative() == ACLMessage.PROPOSE) { //proposal received int price = Integer.parseInt(reply.getContent()); if (bestSeller == null || price < bestPrice) { //the best proposal as for now bestPrice = price; bestSeller = reply.getSender(); } } repliesCnt++; if (repliesCnt >= sellerAgents.length) { //all proposals have been received step = 2; } } else { block(); } break; case 2: //best proposal consumption - purchase if(bestPrice > budget) { System.out.println(getAID().getLocalName() + ": Cannot buy: " + targetBookTitle + " for: " + bestPrice + ". It is more than budget: " + budget); step = 4; break; } 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: //seller confirms the transaction reply = myAgent.receive(mt); if (reply != null) { if (reply.getPerformative() == ACLMessage.INFORM) { //purchase succeeded System.out.println(getAID().getLocalName() + ": " + targetBookTitle + " purchased for " + bestPrice + " from " + reply.getSender().getLocalName()); // Update budget budget = budget - bestPrice; System.out.println("Budget updated, left: " + budget); System.out.println(getAID().getLocalName() + ": waiting for the next purchase order."); targetBookTitle = ""; //myAgent.doDelete(); } else { System.out.println(getAID().getLocalName() + ": purchase has failed. " + targetBookTitle + " was sold in the meantime."); } step = 4; //this state ends the purchase process } else { block(); } break; } } public boolean done() { if (step == 2 && bestSeller == null) { System.out.println(getAID().getLocalName() + ": " + targetBookTitle + " is not on sale."); } //process terminates here if purchase has failed (title not on sale) or book was successfully bought return ((step == 2 && bestSeller == null) || step == 4); } } }