📄 sniffer.java
字号:
/*****************************************************************
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.tools.sniffer;
import java.io.StringReader;
import java.util.Map;
import java.util.TreeMap;
import jade.util.leap.Iterator;
import jade.util.leap.List;
import jade.util.leap.ArrayList;
import jade.util.Logger;
import java.util.LinkedList;
import java.util.Hashtable;
import java.util.Set;
import java.util.HashSet;
import jade.core.*;
import jade.core.behaviours.*;
import jade.domain.FIPANames;
import jade.domain.JADEAgentManagement.*;
import jade.domain.introspection.*;
import jade.domain.FIPAService;
import jade.domain.FIPAAgentManagement.Envelope;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.ACLCodec;
import jade.lang.acl.StringACLCodec;
import jade.content.lang.sl.SLCodec;
import jade.content.AgentAction;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Done;
import jade.proto.SimpleAchieveREResponder;
import jade.proto.SimpleAchieveREInitiator;
import jade.tools.ToolAgent;
import jade.util.ExpandedProperties;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.io.*;
/**
* This is the <em>Sniffer</em> agent.
* <br>
* This class implements the low level part of the Sniffer, interacting with Jade
* environment and with the sniffer GUI.<br>
* At startup, the sniffer subscribes itself as an rma to be informed every time
* an agent is born or dead, a container is created or deleted.
* <br>
* For more information see <a href="../../../../intro.htm" target="_top">Introduction to the Sniffer</a>.
* <p>
* A properties file while may be used to control different sniffer properties.
* These optional properties are as follows:
* <ul>
* <li>preload - A list of preload descriptions seperated by a semi-colon. Each description
* consists of an agent name match string and optional list of performatives each seperated by a space.
* For details on the agent name match string, see the method isMatch().
* If there is no @ in the agent name, it assumes the current HAP for it.
* If the performative list is not present, then the sniffer will display all messages;
* otherwise, only those messages that have a matching performative mentioned will be displayed.
* <br>
* Examples:
* <pre>
* preload=da0;da1 inform propose
* preload=agent?? inform
* preload=*
* </pre>
* <li>clip - A list of agent name prefixes seperated by a semi-colon which will be removed when
* showing the agent's name in the agent box. This is helpful to eliminate common agent prefixes.
* <br>
* Example:
* <pre>
* clip=com.hp.palo-alto.;helper.
* </pre>
* </ul>
* The property file is looked for in the current directory, and if not found, it looks in
* the parent directory and continues this until the file is either found or there isn't a parent
* directory.
* <p>
* The original implementation processed a .inf file. For backward compatability this has
* been preserved but its usage should be converted to use the new .properties file. The format
* of the .inf file is each line contains an agent name and optional list of performatives.
* <br>
* Example:
* <pre>
* da0
* da1 inform propose
* </pre>
* <p>
* Notes:
* <ol>
* <li>If a message is one that is to be ignored, then it is dropped totally. If you
* look at the sniffer dump of messages, it will not be there. Might want to change
* this.
* <li>Should develop a GUI to allow dynamically setting which messages are filtered instead
* of forcing them to be in the properties file.
* <li>Probably should allow one to turn on and off the display of the performative name.
* Although, it seems pretty nice to have this information and although one might
* consider that it clutters the display, it sure provides a lot of information with
* it.
* </ol>
*
* @author <a href="mailto:alessandro.beneventi@re.nettuno.it"> Alessandro Beneventi </a>(Developement)
* @author Gianluca Tanca (Concept & Early Version)
* @author Robert Kessler University of Utah (preload configuration, don't scroll agent boxes)
* @author Martin Griss HP Labs (display additional message information)
* @author Dick Cowan HP Labs (property handling, display full agent name when mouse over)
* @version $Date: 2008-02-25 12:30:57 +0100 (lun, 25 feb 2008) $ $Revision: 6021 $
*
*/
public class Sniffer extends ToolAgent {
public static final boolean SNIFF_ON = true;
public static final boolean SNIFF_OFF = false;
private Set allAgents = null;
private Hashtable preload = null;
private ExpandedProperties properties = null;
private ArrayList agentsUnderSniff = new ArrayList();
// Sends requests to the AMS
private class AMSClientBehaviour extends SimpleAchieveREInitiator {
private String actionName;
public AMSClientBehaviour(String an, ACLMessage request) {
super(Sniffer.this, request);
actionName = an;
}
protected void handleNotUnderstood(ACLMessage reply) {
myGUI.showError("NOT-UNDERSTOOD received during " + actionName);
}
protected void handleRefuse(ACLMessage reply) {
myGUI.showError("REFUSE received during " + actionName);
}
protected void handleAgree(ACLMessage reply) {
if(logger.isLoggable(Logger.FINE))
logger.log(Logger.FINE,"AGREE received");
}
protected void handleFailure(ACLMessage reply) {
myGUI.showError("FAILURE received during " + actionName);
}
protected void handleInform(ACLMessage reply) {
if(logger.isLoggable(Logger.FINE))
logger.log(Logger.FINE,"INFORM received");
}
} // End of AMSClientBehaviour class
private class SniffListenerBehaviour extends CyclicBehaviour {
private MessageTemplate listenSniffTemplate;
SniffListenerBehaviour() {
listenSniffTemplate = MessageTemplate.MatchConversationId(getName() + "-event");
}
public void action() {
ACLMessage current = receive(listenSniffTemplate);
if(current != null) {
try {
Occurred o = (Occurred)getContentManager().extractContent(current);
EventRecord er = o.getWhat();
Event ev = er.getWhat();
String content = null;
Envelope env = null;
AID unicastReceiver = null;
if(ev instanceof SentMessage) {
content = ((SentMessage)ev).getMessage().getPayload();
env = ((SentMessage)ev).getMessage().getEnvelope();
unicastReceiver = ((SentMessage)ev).getReceiver();
} else if(ev instanceof PostedMessage) {
content = ((PostedMessage)ev).getMessage().getPayload();
env = ((PostedMessage)ev).getMessage().getEnvelope();
unicastReceiver = ((PostedMessage)ev).getReceiver();
} else return;
ACLCodec codec = new StringACLCodec();
String charset = null;
if ((env == null) ||
((charset = env.getPayloadEncoding()) == null)) {
charset = ACLCodec.DEFAULT_CHARSET;
}
ACLMessage tmp = codec.decode(content.getBytes(charset),charset);
tmp.setEnvelope(env);
Message msg = new Message(tmp, unicastReceiver);
// If this is a 'posted-message' event and the sender is
// currently under sniff, then the message was already
// displayed when the 'sent-message' event occurred. In that
// case, we simply skip this message.
if(ev instanceof PostedMessage) {
Agent a = new Agent(msg.getSender());
if(agentsUnderSniff.contains(a))
return;
}
// If the message that we just got is one that should be filtered out
// then drop it. WARNING - this means that the log file
// that the sniffer might dump does not include the message!!!!
boolean filters [];
String agentName = msg.getSender().getName();
String key = preloadContains(agentName);
if (key != null) {
filters = (boolean[])preload.get(key);
if ((msg.getPerformative() >= 0) && filters[msg.getPerformative()]) {
myGUI.mainPanel.panelcan.canvMess.recMessage(msg);
}
} else {
myGUI.mainPanel.panelcan.canvMess.recMessage(msg);
}
}
catch(Throwable e) {
//System.out.println("Serious problem Occurred");
myGUI.showError("An error occurred parsing the incoming message.\n" +
" The message was lost.");
if(logger.isLoggable(Logger.WARNING))
logger.log(Logger.WARNING,"The sniffer lost the following message because of a parsing error:"+current);
e.printStackTrace();
}
}
else
block();
}
} // End of SniffListenerBehaviour
//
//
// * Search keys in preload for a string which matches (using isMatch method)
// * the agent name.
// * @param agentName The agent name.
// * @return String The key which matched.
//
protected String preloadContains(String agentName) {
for (Enumeration enumeration = preload.keys(); enumeration.hasMoreElements() ;) {
String key = (String)enumeration.nextElement();
if (isMatch(key, agentName)) {
return key;
}
}
return null;
}
/**
* Given two strings determine if they match. We iterate over the match expression
* string from left to right as follows:
* <ol>
* <li> If we encounter a '*' in the expression token they match.
* <li> If there aren't any more characters in the subject string token they don't match.
* <li> If we encounter a '?' in the expression token we ignore the subject string's
* character and move on to the next iteration.
* <li> If the character in the expression token isn't equal to the character in
* the subject string they don't match.
* </ol>
* If we complete the iteration they match only if there are the same number of
* characters in both strings.
* @param aMatchExpression An expression string with special significance to '?' and '*'.
* @param aString The subject string.
* @return True if they match, false otherwise.
*/
protected boolean isMatch(String aMatchExpression, String aString)
{
int expressionLength = aMatchExpression.length();
for (int i = 0; i < expressionLength; i++)
{
char expChar = aMatchExpression.charAt(i);
if (expChar == '*')
return true; // * matches the remainder of anything
if (i == aString.length())
return false; // if we run out of characters they don't match
if (expChar == '?')
continue; // ? matches any single character so keep going
if (expChar != aString.charAt(i))
return false; // if non wild then must be exactly equal
}
return (expressionLength == aString.length());
}
private SequentialBehaviour AMSSubscribe = new SequentialBehaviour();
/**
@serial
*/
private MainWindow myGUI;
/**
@serial
*/
private String myContainerName;
class SnifferAMSListenerBehaviour extends AMSListenerBehaviour {
protected void installHandlers(Map handlersTable) {
// Fill the event handler table.
handlersTable.put(IntrospectionVocabulary.META_RESETEVENTS, new EventHandler() {
public void handle(Event ev) {
ResetEvents re = (ResetEvents)ev;
myGUI.resetTree();
}
});
handlersTable.put(IntrospectionVocabulary.ADDEDCONTAINER, new EventHandler() {
public void handle(Event ev) {
AddedContainer ac = (AddedContainer)ev;
ContainerID cid = ac.getContainer();
String name = cid.getName();
String address = cid.getAddress();
try {
InetAddress addr = InetAddress.getByName(address);
myGUI.addContainer(name, addr);
}
catch(UnknownHostException uhe) {
myGUI.addContainer(name, null);
}
}
});
handlersTable.put(IntrospectionVocabulary.REMOVEDCONTAINER, new EventHandler() {
public void handle(Event ev) {
RemovedContainer rc = (RemovedContainer)ev;
ContainerID cid = rc.getContainer();
String name = cid.getName();
myGUI.removeContainer(name);
}
});
handlersTable.put(IntrospectionVocabulary.BORNAGENT, new EventHandler() {
public void handle(Event ev) {
BornAgent ba = (BornAgent)ev;
ContainerID cid = ba.getWhere();
String container = cid.getName();
AID agent = ba.getAgent();
myGUI.addAgent(container, agent);
if(agent.equals(getAID()))
myContainerName = container;
// Here we check to see if the agent is one that we automatically will
// start sniffing. If so, we invoke DoSnifferAction's doSniff and start
// the sniffing process.
// Avoid sniffing myself to avoid infinite recursion
if (!agent.equals(getAID())) {
if (preloadContains(agent.getName()) != null) {
ActionProcessor ap = myGUI.actPro;
DoSnifferAction sa = (DoSnifferAction)ap.actions.get(ap.DO_SNIFFER_ACTION);
sa.doSniff(agent.getName());
}
}
}
});
handlersTable.put(IntrospectionVocabulary.DEADAGENT, new EventHandler() {
public void handle(Event ev) {
DeadAgent da = (DeadAgent)ev;
ContainerID cid = da.getWhere();
String container = cid.getName();
AID agent = da.getAgent();
myGUI.removeAgent(container, agent);
}
});
handlersTable.put(IntrospectionVocabulary.MOVEDAGENT, new EventHandler() {
public void handle(Event ev) {
MovedAgent ma = (MovedAgent)ev;
AID agent = ma.getAgent();
ContainerID from = ma.getFrom();
myGUI.removeAgent(from.getName(), agent);
ContainerID to = ma.getTo();
myGUI.addAgent(to.getName(), agent);
}
});
}
} // END of inner class SnifferAMSListenerBehaviour
/**
* ACLMessages for subscription and unsubscription as <em>rma</em> are created and
* corresponding behaviours are set up.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -