package agents;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import vocabularies.NodeVocabulary;
/**
* NodeAgent
*
* @author Smit, Edo
*/
public class NodeAgent extends Agent implements NodeVocabulary {
private String fullServiceName;
private String destinationLocalName;
private boolean busy = false;
private int SUICIDE_TIMEOUT_SECONDS = 10;
private final int SUICIDE_TIMEOUT = SUICIDE_TIMEOUT_SECONDS * 1000;
private Timer suicideTimer;
@Override
public void setup() {
Object[] arguments = getArguments();
if (arguments != null) {
destinationLocalName = (String) arguments[0];
fullServiceName = NODE_AGENT_SERVICE_PREFIX + destinationLocalName;
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType(NODE_AGENT_TYPE);
sd.setName(fullServiceName);
dfd.addServices(sd);
try {
DFService.register(this, dfd);
} catch (FIPAException fe) {
Logger.getLogger(NodeAgent.class.getName()).log(Level.SEVERE, null, fe);
}
if (arguments.length == 2 && arguments[1] instanceof ACLMessage) {
Logger.getLogger(NodeAgent.class.getName()).log(Level.INFO,
"{0} recieved a message at startup.",
getLocalName());
addBehaviour(new NodeBehaviour(this, (ACLMessage) arguments[1]));
} else {
addBehaviour(new NodeBehaviour());
}
} else {
Logger.getLogger(NodeAgent.class.getName()).log(Level.WARNING,
"{0} has improper arguments. Shutting down.",
getLocalName());
addBehaviour(new DeleteBehaviour());
}
resetTimeout();
}
/**
* Returns true if the node is busy
*
* @return
*/
public boolean isBusy() {
return busy;
}
public void resetTimeout() {
if (suicideTimer != null) {
suicideTimer.cancel();
}
suicideTimer = new Timer();
suicideTimer.schedule(new Shutdown(this), SUICIDE_TIMEOUT);
}
/**
* Unregister with the DF service.
*/
@Override
protected void takeDown() {
Logger.getLogger(NodeAgent.class.getName()).log(Level.SEVERE,
"{0} trying to unregister.",
getLocalName());
try {
DFService.deregister(this);
Logger.getLogger(NodeAgent.class.getName()).log(Level.SEVERE,
"{0} unregistered successfully.",
getLocalName());
} catch (Exception ex) {
Logger.getLogger(NodeAgent.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
*/
class DeleteBehaviour extends OneShotBehaviour {
@Override
public void action() {
myAgent.doDelete();
}
} // End inner class DeleteBehaviour
class NodeBehaviour extends CyclicBehaviour {
private ACLMessage currentMessage = null;
public NodeBehaviour() {
}
public NodeBehaviour(Agent a) {
super(a);
}
public NodeBehaviour(Agent a, ACLMessage initialMessage) {
super(a);
sendRequest(initialMessage);
}
@Override
public void action() {
ACLMessage message = myAgent.receive();
if (message != null) {
resetTimeout();
Logger.getLogger(NodeAgent.class.getName()).log(Level.INFO,
"{0} recieved message with performative {1}.",
new Object[]{myAgent.getLocalName(), ACLMessage.getPerformative(message.getPerformative())});
switch (message.getPerformative()) {
case ACLMessage.CANCEL:
Logger.getLogger(NodeAgent.class.getName()).log(Level.INFO,
"{0} shutting down.",
myAgent.getLocalName());
myAgent.doDelete();
break;
case ACLMessage.PROPOSE:
sendRequest(message);
break;
case ACLMessage.QUERY_IF:
if (!isBusy()) {
sendNotBusyMessage(message);
}
break;
case ACLMessage.INFORM:
sendRequestResponse(message);
break;
case ACLMessage.REFUSE:
Logger.getLogger(NodeAgent.class.getName()).log(Level.SEVERE,
"Setting {0} to permanently busy.",
myAgent.getLocalName());
busy = true;
break;
}
} else {
block();
}
}
/**
* Sends an ACL Message with the Request performative to the designated
* resource node.
*
* @param message
*/
private void sendRequest(ACLMessage message) {
busy = true;
Logger.getLogger(NodeAgent.class.getName()).log(Level.INFO,
"{0} is now busy.",
myAgent.getLocalName());
currentMessage = message;
ACLMessage requestMessage = new ACLMessage(ACLMessage.REQUEST);
requestMessage.addReceiver(new AID(destinationLocalName, false));
requestMessage.setContent(message.getContent());
myAgent.send(requestMessage);
}
/**
* Sends an ACL Message reply with the Confirm performative. Used to
* indicate whether or not this node is busy or not.
*
* @param message
*/
private void sendNotBusyMessage(ACLMessage message) {
if (!isBusy()) {
ACLMessage reply = message.createReply();
reply.setPerformative(ACLMessage.CONFIRM);
myAgent.send(reply);
}
}
/**
* Sends an ACL Message with the Inform performative to the client node
* that made the initial request.
*
* @param message
*/
private void sendRequestResponse(ACLMessage message) {
ACLMessage response = currentMessage.createReply();
response.setPerformative(ACLMessage.INFORM);
System.out.println(message.getContent());
response.setContent(message.getContent());
myAgent.send(response);
busy = false;
currentMessage = null;
Logger.getLogger(NodeAgent.class.getName()).log(Level.INFO,
"{0} not busy anymore.",
myAgent.getLocalName());
}
} // End class NodeBehaviour
class Shutdown extends TimerTask {
private NodeAgent myAgent = null;
public Shutdown(NodeAgent a) {
myAgent = a;
}
@Override
public void run() {
if (!myAgent.isBusy()) {
myAgent.addBehaviour(new DeleteBehaviour());
}
}
}
}