
jason.asSemantics.Agent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jason Show documentation
Show all versions of jason Show documentation
Jason is a fully-fledged interpreter for an extended version of AgentSpeak, a BDI agent-oriented logic programming language.
// ----------------------------------------------------------------------------
// Copyright (C) 2003 Rafael H. Bordini, Jomi F. Hubner, et al.
//
// 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; either
// version 2.1 of the License, or (at your option) any later version.
//
// 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
//
// To contact the authors:
// http://www.inf.ufrgs.br/~bordini
// http://www.das.ufsc.br/~jomi
//
//----------------------------------------------------------------------------
package jason.asSemantics;
import jason.JasonException;
import jason.RevisionFailedException;
import jason.architecture.AgArch;
import jason.asSyntax.ASSyntax;
import jason.asSyntax.ArithFunctionTerm;
import jason.asSyntax.InternalActionLiteral;
import jason.asSyntax.Literal;
import jason.asSyntax.LogicalFormula;
import jason.asSyntax.Plan;
import jason.asSyntax.PlanLibrary;
import jason.asSyntax.Rule;
import jason.asSyntax.Term;
import jason.asSyntax.Trigger;
import jason.asSyntax.Trigger.TEOperator;
import jason.asSyntax.Trigger.TEType;
import jason.asSyntax.directives.FunctionRegister;
import jason.asSyntax.directives.Include;
import jason.asSyntax.parser.ParseException;
import jason.asSyntax.parser.as2j;
import jason.bb.BeliefBase;
import jason.bb.DefaultBeliefBase;
import jason.functions.Count;
import jason.functions.RuleToFunction;
import jason.mas2j.ClassParameters;
import jason.profiling.QueryProfiling;
import jason.runtime.Settings;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* The Agent class has the belief base and plan library of an
* AgentSpeak agent. It also implements the default selection
* functions of the AgentSpeak semantics.
*/
public class Agent {
// Members
protected BeliefBase bb = null;
protected PlanLibrary pl = null;
protected TransitionSystem ts = null;
protected String aslSource = null;
private List initialGoals = null; // initial goals in the source code
private List initialBels = null; // initial beliefs in the source code
private Map internalActions = null;
private Map functions = null;
private boolean hasCustomSelOp = true;
private ScheduledExecutorService scheduler = null;
//private QueryCache qCache = null;
private QueryCacheSimple qCache = null;
private QueryProfiling qProfiling = null;
protected Logger logger = Logger.getLogger(Agent.class.getName());
public Agent() {
checkCustomSelectOption();
}
/**
* Setup the default agent configuration.
*
* Creates the agent class defined by agClass, default is jason.asSemantics.Agent.
* Creates the TS for the agent.
* Creates the belief base for the agent.
*/
public static Agent create(AgArch arch, String agClass, ClassParameters bbPars, String asSrc, Settings stts) throws JasonException {
try {
Agent ag = (Agent) Class.forName(agClass).newInstance();
new TransitionSystem(ag, null, stts, arch);
BeliefBase bb = (BeliefBase) Class.forName(bbPars.getClassName()).newInstance();
ag.setBB(bb); // the agent's BB have to be already set for the BB initialisation
ag.initAg();
bb.init(ag, bbPars.getParametersArray());
ag.load(asSrc); // load the source code of the agent
return ag;
} catch (Exception e) {
throw new JasonException("as2j: error creating the customised Agent class! - ", e);
}
}
/** Initialises the TS and other components of the agent */
public void initAg() {
if (bb == null) bb = new DefaultBeliefBase();
if (pl == null) pl = new PlanLibrary();
if (initialGoals == null) initialGoals = new ArrayList();
if (initialBels == null) initialBels = new ArrayList();
if (internalActions == null) internalActions = new HashMap();
initDefaultFunctions();
if (ts == null) ts = new TransitionSystem(this, null, null, new AgArch());
//if (ts.getSettings().hasQueryCache()) qCache = new QueryCache(this);
if (ts.getSettings().hasQueryProfiling()) qProfiling = new QueryProfiling(this);
if (ts.getSettings().hasQueryCache()) qCache = new QueryCacheSimple(this, qProfiling);
}
/** parse and load the agent code, asSrc may be null */
public void initAg(String asSrc) throws JasonException {
initAg();
load(asSrc);
}
/** parse and load the agent code, asSrc may be null */
public void load(String asSrc) throws JasonException {
// set the agent
try {
boolean parsingOk = true;
if (asSrc != null) {
asSrc = asSrc.replaceAll("\\\\", "/");
setASLSrc(asSrc);
if (asSrc.startsWith(Include.CRPrefix)) {
// loads the class from a jar file (for example)
parseAS(Agent.class.getResource(asSrc.substring(Include.CRPrefix.length())).openStream());
} else {
// check whether source is an URL string
try {
parsingOk = parseAS(new URL(asSrc));
} catch (MalformedURLException e) {
parsingOk = parseAS(new File(asSrc));
}
}
}
if (parsingOk) {
if (getPL().hasMetaEventPlans())
getTS().addGoalListener(new GoalListenerForMetaEvents(getTS()));
addInitialBelsFromProjectInBB();
addInitialBelsInBB();
addInitialGoalsFromProjectInBB();
addInitialGoalsInTS();
fixAgInIAandFunctions(this); // used to fix agent reference in functions used inside includes
}
// kqml Plans at the end of the ag PS
if (JasonException.class.getResource("/asl/kqmlPlans.asl") != null) {
setASLSrc("kqmlPlans.asl");
parseAS(JasonException.class.getResource("/asl/kqmlPlans.asl"));
setASLSrc(asSrc);
} else {
logger.warning("The kqmlPlans.asl was not found!");
}
} catch (Exception e) {
logger.log(Level.SEVERE, "Error creating customised Agent class!", e);
throw new JasonException("Error creating customised Agent class! - " + e);
}
}
/** @deprecated Prefer the initAg method with only the source code of the agent as parameter.
*
* A call of this method like
*
* TransitionSystem ts = ag.initAg(arch, bb, asSrc, stts)
*
* can be replaced by
*
* new TransitionSystem(ag, new Circumstance(), stts, arch);
* ag.setBB(bb); // only if you use a custom BB
* ag.initAg(asSrc);
* TransitionSystem ts = ag.getTS();
*
*/
public TransitionSystem initAg(AgArch arch, BeliefBase bb, String asSrc, Settings stts) throws JasonException {
try {
if (bb != null)
setBB(bb);
new TransitionSystem(this, null, stts, arch);
initAg(asSrc);
return ts;
} catch (Exception e) {
logger.log(Level.SEVERE, "Error creating the agent class!", e);
throw new JasonException("Error creating the agent class! - " + e);
}
}
public void stopAg() {
bb.stop();
if (qProfiling != null)
qProfiling.show();
if (scheduler != null)
scheduler.shutdownNow();
for (InternalAction ia: internalActions.values())
try {
ia.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Clone BB, PL, Circumstance.
* A new TS is created (based on the cloned circumstance).
*/
public Agent clone(AgArch arch) {
Agent a = null;
try {
a = this.getClass().newInstance();
} catch (InstantiationException e1) {
logger.severe(" cannot create derived class" +e1);
return null;
} catch (IllegalAccessException e2) {
logger.severe(" cannot create derived class" +e2);
return null;
}
a.setLogger(arch);
if (this.getTS().getSettings().verbose() >= 0)
a.logger.setLevel(this.getTS().getSettings().logLevel());
a.bb = this.bb.clone();
a.pl = this.pl.clone();
try {
fixAgInIAandFunctions(a);
} catch (Exception e) {
e.printStackTrace();
}
a.aslSource = this.aslSource;
a.internalActions = new HashMap();
a.setTS(new TransitionSystem(a, this.getTS().getC().clone(), this.getTS().getSettings(), arch));
if (a.getPL().hasMetaEventPlans())
a.getTS().addGoalListener(new GoalListenerForMetaEvents(a.getTS()));
a.initAg(); //for initDefaultFunctions() and for overridden/custom agent
return a;
}
private void fixAgInIAandFunctions(Agent a) throws Exception {
// find all internal actions and functions and change the pointer for agent
for (Plan p: a.getPL()) {
// search context
if (p.getContext() instanceof Literal)
fixAgInIAandFunctions(a, (Literal)p.getContext());
// search body
if (p.getBody() instanceof Literal)
fixAgInIAandFunctions(a, (Literal)p.getBody());
}
}
private void fixAgInIAandFunctions(Agent a, Literal l) throws Exception {
// if l is internal action/function
if (l instanceof InternalActionLiteral) {
((InternalActionLiteral)l).setIA(null); // reset the IA in the literal, the IA there will be updated next getIA call
}
if (l instanceof ArithFunctionTerm) {
((ArithFunctionTerm)l).setAgent(a);
}
if (l instanceof Rule) {
LogicalFormula f = ((Rule)l).getBody();
if (f instanceof Literal) {
fixAgInIAandFunctions(a, (Literal)f);
}
}
for (int i=0; i();
addFunction(Count.class, false);
}
/** register an arithmetic function implemented in Java */
public void addFunction(Class extends ArithFunction> c) {
addFunction(c,true);
}
/** register an arithmetic function implemented in Java */
private void addFunction(Class extends ArithFunction> c, boolean user) {
try {
ArithFunction af = c.newInstance();
String error = null;
if (user)
error = FunctionRegister.checkFunctionName(af.getName());
if (error != null)
logger.warning(error);
else
functions.put(af.getName(),af);
} catch (Exception e) {
logger.log(Level.SEVERE, "Error registering function "+c.getName(),e);
}
}
/** register an arithmetic function implemented in AS (by a rule, literal, or internal action) */
public void addFunction(String function, int arity, String literal) {
try {
String error = FunctionRegister.checkFunctionName(function);
if (error != null)
logger.warning(error);
else
functions.put(function, new RuleToFunction(literal, arity));
} catch (Exception e) {
logger.log(Level.SEVERE, "Error registering function "+literal,e);
}
}
/** get the object the implements the arithmetic function function/arity,
* either global (like math.max) or local (like .count).
*/
public ArithFunction getFunction(String function, int arity) {
if (functions == null) return null;
ArithFunction af = functions.get(function);
if (af == null || !af.checkArity(arity))
// try global function
af = FunctionRegister.getFunction(function, arity);
if (af != null && af.checkArity(arity))
return af;
else
return null;
}
/** Belief b will be stored to be included as an ordinary belief when the agent will start running.
* This method is usually called by the parser; at compile time, when the TS may not be ready yet and thus
* no events can be produced. Beliefs are then scheduled here to be definitely included later when the
* TS is ready. */
public void addInitialBel(Literal b) {
initialBels.add(b);
}
public List getInitialBels() {
return initialBels;
}
/** add the initial beliefs in BB and produce the corresponding events */
public void addInitialBelsInBB() throws RevisionFailedException {
// Once beliefs are stored in a Stack in the BB, insert them in inverse order
for (int i=initialBels.size()-1; i >=0; i--) {
Literal b = initialBels.get(i);
// if l is not a rule and has free vars (like l(X)), convert it into a rule like "l(X) :- true."
if (!b.isRule() && !b.isGround())
b = new Rule(b,Literal.LTrue);
b.apply(new Unifier()); // to solve arithmetic expressions
// does not do BRF for rules (and so do not produce events +bel for rules)
if (b.isRule())
getBB().add(b);
else
addBel(b);
}
initialBels.clear();
}
protected void addInitialBelsFromProjectInBB() {
String sBels = getTS().getSettings().getUserParameter("beliefs");
if (sBels != null) {
try {
for (Term t: ASSyntax.parseList("["+sBels+"]")) {
getBB().add((Literal)t);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Initial beliefs from project '["+sBels+"]' is not a list of literals.");
}
}
}
/** goal g will be stored to be included as an initial goal when the agent will start running */
public void addInitialGoal(Literal g) {
initialGoals.add(g);
}
/** includes all initial goals in the agent reasoner */
public void addInitialGoalsInTS() {
for (Literal g: initialGoals) {
g.makeVarsAnnon();
if (! g.hasSource())
g.addAnnot(BeliefBase.TSelf);
getTS().getC().addAchvGoal(g,Intention.EmptyInt);
}
}
protected void addInitialGoalsFromProjectInBB() {
String sGoals = getTS().getSettings().getUserParameter("goals");
if (sGoals != null) {
try {
for (Term t: ASSyntax.parseList("["+sGoals+"]")) {
Literal g = (Literal)t;
g.makeVarsAnnon();
if (! g.hasSource())
g.addAnnot(BeliefBase.TSelf);
getTS().getC().addAchvGoal(g,Intention.EmptyInt);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Initial goals from project '["+sGoals+"]' is not a list of literals.");
}
}
}
/** Imports beliefs, plans and initial goals from another agent. Initial beliefs and goals
* are stored in "initialBels" and "initialGoals" lists but not included in the BB / TS.
* The methods addInitialBelsInBB and addInitialGoalsInTS should be called in the sequel to
* add those beliefs and goals into the agent. */
public void importComponents(Agent a) throws JasonException {
if (a != null) {
for (Literal b: a.initialBels) {
this.addInitialBel(b);
try {
fixAgInIAandFunctions(this,b);
} catch (Exception e) {
e.printStackTrace();
}
}
for (Literal g: a.initialGoals)
this.addInitialGoal(g);
for (Plan p: a.getPL())
this.getPL().add(p, false);
if (getPL().hasMetaEventPlans())
getTS().addGoalListener(new GoalListenerForMetaEvents(getTS()));
}
}
/**
* Follows the default implementation for the agent's message acceptance
* relation and selection functions
*/
public boolean socAcc(Message m) {
return true;
}
/** Returns true if this agent accepts to be killed by another agent called agName.
* This method can be overridden to customize this option. */
public boolean killAcc(String agName) {
//System.out.println("I am being killed by "+agName+", but that is ok...");
return true;
}
public Event selectEvent(Queue events) {
// make sure the selected Event is removed from 'events' queue
return events.poll();
}
public Option selectOption(List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy