/***************************************************************** 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. *****************************************************************/ ////////////////////////////////////////////////////////////// //Kaveh Kamyab - Imperial College - 30/10/00 //General Changes // //* Replaced all 'ReteException' with 'JessException' //* Instantiate Rete with 'new Rete()' instead of 'new Rete(NullDisplay ...)' //* Line 193 - replaced 'FileInputStream fis = new FileInputStream(jessFile);' // with 'FileReader fr = new FileReader(jessFile);' //* Line 196 - replaced 'Jesp j = new Jesp(fis, jess);' // with 'Jesp j = new Jesp(fr, jess);' //* Replaced all 'stringValue()' with 'stringValue(context)' //* Replaced '(jess.display()).stderr()' // with 'System.err' //* Updated getAIDListFromCache to take a ValueVector as parameter. It also requires Context as a parameter to // resolve JESS variables ////////////////////////////////////////////////////////////// //Kaveh Kamyab - Imperial College - 30/10/00 //Changes In JessSend // //* Replaced 'name()' with 'getName()' //* Replaced 'engine()' with 'getEngine()' //* Modified Method 'JessFact2ACL(jess.ValueVector vv)' // changed to 'JessFact2ACL(Context context, jess.ValueVector vv)' //* Replaced method call accordingly 'JessFact2ACL(vv)' with 'JessFact2ACL(context, vv)' //* Replaced 'FunCall.TRUE()' with 'FunCall.TRUE' // //* Check for two cases, i.e. if send has a RU.VARIABLE as its first parameter (send ?m) and secondly if //send has an RU.FUNCALL as its first parameter (send (assert (ACLMessage ...))). //1) The first case is straight forward. Get the first parameter of the ValueVector, extract the Fact Id and find the fact //by looking up the Fact Id. Pass the resulting ValueVector to JessFact2ACL(Context context, jess.ValueVector vv). //2) The second case is a little more tricky. Get the first parameter of the ValueVector, extract the function call //(assert). Get the first parameter again and extract the ACLMessage. Jess variables must be resolved with calls to //Value.stringValue(context), Value.listValue(context), etc. package examples.jess; import jade.core.*; import jade.core.behaviours.*; import jade.lang.acl.ACLMessage; import jess.*; import java.io.*; import java.util.List; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.Date; /** Javadoc documentation for the file @author Fabio Bellifemine - CSELT S.p.A @author Kaveh Kamyab - Imperial College of London (upgrade to JESS 5.1) @version $Date: 2003/07/03 09:27:07 $ $Revision: 2.9 $ */ /** * This is the basic class that implements a behaviour of JADE that allows * to embed a Jess engine inside the agent code. *

* Jess * supports the development of rule-based expert systems. *

* This JADE implementation has been tested with version 6.0 of JESS. *

* The programmer can override this class. * In particular, its methods ACL2JessString and * JessFact2ACL to convert between ACLMessage JADE structure and * Jess facts. Also the method ACLJessTemplate might need to * be overide in order to change the deftemplate of the ACLMessage in Jess. *

* When this behaviour is added to the list of agent behaviours, * it creates a Jess engine and initializes the engine by: *

* Then the behaviour loops infinitely by: * *

* Notice for programmers of the Jess .clp file: *

*

* Look at the sample file JadeAgent.clp that is shipped with this example. *

