/*********************************************************************/ /* */ /* AgentService Framework */ /* www.agentservice.it */ /* */ /* Copyright (C) 2007 l.i.d.o. - DIST, University of Genoa, Italy */ /* GNU Lesser General Public License */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Lesser General Public */ /* License as published by the Free Software Foundation, */ /* version 2.1 of the License. */ /* */ /* This library is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* Lesser General Public License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public */ /* License along with this library; if not, write to the */ /* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */ /* Boston, MA 02111-1307, USA. */ /* */ /*********************************************************************/ using System; // namespace che definisce i componenti // di base per l'implementazione di nuovi // tipi di agenti using AgentService.Agent; // namespace che definisce tutti gli // elementi per la creazione di nuovi // tipi di behaviour using AgentService.Agent.Behaviour; // namespace che definisce tutti gli // elementi per la creazione di nuovi // tipi knowledge using AgentService.Agent.Knowledge; // namespace che definisce le interfacce // per i servizi di runtime using AgentService.Agent.Runtime; // using AgentService.Platform.AMS; // namespace che definisce i componenti // per la messaggistica using AgentService.Platform.MTS; // namespace che definisce i componenti // che implementano il servizio di pagine // gialle using AgentService.Platform.DF; namespace AuctionDemo { /// /// this is the behaviour of the auctionner. It waits for the maximum number of bidders /// and then starts the auction. /// [Knowledge(typeof(AuctionData))] public class ManageAuction:Behaviour { /// /// Knowledge that maintains information about the auction session /// private AuctionData auction; /// /// Constructor for the behaviour instance /// /// the name of the instance /// the reference to the knwoledge that holds information about the auction session public ManageAuction(string name, AuctionData auction) : base(name) { this.auction = auction; } /// /// The entry point of the behaviour. /// public override void Body() { this.Runtime.Console.AppendMessage("Behaviour [ManageAuction] started by: " + this.Owner.Name); // it registers the service of the auctioneer at the directory facilitator this.SetupAuctioneerService(); // it creates the message for the auction opening MessageBody msgBody = new MessageBody(); float price = 0.0f; string item = String.Empty; int maxParticipants = 0; try { this.LockKnowledge(this.auction); price = this.auction.GetPrice(this); item = this.auction.GetItem(this); maxParticipants = this.auction.GetMaxParticipants(this); // it creates the starting message msgBody.Add("StartPrice",((object)price)); msgBody.Add("Item",item); } finally { this.ReleaseKnowledge(true); } this.Runtime.Console.AppendMessage("Auction: {0},{1}",item,price); // it waits for the maximum number of bidders. int wait = 10; int timeout = 5000; do { timeout -= wait; System.Threading.Thread.Sleep(wait); } while ((this.IncomingConvs.Count != maxParticipants) && (timeout > 0)) ; if (this.IncomingConvs.Count > 0) { // it sends the opening message foreach (IConversation conv in this.IncomingConvs) { conv.SendMessage(msgBody); } this.Runtime.Console.AppendMessage("Sent Auction Data"); bool bClosed = false; AgentMessage[] recMsg = new AgentMessage[maxParticipants]; AID actualWinner = null; float actualPrice = price; do { // it waits for the messages from each bidders for (int i = 0; i < maxParticipants; i++) { IConversation conv = this.IncomingConvs[i]; if (conv.State == ConversationState.Active) { recMsg[i] = this.IncomingConvs[i].WaitForMessage(); } else { recMsg[i] = null; } } this.Runtime.Console.AppendMessage("Got Proposals"); int buddies = this.EvaluateProposals(recMsg, ref actualWinner, ref actualPrice); this.LockKnowledge(this.auction); this.auction.SetMaxParticipants(this, buddies); this.auction.SetPrice(this, actualPrice); this.auction.Update(this); this.ReleaseKnowledge(true); if (buddies > 0) { if (buddies == 1) { // if it remains only one bidder, then it is the winner MessageBody closeBody = new MessageBody(); closeBody.Add("Verb", "Close"); closeBody.Add("Winner", actualWinner); closeBody.Add("Price", price); for (int ndx = 0; ndx < recMsg.Length; ndx++) { AgentMessage msg = recMsg[ndx]; if (msg != null) { this.IncomingConvs[ndx].SendMessage(closeBody); } } bClosed = true; this.Runtime.Console.AppendMessage("Win: [Winner: {0}, Price: {1}]", actualWinner.Name, actualPrice); } else { // there is no winner: the bidders must to send another raising price MessageBody body = new MessageBody(); body.Add("Verb", "Run"); body.Add("Winner", actualWinner); body.Add("Price", (object)actualPrice); for (int ndx = 0; ndx < recMsg.Length; ndx++) { AgentMessage msg = recMsg[ndx]; if (msg != null) { this.IncomingConvs[ndx].SendMessage(body); } } this.Runtime.Console.AppendMessage("Run: [Winner: {0}, Price: {1}]", actualWinner.Name, actualPrice); } } else { bClosed = true; this.Runtime.Console.AppendMessage("Abort: All Retired"); } } while (bClosed == false); this.Runtime.Console.AppendMessage("Auction Finished"); } else this.Runtime.Console.AppendMessage("Abort: No Bidders"); } /// /// Evaluates the bidders raising price and calculates the current winner and price. /// /// the incoming message array /// the current winner /// the current price /// the number of active bidders private int EvaluateProposals(AgentMessage[] messages, ref AID actualWinner, ref float actualPrice) { int participants = messages.Length; for(int ndx = 0; ndx < messages.Length; ndx++) { // if the message is null then it decrements the number of active bidders. if (messages[ndx] == null) { participants--; } else { // if the message is not null, it gets the information about the raising // price or "escape" AgentMessage msg = messages[ndx]; string verb = msg.Body["Verb"] as string; if (verb == "Offer") { //the current bidder makes a bid //and the auctionner have to decide the winner if (actualWinner == null) { actualPrice = (float) msg.Body["Price"]; actualWinner = msg.Envelope.From; } else { float tmpPrice = (float) msg.Body["Price"]; if (tmpPrice > actualPrice) { actualPrice = tmpPrice; actualWinner = msg.Envelope.From; } } } else { //the current bidder is drop-out messages[ndx] = null; this.IncomingConvs[ndx].Close(); participants--; } } } return participants; } /// /// Constructs the auctioneer service description and sends it to the DF /// /// descrittore del servizio di banditore private void SetupAuctioneerService() { DFAgentDescription dfDescription = new DFAgentDescription(this.Owner); dfDescription.Services.Add(new ServiceDescription("Auctioneer","Auction")); this.Runtime.YPageSvc.Register(dfDescription); } } }