bdi4jade

Changes

bdi-jade-test/src/bdi4jade/examples/helloworld/HelloWorldPlan.java 42(+0 -42)

Details

diff --git a/bdi-jade/src/bdi4jade/core/AbstractBDIAgent.java b/bdi-jade/src/bdi4jade/core/AbstractBDIAgent.java
new file mode 100644
index 0000000..d6304ca
--- /dev/null
+++ b/bdi-jade/src/bdi4jade/core/AbstractBDIAgent.java
@@ -0,0 +1,741 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2011  Ingrid Nunes
+// 
+// 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://inf.ufrgs.br/~ingridnunes/bdi4jade/
+//
+//----------------------------------------------------------------------------
+
+package bdi4jade.core;
+
+import jade.core.Agent;
+import jade.core.behaviours.CyclicBehaviour;
+import jade.lang.acl.ACLMessage;
+import jade.proto.states.MsgReceiver;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import bdi4jade.annotation.GoalOwner;
+import bdi4jade.belief.Belief;
+import bdi4jade.core.GoalUpdateSet.GoalDescription;
+import bdi4jade.event.GoalEvent;
+import bdi4jade.event.GoalListener;
+import bdi4jade.goal.Goal;
+import bdi4jade.goal.GoalStatus;
+import bdi4jade.goal.Softgoal;
+import bdi4jade.message.BDIAgentMsgReceiver;
+import bdi4jade.plan.Plan;
+import bdi4jade.util.ReflectionUtils;
+
+/**
+ * This class is an abstract implementation of the {@link BDIAgent} interface.
+ * It is an extension of {@link Agent}. It also has a set of {@link Capability}
+ * - an agent is an aggregation of capabilities, and a {@link MsgReceiver}
+ * behavior to receive all messages that the agent current plans can process.
+ * 
+ * @author Ingrid Nunes
+ */
+public abstract class AbstractBDIAgent extends Agent implements BDIAgent {
+
+	/**
+	 * This class is a {@link CyclicBehaviour} that runs during all the
+	 * {@link BDIAgent} life in order to provide the reasoning engine.
+	 * 
+	 * @author Ingrid Nunes
+	 */
+	class BDIInterpreter extends CyclicBehaviour {
+
+		private static final long serialVersionUID = -6991759791322598475L;
+
+		private BDIInterpreter(AbstractBDIAgent bdiAgent) {
+			super(bdiAgent);
+		}
+
+		/**
+		 * This method is a variation of the BDI-interpreter cycle of the BDI
+		 * architecture. It first reviews the beliefs of this agent, by invoking
+		 * the {@link BDIAgent#reviewBeliefs()} method.
+		 * 
+		 * After it removes from the intention set the ones that are finished,
+		 * i.e. associated with goals with status achieved, no longer desired or
+		 * unachievable, and notifies goal listeners about this event. This is
+		 * performed using the {@link #processIntentions(Collection)} method.
+		 * 
+		 * Then, it generate a an updated set of goals, dropping existing ones
+		 * that are no longer desired and also creating new ones. This updated
+		 * set of goals is given by the
+		 * {@link BDIAgent#generateGoals(GoalUpdateSet, Map)} method.
+		 * 
+		 * Finally, from the set of current goals, they are now filtered, by
+		 * invoking the {@link BDIAgent#filter(Set, Map)} method, to select the
+		 * current agent intentions. The non-selected goals will be set to wait
+		 * ({@link Intention#doWait()}) and the selected ones will be tried to
+		 * be achieved ({@link Intention#tryToAchive()}).
+		 * 
+		 * @see jade.core.behaviours.Behaviour#action()
+		 */
+		@Override
+		public void action() {
+			log.trace("Beginning BDI-interpreter cycle.");
+
+			log.trace("Reviewing beliefs.");
+			reviewBeliefs();
+
+			synchronized (allIntentions) {
+				// Removing finished goals and generate appropriate goal events
+				GoalUpdateSet agentGoalUpdateSet = processIntentions(agentIntentions);
+				Map<Capability, GoalUpdateSet> capabilityGoalUpdateSets = new HashMap<>();
+				for (Capability capability : capabilities) {
+					GoalUpdateSet capabilityGoalUpdateSet = processIntentions(capability
+							.getIntentions());
+					capabilityGoalUpdateSets.put(capability,
+							capabilityGoalUpdateSet);
+				}
+
+				// Generating new goals and choosing goals to drop
+				generateGoals(agentGoalUpdateSet, capabilityGoalUpdateSets);
+
+				// Adding generated goals
+				for (GoalDescription goal : agentGoalUpdateSet
+						.getGeneratedGoals()) {
+					Intention intention = addIntention(goal.getDispatcher(),
+							goal.getGoal(), null);
+					if (intention != null)
+						agentGoalUpdateSet.addIntention(intention);
+				}
+				for (GoalUpdateSet goalUpdateSet : capabilityGoalUpdateSets
+						.values()) {
+					for (GoalDescription goal : goalUpdateSet
+							.getGeneratedGoals()) {
+						Intention intention = addIntention(
+								goal.getDispatcher(), goal.getGoal(), null);
+						if (intention != null)
+							goalUpdateSet.addIntention(intention);
+					}
+				}
+
+				// Removing dropped goals
+				for (GoalDescription goal : agentGoalUpdateSet
+						.getDroppedGoals()) {
+					goal.getIntention().noLongerDesire();
+					fireGoalEvent(goal.getIntention());
+					agentIntentions.remove(goal.getIntention());
+					allIntentions.remove(goal.getGoal());
+					agentGoalUpdateSet.removeIntention(goal);
+				}
+				for (GoalUpdateSet goalUpdateSet : capabilityGoalUpdateSets
+						.values()) {
+					for (GoalDescription goal : goalUpdateSet.getDroppedGoals()) {
+						goal.getIntention().noLongerDesire();
+						fireGoalEvent(goal.getIntention());
+						goal.getDispatcher().removeIntention(
+								goal.getIntention());
+						allIntentions.remove(goal.getGoal());
+						goalUpdateSet.removeIntention(goal);
+					}
+				}
+
+				// Filtering options
+				Map<Capability, Set<GoalDescription>> capabilityGoals = new HashMap<>();
+				for (Capability capability : capabilityGoalUpdateSets.keySet()) {
+					capabilityGoals.put(capability, capabilityGoalUpdateSets
+							.get(capability).getCurrentGoals());
+				}
+				Set<Goal> selectedGoals = filter(
+						agentGoalUpdateSet.getCurrentGoals(), capabilityGoals);
+
+				log.trace("Selected goals to be intentions: "
+						+ selectedGoals.size());
+				for (Intention intention : allIntentions.values()) {
+					if (selectedGoals.contains(intention.getGoal())) {
+						intention.tryToAchive();
+					} else {
+						intention.doWait();
+					}
+				}
+
+				if (allIntentions.isEmpty()) {
+					log.trace("No goals or intentions: blocking cycle.");
+					this.block();
+				}
+			}
+
+			log.trace("BDI-interpreter cycle finished.");
+		}
+
+		/**
+		 * Processes all intentions of the given collection. Intentions
+		 * associated with goals that finished are removed and goal listeners (
+		 * {@link GoalListener}) are notified. Goal listeners are also notified
+		 * if a plan failed while trying to achieve a goal (intentions with
+		 * {@link GoalStatus#PLAN_FAILED}).
+		 * 
+		 * @param intentions
+		 *            the collection of intentions to be processed.
+		 * @return the {@link GoalUpdateSet} with current goals initialized with
+		 *         current intentions.
+		 */
+		private GoalUpdateSet processIntentions(Collection<Intention> intentions) {
+			GoalUpdateSet goalUpdateSet = new GoalUpdateSet();
+			Iterator<Intention> it = intentions.iterator();
+			while (it.hasNext()) {
+				Intention intention = it.next();
+				GoalStatus status = intention.getStatus();
+				if (status.isFinished()) {
+					fireGoalEvent(intention);
+					it.remove();
+					allIntentions.remove(intention.getGoal());
+				} else {
+					if (GoalStatus.PLAN_FAILED.equals(status)) {
+						fireGoalEvent(intention);
+					}
+					goalUpdateSet.addIntention(intention);
+				}
+			}
+			return goalUpdateSet;
+		}
+
+	}
+
+	private static final long serialVersionUID = -841774495336214256L;
+
+	private final Collection<Intention> agentIntentions;
+	private final Set<Capability> aggregatedCapabilities;
+	private final Map<Goal, Intention> allIntentions;
+	private final BDIInterpreter bdiInterpreter;
+	private Set<Capability> capabilities;
+	protected final List<GoalListener> goalListeners;
+	protected final Log log;
+	private Map<Class<? extends Capability>, Set<Capability>> restrictedAccessOwnersMap;
+	private final Set<Softgoal> softgoals;
+
+	/**
+	 * Default constructor.
+	 */
+	public AbstractBDIAgent() {
+		this.log = LogFactory.getLog(this.getClass());
+		this.bdiInterpreter = new BDIInterpreter(this);
+		this.capabilities = new HashSet<>();
+		this.restrictedAccessOwnersMap = new HashMap<>();
+		this.allIntentions = new HashMap<>();
+		this.aggregatedCapabilities = new HashSet<>();
+		this.agentIntentions = new LinkedList<>();
+		this.softgoals = new HashSet<>();
+		this.goalListeners = new LinkedList<>();
+	}
+
+	/**
+	 * Adds a capability to this agent.
+	 * 
+	 * @param capability
+	 *            capability to be added.
+	 */
+	void addCapability(Capability capability) {
+		synchronized (aggregatedCapabilities) {
+			this.aggregatedCapabilities.add(capability);
+			resetAllCapabilities();
+			computeGoalOwnersMap();
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addGoal(bdi4jade.core.Capability,
+	 *      bdi4jade.goal.Goal)
+	 */
+	@Override
+	public final void addGoal(Capability dispatcher, Goal goal) {
+		addIntention(dispatcher, goal, null);
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addGoal(bdi4jade.core.Capability,
+	 *      bdi4jade.goal.Goal, bdi4jade.event.GoalListener)
+	 */
+	@Override
+	public final void addGoal(Capability dispatcher, Goal goal,
+			GoalListener goalListener) {
+		addIntention(dispatcher, goal, goalListener);
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addGoal(bdi4jade.goal.Goal)
+	 */
+	@Override
+	public final void addGoal(Goal goal) {
+		addIntention(null, goal, null);
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addGoal(bdi4jade.goal.Goal,
+	 *      bdi4jade.event.GoalListener)
+	 */
+	@Override
+	public final void addGoal(Goal goal, GoalListener goalListener) {
+		addIntention(null, goal, goalListener);
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addGoalListener(bdi4jade.event.GoalListener)
+	 */
+	@Override
+	public final void addGoalListener(GoalListener goalListener) {
+		synchronized (goalListeners) {
+			goalListeners.add(goalListener);
+		}
+	}
+
+	/**
+	 * Adds a new goal to this agent to be achieved by creating an intention. It
+	 * also may add a listener to observe events related to this goal.
+	 * 
+	 * @param dispatcher
+	 *            the capability that dispatched this goal.
+	 * @param goal
+	 *            the goal to be achieved.
+	 * @param goalListener
+	 *            the listener to be notified.
+	 */
+	private final Intention addIntention(Capability dispatcher, Goal goal,
+			GoalListener goalListener) {
+		Intention intention = null;
+		try {
+			intention = new Intention(goal, this, dispatcher);
+		} catch (IllegalAccessException exc) {
+			log.error(exc);
+			return null;
+		}
+
+		synchronized (allIntentions) {
+			this.allIntentions.put(goal, intention);
+			if (dispatcher == null) {
+				agentIntentions.add(intention);
+			} else {
+				dispatcher.addIntention(intention);
+			}
+			this.bdiInterpreter.restart();
+			if (goalListener != null) {
+				intention.addGoalListener(goalListener);
+			}
+			fireGoalEvent(new GoalEvent(goal));
+			return intention;
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#addSoftgoal(bdi4jade.goal.Softgoal)
+	 */
+	@Override
+	public final void addSoftgoal(Softgoal softgoal) {
+		synchronized (softgoals) {
+			this.softgoals.add(softgoal);
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#canHandle(jade.lang.acl.ACLMessage)
+	 */
+	@Override
+	public boolean canHandle(ACLMessage msg) {
+		synchronized (aggregatedCapabilities) {
+			for (Capability capability : aggregatedCapabilities) {
+				if (capability.canHandle(msg)) {
+					return true;
+				}
+			}
+			return false;
+		}
+	}
+
+	private final void computeGoalOwnersMap() {
+		this.restrictedAccessOwnersMap = new HashMap<>();
+		for (Capability capability : aggregatedCapabilities) {
+			ReflectionUtils.addGoalOwner(restrictedAccessOwnersMap, capability);
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#dropGoal(bdi4jade.goal.Goal)
+	 */
+	@Override
+	public final void dropGoal(Goal goal) {
+		synchronized (allIntentions) {
+			Intention intention = allIntentions.get(goal);
+			if (intention != null) {
+				intention.noLongerDesire();
+			}
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#dropSoftoal(bdi4jade.goal.Softgoal)
+	 */
+	@Override
+	public final void dropSoftoal(Softgoal softgoal) {
+		synchronized (softgoals) {
+			this.softgoals.remove(softgoal);
+		}
+	}
+
+	/**
+	 * This method is responsible for selecting a set of goals that must be
+	 * tried to be achieved (intentions) from the set of goals. Its default
+	 * implementation selects all agent goals (those not dispatched within the
+	 * scope of a capability) to be achieved, and requests each of its
+	 * capabilities to filter their goals. Subclasses may override this method
+	 * to customize this deliberation function.
+	 * 
+	 * @param agentGoals
+	 *            the set of agent goals, which are goals not dispatched within
+	 *            the scope of a capability.
+	 * @param capabilityGoals
+	 *            the map from capabilities to their set of goals.
+	 * 
+	 * @return the list of selected goals, which will become intentions.
+	 */
+	protected Set<Goal> filter(Set<GoalDescription> agentGoals,
+			Map<Capability, Set<GoalDescription>> capabilityGoals) {
+		Set<Goal> selectedGoals = new HashSet<>();
+		for (GoalDescription goalDescription : agentGoals) {
+			selectedGoals.add(goalDescription.getGoal());
+		}
+		for (Capability capability : capabilityGoals.keySet()) {
+			selectedGoals.addAll(capability.filter(capabilityGoals
+					.get(capability)));
+		}
+		return selectedGoals;
+	}
+
+	/**
+	 * Notifies all listeners, if any, about a goal event.
+	 * 
+	 * @param goalEvent
+	 *            the event to notify.
+	 */
+	private final void fireGoalEvent(GoalEvent goalEvent) {
+		synchronized (goalListeners) {
+			for (GoalListener goalListener : goalListeners) {
+				goalListener.goalPerformed(goalEvent);
+			}
+		}
+	}
+
+	/**
+	 * Creates a goal event given an intention, and notifies all listeners, if
+	 * any, about a goal event.
+	 * 
+	 * @param intention
+	 *            the intention used to create the goal event.
+	 */
+	private final void fireGoalEvent(Intention intention) {
+		Goal goal = intention.getGoal();
+		GoalStatus status = intention.getStatus();
+		log.debug("Goal: " + goal.getClass().getSimpleName() + " (" + status
+				+ ") - " + goal);
+
+		GoalEvent goalEvent = new GoalEvent(goal, status);
+		synchronized (goalListeners) {
+			for (GoalListener goalListener : goalListeners) {
+				goalListener.goalPerformed(goalEvent);
+			}
+			for (GoalListener goalListener : intention.getGoalListeners()) {
+				goalListener.goalPerformed(goalEvent);
+			}
+		}
+	}
+
+	/**
+	 * This method is responsible for generating new goals or dropping existing
+	 * ones. Its default implementation requests each of its capabilities to
+	 * generate or drop goals. Subclasses may override this method to customize
+	 * this options generation function.
+	 * 
+	 * @param agentGoalUpdateSet
+	 *            the {@link GoalUpdateSet} that contains the set of agent
+	 *            current goals. It has also a set of dropped goals and
+	 *            generated goals, which are used as outputs of this method.
+	 * @param capabilityGoalUpdateSets
+	 *            the map from capabilities to their goal update set.
+	 */
+	protected void generateGoals(GoalUpdateSet agentGoalUpdateSet,
+			Map<Capability, GoalUpdateSet> capabilityGoalUpdateSets) {
+		for (Capability capability : capabilityGoalUpdateSets.keySet()) {
+			capability.generateGoals(capabilityGoalUpdateSets.get(capability));
+		}
+	}
+
+	/**
+	 * Returns the root capability of this agent.
+	 * 
+	 * @return the rootCapability
+	 */
+	protected Set<Capability> getAggregatedCapabilities() {
+		synchronized (aggregatedCapabilities) {
+			return aggregatedCapabilities;
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#getAllBeliefs()
+	 */
+	@Override
+	public final Collection<Belief<?>> getAllBeliefs() {
+		synchronized (aggregatedCapabilities) {
+			Collection<Belief<?>> beliefs = new LinkedList<Belief<?>>();
+			for (Capability capability : capabilities) {
+				beliefs.addAll(capability.getBeliefBase().getBeliefs());
+			}
+			return beliefs;
+		}
+	}
+
+	/**
+	 * Returns all capabilities that are part of this agent. This included all
+	 * capabilities composed or associated with other capabilities.
+	 * 
+	 * @return the capabilities.
+	 */
+	protected Collection<Capability> getAllCapabilities() {
+		synchronized (aggregatedCapabilities) {
+			return capabilities;
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#getAllGoals()
+	 */
+	@Override
+	public final Set<Goal> getAllGoals() {
+		synchronized (allIntentions) {
+			return allIntentions.keySet();
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#getAllSoftgoals()
+	 */
+	@Override
+	public final Set<Softgoal> getAllSoftgoals() {
+		synchronized (softgoals) {
+			return this.softgoals;
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#getGoalListeners()
+	 */
+	@Override
+	public final List<GoalListener> getGoalListeners() {
+		return goalListeners;
+	}
+
+	/**
+	 * Returns the capability instances that owns a dispatched goal, considering
+	 * the aggregated capabilities of this agent.
+	 * 
+	 * If this method returns an empty set, it means that this agent cannot add
+	 * a goal without the scope of a dispatcher that has access to it.
+	 * 
+	 * @param owner
+	 *            the annotation with the goal owner.
+	 * @return the capability instances related to this capability that owns the
+	 *         goal, or an empty set if the agent cannot add this goal.
+	 */
+	protected final Set<Capability> getGoalOwner(GoalOwner owner) {
+		Set<Capability> restrictedAccessOwners = restrictedAccessOwnersMap
+				.get(owner.capability());
+		return restrictedAccessOwners == null ? new HashSet<Capability>()
+				: restrictedAccessOwners;
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#getIntentions()
+	 */
+	@Override
+	public final Set<Intention> getIntentions() {
+		synchronized (allIntentions) {
+			Set<Intention> activeIntentions = new HashSet<Intention>();
+			for (Intention intention : activeIntentions) {
+				if (!GoalStatus.WAITING.equals(intention.getStatus()))
+					activeIntentions.add(intention);
+			}
+			return activeIntentions;
+		}
+	}
+
+	/**
+	 * This method initializes the BDI agent. It is invoked by the
+	 * {@link #setup()} method. This is an empty method that should be overriden
+	 * by subclasses.
+	 */
+	protected void init() {
+
+	}
+
+	/**
+	 * Removes a capability from this agent.
+	 * 
+	 * @param capability
+	 *            capability to be removed.
+	 * 
+	 * @return true if the capability exists and was removed, false otherwise.
+	 */
+	boolean removeCapability(Capability capability) {
+		synchronized (aggregatedCapabilities) {
+			boolean removed = this.aggregatedCapabilities.remove(capability);
+			if (removed) {
+				resetAllCapabilities();
+				computeGoalOwnersMap();
+			}
+			return removed;
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.BDIAgent#removeGoalListener(bdi4jade.event.GoalListener)
+	 */
+	@Override
+	public final void removeGoalListener(GoalListener goalListener) {
+		synchronized (goalListeners) {
+			goalListeners.remove(goalListener);
+		}
+	}
+
+	final void resetAllCapabilities() {
+		synchronized (aggregatedCapabilities) {
+			Set<Capability> allCapabilities = new HashSet<>();
+			Set<Capability> capabilitiesToBeProcessed = new HashSet<>(
+					aggregatedCapabilities);
+
+			while (!capabilitiesToBeProcessed.isEmpty()) {
+				Capability current = capabilitiesToBeProcessed.iterator()
+						.next();
+				capabilitiesToBeProcessed.remove(current);
+				allCapabilities.add(current);
+				for (Capability part : current.getPartCapabilities()) {
+					if (!allCapabilities.contains(part))
+						capabilitiesToBeProcessed.add(part);
+				}
+				for (Capability target : current.getAssociatedCapabilities()) {
+					if (!allCapabilities.contains(target))
+						capabilitiesToBeProcessed.add(target);
+				}
+			}
+
+			Set<Capability> removedCapabilities = new HashSet<>(capabilities);
+			removedCapabilities.removeAll(allCapabilities);
+			for (Capability capability : removedCapabilities) {
+				capability.setMyAgent(null);
+			}
+
+			Set<Capability> addedCapabilities = new HashSet<>(allCapabilities);
+			addedCapabilities.removeAll(capabilities);
+			for (Capability capability : addedCapabilities) {
+				if (capability.getMyAgent() != null) {
+					throw new IllegalArgumentException(
+							"Capability already binded to another agent: "
+									+ capability.getFullId());
+				}
+				capability.setMyAgent(this);
+			}
+
+			this.capabilities = allCapabilities;
+			log.debug("Capabilities: " + this.capabilities);
+		}
+	}
+
+	/**
+	 * This method is responsible for reviewing beliefs from this agent. Its
+	 * default implementation requests each of its capabilities to review their
+	 * individual set of beliefs. Subclasses may override this method to
+	 * customize belief revision.
+	 */
+	protected void reviewBeliefs() {
+		for (Capability capability : capabilities) {
+			capability.reviewBeliefs();
+		}
+	}
+
+	/**
+	 * This method is responsible for selecting plans to achieve a goals of this
+	 * agent. Its default implementation requests each of its capabilities to
+	 * select one of its plans, and this method selects one of them, randomly.
+	 * Subclasses may override this method to customize plan selection.
+	 * 
+	 * @param goal
+	 *            the goal to be achieved.
+	 * @param capabilityPlans
+	 *            the set of candidate plans of each capability, as a map.
+	 */
+	protected Plan selectPlan(Goal goal,
+			Map<Capability, Set<Plan>> capabilityPlans) {
+		Set<Plan> preselectedPlans = new HashSet<>();
+		for (Capability capability : capabilityPlans.keySet()) {
+			Plan preselectedPlan = capability.selectPlan(goal,
+					capabilityPlans.get(capability));
+			if (preselectedPlan != null) {
+				preselectedPlans.add(preselectedPlan);
+			}
+		}
+
+		if (preselectedPlans.isEmpty()) {
+			return null;
+		} else {
+			return preselectedPlans.iterator().next();
+		}
+	}
+
+	/**
+	 * Initializes the BDI agent. It adds the behavior to handle message
+	 * received and can be processed by capabilities and the
+	 * {@link BDIInterpreter} behavior as well. It invokes the {@link #init()}
+	 * method, so that customized initializations can be perfomed by subclasses.
+	 * 
+	 * @see jade.core.Agent#setup()
+	 */
+	@Override
+	protected final void setup() {
+		this.addBehaviour(new BDIAgentMsgReceiver(this));
+		this.addBehaviour(bdiInterpreter);
+		init();
+	}
+
+	/**
+	 * Removes all capabilities of this agent, before it stops its execution.
+	 * 
+	 * @see jade.core.Agent#takeDown()
+	 */
+	@Override
+	protected void takeDown() {
+		synchronized (aggregatedCapabilities) {
+			Iterator<Capability> iterator = aggregatedCapabilities.iterator();
+			while (iterator.hasNext()) {
+				removeCapability(iterator.next());
+			}
+		}
+	}
+
+}
diff --git a/bdi-jade/src/bdi4jade/core/BDIAgent.java b/bdi-jade/src/bdi4jade/core/BDIAgent.java
index a5a59a0..54497f8 100644
--- a/bdi-jade/src/bdi4jade/core/BDIAgent.java
+++ b/bdi-jade/src/bdi4jade/core/BDIAgent.java
@@ -22,284 +22,26 @@
 
 package bdi4jade.core;
 
-import jade.core.Agent;
-import jade.core.behaviours.CyclicBehaviour;
-import jade.proto.states.MsgReceiver;
+import jade.lang.acl.ACLMessage;
 
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import bdi4jade.annotation.GoalOwner;
 import bdi4jade.belief.Belief;
-import bdi4jade.core.GoalUpdateSet.GoalDescription;
-import bdi4jade.event.GoalEvent;
 import bdi4jade.event.GoalListener;
 import bdi4jade.goal.Goal;
-import bdi4jade.goal.GoalStatus;
 import bdi4jade.goal.Softgoal;
-import bdi4jade.message.BDIAgentMsgReceiver;
-import bdi4jade.plan.Plan;
-import bdi4jade.util.ReflectionUtils;
 
 /**
- * This class is an extension of {@link Agent} that has a current set of goals,
- * which can be selected to become intentions, that is, to tried to be achieved
- * by means of the selection and execution of plans. It also have a set of
- * {@link Capability} - an agent is an aggregation of capabilities. It has a
- * behavior that runs the BDI-interpreter. This agent also have a
- * {@link MsgReceiver} behavior to receive all messages that the agent current
- * plans can process.
+ * This interfaces represents a BDIAgent that has a current set of goals, which
+ * can be selected to become intentions, that is, to tried to be achieved by
+ * means of the selection and execution of plans. It has a behavior that runs
+ * the BDI-interpreter.
  * 
  * @author Ingrid Nunes
  */
-public class BDIAgent extends Agent {
-
-	/**
-	 * This class is a {@link CyclicBehaviour} that runs during all the
-	 * {@link BDIAgent} life in order to provide the reasoning engine.
-	 * 
-	 * @author Ingrid Nunes
-	 */
-	class BDIInterpreter extends CyclicBehaviour {
-
-		private static final long serialVersionUID = -6991759791322598475L;
-
-		private BDIInterpreter(BDIAgent bdiAgent) {
-			super(bdiAgent);
-		}
-
-		/**
-		 * This method is a variation of the BDI-interpreter cycle of the BDI
-		 * architecture. It first reviews the beliefs of this agent, by invoking
-		 * the {@link BDIAgent#reviewBeliefs()} method.
-		 * 
-		 * After it removes from the intention set the ones that are finished,
-		 * i.e. associated with goals with status achieved, no longer desired or
-		 * unachievable, and notifies goal listeners about this event. This is
-		 * performed using the {@link #processIntentions(Collection)} method.
-		 * 
-		 * Then, it generate a an updated set of goals, dropping existing ones
-		 * that are no longer desired and also creating new ones. This updated
-		 * set of goals is given by the
-		 * {@link BDIAgent#generateGoals(GoalUpdateSet, Map)} method.
-		 * 
-		 * Finally, from the set of current goals, they are now filtered, by
-		 * invoking the {@link BDIAgent#filter(Set, Map)} method, to select the
-		 * current agent intentions. The non-selected goals will be set to wait
-		 * ({@link Intention#doWait()}) and the selected ones will be tried to
-		 * be achieved ({@link Intention#tryToAchive()}).
-		 * 
-		 * @see jade.core.behaviours.Behaviour#action()
-		 */
-		@Override
-		public void action() {
-			log.trace("Beginning BDI-interpreter cycle.");
-
-			log.trace("Reviewing beliefs.");
-			reviewBeliefs();
-
-			synchronized (allIntentions) {
-				// Removing finished goals and generate appropriate goal events
-				GoalUpdateSet agentGoalUpdateSet = processIntentions(agentIntentions);
-				Map<Capability, GoalUpdateSet> capabilityGoalUpdateSets = new HashMap<>();
-				for (Capability capability : capabilities) {
-					GoalUpdateSet capabilityGoalUpdateSet = processIntentions(capability
-							.getIntentions());
-					capabilityGoalUpdateSets.put(capability,
-							capabilityGoalUpdateSet);
-				}
-
-				// Generating new goals and choosing goals to drop
-				generateGoals(agentGoalUpdateSet, capabilityGoalUpdateSets);
-
-				// Adding generated goals
-				for (GoalDescription goal : agentGoalUpdateSet
-						.getGeneratedGoals()) {
-					Intention intention = addIntention(goal.getDispatcher(),
-							goal.getGoal(), null);
-					if (intention != null)
-						agentGoalUpdateSet.addIntention(intention);
-				}
-				for (GoalUpdateSet goalUpdateSet : capabilityGoalUpdateSets
-						.values()) {
-					for (GoalDescription goal : goalUpdateSet
-							.getGeneratedGoals()) {
-						Intention intention = addIntention(
-								goal.getDispatcher(), goal.getGoal(), null);
-						if (intention != null)
-							goalUpdateSet.addIntention(intention);
-					}
-				}
-
-				// Removing dropped goals
-				for (GoalDescription goal : agentGoalUpdateSet
-						.getDroppedGoals()) {
-					goal.getIntention().noLongerDesire();
-					fireGoalEvent(goal.getIntention());
-					agentIntentions.remove(goal.getIntention());
-					allIntentions.remove(goal.getGoal());
-					agentGoalUpdateSet.removeIntention(goal);
-				}
-				for (GoalUpdateSet goalUpdateSet : capabilityGoalUpdateSets
-						.values()) {
-					for (GoalDescription goal : goalUpdateSet.getDroppedGoals()) {
-						goal.getIntention().noLongerDesire();
-						fireGoalEvent(goal.getIntention());
-						goal.getDispatcher().removeIntention(
-								goal.getIntention());
-						allIntentions.remove(goal.getGoal());
-						goalUpdateSet.removeIntention(goal);
-					}
-				}
-
-				// Filtering options
-				Map<Capability, Set<GoalDescription>> capabilityGoals = new HashMap<>();
-				for (Capability capability : capabilityGoalUpdateSets.keySet()) {
-					capabilityGoals.put(capability, capabilityGoalUpdateSets
-							.get(capability).getCurrentGoals());
-				}
-				Set<GoalDescription> selectedGoals = filter(
-						agentGoalUpdateSet.getCurrentGoals(), capabilityGoals);
-
-				log.trace("Selected goals to be intentions: "
-						+ selectedGoals.size());
-				for (Intention intention : allIntentions.values()) {
-					if (selectedGoals.contains(intention.getGoal())) {
-						intention.tryToAchive();
-					} else {
-						intention.doWait();
-					}
-				}
-
-				if (allIntentions.isEmpty()) {
-					log.trace("No goals or intentions: blocking cycle.");
-					this.block();
-				}
-			}
-
-			log.trace("BDI-interpreter cycle finished.");
-		}
-
-		/**
-		 * Processes all intentions of the given collection. Intentions
-		 * associated with goals that finished are removed and goal listeners (
-		 * {@link GoalListener}) are notified. Goal listeners are also notified
-		 * if a plan failed while trying to achieve a goal (intentions with
-		 * {@link GoalStatus#PLAN_FAILED}).
-		 * 
-		 * @param intentions
-		 *            the collection of intentions to be processed.
-		 * @return the {@link GoalUpdateSet} with current goals initialized with
-		 *         current intentions.
-		 */
-		private GoalUpdateSet processIntentions(Collection<Intention> intentions) {
-			GoalUpdateSet goalUpdateSet = new GoalUpdateSet();
-			Iterator<Intention> it = intentions.iterator();
-			while (it.hasNext()) {
-				Intention intention = it.next();
-				GoalStatus status = intention.getStatus();
-				if (status.isFinished()) {
-					fireGoalEvent(intention);
-					it.remove();
-					allIntentions.remove(intention.getGoal());
-				} else {
-					if (GoalStatus.PLAN_FAILED.equals(status)) {
-						fireGoalEvent(intention);
-					}
-					goalUpdateSet.addIntention(intention);
-				}
-			}
-			return goalUpdateSet;
-		}
-
-	}
-
-	private static final long serialVersionUID = -841774495336214256L;
-
-	private final Collection<Intention> agentIntentions;
-	private final Set<Capability> aggregatedCapabilities;
-	private final Map<Goal, Intention> allIntentions;
-	private final BDIInterpreter bdiInterpreter;
-	private Set<Capability> capabilities;
-	protected final List<GoalListener> goalListeners;
-	protected final Log log;
-	private Map<Class<? extends Capability>, Set<Capability>> restrictedAccessOwnersMap;
-	private final Set<Softgoal> softgoals;
-
-	/**
-	 * Default constructor.
-	 */
-	public BDIAgent() {
-		this.log = LogFactory.getLog(this.getClass());
-		this.bdiInterpreter = new BDIInterpreter(this);
-		this.capabilities = new HashSet<>();
-		this.restrictedAccessOwnersMap = new HashMap<>();
-		this.allIntentions = new HashMap<>();
-		this.aggregatedCapabilities = new HashSet<>();
-		this.agentIntentions = new LinkedList<>();
-		this.softgoals = new HashSet<>();
-		this.goalListeners = new LinkedList<>();
-	}
-
-	/**
-	 * Creates a new BDIAgent with a capability.
-	 * 
-	 * @param capability
-	 *            the capability to be added to the agent.
-	 */
-	public BDIAgent(Capability capability) {
-		this();
-		this.addCapability(capability);
-	}
-
-	/**
-	 * Creates a new BDIAgent with a set of capabilities.
-	 * 
-	 * @param capabilities
-	 *            the capabilities to be added to the agent.
-	 */
-	public BDIAgent(Capability[] capabilities) {
-		this();
-		for (Capability capability : capabilities) {
-			this.addCapability(capability);
-		}
-	}
-
-	/**
-	 * Creates a new BDIAgent with a set of capabilities.
-	 * 
-	 * @param capabilities
-	 *            the capabilities to be added to the agent.
-	 */
-	public BDIAgent(Collection<Capability> capabilities) {
-		this();
-		for (Capability capability : capabilities) {
-			this.addCapability(capability);
-		}
-	}
-
-	/**
-	 * Adds a capability to this agent.
-	 * 
-	 * @param capability
-	 *            capability to be added.
-	 */
-	public final void addCapability(Capability capability) {
-		synchronized (aggregatedCapabilities) {
-			this.aggregatedCapabilities.add(capability);
-			resetAllCapabilities();
-			computeGoalOwnersMap();
-		}
-	}
+public interface BDIAgent {
 
 	/**
 	 * Adds a new goal to this agent to be achieved.
@@ -309,9 +51,7 @@ public class BDIAgent extends Agent {
 	 * @param goal
 	 *            the goal to be achieved.
 	 */
-	public final void addGoal(Capability dispatcher, Goal goal) {
-		addIntention(dispatcher, goal, null);
-	}
+	public void addGoal(Capability dispatcher, Goal goal);
 
 	/**
 	 * Adds a new goal to this agent to be achieved and adds a listener to
@@ -324,10 +64,8 @@ public class BDIAgent extends Agent {
 	 * @param goalListener
 	 *            the listener to be notified about this goal events.
 	 */
-	public final void addGoal(Capability dispatcher, Goal goal,
-			GoalListener goalListener) {
-		addIntention(dispatcher, goal, goalListener);
-	}
+	public void addGoal(Capability dispatcher, Goal goal,
+			GoalListener goalListener);
 
 	/**
 	 * Adds a new goal to this agent to be achieved.
@@ -335,9 +73,7 @@ public class BDIAgent extends Agent {
 	 * @param goal
 	 *            the goal to be achieved.
 	 */
-	public final void addGoal(Goal goal) {
-		addIntention(null, goal, null);
-	}
+	public void addGoal(Goal goal);
 
 	/**
 	 * Adds a new goal to this agent to be achieved and adds a listener to
@@ -348,9 +84,7 @@ public class BDIAgent extends Agent {
 	 * @param goalListener
 	 *            the listener to be notified.
 	 */
-	public final void addGoal(Goal goal, GoalListener goalListener) {
-		addIntention(null, goal, goalListener);
-	}
+	public void addGoal(Goal goal, GoalListener goalListener);
 
 	/**
 	 * Adds a listener to be notified when about goal events.
@@ -358,48 +92,7 @@ public class BDIAgent extends Agent {
 	 * @param goalListener
 	 *            the listener to be notified.
 	 */
-	public final void addGoalListener(GoalListener goalListener) {
-		synchronized (goalListeners) {
-			goalListeners.add(goalListener);
-		}
-	}
-
-	/**
-	 * Adds a new goal to this agent to be achieved by creating an intention. It
-	 * also may add a listener to observe events related to this goal.
-	 * 
-	 * @param dispatcher
-	 *            the capability that dispatched this goal.
-	 * @param goal
-	 *            the goal to be achieved.
-	 * @param goalListener
-	 *            the listener to be notified.
-	 */
-	private final Intention addIntention(Capability dispatcher, Goal goal,
-			GoalListener goalListener) {
-		Intention intention = null;
-		try {
-			intention = new Intention(goal, this, dispatcher);
-		} catch (IllegalAccessException exc) {
-			log.error(exc);
-			return null;
-		}
-
-		synchronized (allIntentions) {
-			this.allIntentions.put(goal, intention);
-			if (dispatcher == null) {
-				agentIntentions.add(intention);
-			} else {
-				dispatcher.addIntention(intention);
-			}
-			this.bdiInterpreter.restart();
-			if (goalListener != null) {
-				intention.addGoalListener(goalListener);
-			}
-			fireGoalEvent(new GoalEvent(goal));
-			return intention;
-		}
-	}
+	public void addGoalListener(GoalListener goalListener);
 
 	/**
 	 * Adds a new softgoal to this agent.
@@ -407,18 +100,16 @@ public class BDIAgent extends Agent {
 	 * @param softgoal
 	 *            the softgoal to be pursued.
 	 */
-	public final void addSoftgoal(Softgoal softgoal) {
-		synchronized (softgoals) {
-			this.softgoals.add(softgoal);
-		}
-	}
+	public void addSoftgoal(Softgoal softgoal);
 
-	private void computeGoalOwnersMap() {
-		this.restrictedAccessOwnersMap = new HashMap<>();
-		for (Capability capability : aggregatedCapabilities) {
-			ReflectionUtils.addGoalOwner(restrictedAccessOwnersMap, capability);
-		}
-	}
+	/**
+	 * Checks if this agent is able to process the given message.
+	 * 
+	 * @param msg
+	 *            the message to be checked.
+	 * @return true if this agent is able to handle the message.
+	 */
+	public boolean canHandle(ACLMessage msg);
 
 	/**
 	 * Drops a given goal of this agent, which means setting it as no longer
@@ -428,14 +119,7 @@ public class BDIAgent extends Agent {
 	 * @param goal
 	 *            the goal to be dropped.
 	 */
-	public final void dropGoal(Goal goal) {
-		synchronized (allIntentions) {
-			Intention intention = allIntentions.get(goal);
-			if (intention != null) {
-				intention.noLongerDesire();
-			}
-		}
-	}
+	public void dropGoal(Goal goal);
 
 	/**
 	 * Drops a given softgoal of this agent. If the softgoal is not part of the
@@ -445,104 +129,7 @@ public class BDIAgent extends Agent {
 	 *            the softgoal to be dropped.
 	 */
 
-	public final void dropSoftoal(Softgoal softgoal) {
-		synchronized (softgoals) {
-			this.softgoals.remove(softgoal);
-		}
-	}
-
-	/**
-	 * This method is responsible for selecting a set of goals that must be
-	 * tried to be achieved (intentions) from the set of goals. Its default
-	 * implementation selects all agent goals (those not dispatched within the
-	 * scope of a capability) to be achieved, and requests each of its
-	 * capabilities to filter their goals. Subclasses may override this method
-	 * to customize this deliberation function.
-	 * 
-	 * @param agentGoals
-	 *            the set of agent goals, which are goals not dispatched within
-	 *            the scope of a capability.
-	 * @param capabilityGoals
-	 *            the map from capabilities to their set of goals.
-	 */
-	protected Set<GoalDescription> filter(Set<GoalDescription> agentGoals,
-			Map<Capability, Set<GoalDescription>> capabilityGoals) {
-		Set<GoalDescription> selectedGoals = new HashSet<>();
-		selectedGoals.addAll(agentGoals);
-		for (Capability capability : capabilityGoals.keySet()) {
-			capability.filter(capabilityGoals.get(capability));
-		}
-		return selectedGoals;
-	}
-
-	/**
-	 * Notifies all listeners, if any, about a goal event.
-	 * 
-	 * @param goalEvent
-	 *            the event to notify.
-	 */
-	private final void fireGoalEvent(GoalEvent goalEvent) {
-		synchronized (goalListeners) {
-			for (GoalListener goalListener : goalListeners) {
-				goalListener.goalPerformed(goalEvent);
-			}
-		}
-	}
-
-	/**
-	 * Creates a goal event given an intention, and notifies all listeners, if
-	 * any, about a goal event.
-	 * 
-	 * @param intention
-	 *            the intention used to create the goal event.
-	 */
-	private final void fireGoalEvent(Intention intention) {
-		Goal goal = intention.getGoal();
-		GoalStatus status = intention.getStatus();
-		log.debug("Goal: " + goal.getClass().getSimpleName() + " (" + status
-				+ ") - " + goal);
-
-		GoalEvent goalEvent = new GoalEvent(goal, status);
-		synchronized (goalListeners) {
-			for (GoalListener goalListener : goalListeners) {
-				goalListener.goalPerformed(goalEvent);
-			}
-			for (GoalListener goalListener : intention.getGoalListeners()) {
-				goalListener.goalPerformed(goalEvent);
-			}
-		}
-	}
-
-	/**
-	 * This method is responsible for generating new goals or dropping existing
-	 * ones. Its default implementation requests each of its capabilities to
-	 * generate or drop goals. Subclasses may override this method to customize
-	 * this options generation function.
-	 * 
-	 * @param agentGoalUpdateSet
-	 *            the {@link GoalUpdateSet} that contains the set of agent
-	 *            current goals. It has also a set of dropped goals and
-	 *            generated goals, which are used as outputs of this method.
-	 * @param capabilityGoalUpdateSets
-	 *            the map from capabilities to their goal update set.
-	 */
-	protected void generateGoals(GoalUpdateSet agentGoalUpdateSet,
-			Map<Capability, GoalUpdateSet> capabilityGoalUpdateSets) {
-		for (Capability capability : capabilityGoalUpdateSets.keySet()) {
-			capability.generateGoals(capabilityGoalUpdateSets.get(capability));
-		}
-	}
-
-	/**
-	 * Returns the root capability of this agent.
-	 * 
-	 * @return the rootCapability
-	 */
-	public final Set<Capability> getAggregatedCapabilities() {
-		synchronized (aggregatedCapabilities) {
-			return aggregatedCapabilities;
-		}
-	}
+	public void dropSoftoal(Softgoal softgoal);
 
 	/**
 	 * Returns a collection of all beliefs from all capabilities of this agent.
@@ -550,27 +137,7 @@ public class BDIAgent extends Agent {
 	 * 
 	 * @return the collection of all beliefs of this agent.
 	 */
-	public final Collection<Belief<?>> getAllBeliefs() {
-		synchronized (aggregatedCapabilities) {
-			Collection<Belief<?>> beliefs = new LinkedList<Belief<?>>();
-			for (Capability capability : capabilities) {
-				beliefs.addAll(capability.getBeliefBase().getBeliefs());
-			}
-			return beliefs;
-		}
-	}
-
-	/**
-	 * Returns all capabilities that are part of this agent. This included all
-	 * capabilities composed or associated with other capabilities.
-	 * 
-	 * @return the capabilities.
-	 */
-	public final Collection<Capability> getAllCapabilities() {
-		synchronized (aggregatedCapabilities) {
-			return capabilities;
-		}
-	}
+	public Collection<Belief<?>> getAllBeliefs();
 
 	/**
 	 * Gets all goals of this agent. This goals are the ones in the goal set and
@@ -578,50 +145,21 @@ public class BDIAgent extends Agent {
 	 * 
 	 * @return the set of goals.
 	 */
-	public final Set<Goal> getAllGoals() {
-		synchronized (allIntentions) {
-			return allIntentions.keySet();
-		}
-	}
+	public Set<Goal> getAllGoals();
 
 	/**
 	 * Gets all softgoals of this agent.
 	 * 
 	 * @return the set of softgoals.
 	 */
-	public final Set<Softgoal> getAllSoftgoals() {
-		synchronized (softgoals) {
-			return this.softgoals;
-		}
-	}
+	public Set<Softgoal> getAllSoftgoals();
 
 	/**
 	 * Returns all goal listeners.
 	 * 
 	 * @return the goalListeners.
 	 */
-	public final List<GoalListener> getGoalListeners() {
-		return goalListeners;
-	}
-
-	/**
-	 * Returns the capability instances that owns a dispatched goal, considering
-	 * the aggregated capabilities of this agent.
-	 * 
-	 * If this method returns an empty set, it means that this agent cannot add
-	 * a goal without the scope of a dispatcher that has access to it.
-	 * 
-	 * @param owner
-	 *            the annotation with the goal owner.
-	 * @return the capability instances related to this capability that owns the
-	 *         goal, or an empty set if the agent cannot add this goal.
-	 */
-	public Set<Capability> getGoalOwner(GoalOwner owner) {
-		Set<Capability> restrictedAccessOwners = restrictedAccessOwnersMap
-				.get(owner.capability());
-		return restrictedAccessOwners == null ? new HashSet<Capability>()
-				: restrictedAccessOwners;
-	}
+	public List<GoalListener> getGoalListeners();
 
 	/**
 	 * Returns all agent intentions, which are goals that this agent is
@@ -629,44 +167,7 @@ public class BDIAgent extends Agent {
 	 * 
 	 * @return the intentions.
 	 */
-	public final Set<Intention> getIntentions() {
-		synchronized (allIntentions) {
-			Set<Intention> activeIntentions = new HashSet<Intention>();
-			for (Intention intention : activeIntentions) {
-				if (!GoalStatus.WAITING.equals(intention.getStatus()))
-					activeIntentions.add(intention);
-			}
-			return activeIntentions;
-		}
-	}
-
-	/**
-	 * This method initializes the BDI agent. It is invoked by the
-	 * {@link #setup()} method. This is an empty method that should be overriden
-	 * by subclasses.
-	 */
-	protected void init() {
-
-	}
-
-	/**
-	 * Removes a capability from this agent.
-	 * 
-	 * @param capability
-	 *            capability to be removed.
-	 * 
-	 * @return true if the capability exists and was removed, false otherwise.
-	 */
-	public final boolean removeCapability(Capability capability) {
-		synchronized (aggregatedCapabilities) {
-			boolean removed = this.aggregatedCapabilities.remove(capability);
-			if (removed) {
-				resetAllCapabilities();
-				computeGoalOwnersMap();
-			}
-			return removed;
-		}
-	}
+	public Set<Intention> getIntentions();
 
 	/**
 	 * Removes a goal listener, so it will not be notified about the goal events
@@ -675,118 +176,6 @@ public class BDIAgent extends Agent {
 	 * @param goalListener
 	 *            the goal listener to be removed.
 	 */
-	public final void removeGoalListener(GoalListener goalListener) {
-		synchronized (goalListeners) {
-			goalListeners.remove(goalListener);
-		}
-	}
-
-	final void resetAllCapabilities() {
-		synchronized (aggregatedCapabilities) {
-			Set<Capability> allCapabilities = new HashSet<>();
-			Set<Capability> capabilitiesToBeProcessed = new HashSet<>(
-					aggregatedCapabilities);
-
-			while (!capabilitiesToBeProcessed.isEmpty()) {
-				Capability current = capabilitiesToBeProcessed.iterator()
-						.next();
-				allCapabilities.add(current);
-				for (Capability part : current.getPartCapabilities()) {
-					if (!allCapabilities.contains(part))
-						capabilitiesToBeProcessed.add(part);
-				}
-				for (Capability target : current.getAssociatedCapabilities()) {
-					if (!allCapabilities.contains(target))
-						capabilitiesToBeProcessed.add(target);
-				}
-			}
-
-			Set<Capability> removedCapabilities = new HashSet<>(capabilities);
-			removedCapabilities.removeAll(allCapabilities);
-			for (Capability capability : removedCapabilities) {
-				capability.setMyAgent(null);
-			}
-
-			Set<Capability> addedCapabilities = new HashSet<>(allCapabilities);
-			addedCapabilities.removeAll(capabilities);
-			for (Capability capability : addedCapabilities) {
-				if (capability.getMyAgent() != null) {
-					throw new IllegalArgumentException(
-							"Capability already binded to another agent: "
-									+ capability.getFullId());
-				}
-				capability.setMyAgent(this);
-			}
-
-			this.capabilities = allCapabilities;
-			log.debug("Capabilities: " + this.capabilities);
-		}
-	}
-
-	/**
-	 * This method is responsible for reviewing beliefs from this agent. Its
-	 * default implementation requests each of its capabilities to review their
-	 * individual set of beliefs. Subclasses may override this method to
-	 * customize belief revision.
-	 */
-	protected void reviewBeliefs() {
-		for (Capability capability : capabilities) {
-			capability.reviewBeliefs();
-		}
-	}
-
-	/**
-	 * This method is responsible for selecting plans to achieve a goals of this
-	 * agent. Its default implementation requests each of its capabilities to
-	 * select one of its plans, and this method selects one of them, randomly.
-	 * Subclasses may override this method to customize plan selection.
-	 * 
-	 * @param goal
-	 *            the goal to be achieved.
-	 * @param capabilityPlans
-	 *            the set of candidate plans of each capability, as a map.
-	 */
-	protected Plan selectPlan(Goal goal,
-			Map<Capability, Set<Plan>> capabilityPlans) {
-		Set<Plan> preselectedPlans = new HashSet<>();
-		for (Capability capability : capabilityPlans.keySet()) {
-			capability.selectPlan(goal, capabilityPlans.get(capability));
-		}
-
-		if (preselectedPlans.isEmpty()) {
-			return null;
-		} else {
-			return preselectedPlans.iterator().next();
-		}
-	}
-
-	/**
-	 * Initializes the BDI agent. It adds the behavior to handle message
-	 * received and can be processed by capabilities and the
-	 * {@link BDIInterpreter} behavior as well. It invokes the {@link #init()}
-	 * method, so that customized initializations can be perfomed by subclasses.
-	 * 
-	 * @see jade.core.Agent#setup()
-	 */
-	@Override
-	protected final void setup() {
-		this.addBehaviour(new BDIAgentMsgReceiver(this));
-		this.addBehaviour(bdiInterpreter);
-		init();
-	}
-
-	/**
-	 * Removes all capabilities of this agent, before it stops its execution.
-	 * 
-	 * @see jade.core.Agent#takeDown()
-	 */
-	@Override
-	protected void takeDown() {
-		synchronized (aggregatedCapabilities) {
-			Iterator<Capability> iterator = aggregatedCapabilities.iterator();
-			while (iterator.hasNext())
-				removeCapability(iterator.next());
-		}
-	}
+	public void removeGoalListener(GoalListener goalListener);
 
 }
diff --git a/bdi-jade/src/bdi4jade/core/Capability.java b/bdi-jade/src/bdi4jade/core/Capability.java
index 395a0e2..2ee9629 100644
--- a/bdi-jade/src/bdi4jade/core/Capability.java
+++ b/bdi-jade/src/bdi4jade/core/Capability.java
@@ -74,7 +74,7 @@ public class Capability implements Serializable {
 	protected final String id;
 	private final Collection<Intention> intentions;
 	protected final Log log;
-	private BDIAgent myAgent;
+	private AbstractBDIAgent myAgent;
 	private OptionGenerationFunction optionGenerationFunction;
 	private final List<Class<? extends Capability>> parentCapabilities;
 	private final Set<Capability> partCapabilities;
@@ -328,7 +328,7 @@ public class Capability implements Serializable {
 	 * 
 	 * @see DeliberationFunction
 	 */
-	public final Set<GoalDescription> filter(Set<GoalDescription> goals) {
+	public final Set<Goal> filter(Set<GoalDescription> goals) {
 		return this.deliberationFunction.filter(goals);
 	}
 
@@ -654,7 +654,7 @@ public class Capability implements Serializable {
 	 * @param myAgent
 	 *            the myAgent to set
 	 */
-	final void setMyAgent(BDIAgent myAgent) {
+	final void setMyAgent(AbstractBDIAgent myAgent) {
 		synchronized (this) {
 			if (this.myAgent != null && myAgent == null) {
 				takeDown();
diff --git a/bdi-jade/src/bdi4jade/core/Intention.java b/bdi-jade/src/bdi4jade/core/Intention.java
index c4da57d..06d5274 100644
--- a/bdi-jade/src/bdi4jade/core/Intention.java
+++ b/bdi-jade/src/bdi4jade/core/Intention.java
@@ -62,7 +62,7 @@ public class Intention {
 	private final Goal goal;
 	private final List<GoalListener> goalListeners;
 	private final Log log;
-	private final BDIAgent myAgent;
+	private final AbstractBDIAgent myAgent;
 	private boolean noLongerDesired;
 	private final Set<Capability> owners;
 	private boolean unachievable;
@@ -77,7 +77,7 @@ public class Intention {
 	 * @param bdiAgent
 	 *            the bdiAgent associated with this intention.
 	 */
-	public Intention(Goal goal, BDIAgent bdiAgent)
+	public Intention(Goal goal, AbstractBDIAgent bdiAgent)
 			throws IllegalAccessException {
 		this(goal, bdiAgent, null);
 	}
@@ -94,7 +94,7 @@ public class Intention {
 	 * @param dispatcher
 	 *            the Capability that dispatched the goal.
 	 */
-	public Intention(Goal goal, BDIAgent bdiAgent, Capability dispatcher)
+	public Intention(Goal goal, AbstractBDIAgent bdiAgent, Capability dispatcher)
 			throws IllegalAccessException {
 		this.log = LogFactory.getLog(this.getClass());
 		this.goal = goal;
@@ -243,7 +243,7 @@ public class Intention {
 	 * 
 	 * @return the myAgent.
 	 */
-	public BDIAgent getMyAgent() {
+	public AbstractBDIAgent getMyAgent() {
 		return myAgent;
 	}
 
diff --git a/bdi-jade/src/bdi4jade/core/MultipleCapabilityAgent.java b/bdi-jade/src/bdi4jade/core/MultipleCapabilityAgent.java
new file mode 100644
index 0000000..11928da
--- /dev/null
+++ b/bdi-jade/src/bdi4jade/core/MultipleCapabilityAgent.java
@@ -0,0 +1,113 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2011  Ingrid Nunes
+// 
+// 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://inf.ufrgs.br/~ingridnunes/bdi4jade/
+//
+//----------------------------------------------------------------------------
+
+package bdi4jade.core;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * This class is a BDIAgent that has multiple aggregated capabilities.
+ * 
+ * @author Ingrid Nunes
+ */
+public class MultipleCapabilityAgent extends AbstractBDIAgent {
+
+	private static final long serialVersionUID = 6369037881807947402L;
+
+	/**
+	 * Default constructor.
+	 */
+	public MultipleCapabilityAgent() {
+
+	}
+
+	/**
+	 * Creates a new BDIAgent with a single capability.
+	 * 
+	 * @param capability
+	 *            the capability to be added to the agent.
+	 */
+	public MultipleCapabilityAgent(Capability capability) {
+		super();
+		this.addCapability(capability);
+	}
+
+	/**
+	 * Creates a new BDIAgent with a set of capabilities.
+	 * 
+	 * @param capabilities
+	 *            the capabilities to be added to the agent.
+	 */
+	public MultipleCapabilityAgent(Capability[] capabilities) {
+		super();
+		for (Capability capability : capabilities) {
+			this.addCapability(capability);
+		}
+	}
+
+	/**
+	 * Creates a new BDIAgent with a set of capabilities.
+	 * 
+	 * @param capabilities
+	 *            the capabilities to be added to the agent.
+	 */
+	public MultipleCapabilityAgent(Collection<Capability> capabilities) {
+		super();
+		for (Capability capability : capabilities) {
+			this.addCapability(capability);
+		}
+	}
+
+	/**
+	 * @see bdi4jade.core.AbstractBDIAgent#addCapability(bdi4jade.core.Capability)
+	 */
+	@Override
+	public final void addCapability(Capability capability) {
+		super.addCapability(capability);
+	}
+
+	/**
+	 * @see bdi4jade.core.AbstractBDIAgent#getAggregatedCapabilities()
+	 */
+	@Override
+	public final Set<Capability> getAggregatedCapabilities() {
+		return super.getAggregatedCapabilities();
+	}
+
+	/**
+	 * @see bdi4jade.core.AbstractBDIAgent#getAllCapabilities()
+	 */
+	@Override
+	public final Collection<Capability> getAllCapabilities() {
+		return super.getAllCapabilities();
+	}
+
+	/**
+	 * @see bdi4jade.core.AbstractBDIAgent#removeCapability(bdi4jade.core.Capability)
+	 */
+	@Override
+	public final boolean removeCapability(Capability capability) {
+		return super.removeCapability(capability);
+	}
+
+}
diff --git a/bdi-jade/src/bdi4jade/core/SingleCapabilityAgent.java b/bdi-jade/src/bdi4jade/core/SingleCapabilityAgent.java
new file mode 100644
index 0000000..fefe2c8
--- /dev/null
+++ b/bdi-jade/src/bdi4jade/core/SingleCapabilityAgent.java
@@ -0,0 +1,77 @@
+//----------------------------------------------------------------------------
+// Copyright (C) 2011  Ingrid Nunes
+// 
+// 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://inf.ufrgs.br/~ingridnunes/bdi4jade/
+//
+//----------------------------------------------------------------------------
+
+package bdi4jade.core;
+
+/**
+ * This class is a BDIAgent that has a single capability.
+ * 
+ * @author Ingrid Nunes
+ */
+public class SingleCapabilityAgent extends AbstractBDIAgent {
+
+	private static final long serialVersionUID = 6369037881807947402L;
+
+	private Capability capability;
+
+	/**
+	 * Default constructor. Creates a new BDIAgent with a single capability.
+	 */
+	public SingleCapabilityAgent() {
+		this(new Capability());
+	}
+
+	/**
+	 * Creates a new BDIAgent with the given capability.
+	 * 
+	 * @param capability
+	 *            the capability to be added to the agent.
+	 */
+	public SingleCapabilityAgent(Capability capability) {
+		super();
+		setCapability(capability);
+	}
+
+	/**
+	 * Returns the capability of this agent.
+	 * 
+	 * @return the capability.
+	 */
+	public synchronized Capability getCapability() {
+		return capability;
+	}
+
+	/**
+	 * Sets the capability of this agent.
+	 * 
+	 * @param capability
+	 *            the capability to set.
+	 */
+	public synchronized void setCapability(Capability capability) {
+		if (this.capability != null) {
+			this.removeCapability(this.capability);
+		}
+		this.addCapability(capability);
+		this.capability = capability;
+	}
+
+}
diff --git a/bdi-jade/src/bdi4jade/message/BDIAgentMsgReceiver.java b/bdi-jade/src/bdi4jade/message/BDIAgentMsgReceiver.java
index 4e414d9..ebbc865 100644
--- a/bdi-jade/src/bdi4jade/message/BDIAgentMsgReceiver.java
+++ b/bdi-jade/src/bdi4jade/message/BDIAgentMsgReceiver.java
@@ -28,16 +28,10 @@ import jade.lang.acl.MessageTemplate;
 import jade.lang.acl.MessageTemplate.MatchExpression;
 import jade.proto.states.MsgReceiver;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
-import bdi4jade.core.BDIAgent;
-import bdi4jade.core.Capability;
+import bdi4jade.core.AbstractBDIAgent;
 
 /**
  * This class extends the {@link MsgReceiver} behavior from the JADE platform
@@ -63,29 +57,16 @@ public class BDIAgentMsgReceiver extends MsgReceiver {
 
 		private static final long serialVersionUID = -1076583615928481034L;
 
-		private Set<Capability> getCanProcessCapabilities(final ACLMessage msg) {
-			Set<Capability> capabilities = new HashSet<Capability>();
-			for (Capability capability : getMyAgent()
-					.getAggregatedCapabilities()) {
-				if (capability.canHandle(msg)) {
-					capabilities.add(capability);
-				}
-			}
-			return capabilities;
-		}
-
 		/**
 		 * @see jade.lang.acl.MessageTemplate.MatchExpression#match(jade.lang.acl.ACLMessage)
 		 */
 		@Override
 		public boolean match(ACLMessage msg) {
-			Set<Capability> capabilities = getCanProcessCapabilities(msg);
-			if (!capabilities.isEmpty()) {
-				synchronized (msgs) {
-					msgs.put(msg, capabilities);
-				}
+			log.debug("Message received.");
+			if (getMyAgent().canHandle(msg)) {
 				return true;
 			} else {
+				log.debug("Message cannot be handled:" + msg);
 				return false;
 			}
 		}
@@ -96,7 +77,6 @@ public class BDIAgentMsgReceiver extends MsgReceiver {
 	private static final long serialVersionUID = -4435254708782532901L;
 
 	private final Log log;
-	private final Map<ACLMessage, Set<Capability>> msgs;
 
 	/**
 	 * Initializes this message receiver, which is associated with a BDI agent.
@@ -104,11 +84,10 @@ public class BDIAgentMsgReceiver extends MsgReceiver {
 	 * @param agent
 	 *            the BDI agent that this behavior is associated with.
 	 */
-	public BDIAgentMsgReceiver(BDIAgent agent) {
+	public BDIAgentMsgReceiver(AbstractBDIAgent agent) {
 		super(agent, MessageTemplate.MatchAll(), INFINITE, new DataStore(),
 				MSG_KEY);
 		this.template = new MessageTemplate(new BDIAgentMatchExpression());
-		this.msgs = new HashMap<ACLMessage, Set<Capability>>();
 		this.log = LogFactory.getLog(this.getClass());
 	}
 
@@ -123,8 +102,8 @@ public class BDIAgentMsgReceiver extends MsgReceiver {
 		return false;
 	}
 
-	private BDIAgent getMyAgent() {
-		return (BDIAgent) this.myAgent;
+	private AbstractBDIAgent getMyAgent() {
+		return (AbstractBDIAgent) this.myAgent;
 	}
 
 	/**
@@ -136,18 +115,9 @@ public class BDIAgentMsgReceiver extends MsgReceiver {
 	@Override
 	protected void handleMessage(ACLMessage msg) {
 		log.debug("Message received.");
-		synchronized (msgs) {
-			Set<Capability> capabilities = msgs.get(msg);
-			if (capabilities != null) {
-				MessageGoal goal = new MessageGoal(msg);
-				log.debug("This capabilities can process the message:");
-				for (Capability capability : capabilities) {
-					log.debug("* " + capability);
-				}
-				getMyAgent().addGoal(goal);
-				msgs.remove(msg);
-			}
-		}
+		MessageGoal goal = new MessageGoal(msg);
+		getMyAgent().addGoal(goal);
+		log.debug("Message goal added for message: " + msg);
 	}
 
 }
diff --git a/bdi-jade/src/bdi4jade/reasoning/DefaultDeliberationFunction.java b/bdi-jade/src/bdi4jade/reasoning/DefaultDeliberationFunction.java
index c2227db..0ad8af7 100644
--- a/bdi-jade/src/bdi4jade/reasoning/DefaultDeliberationFunction.java
+++ b/bdi-jade/src/bdi4jade/reasoning/DefaultDeliberationFunction.java
@@ -26,6 +26,7 @@ import java.util.HashSet;
 import java.util.Set;
 
 import bdi4jade.core.GoalUpdateSet.GoalDescription;
+import bdi4jade.goal.Goal;
 
 /**
  * This class is the default implementation of the strategy
@@ -43,8 +44,12 @@ public class DefaultDeliberationFunction extends AbstractReasoningStrategy
 	 * @see DeliberationFunction#filter(Set)
 	 */
 	@Override
-	public Set<GoalDescription> filter(Set<GoalDescription> goals) {
-		return new HashSet<>(goals);
+	public Set<Goal> filter(Set<GoalDescription> goals) {
+		Set<Goal> selectedGoals = new HashSet<>();
+		for (GoalDescription goalDescription : goals) {
+			selectedGoals.add(goalDescription.getGoal());
+		}
+		return selectedGoals;
 	}
 
 }
diff --git a/bdi-jade/src/bdi4jade/reasoning/DeliberationFunction.java b/bdi-jade/src/bdi4jade/reasoning/DeliberationFunction.java
index 991c0d6..1eb0f02 100644
--- a/bdi-jade/src/bdi4jade/reasoning/DeliberationFunction.java
+++ b/bdi-jade/src/bdi4jade/reasoning/DeliberationFunction.java
@@ -25,6 +25,7 @@ package bdi4jade.reasoning;
 import java.util.Set;
 
 import bdi4jade.core.GoalUpdateSet.GoalDescription;
+import bdi4jade.goal.Goal;
 
 /**
  * This interface defines the deliberation function to be used within the scope
@@ -43,9 +44,8 @@ public interface DeliberationFunction extends ReasoningStrategy {
 	 *            the list of current goals dispatched by the capability
 	 *            associated with this strategy.
 	 * 
-	 * @return the list of selected goals (which are in the for of
-	 *         {@link GoalDescription}), which will become intentions.
+	 * @return the list of selected goals, which will become intentions.
 	 */
-	public Set<GoalDescription> filter(Set<GoalDescription> goals);
+	public Set<Goal> filter(Set<GoalDescription> goals);
 
 }
diff --git a/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesAction.java b/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesAction.java
new file mode 100644
index 0000000..4816acb
--- /dev/null
+++ b/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesAction.java
@@ -0,0 +1,54 @@
+package bdi4jade.examples;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import bdi4jade.core.AbstractBDIAgent;
+
+/**
+ * This class is an abstract action used as a base for actions to test BDI4JADE
+ * agents. Each action has an agent and a name, and subclasses should implement
+ * the {@link #actionPerformed(java.awt.event.ActionEvent)} method to add goals
+ * to agents, for example.
+ * 
+ * @author Ingrid Nunes
+ */
+public abstract class BDI4JADEExamplesAction extends AbstractAction {
+
+	private static final long serialVersionUID = 6251170147656457707L;
+
+	protected final Log log;
+
+	protected BDI4JADEExamplesAction() {
+		super();
+		this.log = LogFactory.getLog(this.getClass());
+
+		super.putValue(Action.ACCELERATOR_KEY, null);
+		super.putValue(Action.ACTION_COMMAND_KEY, this.getClass()
+				.getSimpleName());
+		super.putValue(Action.LONG_DESCRIPTION, null);
+		super.putValue(Action.MNEMONIC_KEY, null);
+		super.putValue(Action.NAME, null);
+		super.putValue(Action.SHORT_DESCRIPTION, null);
+		super.putValue(Action.SMALL_ICON, null);
+		super.setEnabled(true);
+	}
+
+	public Map<String, AbstractBDIAgent> getAgentMap() {
+		Map<String, AbstractBDIAgent> agentMap = new HashMap<>();
+		for (AbstractBDIAgent agent : getAgents()) {
+			agentMap.put(agent.getClass().getSimpleName(), agent);
+		}
+		return agentMap;
+	}
+
+	public abstract Set<AbstractBDIAgent> getAgents();
+
+}
diff --git a/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesPanel.java b/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesPanel.java
new file mode 100644
index 0000000..784adbd
--- /dev/null
+++ b/bdi-jade-test/src/bdi4jade/examples/BDI4JADEExamplesPanel.java
@@ -0,0 +1,79 @@
+package bdi4jade.examples;
+
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JPanel;
+
+import bdi4jade.core.AbstractBDIAgent;
+import bdi4jade.examples.helloworld.HelloWorldAgent;
+import bdi4jade.examples.helloworld.HelloWorldAgent.HelloWorldGoal;
+
+/**
+ * This class is a panel that is used as content pane of the application with
+ * examples of BDI4JADE. It has a set of {@link BDI4JADEExamplesAction}, and
+ * creates a button to perform each of them.
+ * 
+ * @author Ingrid Nunes
+ */
+public class BDI4JADEExamplesPanel extends JPanel {
+
+	private class HelloWorldAction extends BDI4JADEExamplesAction {
+
+		private static final long serialVersionUID = 2100583035268414082L;
+
+		private final HelloWorldAgent helloWorldAgent;
+
+		public HelloWorldAction() {
+			super.putValue(Action.NAME, "Hello World Agent");
+			this.helloWorldAgent = new HelloWorldAgent();
+		}
+
+		@Override
+		public void actionPerformed(ActionEvent e) {
+			helloWorldAgent.addGoal(new HelloWorldGoal("reader"));
+		}
+
+		@Override
+		public Set<AbstractBDIAgent> getAgents() {
+			Set<AbstractBDIAgent> agents = new HashSet<>();
+			agents.add(helloWorldAgent);
+			return agents;
+		}
+	}
+
+	private static final long serialVersionUID = -1080267169700651610L;
+
+	private final BDI4JADEExamplesAction[] actions;
+
+	// agents.put(HelloWorldParamAgent.class.getSimpleName(),
+	// new HelloWorldParamAgent());
+	// agents.put(BDIAgent1.MY_NAME, new BDIAgent1());
+	// agents.put(BDIAgent2.MY_NAME, new BDIAgent2());
+	// agents.put(MyAgent.class.getSimpleName(), new MyAgent());
+	// agents.put(NestedCapabilitiesAgent.class.getSimpleName(),
+	// new NestedCapabilitiesAgent());
+
+	public BDI4JADEExamplesPanel() {
+		this.actions = new BDI4JADEExamplesAction[] { new HelloWorldAction() };
+		this.setLayout(new GridLayout(actions.length, 1));
+		for (BDI4JADEExamplesAction action : actions) {
+			this.add(new JButton(action));
+		}
+	}
+
+	public Map<String, AbstractBDIAgent> getAgents() {
+		Map<String, AbstractBDIAgent> agents = new HashMap<>();
+		for (BDI4JADEExamplesAction action : actions) {
+			agents.putAll(action.getAgentMap());
+		}
+		return agents;
+	}
+
+}
diff --git a/bdi-jade-test/src/bdi4jade/examples/BDIAgent1.java b/bdi-jade-test/src/bdi4jade/examples/BDIAgent1.java
index 27ebc0e..d6aba50 100644
--- a/bdi-jade-test/src/bdi4jade/examples/BDIAgent1.java
+++ b/bdi-jade-test/src/bdi4jade/examples/BDIAgent1.java
@@ -22,14 +22,14 @@
 
 package bdi4jade.examples;
 
-import bdi4jade.core.BDIAgent;
+import bdi4jade.core.MultipleCapabilityAgent;
 import bdi4jade.examples.ping.PingPongCapability;
 
 /**
  * @author ingrid
  * 
  */
-public class BDIAgent1 extends BDIAgent {
+public class BDIAgent1 extends MultipleCapabilityAgent {
 
 	public static final String MY_NAME = "AGENT_1";
 	private static final long serialVersionUID = -8505187840524213951L;
diff --git a/bdi-jade-test/src/bdi4jade/examples/BDIAgent2.java b/bdi-jade-test/src/bdi4jade/examples/BDIAgent2.java
index a8e53e1..6d247e8 100644
--- a/bdi-jade-test/src/bdi4jade/examples/BDIAgent2.java
+++ b/bdi-jade-test/src/bdi4jade/examples/BDIAgent2.java
@@ -22,14 +22,14 @@
 
 package bdi4jade.examples;
 
-import bdi4jade.core.BDIAgent;
+import bdi4jade.core.MultipleCapabilityAgent;
 import bdi4jade.examples.ping.PingPongCapability;
 
 /**
  * @author ingrid
  * 
  */
-public class BDIAgent2 extends BDIAgent {
+public class BDIAgent2 extends MultipleCapabilityAgent {
 
 	private static final long serialVersionUID = -8505187840524213951L;
 	public static final String MY_NAME = "AGENT_2";
diff --git a/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldAgent.java b/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldAgent.java
index 9038045..d1b0b81 100644
--- a/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldAgent.java
@@ -24,8 +24,8 @@ package bdi4jade.examples.blocksworld;
 
 import bdi4jade.belief.BeliefSet;
 import bdi4jade.belief.TransientBeliefSet;
-import bdi4jade.core.BDIAgent;
 import bdi4jade.core.Capability;
+import bdi4jade.core.MultipleCapabilityAgent;
 import bdi4jade.examples.blocksworld.domain.Clear;
 import bdi4jade.examples.blocksworld.domain.On;
 import bdi4jade.examples.blocksworld.domain.Thing;
@@ -42,7 +42,7 @@ import bdi4jade.plan.DefaultPlan;
  * @author ingrid
  * 
  */
-public class BlocksWorldAgent extends BDIAgent {
+public class BlocksWorldAgent extends MultipleCapabilityAgent {
 
 	public static final String BELIEF_CLEAR = "clear";
 	public static final String BELIEF_ON = "on";
diff --git a/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldApp.java b/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldApp.java
index edf3837..2580b41 100644
--- a/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldApp.java
+++ b/bdi-jade-test/src/bdi4jade/examples/blocksworld/BlocksWorldApp.java
@@ -21,7 +21,7 @@ import org.apache.log4j.PropertyConfigurator;
 
 import bdi4jade.event.GoalEvent;
 import bdi4jade.event.GoalListener;
-import bdi4jade.examples.AgentStarter;
+import bdi4jade.examples.BDI4JADEExamplesApp;
 import bdi4jade.examples.blocksworld.domain.On;
 import bdi4jade.examples.blocksworld.domain.Thing;
 import bdi4jade.examples.blocksworld.goal.AchieveBlocksStacked;
@@ -39,7 +39,7 @@ public class BlocksWorldApp implements GoalListener {
 			new On(Thing.BLOCK_1, Thing.BLOCK_2) };
 
 	public static void main(String[] args) {
-		PropertyConfigurator.configure(AgentStarter.class
+		PropertyConfigurator.configure(BDI4JADEExamplesApp.class
 				.getResource("log4j.properties"));
 		new BlocksWorldApp();
 	}
diff --git a/bdi-jade-test/src/bdi4jade/examples/compositegoal/CompositeGoalCapability.java b/bdi-jade-test/src/bdi4jade/examples/compositegoal/CompositeGoalCapability.java
index 0cf8ddd..49b55f4 100644
--- a/bdi-jade-test/src/bdi4jade/examples/compositegoal/CompositeGoalCapability.java
+++ b/bdi-jade-test/src/bdi4jade/examples/compositegoal/CompositeGoalCapability.java
@@ -137,7 +137,7 @@ public class CompositeGoalCapability extends Capability implements GoalListener 
 				&& event.getGoal() instanceof CompositeGoal) {
 			log.info(event.getGoal() + " Status: " + event.getStatus());
 			log.info("Goal finished!! Removing capability of this agent...");
-			getMyAgent().removeCapability(this);
+			//getMyAgent().removeCapability(this);
 
 		}
 	}
diff --git a/bdi-jade-test/src/bdi4jade/examples/helloworld/HelloWorldAgent.java b/bdi-jade-test/src/bdi4jade/examples/helloworld/HelloWorldAgent.java
index 9a405ad..60f95f7 100644
--- a/bdi-jade-test/src/bdi4jade/examples/helloworld/HelloWorldAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/helloworld/HelloWorldAgent.java
@@ -22,41 +22,48 @@
 
 package bdi4jade.examples.helloworld;
 
-import bdi4jade.core.BDIAgent;
-import bdi4jade.core.Capability;
+import bdi4jade.core.SingleCapabilityAgent;
 import bdi4jade.goal.Goal;
 import bdi4jade.plan.DefaultPlan;
+import bdi4jade.plan.Plan.EndState;
+import bdi4jade.plan.planbody.AbstractPlanBody;
 
-public class HelloWorldAgent extends BDIAgent {
+public class HelloWorldAgent extends SingleCapabilityAgent {
 
-	private static final long serialVersionUID = 2712019445290687786L;
+	public static class HelloWorldGoal implements Goal {
 
-	protected void init() {
-		Capability capability = new Capability();
-		capability.getPlanLibrary().addPlan(
-				new DefaultPlan(HelloWorldGoal.class, HelloWorldPlan.class));
-		this.addCapability(capability);
+		private static final long serialVersionUID = -9039447524062487795L;
 
-		addGoal(new HelloWorldGoal("reader"));
-	}
+		private String name;
 
-}
+		public HelloWorldGoal(String name) {
+			this.name = name;
+		}
+
+		public String getName() {
+			return name;
+		}
+	}
 
-/**
- * @author ingridn
- * 
- */
-class HelloWorldGoal implements Goal {
+	public static class HelloWorldPlanBody extends AbstractPlanBody {
 
-	private static final long serialVersionUID = -9039447524062487795L;
+		private static final long serialVersionUID = -9039447524062487795L;
 
-	private String name;
+		public void action() {
+			System.out.println("Hello, "
+					+ ((HelloWorldGoal) getGoal()).getName() + "!");
+			setEndState(EndState.SUCCESSFULL);
+		}
 
-	public HelloWorldGoal(String name) {
-		this.name = name;
 	}
 
-	public String getName() {
-		return name;
+	private static final long serialVersionUID = 2712019445290687786L;
+
+	public HelloWorldAgent() {
+		getCapability().getPlanLibrary()
+				.addPlan(
+						new DefaultPlan(HelloWorldGoal.class,
+								HelloWorldPlanBody.class));
 	}
+
 }
diff --git a/bdi-jade-test/src/bdi4jade/examples/nestedcapabilities/NestedCapabilitiesAgent.java b/bdi-jade-test/src/bdi4jade/examples/nestedcapabilities/NestedCapabilitiesAgent.java
index 4ae3b8f..7ac6c85 100644
--- a/bdi-jade-test/src/bdi4jade/examples/nestedcapabilities/NestedCapabilitiesAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/nestedcapabilities/NestedCapabilitiesAgent.java
@@ -23,8 +23,8 @@
 package bdi4jade.examples.nestedcapabilities;
 
 import bdi4jade.belief.TransientBelief;
-import bdi4jade.core.BDIAgent;
 import bdi4jade.core.Capability;
+import bdi4jade.core.MultipleCapabilityAgent;
 import bdi4jade.goal.Goal;
 import bdi4jade.plan.DefaultPlan;
 import bdi4jade.plan.planbody.PlanBody;
@@ -37,7 +37,7 @@ class MyGoal implements Goal {
 	private static final long serialVersionUID = -5054184951317760743L;
 }
 
-public class NestedCapabilitiesAgent extends BDIAgent {
+public class NestedCapabilitiesAgent extends MultipleCapabilityAgent {
 
 	public enum Belief {
 
diff --git a/bdi-jade-test/src/bdi4jade/examples/planfailed/PlanFailedCapability.java b/bdi-jade-test/src/bdi4jade/examples/planfailed/PlanFailedCapability.java
index 58fbb94..49c8b16 100644
--- a/bdi-jade-test/src/bdi4jade/examples/planfailed/PlanFailedCapability.java
+++ b/bdi-jade-test/src/bdi4jade/examples/planfailed/PlanFailedCapability.java
@@ -85,7 +85,7 @@ public class PlanFailedCapability extends Capability implements GoalListener {
 			counter++;
 			if (counter >= GOALS) {
 				log.info("Goal finished!! Removing capability of this agent...");
-				getMyAgent().removeCapability(this);
+				// TODO getMyAgent().removeCapability(this);
 			}
 		}
 	}
diff --git a/bdi-jade-test/src/bdi4jade/examples/planparameter/HelloWorldParamAgent.java b/bdi-jade-test/src/bdi4jade/examples/planparameter/HelloWorldParamAgent.java
index 62227ed..48cd0d4 100644
--- a/bdi-jade-test/src/bdi4jade/examples/planparameter/HelloWorldParamAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/planparameter/HelloWorldParamAgent.java
@@ -24,14 +24,15 @@ package bdi4jade.examples.planparameter;
 
 import bdi4jade.annotation.Parameter;
 import bdi4jade.annotation.Parameter.Direction;
-import bdi4jade.core.BDIAgent;
 import bdi4jade.core.Capability;
+import bdi4jade.core.SingleCapabilityAgent;
 import bdi4jade.event.GoalEvent;
 import bdi4jade.event.GoalListener;
 import bdi4jade.goal.Goal;
 import bdi4jade.plan.DefaultPlan;
 
-public class HelloWorldParamAgent extends BDIAgent implements GoalListener {
+public class HelloWorldParamAgent extends SingleCapabilityAgent implements
+		GoalListener {
 
 	public class HelloWorldParamGoal implements Goal {
 
@@ -73,7 +74,7 @@ public class HelloWorldParamAgent extends BDIAgent implements GoalListener {
 		capability.getPlanLibrary().addPlan(
 				new DefaultPlan(HelloWorldParamGoal.class,
 						HelloWorldParamPlan.class));
-		addCapability(capability);
+		setCapability(capability);
 
 		addGoal(new HelloWorldParamGoal("reader"), this);
 	}
diff --git a/bdi-jade-test/src/bdi4jade/examples/planselection/ExperimentRunner.java b/bdi-jade-test/src/bdi4jade/examples/planselection/ExperimentRunner.java
index f26d649..b5140d7 100644
--- a/bdi-jade-test/src/bdi4jade/examples/planselection/ExperimentRunner.java
+++ b/bdi-jade-test/src/bdi4jade/examples/planselection/ExperimentRunner.java
@@ -37,7 +37,7 @@ import org.apache.log4j.PropertyConfigurator;
 
 import bdi4jade.event.GoalEvent;
 import bdi4jade.event.GoalListener;
-import bdi4jade.examples.AgentStarter;
+import bdi4jade.examples.BDI4JADEExamplesApp;
 
 /**
  * @author ingrid
@@ -48,7 +48,7 @@ public class ExperimentRunner implements GoalListener {
 	public static final int ITERATIONS = 5000;
 
 	public static void main(String[] args) {
-		PropertyConfigurator.configure(AgentStarter.class
+		PropertyConfigurator.configure(BDI4JADEExamplesApp.class
 				.getResource("log4j.properties"));
 		ExperimentRunner runner = new ExperimentRunner();
 		runner.run();
@@ -98,7 +98,7 @@ public class ExperimentRunner implements GoalListener {
 			} else {
 				log.info("Iterations finished!!");
 				log.info(((GenericValueFunction<?>) transportationAgent
-						.getRootCapability().getBeliefBase()
+						.getCapability().getBeliefBase()
 						.getBelief(TransportationAgent.SATISFACTION).getValue())
 						.stats());
 			}
diff --git a/bdi-jade-test/src/bdi4jade/examples/planselection/TransportationAgent.java b/bdi-jade-test/src/bdi4jade/examples/planselection/TransportationAgent.java
index e58f77a..51de8ee 100644
--- a/bdi-jade-test/src/bdi4jade/examples/planselection/TransportationAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/planselection/TransportationAgent.java
@@ -28,8 +28,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import bdi4jade.belief.TransientBelief;
-import bdi4jade.core.BDIAgent;
-import bdi4jade.core.Capability;
+import bdi4jade.core.SingleCapabilityAgent;
 import bdi4jade.extension.planselection.utilitybased.SoftgoalPreferences;
 import bdi4jade.extension.planselection.utilitybased.UtilityBasedBDIAgent;
 import bdi4jade.goal.Softgoal;
@@ -39,7 +38,7 @@ import bdi4jade.plan.Plan;
  * @author ingrid
  * 
  */
-public class TransportationAgent extends BDIAgent {
+public class TransportationAgent extends SingleCapabilityAgent {
 
 	public static final String SATISFACTION = "Satisfaction";
 
@@ -47,17 +46,11 @@ public class TransportationAgent extends BDIAgent {
 
 	private final Log log;
 	private final Random rand;
-	private final Capability rootCapability;
 
 	public TransportationAgent() {
+		super(new UtilityBasedBDIAgent());
 		this.log = LogFactory.getLog(this.getClass());
 		this.rand = new Random(System.currentTimeMillis());
-		this.rootCapability = new UtilityBasedBDIAgent();
-		this.addCapability(rootCapability);
-	}
-
-	public Capability getRootCapability() {
-		return rootCapability;
 	}
 
 	protected void init() {
@@ -65,19 +58,16 @@ public class TransportationAgent extends BDIAgent {
 			this.addSoftgoal(softgoal);
 		}
 		for (Plan plan : Plans.PLANS) {
-			this.getRootCapability().getPlanLibrary().addPlan(plan);
+			getCapability().getPlanLibrary().addPlan(plan);
 		}
-		this.getRootCapability()
-				.getBeliefBase()
-				.addBelief(
-						new TransientBelief<GenericValueFunction<Integer>>(
-								SATISFACTION,
-								new GenericValueFunction<Integer>()));
+		getCapability().getBeliefBase().addBelief(
+				new TransientBelief<GenericValueFunction<Integer>>(
+						SATISFACTION, new GenericValueFunction<Integer>()));
 	}
 
 	public void updatePreferences() {
 		SoftgoalPreferences preferences = (SoftgoalPreferences) this
-				.getRootCapability().getBeliefBase()
+				.getCapability().getBeliefBase()
 				.getBelief(SoftgoalPreferences.NAME);
 
 		double total = 0;
diff --git a/bdi-jade-test/src/bdi4jade/examples/template/MyAgent.java b/bdi-jade-test/src/bdi4jade/examples/template/MyAgent.java
index 2abcf7b..74736d3 100644
--- a/bdi-jade-test/src/bdi4jade/examples/template/MyAgent.java
+++ b/bdi-jade-test/src/bdi4jade/examples/template/MyAgent.java
@@ -22,8 +22,8 @@
 
 package bdi4jade.examples.template;
 
-import bdi4jade.core.BDIAgent;
 import bdi4jade.core.Capability;
+import bdi4jade.core.MultipleCapabilityAgent;
 import bdi4jade.examples.template.goal.MyGoal;
 import bdi4jade.examples.template.plan.MyPlan1;
 import bdi4jade.examples.template.plan.MyPlan2;
@@ -35,7 +35,7 @@ import bdi4jade.goal.Softgoal;
  * @author ingrid
  * 
  */
-public class MyAgent extends BDIAgent {
+public class MyAgent extends MultipleCapabilityAgent {
 
 	static final long serialVersionUID = 2712019445290687786L;