package siebog.interaction.contractnet;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import siebog.agents.AID;
import siebog.agents.XjafAgent;
import siebog.interaction.ACLMessage;
import siebog.interaction.Performative;
import siebog.utils.ObjectFactory;
/**
*
* @author <a href="jovanai.191@gmail.com">Jovana Ivkovic</a>
*/
public abstract class Initiator extends XjafAgent {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(Initiator.class);
private int pendingProposals;
private Proposal bestProposal;
private List<AID> rejectedAID = new ArrayList<AID>();
private List<Proposal> proposals = new ArrayList<Proposal>();
/*
* 1 - all proposals received 2 - acceptance sent, waiting for response 3 - all done
*/
private int status = 0;
public void cfp(CallForProposal proposal) {
status = 0;
proposal.setInitiator(myAid);
List<AID> participants = ObjectFactory.getAgentManager().getRunningAgents();
ACLMessage msg = new ACLMessage(Performative.CALL_FOR_PROPOSAL);
msg.receivers.addAll(participants);
msg.contentObj = proposal;
msg.sender = myAid;
msg.replyBy = proposal.getReplyBy();
msm().post(msg);
pendingProposals = participants.size() - 1;
LOG.info("A call for proposals is out!");
// fault checking
ACLMessage delayedMsg = new ACLMessage();
delayedMsg.sender = myAid;
delayedMsg.receivers.add(myAid);
delayedMsg.content = "replyBy";
msm().post(delayedMsg, proposal.getReplyBy() - System.currentTimeMillis());
}
public void rejectProposal() {
ACLMessage msg = new ACLMessage(Performative.REJECT_PROPOSAL);
msg.sender = myAid;
msg.receivers = rejectedAID;
msm().post(msg);
rejectedAID.clear();
bestProposal = null;
}
public void acceptProposal() {
ACLMessage msg = new ACLMessage(Performative.ACCEPT_PROPOSAL);
msg.sender = myAid;
bestProposal = getOptimalProposal(proposals);
proposals.remove(bestProposal);
rejectedAID.remove(bestProposal.getParticipant());
if (bestProposal != null) {
msg.receivers.add(bestProposal.getParticipant());
status = 2;
msm().post(msg);
// fault checking
ACLMessage delayedMsg = new ACLMessage();
delayedMsg.sender = myAid;
delayedMsg.receivers.add(myAid);
delayedMsg.content = "waiting";
delayedMsg.contentObj = bestProposal.getParticipant();
msm().post(delayedMsg, bestProposal.getTimeEstimate());
} else {
LOG.info("No proposals made");
}
}
public void handleRefuse() {
pendingProposals--;
if (pendingProposals == 0) {
acceptProposal();
}
}
public void handlePropose(ACLMessage msg) {
proposals.add((Proposal) msg.contentObj);
rejectedAID.add(((Proposal) msg.contentObj).getParticipant());
pendingProposals--;
if (pendingProposals == 0) {
acceptProposal();
}
}
public abstract Proposal getOptimalProposal(List<Proposal> proposals);
public abstract void failure();
public abstract void success(Result result);
public void handleFailure() {
bestProposal = getOptimalProposal(proposals);
if (bestProposal == null) {
status = 3;
failure();
} else {
proposals.remove(bestProposal);
rejectedAID.remove(bestProposal.getParticipant());
acceptProposal();
}
}
public void handleDone(ACLMessage msg) {
status = 3;
rejectProposal();
success((Result) msg.contentObj);
}
public abstract CallForProposal createCfp();
@Override
protected void onMessage(ACLMessage msg) {
switch (msg.performative) {
case REQUEST:
CallForProposal cfp = createCfp();
cfp(cfp);
break;
case PROPOSE:
handlePropose(msg);
break;
case REFUSE:
handleRefuse();
break;
case INFORM:
handleDone(msg);
break;
case FAILURE:
handleFailure();
break;
case CALL_FOR_PROPOSAL:
break;
default: // delayedMsg
if (msg.content.equals("replyBy") && status < 1) {
LOG.info("ReplyBy time has passed.");
pendingProposals = 0;
acceptProposal();
} else if (msg.content.equals("waiting") && status > 1) {
if (bestProposal != null
&& ((AID) msg.contentObj).equals(bestProposal.getParticipant())) {
LOG.info("Participant hasn't finished in time. {}", ((AID) msg.contentObj));
handleFailure();
}
}
break;
}
}
}