All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.bdi.planlib.protocols.dutchauction.DAInitiatorPlan Maven / Gradle / Ivy

Go to download

The Jadex applib BDI package contains ready to use functionalities for BDI agents mostly in form of modules called capabilities.

The newest version!
package jadex.bdi.planlib.protocols.dutchauction;

import java.util.List;

import jadex.bdi.planlib.protocols.AbstractInitiatorPlan;
import jadex.bdi.planlib.protocols.AuctionDescription;
import jadex.bdiv3.runtime.BDIFailureException;
import jadex.bdiv3.runtime.IGoal;
import jadex.bdiv3x.runtime.IMessageEvent;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.fipa.SFipa;
import jadex.commons.SUtil;
import jadex.commons.TimeoutException;
import jadex.commons.collection.SCollection;


/**
 *  This plan implements the initiator of the "FIPA Dutch Auction Interaction
 *  Protocol Specification" (XC00032 - Experimental)
 *  
 *  A dutch auction is one where the auctioneer starts with a high start price
 *  and continually lowers it until the first bidder accepts the price.
 */
public class DAInitiatorPlan extends AbstractInitiatorPlan
{
	//-------- attributes --------
	
	/** The initial message. */
	// Hack!!! Needed for cancel-meta-protocol and for avoiding garbage collection.
	protected IMessageEvent	start;
	
	//-------- methods --------
	
	/**
	 * The plan body.
	 */
	public void body()
	{
		super.body();	// Hack???
		
//		System.out.println("DA initiator plan started");
		
		AuctionDescription auctiondesc = (AuctionDescription)getParameter("auction_description").getValue();
		if(auctiondesc.getRoundTimeout()<=0)
		{
			getLogger().warning(getComponentName()+"No round timeout specified");
			fail();
		}
		
		// Fetch the timeout for each round of the auction.
		long roundtimeout = auctiondesc.getRoundTimeout();
		
		// Fetch the receivers.
		List receivers = SUtil.arrayToList(getParameterSet("receivers").getValues());
		
		// Initialize negotiations.
		String convid;
		if(getParameter("conversation_id").getValue()!=null)
		{
			convid	= (String)getParameter("conversation_id").getValue();
		}
		else
		{
			convid = SUtil.createUniqueId(getComponentName());			
		}
		
		// Announce the auction by sending information about it.
		announceAuction(auctiondesc, receivers, convid);
		
		// Wait for the auction to begin.
		// Removes receivers that do not want to participate.
		waitForAuctionStart(auctiondesc, receivers);
		
		// Send calls for proposal until no more proposals are received.
		boolean running = true;
		Object winning_offer = null;
		IComponentIdentifier winner = null;
		Object cfp = getParameter("cfp").getValue();
		Object cfp_info = getParameter("cfp_info").getValue();
		List history = SCollection.createArrayList();
		history.add(cfp);
		
		// Send calls for proposal until the limit price is reached or an agent is
		// willing to pay the actual price.
		// Auction ends when winner is determined, limit price is reached or
		// no receiver is left.
		while(running && receivers.size()>0) 
		{
			//System.out.println(getAgentName()+" current offer is: "+cfp+" "+receivers);
			
			// Send CFP.
			sendCFP(cfp, convid, receivers);
			
			// Wait for proposals.
			// Removes receivers that do not offer.
			winner = waitForProposals(cfp, roundtimeout, receivers);
			//System.out.println(getAgentName()+" winner is: "+winner);
		
			// Set the winner if propsals have been received, otherwise
			// cease sending CFP-messages (so the winner of the last round will
			// be the winner of the auction).
			if(winner != null)
			{
				winning_offer = cfp;
				running = false;
			}
			else
			{
				Object[] next = decideIteration(cfp_info, history.toArray());
				//System.out.println(getAgentName()+" next cfp: "+next);
				if(next==null)
				{
					// The initiator has decided to cancel the next round for some reason.
					running = false;
				}
				else
				{
					cfp = next[0];
					cfp_info = next[1];
					history.add(cfp);
				}
			}
		}	
			
		//System.out.println("END----------END---------END");
		
		// Evaluate the auction results and determine if a winner exists.
		evaluateAuctionResults(auctiondesc, cfp_info, history.toArray(), 
			winner, winning_offer);
		
		// Announce the auction end to all (still involved) participants.
		announceAuctionEnd(receivers, convid, winning_offer, winner);
	}
	
