All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jason.asSyntax.PlanLibrary Maven / Gradle / Ivy

Go to download

Jason is a fully-fledged interpreter for an extended version of AgentSpeak, a BDI agent-oriented logic programming language.

There is a newer version: 2.3
Show newest version
//----------------------------------------------------------------------------
// 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.asSyntax;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import jason.JasonException;
import jason.asSyntax.Trigger.TEOperator;
import jason.asSyntax.Trigger.TEType;
import jason.asSyntax.parser.ParseException;
import jason.bb.BeliefBase;
import jason.util.Config;

/** Represents a set of plans used by an agent 

    @has - plans 0..* Plan
*/  
public class PlanLibrary implements Iterable {

    /** a MAP from TE to a list of relevant plans */
    private Map> relPlans = new ConcurrentHashMap>();

    /**
     * All plans as defined in the AS code (maintains the order of the plans)
     */
    private List plans = new ArrayList();
    
    /** list of plans that have var as TE */
    private List varPlans = new ArrayList();
    
    /** A map from labels to plans */
    private Map planLabels = new ConcurrentHashMap();
    
    private boolean hasMetaEventPlans = false; 
    
    private static AtomicInteger lastPlanLabel = new AtomicInteger(0);

    private boolean hasUserKqmlReceived = false;
    
    //private Logger logger = Logger.getLogger(PlanLibrary.class.getName());
    
    private final Object lockPL = new Object();
    
    public Object getLock() {
        return lockPL;
    }
    
    /** 
     *  Add a new plan written as a String. The source
     *  normally is "self" or the agent that sent this plan.
     *  If the PL already has a plan equals to "stPlan", only a
     *  new source is added.
     *  
     *  The plan is added in the end of the PlanLibrary.
     *  
     *  @returns the plan just added
     *  @deprecated parse the plan before (ASSyntax methods) and call add(Plan, ...) methods
     */
    public Plan add(StringTerm stPlan, Term tSource) throws ParseException, JasonException {
       return add(stPlan, tSource, false); 
    }
    
    /** 
     *  Add a new plan written as a String. The source
     *  normally is "self" or the agent that sent this plan.
     *  If the PL already has a plan equals to "stPlan", only a
     *  new source is added.
     *  
     *  If before is true, the plan will be added in the
     *  begin of the PlanLibrary; otherwise, it is added in
     *  the end.
     *  
     *  @returns the plan just added
     *  @deprecated parse the plan before (ASSyntax methods) and call add(Plan, ...) methods
     */
    public Plan add(StringTerm stPlan, Term tSource, boolean before) throws ParseException, JasonException {
        String sPlan = stPlan.getString();
        // remove quotes \" -> "
        StringBuilder sTemp = new StringBuilder();
        for (int c=0; c before is true, the plan will be added in the
     *  begin of the PlanLibrary; otherwise, it is added in
     *  the end.
     *  
     *  @returns the plan just added
     */
    public Plan add(Plan p, Term source, boolean before) throws JasonException {
        synchronized (lockPL) {
            int i = plans.indexOf(p);
            if (i < 0) {
                // add label, if necessary
                if (p.getLabel() == null)
                    p.setLabel(getUniqueLabel());
                p.getLabel().addSource(source);
                add(p, before);
            } else {
                p = plans.get(i);
                p.getLabel().addSource(source);
            }
            return p;
        }
    }

    public void add(Plan p) throws JasonException {
        add(p,false);
    }
    
    private final String kqmlReceivedFunctor = Config.get().getKqmlFunctor();
    
    /**
     * Adds a plan into the plan library, either before or after all other
     * plans depending on the boolean parameter.
     * 
     * @param p The plan to be added to the plan library
     * @param before Whether or not to place the new plan before others
     * @throws JasonException
     */
    public void add(Plan p, boolean before) throws JasonException {
        synchronized (lockPL) {

            // test p.label
            if (p.getLabel() != null && planLabels.keySet().contains( getStringForLabel(p.getLabel()))) {
                // test if the new plan is equal, in this case, just add a source
                Plan planInPL = get(p.getLabel());
                if (p.equals(planInPL)) {
                    planInPL.getLabel().addSource(p.getLabel().getSources().get(0));
                    return;
                } else {
                    throw new JasonException("There already is a plan with label " + p.getLabel());
                }
            }
            
            // add label, if necessary
            if (p.getLabel() == null) 
                p.setLabel(getUniqueLabel());
    
            // add self source
            if (!p.getLabel().hasSource()) 
                p.getLabel().addAnnot(BeliefBase.TSelf);
            
            if (p.getTrigger().getLiteral().getFunctor().equals(kqmlReceivedFunctor)) {
                if (! (p.getSrcInfo() != null && "kqmlPlans.asl".equals(p.getSrcInfo().getSrcFile()))) {
                    hasUserKqmlReceived = true;
                }
            }
    
            p.setAsPlanTerm(false); // it is not a term anymore
    
            planLabels.put( getStringForLabel(p.getLabel()), p);
    
            Trigger pte = p.getTrigger();
            if (pte.getLiteral().isVar() || pte.getLiteral().getNS().isVar()) {
                if (before) 
                    varPlans.add(0,p); 
                else 
                    varPlans.add(p);
                // add plan p in all entries
                for (List lp: relPlans.values())
                    if (!lp.isEmpty() && lp.get(0).getTrigger().sameType(pte)) // only add if same type
                        if (before)
                            lp.add(0,p);
                        else
                            lp.add(p);
            } else {
                List codesList = relPlans.get(pte.getPredicateIndicator());
                if (codesList == null) {
                    codesList = new ArrayList();
                    // copy plans from var plans
                    for (Plan vp: varPlans)
                        if (vp.getTrigger().sameType(pte))
                            codesList.add(vp);
                    relPlans.put(pte.getPredicateIndicator(), codesList);
                }
                if (before)
                    codesList.add(0,p);
                else
                    codesList.add(p);
            }
    
            if (pte.getOperator() == TEOperator.goalState)
                hasMetaEventPlans = true;
            
            if (before)
                plans.add(0,p);
            else
                plans.add(p);
        }
    }
    
    public void addAll(PlanLibrary pl) throws JasonException {
        synchronized (lockPL) {
            for (Plan p: pl) { 
                add(p, false);
            }
        }
    }

    public void addAll(List plans) throws JasonException {
        synchronized (lockPL) {
            for (Plan p: plans) { 
                add(p, false);
            }
        }
    }
    
    private String getStringForLabel(Atom p) {
        if (p.getNS() == Literal.DefaultNS)
            return p.getFunctor();
        else
            return p.getNS()+"::"+p.getFunctor();
    }
    
    public boolean hasMetaEventPlans() {
        return hasMetaEventPlans; 
    }
    
    public boolean hasUserKqmlReceivedPlans() {
        return hasUserKqmlReceived;
    }

    /** add a label to the plan */
    private Pred getUniqueLabel() {
        String l;
        do {
            l = "l__" + (lastPlanLabel.incrementAndGet());
        } while (planLabels.keySet().contains(l));
        return new Pred(l);
    }
    
    /** return a plan for a label */
    public Plan get(String label) {
        return get(new Atom(label));
    }
    /** return a plan for a label */
    public Plan get(Atom label) {
        return planLabels.get(getStringForLabel(label));
    }
    
    public int size() {
        return plans.size();
    }
    
    public List getPlans() {
        return plans;
    }
    
    public Iterator iterator() {
        return plans.iterator();
    }

    /** remove all plans */
    public void clear() {
        planLabels.clear();
        plans.clear();
        varPlans.clear();
        relPlans.clear();
    }
    
    /** 
     * Remove a plan represented by the label pLabel.
     * In case the plan has many sources, only the plan's source is removed. 
	 */
	public boolean remove(Atom pLabel, Term source) {
		// find the plan
		Plan p = get(pLabel);
		if (p != null) {
			boolean hasSource = p.getLabel().delSource(source);

			// if no source anymore, remove the plan
			if (hasSource && !p.getLabel().hasSource()) {
			    remove(pLabel);
			}
			return true;
		}
		return false;
	}

	/** remove the plan with label pLabel */
    public Plan remove(Atom pLabel) {
        synchronized (lockPL) {
            Plan p = planLabels.remove( getStringForLabel(pLabel) );
    
            // remove it from plans' list
            plans.remove(p);
    
            if (p.getTrigger().getLiteral().isVar()) {
                varPlans.remove(p);
                // remove p from all entries and
                // clean empty entries
                Iterator ipi = relPlans.keySet().iterator();
                while (ipi.hasNext()) {
                    PredicateIndicator pi = ipi.next();
                    List lp = relPlans.get(pi); 
                    lp.remove(p);
                    if (lp.isEmpty()) {
                        ipi.remove();
                    }
                }
            } else {
                List codesList = relPlans.get(p.getTrigger().getPredicateIndicator());
                codesList.remove(p);
                if (codesList.isEmpty()) {
                    // no more plans for this TE
                    relPlans.remove(p.getTrigger().getPredicateIndicator());
                }
            }
            return p;
        }
    }

    /** @deprecated use hasCandidatePlan(te) instead */
    public boolean isRelevant(Trigger te) {
        return hasCandidatePlan(te);
    }

    public boolean hasCandidatePlan(Trigger te) {
        if (te == null)
            return false;
        else
            return getCandidatePlans(te) != null;
    }

    
    /** @deprecated use getCandidatePlans(te) instead */
    public List getAllRelevant(Trigger te) {
        return getCandidatePlans(te);
    }
    
    public List getCandidatePlans(Trigger te) {
        synchronized (lockPL) {
            List l = null;
            if (te.getLiteral().isVar() || te.getNS().isVar()) { // add all plans!
                for (Plan p: this)
                    if (p.getTrigger().sameType(te)) {
                        if (l == null)
                            l = new ArrayList();
                        l.add(p);
                    }            
            } else {
                l = relPlans.get(te.getPredicateIndicator());
                if ((l == null || l.isEmpty()) && !varPlans.isEmpty() && te != TE_JAG_SLEEPING && te != TE_JAG_AWAKING) {  // no rel plan, try varPlan
                    for (Plan p: varPlans)
                        if (p.getTrigger().sameType(te)) {
                            if (l == null)
                                l = new ArrayList();
                            l.add(p);
                        }
                }
            }
            return l; // if no rel plan, have to return null instead of empty list
        }
    }

    public static final Trigger TE_JAG_SLEEPING  = new Trigger(TEOperator.add, TEType.achieve, new Atom("jag_sleeping"));
    public static final Trigger TE_JAG_AWAKING   = new Trigger(TEOperator.add, TEType.achieve, new Atom("jag_awaking"));

    public PlanLibrary clone() {
        PlanLibrary pl = new PlanLibrary();
        try {
            synchronized (lockPL) {
                for (Plan p: this) { 
                    pl.add((Plan)p.clone(), false);
                }
            }
        } catch (JasonException e) {
            e.printStackTrace();
        }
        return pl;
    }

    public String toString() {
        return plans.toString();
    }
    
    /** get as XML */
    public Element getAsDOM(Document document) {
        Element eplans = (Element) document.createElement("plans");
        String lastFunctor = null;
        synchronized (lockPL) {
            for (Plan p: plans) {
                String currentFunctor = p.getTrigger().getLiteral().getFunctor();
                if (lastFunctor != null && !currentFunctor.equals(lastFunctor)) {
                    eplans.appendChild((Element) document.createElement("new-set-of-plans"));
                }
                lastFunctor = currentFunctor;
                eplans.appendChild(p.getAsDOM(document));
            }
        }
        return eplans;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy