/* Lookup agent rev 0.0.2 for FIPAOS 1.3.3 Written as a proof of concept by Ognen Duzlevski ( http://www.cs.usask.ca/undegrads/ogd116 ) Mobile and Ubiquitous Computing Lab University of Saskatchewan, Saskatoon, Canada Purpose: The agent acts as a proxy for all other agents wishing to do a federated lookup. Since the current implementation of FipaOS (1.3.3) does not provide for inter-registering of directory facilitators on different platforms, we need to have an agent that will extract the foreign platforms from the acc.profile and register itself with all DFs on these platforms, thus being able to perform lookups when requested. The extraction, for now (it was easier) is done by simple string search for string "" in the acc.profile. Guidelines: Look at the fipaos\examples\dfsearch.txt file to see how to formulate a search. The reply will come back in the same form as the reply from a DF (test this with the iotestagent). There will be as many replies as there are DFs to be searched. You will know on which platform a particular agent is registered by parsing the contents of a reply and searching for a string starting with "df@" -> the rest will be the HAP. You can then extract the agents in the result string and utilize them by sending them direct messages. Limitations: the agent is tied to the platform it runs on -> it will only be able to register itself with and search the platforms listed in the acc.profile on a particular platform. Future: If we had an agent per platform waking up after the df/ams automatcally, we could have a federated search ability built-in. Although cross-registering DFs is the correct approach. Note: this is rev 0.0.1 - it was coded without designing ;) and is considered an ob-hack. I have tested the agent on a platform of three fipa-os'd machines and it worked fine. If the code seems messy and incorrect, it is only because it was done by a messy person. History: rev 0.0.2: separated the registration into a RegistrationTask. Things should work now (Tom) :) */ import fipaos.agent.*; import fipaos.agent.task.*; import fipaos.ont.fipa.*; import fipaos.agent.conversation.*; import fipaos.ont.fipa.fipaman.*; //import fipaos.skill.db.*; import fipaos.parser.acl.*; import fipaos.agent.conversation.content.*; import fipaos.util.StringParser; import fipaos.parser.sl.*; import fipaos.platform.df.SearchTask; import fipaos.parser.ParserException; import java.io.*; import java.util.Vector; import java.util.LinkedList; public class LookupAgent extends FIPAOSAgent { private String platform_filename; private Vector HAP = new Vector(); // to keep possible HAPs private Vector DF = new Vector(); // to keep confirmed DFs public LookupAgent(String profile, String name, String owner) { super(profile, name, owner); // remember the filename for later // we will use it to get the acc.profile file platform_filename = profile; // now go on with the setup System.out.println("Initializing agent."); setListenerTask(new IdleTask()); registerWithAMS(); registerWithDF("lookup-agent"); // get foreign HAPs //getPlatformAddresses(); // register with all DFs //registerWithDFs(); } public void registrationSucceeded(String agent) { System.out.println("Registration succeeded with " + agent + "."); if (!DF.contains(getLocalDFAID())) { DF.add(getLocalDFAID()); System.out.println("Adding local df@" + getHAP()); } } public void registrationFailed(String agent, String reason) { if (reason.compareTo(FIPAMANCONSTANTS.AGENT_ALREADY_REGISTERED) != 0) shutdown(); } public void registrationRefused(String agent, String reason) { if (reason.compareTo(FIPAMANCONSTANTS.AGENT_ALREADY_REGISTERED) != 0) shutdown(); } public void shutdown() { // empty for now } public class IdleTask extends Task { public IdleTask() { // do nothing } public void startTask() { // do nothing for now newTask(new RegistrationTask()); } public void handleOther(Conversation conv) { System.out.println("handleOther() invoked -> sending a NOT_UNDERSTOOD back."); /* we are sending a "not-understood" if this method was invoked */ ACL msg = conv.getACL(conv.getLatestMessageIndex()); // print out the contents System.out.println("Performative: " + msg.getPerformative()); AgentID sender = msg.getSenderAID(); msg.setPerformative(FIPACONSTANTS.NOT_UNDERSTOOD); msg.setSenderAID(getAID()); msg.setReceiverAID(sender); forward(msg); } public void handleAgree(Conversation conv) { // here we will add all valid DFs to our DF vector ACL msg = conv.getACL(conv.getLatestMessageIndex()); // get last message AgentID sender = msg.getSenderAID(); // get sender AID String senderName = sender.getName(); // get sender name if (senderName.startsWith("df@")) // is it a DF? // if the df sender is not in the vector -> add it ;) if (!DF.contains(sender)) System.out.println("An agree for a search came in from an unknown DF?"); } // handleAgree() public void handleRequest(Conversation conv) { /* in this method we have to create an ACL message out of all agents that match the search criteria -> we are using the DF vector for a list of active DFs (this list is static!) due to a lack of forwarding features in fipaos rev 1.3.3 we need to break down the communication two ways: * agent->lookup-agent->df * fd->lookup-agent->agent */ // first get this instance's name String this_agent = getAID().getName(); // get last message ACL msg = conv.getACL(conv.getLatestMessageIndex()); // get original content String cnt = StringParser.trimBrackets((String)msg.getContentObject()); try { AgentManagementAction ama = new AgentManagementAction(cnt); // get the management request action String function = ama.getAction(); if (function.equals("search")) { // send "Agree" first System.out.println("Incoming search message from: " + msg.getSenderAID().getName()); ACL agree = new ACL(); agree.setPerformative(FIPACONSTANTS.AGREE); agree.setSenderAID(getAID()); agree.setReceiverAID(msg.getSenderAID()); agree.setInReplyTo( msg.getReplyWith() ); agree.setReplyWith( null ); forward(agree); System.out.println("Sent agree msg to: " + msg.getSenderAID().getName()); // now reroute the search requests to all known DFs for (int i=0; i 0) // yes, get the receiver receiver = (AgentID)ll.get(0); else // nothing to do with the inform so far return; // construct a new message System.out.println("Search reply came in from: " + senderName); ACL fwd = new ACL(); //fwd.setProtocol(msg.getProtocol()); fwd.setPerformative(FIPACONSTANTS.INFORM); //fwd.setLanguage(msg.getLanguage()); //fwd.setOntology(msg.getOntology()); fwd.setSenderAID(getAID()); fwd.setReceiverAID(receiver); fwd.setInReplyTo(msg.getInReplyTo()); // mangle the contents to change df name to this agent's name StringBuffer newContent = new StringBuffer(content); int start = content.indexOf(senderName); int end = senderName.length() + start; //replace the df name with this agent's name //newContent.replace(start, end, this_agent); // set the new contents fwd.setContentObject(newContent.toString()); //System.out.println("Content: " + newContent.toString()); // send the message forward(fwd); System.out.println("Rerouted message from " + senderName + " to " + receiver.getName()); } public void handleRefuse(Conversation conv) { ACL msg = conv.getACL(conv.getLatestMessageIndex()); AgentID sender = msg.getSenderAID(); System.out.println("Refuse from " + sender.getName()); if (sender.getName().indexOf("df") != -1) System.out.println("Registration with " + sender.getName() + " refused."); } public void shutdown() { System.exit(0); } } // IdleTask public class RegistrationTask extends Task { // added in rev 0.0.2 public RegistrationTask() { // do nothing } public void startTask() { getDFAddresses(); registerWithDFs(); } private void getDFAddresses() { // obtain the platform addresses by parsing the acc.profile file by treating it line-by-line String startStr = ""; String endStr = ""; int startStrLen = startStr.length(); StringBuffer sb = null; /* we are using the filename that was passed as the platform profile */ try { File f = new File(platform_filename); // get the full path of the platform.profile file String absPath = f.getAbsolutePath(); // get the last occurence of the path separator int lastIndex = absPath.lastIndexOf(f.separator); // now extract everything before that sb = new StringBuffer(absPath.substring(0, lastIndex+1)); // get the new full pathname of acc.profile sb.append("acc.profile"); // try to open the acc.profile file FileReader fr = new FileReader(new String(sb)); LineNumberReader lr = new LineNumberReader(fr); String line = lr.readLine(); while (line != null) { // look for HAP in line int startPos = line.indexOf(startStr); if (startPos > -1) { // string found, obtain ending marker int endPos = line.indexOf(endStr); if (endPos > -1) { // get the HAP (between start and end marker // and add it to the global vector String HAPn = line.substring(startPos+startStrLen, endPos); HAP.add(HAPn); } } line = lr.readLine(); } // while } catch (NullPointerException np) { System.out.println("No acc.profile to parse. Shutting down..."); shutdown(); } catch (FileNotFoundException fe) { System.out.println("File " + sb + " not found. Shutting down..."); shutdown(); } catch (IOException ioe) { System.out.println("I/O error reading file " + sb + ". Shutting down..."); shutdown(); } } private void registerWithDFs() { // this method has to send registration requests with all DF@HAPs String content1 = "((action (agent-identifier :name "; String dfdesc = " :services (set (service-description :name lookup-agent :type lookup-agent ))"; String content2 = " ) (register (df-agent-description "; String content3 = " :name (agent-identifier :name "; String content4 = " ) ) ) ) )"; if (HAP.size() > 0) { // at least one HAP in the vector for (int i=0; i < HAP.size(); i++) { // build a registration message for each df ACLMessage msg = new ACLMessage(); msg.setPerformative(FIPACONSTANTS.REQUEST); msg.setOntology(FIPAMANCONSTANTS.FIPA_AGENT_MANAGEMENT); msg.setLanguage(FIPAMANCONSTANTS.FIPA_SL0); msg.setProtocol(FIPACONSTANTS.FIPA_REQUEST); String agentName = getAID().getName(); msg.setSender("(agent-identifier :name " + agentName + " )"); String DFName = "df@" + (String)HAP.elementAt(i); msg.setReceiver("(agent-identifier :name " + DFName + " )"); String content = content1+DFName+content2+dfdesc+content3+agentName+content4; msg.setContent(content); // send the message, reply as "inform" System.out.println("Trying to register with " + DFName); forward(msg); } // for } // if } // registerWithDFs() public void handleAgree(Conversation conv) { // this method is usually invoked upon registration from a DF // (but can be invoked by any agent agreeing to perform a service) // here we will add all valid DFs to our DF vector ACL msg = conv.getACL(conv.getLatestMessageIndex()); // get last message AgentID sender = msg.getSenderAID(); // get sender AID String senderName = sender.getName(); // get sender name if (senderName.startsWith("df@")) // is it a DF? // if the df sender is not in the vector -> add it ;) if (!DF.contains(sender)) { System.out.println("Added " + senderName + " (registration succeeded)."); DF.add(sender); } } // handleAgree() } // RegistrationTask public static void main(String args[]) { new LookupAgent(args[0], args[1], "FIPA-OS"); } }