	@Override
	public void passed()
	{
		if(start!=null)
		{
			getWaitqueue().removeReply(start);
		}
		super.passed();
	}
	
	@Override
	public void failed()
	{
		if(start!=null)
		{
			getWaitqueue().removeReply(start);
		}
		super.failed();
	}
	
	@Override
	public void aborted()
	{
		if(start!=null)
		{
			getWaitqueue().removeReply(start);
		}
		super.aborted();
	}
	
	/**
	 *  Announce the planned auction.
	 *  @param auctiondesc the auction description.
	 *  @param receivers The receivers.
	 *  @param convid The conversation id.
	 */
	protected void	announceAuction(Object auctiondesc, List receivers, String convid)
	{
		// Send the inform_start_auction-message to all receivers.
		start = getEventbase().createMessageEvent("da_inform_start_auction");
		start.getParameterSet(SFipa.RECEIVERS).addValues(receivers.toArray());
		start.getParameter(SFipa.CONTENT).setValue(auctiondesc);
		start.getParameter(SFipa.CONVERSATION_ID).setValue(convid);
		getLogger().info(getComponentName() + ": inform_start_auction");
		getWaitqueue().addReply(start);
		
		sendMessage(start);
	}
	
	
	/** 
	 *  Wait for the auction start time.
	 *  @param auctiondesc The auction description.
	 *  @param receivers The receivers.
	 */
	protected void waitForAuctionStart(AuctionDescription auctiondesc, List receivers)
	{
		// The initiator of the interaction protocol shall wait until interested
		// agents are ready to participate.
		// If agents indicate that they do not wish to participate they are excluded
		// from the auction.
		
		long timetowait = auctiondesc.getStarttime()==0? 0: 
			auctiondesc.getStarttime() - getTime();

		//System.out.println(getAgentName()+" waiting for: "+timetowait);
		while(timetowait > 0)
		{
			IMessageEvent removebidder;
			try
			{
				removebidder = (IMessageEvent)waitForReply(start, timetowait);
			}
			catch(TimeoutException e)
			{
				break;
			}
			
			if(removebidder.getType().equals("da_not_understood"))
			{
				receivers.remove(removebidder.getParameter(SFipa.SENDER).getValue());
				getLogger().info("Removed "+((IComponentIdentifier)removebidder.getParameter(SFipa.SENDER).getValue()).getName() + ".");
			}
			else
			{
				getLogger().warning("Could not handle message of type "+removebidder.getType() 
					+" from "+((IComponentIdentifier)removebidder.getParameter(SFipa.SENDER).getValue()).getName()+".");
			}
			
			timetowait =  auctiondesc.getStarttime() - getTime();
		}
	}
	
	/**
	 *  Send cfps to all receivers.
	 *  @param cfp The cfp.
	 *  @param convid The conversation id.
	 *  @param receivers The receivers.
	 */
	protected void sendCFP(Object cfp, String convid, List receivers)
	{
		// Send CFP.
		IMessageEvent cfpm = getEventbase().createMessageEvent("da_cfp");
		cfpm.getParameterSet(SFipa.RECEIVERS).addValues(receivers.toArray());
		cfpm.getParameter(SFipa.CONTENT).setValue(cfp);
		cfpm.getParameter(SFipa.CONVERSATION_ID).setValue(convid);
		getLogger().info(getComponentName() + ": cfp(" + cfp + ")");
		sendMessage(cfpm);
	}
	
	/**
	 *  Decide about the next iteration.
	 *  @param cfp_info The cfp info.
	 *  @param history The history.
	 *  @return The new cfp and cfp_info as an object array.
	 */
	protected Object[] decideIteration(Object cfp_info, Object[] history)
	{
		Object[] ret = null;
		IGoal di = createGoal("da_decide_iteration");
		di.getParameter("cfp_info").setValue(cfp_info);
		di.getParameterSet("history").addValues(history);
		try
		{
			dispatchSubgoalAndWait(di);
			ret = new Object[2];
			ret[0] = di.getParameter("cfp").getValue();
			ret[1] = di.getParameter("cfp_info").getValue();
			
			getLogger().info(getComponentName() + "calculated new cfp: "+ret[0]);
		}
		catch(BDIFailureException e)
		{
			getLogger().fine("No further iteration: "+e);
			//e.printStackTrace();
		}
		return ret;
	}
	
	
	/**
	 *  Wait for proposals of participants.
	 *  @param cfp the cfp.
	 *  @param roundtimeout The round timeout.
	 *  @param receivers The receivers.
	 *  @return The message of the winner.
	 */
	protected IComponentIdentifier waitForProposals(Object cfp, long roundtimeout, List receivers)
	{
		IComponentIdentifier winner = null;
		
		// Perform a negotiation round as long as no winner could be determined.
		long roundstart = getTime();
		while(getTime() - roundstart < roundtimeout)
		{
			IMessageEvent tmp = null;
			try
			{
				tmp = (IMessageEvent)waitForReply(start, roundtimeout);
				if(tmp.getType().equals("da_propose"))
				{
					// Accept the first winner
					if(winner==null)
					{
						// Send the accept_proposal-message to the agent with the first proposal.
						sendMessage(getEventbase().createReply(tmp, "da_accept_proposal"));
						getLogger().info(getComponentName() + " found winner: "+tmp.getParameter(SFipa.SENDER).getValue());
												
						// Set the parameter "winner" to the identifier of the
						// winning agent.
						winner = (IComponentIdentifier)tmp.getParameter(SFipa.SENDER).getValue();
					}
					// Reject all other proposals
					else
					{
						// Send reject_proposal-message.
						sendMessage(getEventbase().createReply(tmp, "da_reject_proposal"));
						getLogger().info(getComponentName() + ": rejected proposal");
					}
				}
				else
				{
					// Remove agent from the list of receivers on any
					// other of message. So you can use e.g. a
					// not_understood_message to exit the auction
					receivers.remove(tmp.getParameter(SFipa.SENDER).getValue());
				}
			}
			catch(TimeoutException e)
			{
			}
		}
		return winner;
	}
	
	/**
	 *  Evaluate the auction results and decide about participation.
	 *  @param auctiondesc The auction description.
	 *  @param cfp_info The cfp info.
	 *  @param history The historz of cfps.
	 *  @param winner the winner.
	 *  @param winning_offer The winning offer.
	 */
	protected void evaluateAuctionResults(AuctionDescription auctiondesc, Object cfp_info, 
		Object[] history, IComponentIdentifier winner, Object winning_offer)
	{
		if(winner == null)
		{
			getLogger().info(getComponentName() + ": auction finished (no winner)");
		}
		else
		{
			getLogger().info(getComponentName() + ": auction finished (winner: " 
				+winner.getName() + " - winning offer: " + winning_offer + ")");
		
			getParameter("result").setValue(new Object[]{winner, winning_offer});
		}	
	}
	
	/**
	 *  Announce the end of the auction to all participants that did not leave the auction.
	 *  @param receivers The receivers.
	 *  @param convid The conversation id.
	 *  @param winning_offer The winning offer.
	 */
	protected void announceAuctionEnd(List receivers, String convid, Object winning_offer, IComponentIdentifier winner)
	{
		// Send the inform_end_auction-message.
		List losers = SCollection.createArrayList();
		losers.addAll(receivers);
		
		if(winner!=null)
		{
			IMessageEvent end = getEventbase().createMessageEvent("da_inform_end_auction");
			end.getParameter(SFipa.CONTENT).setValue(new Object[]{Boolean.TRUE,winning_offer});
			end.getParameterSet(SFipa.RECEIVERS).addValue(winner);
			end.getParameter(SFipa.CONVERSATION_ID).setValue(convid);
			sendMessage(end);
			// Remove the winner from list of losers to inform.
			losers.remove(winner);
		}
		if(losers.size()>0)
		{
			IMessageEvent end = getEventbase().createMessageEvent("da_inform_end_auction");
			end.getParameter(SFipa.CONTENT).setValue(new Object[]{Boolean.FALSE,winning_offer});
			end.getParameterSet(SFipa.RECEIVERS).addValues(losers.toArray());
			end.getParameter(SFipa.CONVERSATION_ID).setValue(convid);
			sendMessage(end);
		}

		getWaitqueue().removeReply(start);
	}
	
	//-------- AbstractInitiatorPlan template methods --------
	
	/**
	 *  Get the initial message.
	 */
	protected IMessageEvent getInitialMessage()
	{
		return start;
	}
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy