subscriptionresponder.java
来自「JADE(JAVA Agent开发框架)是一个完全由JAVA语言开发的软件,它简」· Java 代码 · 共 533 行 · 第 1/2 页
JAVA
533 行
/*****************************************************************
JADE - Java Agent DEvelopment Framework is a framework to develop
multi-agent systems in compliance with the FIPA specifications.
Copyright (C) 2000 CSELT S.p.A.
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.
*****************************************************************/
package jade.proto;
//#CUSTOM_EXCLUDE_FILE
import jade.core.*;
import jade.core.behaviours.*;
import jade.lang.acl.*;
import jade.domain.FIPAAgentManagement.NotUnderstoodException;
import jade.domain.FIPAAgentManagement.RefuseException;
import jade.domain.FIPAAgentManagement.FailureException;
import jade.domain.FIPANames;
import jade.proto.states.*;
import jade.util.leap.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* This is a single homogeneous and effective implementation of the responder role in
* all the FIPA-Subscribe-like interaction protocols defined by FIPA,
* that is all those protocols
* where the initiator sends a single "subscription" message
* and receives notifications each time a given condition becomes true.
* @see SubscriptionInitiator
* @author Elisabetta Cortese - TILAB
* @author Giovanni Caire - TILAB
*/
public class SubscriptionResponder extends FSMBehaviour implements FIPANames.InteractionProtocol {
/**
* key to retrieve from the DataStore of the behaviour the ACLMessage
* object sent by the initiator as a subscription.
**/
public final String SUBSCRIPTION_KEY = "__subs_canc" + hashCode();
/**
* key to retrieve from the DataStore of the behaviour the ACLMessage
* object sent by the initiator to cancel a subscription.
**/
public final String CANCEL_KEY = SUBSCRIPTION_KEY;
/**
* key to retrieve from the DataStore of the behaviour the ACLMessage
* object sent as a response to the initiator.
**/
public final String RESPONSE_KEY = "__response" + hashCode();
// FSM states names
private static final String RECEIVE_SUBSCRIPTION = "Receive-subscription";
private static final String HANDLE_SUBSCRIPTION = "Handle-subscription";
private static final String HANDLE_CANCEL = "Handle-cancel";
private static final String SEND_RESPONSE = "Send-response";
private static final String SEND_NOTIFICATIONS = "Send-notifications";
// The MsgReceiver behaviour used to receive subscription messages
private MsgReceiver msgRecBehaviour = null;
private Hashtable subscriptions = new Hashtable();
private List notifications = new ArrayList();
/**
The <code>SubscriptionManager</code> used by this
<code>SubscriptionResponder</code> to register subscriptions
*/
protected SubscriptionManager mySubscriptionManager = null;
/**
This static method can be used
to set the proper message Template (based on the performative of the
subscription message) into the constructor of this behaviour.
@param perf The performative of the subscription message
*/
public static MessageTemplate createMessageTemplate(int perf) {
return MessageTemplate.and(
MessageTemplate.MatchProtocol(FIPA_SUBSCRIBE),
MessageTemplate.or(MessageTemplate.MatchPerformative(perf), MessageTemplate.MatchPerformative(ACLMessage.CANCEL)));
}
/**
* Constructor of the behaviour that creates a new empty DataStore
* @see #SubscriptionResponder(Agent,MessageTemplate,SubscriptionResponder.SubscriptionManager,DataStore)
**/
public SubscriptionResponder(Agent a, MessageTemplate mt, SubscriptionManager sm){
this(a, mt, sm, new DataStore());
}
/**
* Constructor.
* @param a is the reference to the Agent performing this behaviour.
* @param mt is the MessageTemplate that must be used to match
* subscription messages sent by the initiators. Take care that
* if mt is null every message is consumed by this protocol.
* @param sm The <code>SubscriptionManager</code> object that manages
* subscriptions.
* @param store the DataStore for this protocol
**/
public SubscriptionResponder(Agent a, MessageTemplate mt, SubscriptionManager sm, DataStore store) {
super(a);
setDataStore(store);
mySubscriptionManager = sm;
// Register the FSM transitions
registerDefaultTransition(RECEIVE_SUBSCRIPTION, HANDLE_SUBSCRIPTION);
registerTransition(RECEIVE_SUBSCRIPTION, HANDLE_CANCEL, ACLMessage.CANCEL);
registerTransition(RECEIVE_SUBSCRIPTION, SEND_NOTIFICATIONS, MsgReceiver.INTERRUPTED);
registerDefaultTransition(HANDLE_SUBSCRIPTION, SEND_RESPONSE);
registerDefaultTransition(HANDLE_CANCEL, SEND_RESPONSE);
registerDefaultTransition(SEND_RESPONSE, RECEIVE_SUBSCRIPTION, new String[] {HANDLE_SUBSCRIPTION, HANDLE_CANCEL});
registerDefaultTransition(SEND_NOTIFICATIONS, RECEIVE_SUBSCRIPTION);
//***********************************************
// For each state create and register a behaviour
//***********************************************
Behaviour b = null;
// RECEIVE_SUBSCRIPTION
msgRecBehaviour = new MsgReceiver(myAgent, mt, MsgReceiver.INFINITE, getDataStore(), SUBSCRIPTION_KEY);
registerFirstState(msgRecBehaviour, RECEIVE_SUBSCRIPTION);
// HANDLE_SUBSCRIPTION
b = new OneShotBehaviour(myAgent) {
public void action() {
DataStore ds = getDataStore();
ACLMessage subscription = (ACLMessage) ds.get(SUBSCRIPTION_KEY);
ACLMessage response = null;
try {
response = handleSubscription(subscription);
}
catch (NotUnderstoodException nue) {
response = nue.getACLMessage();
}
catch (RefuseException re) {
response = re.getACLMessage();
}
ds.put(RESPONSE_KEY, response);
}
};
b.setDataStore(getDataStore());
registerState(b, HANDLE_SUBSCRIPTION);
// HANDLE_CANCEL
b = new OneShotBehaviour(myAgent) {
public void action() {
DataStore ds = getDataStore();
ACLMessage cancel = (ACLMessage) ds.get(CANCEL_KEY);
ACLMessage response = null;
try {
response = handleCancel(cancel);
}
catch (FailureException fe) {
response = fe.getACLMessage();
}
ds.put(RESPONSE_KEY, response);
}
};
b.setDataStore(getDataStore());
registerState(b, HANDLE_CANCEL);
// SEND_RESPONSE
b = new ReplySender(myAgent, RESPONSE_KEY, SUBSCRIPTION_KEY);
b.setDataStore(getDataStore());
registerState(b, SEND_RESPONSE);
// SEND_NOTIFICATIONS
b = new OneShotBehaviour(myAgent) {
public void action() {
sendNotifications();
}
};
b.setDataStore(getDataStore());
registerState(b, SEND_NOTIFICATIONS);
} // End of Constructor
/**
Reset this behaviour
*/
// FIXME: reset deve resettare anche le sottoscrizioni?
public void reset() {
super.reset();
DataStore ds = getDataStore();
ds.remove(SUBSCRIPTION_KEY);
ds.remove(RESPONSE_KEY);
}
/**
This method resets the protocol and allows to change the
<code>MessageTemplate</code>
that defines what messages this SubscriptionResponder
will react to.
*/
public void reset(MessageTemplate mt) {
this.reset();
msgRecBehaviour.reset(mt, MsgReceiver.INFINITE, getDataStore(), SUBSCRIPTION_KEY);
}
/**
* This method is called when a subscription
* message is received that matches the message template
* specified in the constructor.
* The default implementation creates an new <code>Subscription</code>
* object and registers it to the <code>SubscriptionManager</code>
* used by this responder. Then it returns null which has
* the effect of sending no reponse. Programmers in general do not need
* to override this method, but just implement the <code>register()</code>
* method of the <code>SubscriptionManager</code> used by this
* <code>SubscriptionResponder</code>. However they could
* override it in case they need to react to the reception of a
* subscription message in a different way, e.g. by sending back an AGREE.
* @param subscription the received message
* @return the ACLMessage to be sent as a response (i.e. one of
* <code>agree, refuse, not-understood</code>.
*/
protected ACLMessage handleSubscription(ACLMessage subscription) throws NotUnderstoodException, RefuseException {
// Call prepareResponse() for backward compatibility
return prepareResponse(subscription);
}
/**
* @deprecated Use handleSubscription() instead
*/
protected ACLMessage prepareResponse(ACLMessage subscription) throws NotUnderstoodException, RefuseException {
mySubscriptionManager.register(createSubscription(subscription));
return null;
}
/**
* This method is called when a CANCEL
* message is received for a previous subscription.
* The default implementation retrieves the <code>Subscription</code>
* object the received cancel message refers to and deregisters it from the
* <code>SubscriptionManager</code> used by this responder. Then it
* returns null which has the effect of sending no reponse.
* Programmers in general do not need
* to override this method, but just implement the <code>deregister()</code>
* method of the <code>SubscriptionManager</code> used by this
* <code>SubscriptionResponder</code>. However they could
* override it in case they need to react to the reception of a
* cancel message in a different way, e.g. by sending back an INFORM.
* @param cancel the received CANCEL message
* @return the ACLMessage to be sent as a response to the
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?