* WARNING: * FIPA2000 standard has specified an AgentIdentifier to have a * template * composed of several slots, where the only mandatory one is the agent name, * i.e. the globally unique identifier of the agent (GUID). * In order to reduce the porting of the JESS user code, this basic * behaviour automatically * takes care of replacing the GUIDs with full-fledged AgentIdentifiers. */ public class BasicJessBehaviour extends CyclicBehaviour{ /** * This class implements the Jess userfunction to send ACLMessages * directly from Jess. * It can be used by Jess by using the name send. */ public class JessSend implements Userfunction { // data Agent my_agent; BasicJessBehaviour bjb; public JessSend(Agent a, BasicJessBehaviour b){ my_agent = a; bjb=b; } // The name method returns the name by which the function appears in Jess public String getName() { return("send"); } //Called when (send ...) is encountered public Value call(ValueVector vv, Context context) throws JessException { //for (int i=0; i)) jess.executeCommand("(deffacts MyAgent \"All facts about this agent\" (MyAgent (name " + myAgent.getName() + ")))"); // Open the file test.clp FileReader fr = new FileReader(jessFile); // Create a parser for the file, telling it where to take input // from and which engine to send the results to Jesp j = new Jesp(fr, jess); // parse and execute one construct, without printing a prompt j.parse(false); } catch (JessException re) { System.out.println(re); } catch (FileNotFoundException e) { System.out.println(e); } } /** * Creates a BasicJessBehaviour instance that limits * the reasoning time of Jess before looking again for arrival of messages. * * @param agent the agent that adds the behaviour * @param jessFile the name of the Jess file to be executed * @param maxJessPasses the maximum number of passes that every run of Jess * can execute before giving again the control to this behaviour; * put 0 if you do not ever want to stop Jess. */ public BasicJessBehaviour(Agent agent, String jessFile, int maxJessPasses){ this(agent,jessFile); m_maxJessPasses = maxJessPasses; } /** * executes the behaviour */ public void action() { ACLMessage msg; // to keep the ACLMessage // wait a message if (executedPasses < m_maxJessPasses) { System.out.println(myAgent.getName()+ " is blocked to wait a message..."); msg = myAgent.blockingReceive(); // assert the fact message in Jess assert(ACL2JessString(msg)); } else { System.out.println(myAgent.getName()+ " is checking if there is a message..."); msg = myAgent.receive(); if (msg != null) // assert the fact message in Jess assert(ACL2JessString(msg)); } // run jess try { // jess.executeCommand("(facts)"); if (m_maxJessPasses > 0) { executedPasses=jess.run(m_maxJessPasses); System.out.println("Jess has executed "+executedPasses+" passes"); } else jess.run(); } catch (JessException re) { re.printStackTrace(System.err); } } private boolean isEmpty(String string) { return string == null || string.equals(""); } /** * asserts a fact representing an ACLMessage in Jess. It is called after * the arrival of a message. */ private void assert(String fact) { try { jess.executeCommand(fact); } catch (JessException re) { re.printStackTrace(System.err); } } /* * replace a char in a String with a String * It is used to convert all the quotation marks in backslash quote * before asserting the content of a message in Jess. * @return the new String */ private String stringReplace(String str, char oldChar, String s) { int len = str.length(); int i = 0; int j=0; int k=0; char[] val = new char[len]; str.getChars(0,len,val,0); // put chars into val char buf[] = new char[len*s.length()]; while (i < len) { if (val[i] == oldChar) { s.getChars(0,s.length(),buf,j); j+=s.length(); } else { buf[j]=val[i]; j++; } i++; } return new String(buf, 0, j); } /** * Remove the first and the last character of the string * (if it is a quotation mark) and convert all backslash quote in quote * It is used to convert a Jess content into an ACL message content. */ private String unquote(String str) { String t1= str.trim(); if (t1.startsWith("\"")) t1 = t1.substring(1); if (t1.endsWith("\"")) t1 = t1.substring(0,t1.length()-1); int len = t1.length(); int i = 0; int j=0; int k=0; char[] val = new char[len]; t1.getChars(0,len,val,0); // put chars into val char buf[] = new char[len]; boolean maybe = false; while (i < len) { if (maybe) { if (val[i] == '\"') j--; buf[j] = val[i]; maybe=false; i++; j++; } else { if (val[i] == '\\') { maybe=true; } buf[j] = val[i]; i++; j++; } } return new String(buf, 0, j); } /** * Insert the first and the last character of the string as a quotation mark * Replace all the quote characters into backslash quote. * It is used to convert an ACL message content into a Jess content. */ private String quote(java.lang.String str) { //replace all chars " in \ " return "\"" + stringReplace(str,'"',"\\\"") + "\""; } /** * This method searches in the local cache for the full AID of the passed agentName. * If not found it creates a new AID where only the guid is set. **/ public AID getAIDFromCache(String agentName) { AID result; result = (AID)AIDCache.get(agentName); if (result == null){ result = new AID(agentName); } return result; } /** * This method searches in the local cache for the full AID of the passed list of agent names. * @param context represents the Rete engine context needed to resolve the value of JESS variables * @param list is a ValueVector of agent names * @return a List of AID */ public List getAIDListFromCache(Context context, ValueVector list) { ArrayList l = new ArrayList(); for(int i = 0; i < list.size(); i++){ try{ l.add(getAIDFromCache(list.get(i).stringValue(context))); } catch(JessException je) {} } return l; } /** * put a new AID in the local cache. * If one exists already with the same agentName, it is overwritten */ public void putAIDInCache(AID aid) { AIDCache.put(aid.getName(),aid); } /** @return a String with the deftemplate command to be executed in Jess **/ public String ACLJessTemplate() { return "(deftemplate ACLMessage (slot communicative-act) (slot sender) (multislot receiver) (slot reply-with) (slot in-reply-to) (slot envelope) (slot conversation-id) (slot protocol) (slot language) (slot ontology) (slot content) (slot encoding) (multislot reply-to) (slot reply-by))"; } /** * @return the ACLMessage representing the passed Jess Fact. This message * will be then sent by the caller. */ public ACLMessage JessFact2ACL(Context context, jess.ValueVector vv) throws jess.JessException { // System.err.println("JessFact2ACL "+vv.toString()); int perf = ACLMessage.getInteger(vv.get(0).stringValue(context)); ACLMessage msg = new ACLMessage(perf); System.out.println("******** Sender ********* " + vv.get(1).toString()); if (vv.get(1).stringValue(context) != "nil") msg.setSender(getAIDFromCache(vv.get(1).stringValue(context))); if (vv.get(2).toString() != "nil") { List l = getAIDListFromCache(context, vv.get(2).listValue(context)); for (int i=0; i