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

jadex.bdiv3.features.impl.BDILifecycleAgentFeature Maven / Gradle / Ivy

package jadex.bdiv3.features.impl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jadex.bdiv3.IBDIClassGenerator;
import jadex.bdiv3.features.IBDIAgentFeature;
import jadex.bdiv3.features.impl.BDIAgentFeature.GoalsExistCondition;
import jadex.bdiv3.features.impl.BDIAgentFeature.LifecycleStateCondition;
import jadex.bdiv3.features.impl.BDIAgentFeature.NotInShutdownCondition;
import jadex.bdiv3.features.impl.BDIAgentFeature.PlansExistCondition;
import jadex.bdiv3.model.BDIModel;
import jadex.bdiv3.model.IBDIModel;
import jadex.bdiv3.model.MBelief;
import jadex.bdiv3.model.MCapability;
import jadex.bdiv3.model.MCondition;
import jadex.bdiv3.model.MConfigBeliefElement;
import jadex.bdiv3.model.MConfigParameterElement;
import jadex.bdiv3.model.MConfiguration;
import jadex.bdiv3.model.MElement;
import jadex.bdiv3.model.MGoal;
import jadex.bdiv3.model.MInternalEvent;
import jadex.bdiv3.model.MMessageEvent;
import jadex.bdiv3.model.MParameter;
import jadex.bdiv3.model.MParameter.EvaluationMode;
import jadex.bdiv3.model.MPlan;
import jadex.bdiv3.model.MTrigger;
import jadex.bdiv3.runtime.ChangeEvent;
import jadex.bdiv3.runtime.EasyDeliberationStrategy;
import jadex.bdiv3.runtime.IDeliberationStrategy;
import jadex.bdiv3.runtime.impl.APL;
import jadex.bdiv3.runtime.impl.APL.CandidateInfoMPlan;
import jadex.bdiv3.runtime.impl.APL.MPlanInfo;
import jadex.bdiv3.runtime.impl.GoalDroppedException;
import jadex.bdiv3.runtime.impl.RCapability;
import jadex.bdiv3.runtime.impl.RGoal;
import jadex.bdiv3.runtime.impl.RParameterElement.RParameter;
import jadex.bdiv3.runtime.impl.RParameterElement.RParameterSet;
import jadex.bdiv3.runtime.impl.RPlan;
import jadex.bdiv3.runtime.impl.RProcessableElement;
import jadex.bdiv3x.runtime.CapabilityWrapper;
import jadex.bdiv3x.runtime.ICandidateInfo;
import jadex.bdiv3x.runtime.IInternalEvent;
import jadex.bdiv3x.runtime.IMessageEvent;
import jadex.bdiv3x.runtime.RInternalEvent;
import jadex.bdiv3x.runtime.RMessageEvent;
import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentStep;
import jadex.bridge.IInternalAccess;
import jadex.bridge.component.ComponentCreationInfo;
import jadex.bridge.component.IComponentFeatureFactory;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.ILifecycleComponentFeature;
import jadex.bridge.component.IMessageFeature;
import jadex.bridge.component.IPojoComponentFeature;
import jadex.bridge.component.ISubcomponentsFeature;
import jadex.bridge.component.impl.ComponentFeatureFactory;
import jadex.bridge.modelinfo.UnparsedExpression;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.CheckNotNull;
import jadex.bridge.service.component.IProvidedServicesFeature;
import jadex.bridge.service.component.IRequiredServicesFeature;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.clock.IClockService;
import jadex.bridge.service.types.clock.ITimedObject;
import jadex.commons.ICommand;
import jadex.commons.MethodInfo;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.Tuple2;
import jadex.commons.future.CollectionResultListener;
import jadex.commons.future.CounterResultListener;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.FutureBarrier;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
import jadex.javaparser.SJavaParser;
import jadex.micro.features.impl.MicroLifecycleComponentFeature;
import jadex.rules.eca.ChangeInfo;
import jadex.rules.eca.EventType;
import jadex.rules.eca.IAction;
import jadex.rules.eca.ICondition;
import jadex.rules.eca.IEvent;
import jadex.rules.eca.IRule;
import jadex.rules.eca.MethodCondition;
import jadex.rules.eca.Rule;
import jadex.rules.eca.RuleSystem;
import jadex.rules.eca.annotations.CombinedCondition;

/**
 *  Feature that ensures the agent created(), body() and killed() are called on the pojo. 
 */
public class BDILifecycleAgentFeature extends MicroLifecycleComponentFeature implements IInternalBDILifecycleFeature
{
	/** The factory. */
	public static final IComponentFeatureFactory FACTORY = new ComponentFeatureFactory(ILifecycleComponentFeature.class, BDILifecycleAgentFeature.class,
		new Class[]{IRequiredServicesFeature.class, IProvidedServicesFeature.class, ISubcomponentsFeature.class}, null, false);
	
	/** Is the agent inited and allowed to execute rules? */
	protected boolean inited;
	
	/** Is the agent in shutdown?. */
	protected boolean shutdown;
	
	/**
	 *  Factory method constructor for instance level.
	 */
	public BDILifecycleAgentFeature(IInternalAccess component, ComponentCreationInfo cinfo)
	{
		super(component, cinfo);
	}
	
	/**
	 *  Execute the functional body of the agent.
	 *  Is only called once.
	 */
	public IFuture body()
	{
		IInternalBDIAgentFeature bdif = component.getComponentFeature(IInternalBDIAgentFeature.class);
		createStartBehavior().startBehavior(bdif.getBDIModel(), bdif.getRuleSystem(), bdif.getCapability());
		return super.body();
	}
	
	/**
	 *  Create the start behavior.
	 */
	protected StartBehavior createStartBehavior()
	{
		return new StartBehavior(component);
	}
	
	/**
	 *  Create the end behavior.
	 */
	protected EndBehavior createEndBehavior()
	{
		return new EndBehavior(component);
	}
	
	/**
	 *  Cleanup the agent.
	 */
	public IFuture shutdown()
	{
		setShutdown(true);
		
		final Future	ret	= new Future();
		final IInternalBDIAgentFeature bdif = component.getComponentFeature(IInternalBDIAgentFeature.class);

		createEndBehavior().startEndBehavior(bdif.getBDIModel(), bdif.getRuleSystem(), bdif.getCapability())
			.addResultListener(new IResultListener()
		{
			public void resultAvailable(Void result)
			{
				BDILifecycleAgentFeature.super.shutdown().addResultListener(new DelegationResultListener(ret));
			}

			public void exceptionOccurred(Exception exception)
			{
				exception.printStackTrace();
				BDILifecycleAgentFeature.super.shutdown().addResultListener(new DelegationResultListener(ret));
			}
		});
		return ret;
	}
	
	/**
	 *  Execute a goal method.
	 */
	protected static IFuture executeGoalMethod(Method m, RProcessableElement goal, IEvent event, IInternalAccess component)
	{
		return invokeBooleanMethod(goal.getPojoElement(), m, goal.getModelElement(), event, null, component);
	}
	
	/**
	 *  Assemble fitting parameters from context and invoke a boolean method. 
	 */
	public static IFuture invokeBooleanMethod(Object pojo, Method m, MElement modelelement, IEvent event, RPlan rplan, IInternalAccess component)
	{
		final Future ret = new Future();
		try
		{
			m.setAccessible(true);
			
			Object[] vals = BDIAgentFeature.getInjectionValues(m.getParameterTypes(), m.getParameterAnnotations(),
				modelelement, event!=null ? new ChangeEvent(event) : null, rplan, null, component);
			if(vals==null)
				System.out.println("Invalid parameter assignment");
			Object app = m.invoke(pojo, vals);
			if(app instanceof Boolean)
			{
				ret.setResult((Boolean)app);
			}
			else if(app instanceof IFuture)
			{
				((IFuture)app).addResultListener(new DelegationResultListener(ret));
			}
		}
		catch(Exception e)
		{
			System.err.println("method: "+m);
			e.printStackTrace();
			ret.setException(e);
		}
		return ret;
	}
	
	/**
	 *  Get the inited.
	 *  @return The inited.
	 */
	public boolean isInited()
	{
		return inited;
	}

	/**
	 *  The inited to set.
	 *  @param inited The inited to set
	 */
	public void setInited(boolean inited)
	{
		this.inited = inited;
	}
	

	/**
	 *  Get the shutdown. 
	 *  @return The shutdown
	 */
	public boolean isShutdown()
	{
		return shutdown;
	}

	/**
	 *  Set the shutdown.
	 *  @param shutdown The shutdown to set
	 */
	public void setShutdown(boolean shutdown)
	{
		this.shutdown = shutdown;
	}
	
	// for xml

	/**
	 *  Evaluate the condition.
	 *  @return
	 */
	public static boolean evaluateCondition(IInternalAccess agent, MCondition cond, MElement owner, Map vals)
	{
		boolean ret = false;
		
		UnparsedExpression uexp = cond.getExpression();
		try
		{
			Object res = SJavaParser.getParsedValue(uexp, agent.getModel().getAllImports(), CapabilityWrapper.getFetcher(agent, uexp.getLanguage(), vals), agent.getClassLoader());
			if(res instanceof Boolean)
			{
				ret = ((Boolean)res).booleanValue();
			}
			else
			{
				agent.getLogger().warning("Condition does not evaluate to boolean: "+uexp.getValue());
			}
		}
		catch(Exception e)
		{
			agent.getLogger().warning("Condition evaluation produced exception: "+uexp.getValue()+", "+e);
		}
		
		return ret;
	}
	
	/**
	 *  Condition that tests if an expression evalutes to true.
	 */
	public static class EvaluateExpressionCondition implements ICondition
	{
		protected MCondition cond;
		protected MElement owner;
		protected IInternalAccess agent;
		protected Map vals;
		
		public EvaluateExpressionCondition(IInternalAccess agent, MCondition cond, MElement owner, Map vals)
		{
			this.agent = agent;
			this.cond = cond;
			this.owner = owner;
			this.vals = vals;
		}
		
		public IFuture> evaluate(IEvent event)
		{
//			vals.put("$event", event);
			boolean res = evaluateCondition(agent, cond, owner, vals);
			return new Future>(res? ICondition.TRUE: ICondition.FALSE);
		}
	}
	
	/**
	 *  Extracted start behavior. 
	 */
	public static class LifecycleBehavior
	{
		/** The agent. */
		protected IInternalAccess component;
		
		/**
		 *  Create a new start behavior.
		 */
		public LifecycleBehavior(IInternalAccess component)
		{
			this.component = component;
		}
		
		/**
		 *  Get the capability object (only for pojo).
		 */
		public Object getCapabilityObject(String name)
		{
			IBDIAgentFeature bdif = component.getComponentFeature(IBDIAgentFeature.class);
			return ((BDIAgentFeature)bdif).getCapabilityObject(name);
		}
		
		/**
		 *  Dispatch a top level goal.
		 */
		public IFuture dispatchTopLevelGoal(Object goal)
		{
			IBDIAgentFeature bdif = component.getComponentFeature(IBDIAgentFeature.class);
			return bdif.dispatchTopLevelGoal(goal);
		}
		
		/**
		 *  Dispatch a message event.
		 */
		public IFuture sendMessageEvent(IMessageEvent message)
		{
			IMessageFeature mf = component.getComponentFeature(IMessageFeature.class);
			return mf.sendMessage((Map)message.getMessage(), message.getMessageType());
		}
		
		/**
		 *  Dispatch an internal event.
		 */
		public IFuture dispatchInternalEvent(IInternalEvent event)
		{
			// Pojo bdi does not support internal events
			throw new UnsupportedOperationException();
		}
		
		/**
		 *  Dispatch the configuration plans.
		 */
		protected IFuture dispatchConfigPlans(final IInternalAccess component, List cplans, IBDIModel bdimodel)
		{
			Future ret = new Future();
			if(cplans!=null && cplans.size()>0)
			{
				FutureBarrier barrier = new FutureBarrier();
				for(MConfigParameterElement cplan: cplans)
				{
					MPlan mplan = bdimodel.getCapability().getPlan(cplan.getRef());
					// todo: allow Java plan constructor calls
	//				Object val = SJavaParser.parseExpression(uexp, model.getModelInfo().getAllImports(), getClassLoader());
					
					// todo: bindings in config elems
					
					List> bindings = APL.calculateBindingElements(component, mplan, null);
					
					if(bindings!=null)
					{
						for(Map binding: bindings)
						{
							RPlan rplan = RPlan.createRPlan(mplan, new CandidateInfoMPlan(new MPlanInfo(mplan, binding), null, component), null, component, null, cplan);
							barrier.addFuture(RPlan.executePlan(rplan, component));
						}
					}
					// No binding: generate one candidate.
					else
					{
						RPlan rplan = RPlan.createRPlan(mplan, new CandidateInfoMPlan(new MPlanInfo(mplan, null), null, component), null, component, null, cplan);
						barrier.addFuture(RPlan.executePlan(rplan, component));
					}
				}
				
				barrier.waitForIgnoreFailures(new ICommand()
				{
					@Override
					public void execute(Exception e)
					{
						component.getLogger().severe("Failure during config plan execution: "+SUtil.getExceptionStacktrace(e));
					}
				}).addResultListener(new DelegationResultListener(ret));
			}
			else
			{
				ret.setResult(null);
			}
			return ret;
		}
		
		/**
		 *  Dispatch the configuration goals.
		 */
		protected IFuture dispatchConfigGoals(final IInternalAccess component, List cgoals, IBDIModel bdimodel)
		{
			Future ret = new Future();
			if(cgoals!=null && cgoals.size()>0)
			{
				FutureBarrier barrier = new FutureBarrier();
				
				for(MConfigParameterElement cgoal: cgoals)
				{
					MGoal mgoal = null;
					Class gcl = null;
					Object goal = null;
					
					// try to fetch via name
					mgoal = bdimodel.getCapability().getGoal(cgoal.getRef());
					if(mgoal==null && cgoal.getRef().indexOf(".")==-1)
					{
						// try with package
						mgoal = bdimodel.getCapability().getGoal(component.getModel().getPackage()+"."+cgoal.getRef());
					}
					
					if(mgoal!=null)
					{
						gcl = mgoal.getTargetClass(component.getClassLoader());
					}
					// if not found, try expression
					else
					{
						Object o = SJavaParser.parseExpression(cgoal.getRef(), component.getModel().getAllImports(), component.getClassLoader())
							.getValue(CapabilityWrapper.getFetcher(component, cgoal.getCapabilityName()));
						if(o instanceof Class)
						{
							gcl = (Class)o;
						}
						else
						{
							goal = o;
							gcl = o.getClass();
						}
						mgoal = bdimodel.getCapability().getGoal(gcl.getName());
					}
		
//					// Create goal if expression available
//					if(uexp.getName()!=null && uexp.getValue().length()>0)
//					{
//						Object o = SJavaParser.parseExpression(uexp, component.getModel().getAllImports(), component.getClassLoader()).getValue(component.getFetcher());
//						if(o instanceof Class)
//						{
//							gcl = (Class)o;
//						}
//						else
//						{
//							goal = o;
//							gcl = o.getClass();
//						}
//					}
//					
//					if(gcl==null && uexp.getClazz()!=null)
//					{
//						gcl = uexp.getClazz().getType(component.getClassLoader(), component.getModel().getAllImports());
//					}
//					if(gcl==null)
//					{
//						// try to fetch via name
//						mgoal = bdimodel.getCapability().getGoal(uexp.getName());
//						if(mgoal==null && uexp.getName().indexOf(".")==-1)
//						{
//							// try with package
//							mgoal = bdimodel.getCapability().getGoal(component.getModel().getPackage()+"."+uexp.getName());
//						}
//						if(mgoal!=null)
//						{
//							gcl = mgoal.getTargetClass(component.getClassLoader());
//						}
//					}						
//					if(mgoal==null)
//					{
//						mgoal = bdimodel.getCapability().getGoal(gcl.getName());
//					}
					
					// Create goal instance
					if(goal==null && gcl!=null)
					{
						try
						{
							Object agent = component.getComponentFeature(IPojoComponentFeature.class).getPojoAgent();
							Class agcl = agent.getClass();
							Constructor[] cons = gcl.getDeclaredConstructors();
							for(Constructor c: cons)
							{
								Class[] params = c.getParameterTypes();
								if(params.length==0)
								{
									// perfect found empty con
									goal = gcl.newInstance();
									break;
								}
								else if(params.length==1 && params[0].equals(agcl))
								{
									// found (first level) inner class constructor
									goal = c.newInstance(new Object[]{agent});
									break;
								}
							}
						}
						catch(RuntimeException e)
						{
							throw e;
						}
						catch(Exception e)
						{
							throw new RuntimeException(e);
						}
					}
					
					if(mgoal==null || (goal==null && gcl!=null))
					{
						throw new RuntimeException("Could not create goal: "+cgoal);
					}
					
					List> bindings = APL.calculateBindingElements(component, mgoal, null);
					
					if(goal==null)
					{
						// XML only
						if(bindings!=null)
						{
							for(Map binding: bindings)
							{
								RGoal rgoal = new RGoal(component, mgoal, null, null, binding, cgoal, null);
								barrier.addFuture(dispatchTopLevelGoal(rgoal));//.addResultListener(goallis);
							}
						}
						// No binding: generate one candidate.
						else
						{
							RGoal rgoal = new RGoal(component, mgoal, goal, null, null, cgoal, null);
							barrier.addFuture(dispatchTopLevelGoal(rgoal));//.addResultListener(goallis);
						}
					}
					else
					{
						// Pojo only
						barrier.addFuture(dispatchTopLevelGoal(goal));//.addResultListener(goallis);								
					}
				}
				
				// wait for all goals being finished
				barrier.waitForIgnoreFailures(new ICommand()
				{
					@Override
					public void execute(Exception e)
					{
						if(e instanceof GoalDroppedException)
						{
							component.getLogger().info("Config goal has been dropped: "+e);
						}
						else
						{
							component.getLogger().severe("Failure during config goal processing: "+SUtil.getExceptionStacktrace(e));							
						}
					}
				}).addResultListener(new DelegationResultListener(ret));
			}
			else
			{
				ret.setResult(null);
			}
			
			return ret;
		}
		
		/**
		 *  Dispatch the configuration events.
		 */
		protected IFuture dispatchConfigEvents(IInternalAccess component, List cevents, IBDIModel bdimodel)
		{
			Future ret = new Future();
			FutureBarrier barrier = new FutureBarrier();
			
			IInternalBDIAgentFeature bdif = component.getComponentFeature(IInternalBDIAgentFeature.class);
			MCapability mcapa = (MCapability)bdif.getCapability().getModelElement();
			
			// Send initial messages
			// Throw initial internal events
			for(MConfigParameterElement cpe: SUtil.safeList(cevents))
			{
				MInternalEvent mievent = mcapa.getInternalEvent(cpe.getRef());
				if(mievent!=null)
				{
					RInternalEvent rievent = new RInternalEvent(mievent, component, cpe);
					dispatchInternalEvent(rievent);
				}
				else
				{
					MMessageEvent mmevent = mcapa.getResolvedMessageEvent(null, cpe.getRef());
					RMessageEvent rmevent = new RMessageEvent(mmevent, component, cpe);
					barrier.addFuture(sendMessageEvent(rmevent));
				}
			}
			
			barrier.waitFor().addResultListener(new DelegationResultListener(ret));
			return ret;
		}
	}
	
	/**
	 *  Extracted start behavior. 
	 */
	public static class StartBehavior extends LifecycleBehavior
	{
		/**
		 *  Create a new start behavior.
		 */
		public StartBehavior(IInternalAccess component)
		{
			super(component);
		}
		
		/**
		 *  Start the component behavior.
		 */
		public void startBehavior(final IBDIModel bdimodel, final RuleSystem rulesystem, final RCapability rcapa)
		{
//			super.startBehavior();
			
//			final Object agent = microagent instanceof PojoBDIAgent? ((PojoBDIAgent)microagent).getPojoAgent(): microagent;
					
//			final IBDIAgentFeature bdif = component.getComponentFeature(IBDIAgentFeature.class);
//			final IInternalBDIAgentFeature ibdif = (IInternalBDIAgentFeature)bdif; 
//			final IBDIModel bdimodel = ibdif.getBDIModel();
			
			final IResultListener goallis = new IResultListener()
			{
				public void resultAvailable(Object result)
				{
					component.getLogger().info("Goal succeeded: "+result);
				}
				
				public void exceptionOccurred(Exception exception)
				{
					component.getLogger().info("Goal failed: "+exception);
				}
			};
			
			// Init bdi configuration
			String confname = component.getConfiguration();
			if(confname!=null)
			{
				MConfiguration mconf = bdimodel.getCapability().getConfiguration(confname);
				
				if(mconf!=null)
				{
					// only for pojo agents / xml is inited in beliefbase init
					if(bdimodel instanceof BDIModel)
					{
						// Set initial belief values
						List ibels = mconf.getInitialBeliefs();
						if(ibels!=null)
						{
							for(MConfigBeliefElement ibel: ibels)
							{
								try
								{
									UnparsedExpression	fact	= ibel.getFacts().get(0);	// pojo initial beliefs are @NameValue, thus exactly one fact.
									MBelief mbel = bdimodel.getCapability().getBelief(ibel.getName());
									Object val = SJavaParser.parseExpression(fact, component.getModel().getAllImports(), component.getClassLoader()).getValue(CapabilityWrapper.getFetcher(component, fact.getLanguage()));
									mbel.setValue(component, val);
								}
								catch(RuntimeException e)
								{
									throw e;
								}
								catch(Exception e)
								{
									throw new RuntimeException(e);
								}
							}
						}
					}
					
					// Create initial plans (create plans before other elements as they might want to react to these)
					List iplans = mconf.getInitialPlans();
					dispatchConfigPlans(component, iplans, bdimodel);
					
					// Create initial goals
					List igoals = mconf.getInitialGoals();
					dispatchConfigGoals(component, igoals, bdimodel);
					
					// Create initial events
					List ievents = mconf.getInitialEvents();
					dispatchConfigEvents(component, ievents, bdimodel);
				}
			}
			
			// Observe dynamic beliefs
			List beliefs = bdimodel.getCapability().getBeliefs();
			
			for(final MBelief mbel: beliefs)
			{
				List events = mbel.getEvents();
				
//				Object cap = null;
//				if(component.getComponentFeature0(IPojoComponentFeature.class)!=null)
//				{
//					Object agent = component.getComponentFeature(IPojoComponentFeature.class).getPojoAgent();
//					Object ocapa = agent;
//					int	i	= mbel.getName().indexOf(MElement.CAPABILITY_SEPARATOR);
//					if(i!=-1)
//					{
//						ocapa	= ((BDIAgentFeature)bdif).getCapabilityObject(mbel.getName().substring(0, mbel.getName().lastIndexOf(MElement.CAPABILITY_SEPARATOR)));
//					}
//					cap	= ocapa;
//				}
//				final Object fcapa = cap;
				
				String name = null;
				Object capa = null;
				if(component.getComponentFeature0(IPojoComponentFeature.class)!=null)
				{
					int	i	= mbel.getName().indexOf(MElement.CAPABILITY_SEPARATOR);
					if(i!=-1)
					{
						capa	= getCapabilityObject(mbel.getName().substring(0, mbel.getName().lastIndexOf(MElement.CAPABILITY_SEPARATOR)));
						name	= mbel.getName().substring(mbel.getName().lastIndexOf(MElement.CAPABILITY_SEPARATOR)+1); 
					}
					else
					{
						Object agent = component.getComponentFeature(IPojoComponentFeature.class).getPojoAgent();
						capa	= agent;
						name	= mbel.getName();
					}
				}
				final String fname = name;
				final Object fcapa = capa;
				
				// Automatic reevaluation if belief depends on other beliefs
				if(!events.isEmpty() && mbel.getEvaluationMode().equals(EvaluationMode.PUSH))
				{
					Rule rule = new Rule(mbel.getName()+"_belief_update", 
						ICondition.TRUE_CONDITION, new IAction()
					{
						Object oldval = null;
						
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
//							System.out.println("belief update: "+event);
							// Invoke dynamic update method if field belief
							if(mbel.isFieldBelief())
							{
								try
								{
									Method um = fcapa.getClass().getMethod(IBDIClassGenerator.DYNAMIC_BELIEF_UPDATEMETHOD_PREFIX+SUtil.firstToUpperCase(mbel.getName()), new Class[0]);
									um.invoke(fcapa, new Object[0]);
								}
								catch(Exception e)
								{
									e.printStackTrace();
								}
							}
							// Otherwise just call getValue and throw event
							else if(fcapa!=null) // if is pojo 
							{
								Object value = mbel.getValue(component);
								// todo: save old value?!
								BDIAgentFeature.createChangeEvent(value, oldval, null, component, mbel.getName());
								oldval = value;
							}
							else // xml belief push mode
							{
								// reevaluate the belief on change events
								Object value = SJavaParser.parseExpression(mbel.getDefaultFact(), 
									component.getModel().getAllImports(), component.getClassLoader()).getValue(CapabilityWrapper.getFetcher(component, mbel.getDefaultFact().getLanguage()));
								// save the value
								mbel.setValue(component, value);
//								oldval = value;	// not needed for xml
							}
							return IFuture.DONE;
						}
					});
					rule.setEvents(events);
					rulesystem.getRulebase().addRule(rule);
				}
				
				if(mbel.getUpdaterateValue(component)>0)
				{
					final IClockService cs = SServiceProvider.getLocalService(component, IClockService.class, RequiredServiceInfo.SCOPE_PLATFORM);
//					cs.createTimer(mbel.getUpdaterate(), new ITimedObject()
					ITimedObject to = new ITimedObject()
					{
						ITimedObject	self	= this;
						Object oldval = null;
						
						public void timeEventOccurred(long currenttime)
						{
							try
							{
								component.getComponentFeature(IExecutionFeature.class).scheduleStep(new IComponentStep()
								{
									public IFuture execute(IInternalAccess ia)
									{
										try
										{
											// Invoke dynamic update method if field belief
											if(mbel.isFieldBelief())
											{
												Method um = fcapa.getClass().getMethod(IBDIClassGenerator.DYNAMIC_BELIEF_UPDATEMETHOD_PREFIX+SUtil.firstToUpperCase(fname), new Class[0]);
												um.invoke(fcapa, new Object[0]);
											}
											// Otherwise just call getValue and throw event
											else if(fcapa!=null)
											{
												Object value = mbel.getValue(fcapa, component.getClassLoader());
												BDIAgentFeature.createChangeEvent(value, oldval, null, component, mbel.getName());
												oldval = value;
											}
											else // xml belief updaterate
											{
												// reevaluate the belief on change events
												Object value = SJavaParser.parseExpression(mbel.getDefaultFact(), 
													component.getModel().getAllImports(), component.getClassLoader()).getValue(CapabilityWrapper.getFetcher(component, mbel.getDefaultFact().getLanguage()));
												// save the value 
												// change event is automatically thrown
												mbel.setValue(component, value);
												oldval = value;
											}
										}
										catch(Exception e)
										{
											e.printStackTrace();
										}
										
										cs.createTimer(mbel.getUpdaterateValue(component), self);
										return IFuture.DONE;
									}
								});
							}
							catch(ComponentTerminatedException cte)
							{
								
							}
						}
					
						@Override
						public String toString()
						{
							return "updateBelief("+mbel.getName()+"@"+component.getComponentIdentifier()+")";
						}
						
//						public void exceptionOccurred(Exception exception)
//						{
//							component.getLogger().severe("Cannot update belief "+mbel.getName()+": "+exception);
//						}
					};
					// Evaluate at time 0, updaterate*1, updaterate*2, ...
					to.timeEventOccurred(cs.getTime());
				}
			}
			
			// Observe dynamic parameters of goals
			// todo: other parameter elements?!
			List mgoals = bdimodel.getCapability().getGoals();
			
			for(final MGoal mgoal: mgoals)
			{
				List mparams = mgoal.getParameters();
				
				if(mparams!=null)
				{
					for(final MParameter mparam: mparams)
					{
						if(mparam.getEvaluationMode().equals(EvaluationMode.PUSH))
						{
							List events = mparam.getEvents();
						
							// Automatic reevaluation if belief depends on other beliefs
							if(!events.isEmpty())
							{
								Rule rule = new Rule(mgoal.getName()+"_"+mparam.getName()+"_parameter_update", 
									ICondition.TRUE_CONDITION, new IAction()
								{
									// todo: oldval
			//						Object oldval = null;
									
									public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
									{
//										System.out.println("parameter update: "+event);
										
										RCapability capa = BDIAgentFeature.getCapability(component);
										for(RGoal goal: SUtil.safeCollection(capa.getGoals(mgoal)))
										{
											if(!mparam.isMulti(component.getClassLoader()))
											{
												((RParameter)goal.getParameter(mparam.getName())).updateDynamicValue();
											}
											else
											{
												((RParameterSet)goal.getParameterSet(mparam.getName())).updateDynamicValues();
											}
										}
										
										return IFuture.DONE;
									}
								});
								
								rule.setEvents(events);
								rulesystem.getRulebase().addRule(rule);
							}
							
							if(mparam.getUpdaterateValue(component)>0)
							{
								final IClockService cs = SServiceProvider.getLocalService(component, IClockService.class, RequiredServiceInfo.SCOPE_PLATFORM);
								ITimedObject to = new ITimedObject()
								{
									ITimedObject self = this;
			//						Object oldval = null;
									
									public void timeEventOccurred(long currenttime)
									{
										try
										{
											component.getComponentFeature(IExecutionFeature.class).scheduleStep(new IComponentStep()
											{
												public IFuture execute(IInternalAccess ia)
												{
													try
													{
														System.out.println("parameter updaterate: "+mparam.getUpdaterateValue(component));
														
														RCapability capa = BDIAgentFeature.getCapability(component);
														for(RGoal goal: SUtil.safeCollection(capa.getGoals(mgoal)))
														{
															if(!mparam.isMulti(component.getClassLoader()))
															{
																((RParameter)goal.getParameter(mparam.getName())).updateDynamicValue();
															}
															else
															{
																((RParameterSet)goal.getParameterSet(mparam.getName())).updateDynamicValues();
															}
														}
													}
													catch(Exception e)
													{
														e.printStackTrace();
													}
													
													cs.createTimer(mparam.getUpdaterateValue(component), self);
													return IFuture.DONE;
												}
											});
										}
										catch(ComponentTerminatedException cte)
										{
										}
									}
								};
								// Evaluate at time 0, updaterate*1, updaterate*2, ...
								to.timeEventOccurred(cs.getTime());
							}
						}
					}
				}
			}
			
			// Observe goal types
			List goals = bdimodel.getCapability().getGoals();
			for(final MGoal mgoal: goals)
			{
//				todo: explicit bdi creation rule
//				rulesystem.observeObject(goals.get(i).getTargetClass(getClassLoader()));
			
//				boolean fin = false;
				
				final Class gcl = mgoal.getTargetClass(component.getClassLoader());
//				boolean declarative = false;
//				boolean maintain = false;
				
				List conds = mgoal.getConditions(MGoal.CONDITION_CREATION);
				if(conds!=null)
				{
					for(MCondition cond: conds)
					{
						if(cond.getConstructorTarget()!=null)
						{
							final Constructor c = cond.getConstructorTarget().getConstructor(component.getClassLoader());
							
							Rule rule = new Rule(mgoal.getName()+"_goal_create", 
								new NotInShutdownCondition(component), new IAction()
							{
								public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
								{
		//							System.out.println("create: "+context);
									
									Object pojogoal = null;
									try
									{
										boolean ok = true;
										Class[] ptypes = c.getParameterTypes();
										Object[] pvals = new Object[ptypes.length];
										
										Annotation[][] anns = c.getParameterAnnotations();
										int skip = ptypes.length - anns.length;
										
										for(int i=0; i && ((ChangeInfo)o).getValue()!=null && SReflect.isSupertype(ptypes[i], ((ChangeInfo)o).getValue().getClass()))
											{
												pvals[i] = ((ChangeInfo)o).getValue();
											}
											else if(SReflect.isSupertype(agent.getClass(), ptypes[i]))
											{
												pvals[i] = agent;
											}
											
											// ignore implicit parameters of inner class constructor
											if(pvals[i]==null && i>=skip)
											{
												for(int j=0; anns!=null && j rule = new Rule(mgoal.getName()+"_goal_create", 
								new CombinedCondition(new ICondition[]{new NotInShutdownCondition(component), new MethodCondition(null, m)
							{
								protected Object invokeMethod(IEvent event) throws Exception
								{
									m.setAccessible(true);
									Object[] pvals = BDIAgentFeature.getInjectionValues(m.getParameterTypes(), m.getParameterAnnotations(),
										mgoal, new ChangeEvent(event), null, null, component);
									return pvals!=null? m.invoke(null, pvals): null;
								}
							}}), new IAction()
							{
								public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
								{
			//						System.out.println("create: "+context);
									
									if(condresult!=null)
									{
										if(SReflect.isIterable(condresult))
										{
											for(Iterator it = SReflect.getIterator(condresult); it.hasNext(); )
											{
												Object pojogoal = it.next();
												dispatchTopLevelGoal(pojogoal).addResultListener(goallis);
											}
										}
										else
										{
											dispatchTopLevelGoal(condresult).addResultListener(goallis);
										}
									}
									else
									{
										Constructor[] cons = gcl.getConstructors();
										Object pojogoal = null;
										boolean ok = false;
										for(Constructor c: cons)
										{
											try
											{
												Object[] vals = BDIAgentFeature.getInjectionValues(c.getParameterTypes(), c.getParameterAnnotations(),
													mgoal, new ChangeEvent(event), null, null, component);
												if(vals!=null)
												{
													pojogoal = c.newInstance(vals);
													dispatchTopLevelGoal(pojogoal).addResultListener(goallis);
													break;
												}
												else
												{
													ok = true;
												}
											}
											catch(Exception e)
											{
											}
										}
										if(pojogoal==null && !ok)
											throw new RuntimeException("Unknown how to create goal: "+gcl);
									}
									return IFuture.DONE;
								}
							});
							rule.setEvents(cond.getEvents());
							rulesystem.getRulebase().addRule(rule);
						}
						else
						{
							Rule rule = new Rule(mgoal.getName()+"_goal_create", 
								new CombinedCondition(new ICondition[]{new NotInShutdownCondition(component), new EvaluateExpressionCondition(component, cond, mgoal, null)}), new IAction()
							{
								public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
								{
			//						System.out.println("create: "+create);
									
									List> bindings = APL.calculateBindingElements(component, mgoal, null);
									
									if(bindings!=null)
									{
										for(Map binding: bindings)
										{
											RGoal rgoal = new RGoal(component, mgoal, null, null, binding, null, null);
											dispatchTopLevelGoal(rgoal).addResultListener(goallis);
										}
									}
									// No binding: generate one candidate.
									else
									{
										RGoal rgoal = new RGoal(component, mgoal, null, null, null, null, null);
										dispatchTopLevelGoal(rgoal).addResultListener(goallis);
									}
									
									return IFuture.DONE;
								}
							});
							
							rule.setEvents(cond.getEvents());
							rulesystem.getRulebase().addRule(rule);
						}
					}
				}
				
				conds = mgoal.getConditions(MGoal.CONDITION_DROP);
				if(conds!=null)
				{
					for(final MCondition cond: conds)
					{
						final Method m = cond.getMethodTarget()==null? null: cond.getMethodTarget().getMethod(component.getClassLoader());
						
						Rule rule = new Rule(mgoal.getName()+"_goal_drop", 
							new GoalsExistCondition(mgoal, rcapa), new IAction()
						{
							public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
							{
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(!RGoal.GoalLifecycleState.DROPPING.equals(goal.getLifecycleState())
										 && !RGoal.GoalLifecycleState.DROPPED.equals(goal.getLifecycleState()))
									{
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(result.booleanValue())
													{
		//												System.out.println("Goal dropping triggered: "+goal);
						//								rgoal.setLifecycleState(BDIAgent.this, rgoal.GOALLIFECYCLESTATE_DROPPING);
														if(!goal.isFinished())
														{
															goal.setException(new GoalDroppedException("drop condition: "+m.getName()));
//															{
//																public void printStackTrace() 
//																{
//																	super.printStackTrace();
//																}
//															});
															goal.setProcessingState(component, RGoal.GoalProcessingState.FAILED);
														}
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else
										{
											if(evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												if(!goal.isFinished())
												{
													goal.setException(new GoalDroppedException("drop condition: "+goal));
													goal.setProcessingState(component, RGoal.GoalProcessingState.FAILED);
												}
											}
										}
									}
								}
								
								return IFuture.DONE;
							}
						});
						List events = new ArrayList(cond.getEvents());
						events.add(new EventType(new String[]{ChangeEvent.GOALADOPTED, mgoal.getName()}));
						rule.setEvents(events);
						rulesystem.getRulebase().addRule(rule);
//							rule.setEvents(cond.getEvents());
//							rulesystem.getRulebase().addRule(rule);
					}
				}
				
				conds = mgoal.getConditions(MGoal.CONDITION_CONTEXT);
				if(conds!=null)
				{
					for(final MCondition cond: conds)
					{
						final Method m = cond.getMethodTarget()==null? null: cond.getMethodTarget().getMethod(component.getClassLoader());
						
						Rule rule = new Rule(mgoal.getName()+"_goal_suspend", 
							new GoalsExistCondition(mgoal, rcapa), new IAction()
						{
							public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
							{
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(!RGoal.GoalLifecycleState.SUSPENDED.equals(goal.getLifecycleState())
									  && !RGoal.GoalLifecycleState.DROPPING.equals(goal.getLifecycleState())
									  && !RGoal.GoalLifecycleState.DROPPED.equals(goal.getLifecycleState()))
									{	
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(!result.booleanValue())
													{
		//												if(goal.getMGoal().getName().indexOf("AchieveCleanup")!=-1)
		//													System.out.println("Goal suspended: "+goal);
														goal.setLifecycleState(component, RGoal.GoalLifecycleState.SUSPENDED);
														goal.setState(RProcessableElement.State.INITIAL);
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else
										{
											if(!evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												goal.setLifecycleState(component, RGoal.GoalLifecycleState.SUSPENDED);
												goal.setState(RProcessableElement.State.INITIAL);
											}
										}
									}
								}
								return IFuture.DONE;
							}
						});
						List events = new ArrayList(cond.getEvents());
						events.add(new EventType(new String[]{ChangeEvent.GOALADOPTED, mgoal.getName()}));
						rule.setEvents(events);
						rulesystem.getRulebase().addRule(rule);
						
//							rule.setEvents(cond.getEvents());
//							rulesystem.getRulebase().addRule(rule);
						
						rule = new Rule(mgoal.getName()+"_goal_option", 
							new GoalsExistCondition(mgoal, rcapa), new IAction()
						{
							public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
							{
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(RGoal.GoalLifecycleState.SUSPENDED.equals(goal.getLifecycleState()))
									{	
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(result.booleanValue())
													{
		//												if(goal.getMGoal().getName().indexOf("AchieveCleanup")!=-1)
		//												System.out.println("Goal made option: "+goal);
														goal.setLifecycleState(component, RGoal.GoalLifecycleState.OPTION);
		//												setState(ia, PROCESSABLEELEMENT_INITIAL);
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else
										{
											if(evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												goal.setLifecycleState(component, RGoal.GoalLifecycleState.OPTION);
											}
										}
									}
								}
								
								return IFuture.DONE;
							}
						});
						rule.setEvents(events);
						rulesystem.getRulebase().addRule(rule);
						
//							rule.setEvents(cond.getEvents());
//							rulesystem.getRulebase().addRule(rule);
					}
				}
				
				conds = mgoal.getConditions(MGoal.CONDITION_TARGET);
				if(conds!=null)
				{
					for(final MCondition cond: conds)
					{
						final Method m = cond.getMethodTarget()==null? null: cond.getMethodTarget().getMethod(component.getClassLoader());
											
						Rule rule = new Rule(mgoal.getName()+"_goal_target", 
							new CombinedCondition(new ICondition[]{
								new GoalsExistCondition(mgoal, rcapa)
			//							, new LifecycleStateCondition(SUtil.createHashSet(new String[]
			//							{
			//								RGoal.GOALLIFECYCLESTATE_ACTIVE,
			//								RGoal.GOALLIFECYCLESTATE_ADOPTED,
			//								RGoal.GOALLIFECYCLESTATE_OPTION,
			//								RGoal.GOALLIFECYCLESTATE_SUSPENDED
			//							}))
							}),
							new IAction()
						{
							public IFuture execute(final IEvent event, final IRule rule, final Object context, Object condresult)
							{
//								if(mgoal.getName().indexOf("cleanup")!=-1)
//									System.out.println("target test");
								
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(m!=null)
									{
										executeGoalMethod(m, goal, event, component)
											.addResultListener(new IResultListener()
										{
											public void resultAvailable(Boolean result)
											{
												if(result.booleanValue())
												{
													if(!goal.isFinished())
													{
														goal.targetConditionTriggered(component, event, rule, context);
													}
												}
											}
											
											public void exceptionOccurred(Exception exception)
											{
											}
										});
									}
									else
									{
										if(!goal.isFinished() && evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
										{
											goal.targetConditionTriggered(component, event, rule, context);
										}
									}
								}
							
								return IFuture.DONE;
							}
						});
						List events = cond.getEvents()==null || cond.getEvents().size()==0? new ArrayList(): new ArrayList(cond.getEvents());
						events.add(new EventType(new String[]{ChangeEvent.GOALADOPTED, mgoal.getName()}));
						rule.setEvents(events);
						rulesystem.getRulebase().addRule(rule);
					}
				}
				
				conds = mgoal.getConditions(MGoal.CONDITION_RECUR);
				if(conds!=null)
				{
					for(final MCondition cond: conds)
					{
						final Method m = cond.getMethodTarget()==null? null: cond.getMethodTarget().getMethod(component.getClassLoader());
											
						Rule rule = new Rule(mgoal.getName()+"_goal_recur",
							new GoalsExistCondition(mgoal, rcapa), new IAction()
		//						new CombinedCondition(new ICondition[]{
		//							new LifecycleStateCondition(GOALLIFECYCLESTATE_ACTIVE),
		//							new ProcessingStateCondition(GOALPROCESSINGSTATE_PAUSED),
		//							new MethodCondition(getPojoElement(), m),
		//						}), new IAction()
						{
							public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
							{
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(RGoal.GoalLifecycleState.ACTIVE.equals(goal.getLifecycleState())
										&& RGoal.GoalProcessingState.PAUSED.equals(goal.getProcessingState()))
									{	
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(result.booleanValue())
													{
														goal.setTriedPlans(null);
														goal.setApplicablePlanList(null);
														goal.setProcessingState(component, RGoal.GoalProcessingState.INPROCESS);
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else
										{
											if(evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												goal.setTriedPlans(null);
												goal.setApplicablePlanList(null);
												goal.setProcessingState(component, RGoal.GoalProcessingState.INPROCESS);
											}
										}
									}
								}
								return IFuture.DONE;
							}
						});
						rule.setEvents(cond.getEvents());
						rulesystem.getRulebase().addRule(rule);
					}
				}
				
				conds = mgoal.getConditions(MGoal.CONDITION_MAINTAIN);
				if(conds!=null)
				{
					for(final MCondition cond: conds)
					{
						final Method m = cond.getMethodTarget()==null? null: cond.getMethodTarget().getMethod(component.getClassLoader());
						
						Rule rule = new Rule(mgoal.getName()+"_goal_maintain", 
							new GoalsExistCondition(mgoal, rcapa), new IAction()
		//						new CombinedCondition(new ICondition[]{
		//							new LifecycleStateCondition(GOALLIFECYCLESTATE_ACTIVE),
		//							new ProcessingStateCondition(GOALPROCESSINGSTATE_IDLE),
		//							new MethodCondition(getPojoElement(), mcond, true),
		//						}), new IAction()
						{
							public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
							{
								for(final RGoal goal: rcapa.getGoals(mgoal))
								{
									if(RGoal.GoalLifecycleState.ACTIVE.equals(goal.getLifecycleState())
										&& RGoal.GoalProcessingState.IDLE.equals(goal.getProcessingState()))
									{	
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(!result.booleanValue())
													{
		//												System.out.println("Goal maintain triggered: "+goal);
		//												System.out.println("state was: "+goal.getProcessingState());
														goal.setProcessingState(component, RGoal.GoalProcessingState.INPROCESS);
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else // xml expression
										{
											if(!evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												goal.setProcessingState(component, RGoal.GoalProcessingState.INPROCESS);
											}
										}
									}
								}
								return IFuture.DONE;
							}
						});
						List events = new ArrayList(cond.getEvents());
						events.add(new EventType(new String[]{ChangeEvent.GOALADOPTED, mgoal.getName()}));
						rule.setEvents(events);
						rulesystem.getRulebase().addRule(rule);
						
						// if has no own target condition
						if(mgoal.getConditions(MGoal.CONDITION_TARGET)==null)
						{
							// if not has own target condition use the maintain cond
							rule = new Rule(mgoal.getName()+"_goal_target", 
								new GoalsExistCondition(mgoal, rcapa), new IAction()
		//							new MethodCondition(getPojoElement(), mcond), new IAction()
							{
								public IFuture execute(final IEvent event, final IRule rule, final Object context, Object condresult)
								{
									for(final RGoal goal: rcapa.getGoals(mgoal))
									{
										if(m!=null)
										{
											executeGoalMethod(m, goal, event, component)
												.addResultListener(new IResultListener()
											{
												public void resultAvailable(Boolean result)
												{
													if(result.booleanValue())
													{
														goal.targetConditionTriggered(component, event, rule, context);
													}
												}
												
												public void exceptionOccurred(Exception exception)
												{
												}
											});
										}
										else // xml expression
										{
											if(evaluateCondition(component, cond, mgoal, SUtil.createHashMap(new String[]{goal.getFetcherName()}, new Object[]{goal})))
											{
												goal.targetConditionTriggered(component, event, rule, context);
											}
										}
									}
									
									return IFuture.DONE;
								}
							});
							rule.setEvents(cond.getEvents());
							rulesystem.getRulebase().addRule(rule);
						}
					}
				}
			}
			
			// Observe plan types
			List mplans = bdimodel.getCapability().getPlans();
			for(int i=0; i createplan = new IAction()
				{
					public IFuture execute(final IEvent event, IRule rule, Object context, Object condresult)
					{
						// Create all binding plans
						List cands = APL.createMPlanCandidates(component, mplan, null);

						final CollectionResultListener lis = new CollectionResultListener(cands.size(), 
							new IResultListener>()
						{
							public void resultAvailable(final Collection result)
							{
								for(ICandidateInfo ci: result)
								{
//									System.out.println("Create plan 1: "+mplan);
									RPlan rplan = RPlan.createRPlan(mplan, new CandidateInfoMPlan(new MPlanInfo(mplan, null), null, component), new ChangeEvent(event), component, ((MPlanInfo)ci.getRawCandidate()).getBinding(), null);
//									System.out.println("Create plan 2: "+mplan);
									RPlan.executePlan(rplan, component);
								}
							}
							
							public void exceptionOccurred(Exception exception)
							{
							}
						});
						
						for(final ICandidateInfo cand: cands)
						{
							// check precondition
							APL.checkMPlan(component, cand, null).addResultListener(new IResultListener()
							{
								public void resultAvailable(Boolean result)
								{
									if(result.booleanValue())
									{
										lis.resultAvailable(cand);
									}
									else
									{
										lis.exceptionOccurred(null);
									}
								}
								
								public void exceptionOccurred(Exception exception)
								{
									lis.exceptionOccurred(exception);
								}
							});
						}
						
						return IFuture.DONE;
					}
				};
				
				MTrigger trigger = mplan.getTrigger();
				
				if(trigger!=null)
				{
					List fas = trigger.getFactAddeds();
					if(fas!=null && fas.size()>0)
					{
						// todo: hmm turn off these too? new NotInShutdownCondition(component)
						Rule rule = new Rule("create_plan_factadded_"+mplan.getName(), ICondition.TRUE_CONDITION, createplan);
						for(String fa: fas)
						{
							rule.addEvent(new EventType(new String[]{ChangeEvent.FACTADDED, fa}));
						}
						rulesystem.getRulebase().addRule(rule);
					}
		
					List frs = trigger.getFactRemoveds();
					if(frs!=null && frs.size()>0)
					{
						Rule rule = new Rule("create_plan_factremoved_"+mplan.getName(), ICondition.TRUE_CONDITION, createplan);
						for(String fr: frs)
						{
							rule.addEvent(new EventType(new String[]{ChangeEvent.FACTREMOVED, fr}));
						}
						rulesystem.getRulebase().addRule(rule);
					}
					
					List fcs = trigger.getFactChangeds();
					if(fcs!=null && fcs.size()>0)
					{
						Rule rule = new Rule("create_plan_factchanged_"+mplan.getName(), ICondition.TRUE_CONDITION, createplan);
						for(String fc: fcs)
						{
							rule.addEvent(new EventType(new String[]{ChangeEvent.FACTCHANGED, fc}));
							rule.addEvent(new EventType(new String[]{ChangeEvent.BELIEFCHANGED, fc}));
						}
						rulesystem.getRulebase().addRule(rule);
					}
					
					List gfs = trigger.getGoalFinisheds();
					if(gfs!=null && gfs.size()>0)
					{
						Rule rule = new Rule("create_plan_goalfinished_"+mplan.getName(), ICondition.TRUE_CONDITION, createplan);
						for(MGoal gf: gfs)
						{
							rule.addEvent(new EventType(new String[]{ChangeEvent.GOALDROPPED, gf.getName()}));
						}
						rulesystem.getRulebase().addRule(rule);
					}
					
					final MCondition mcond = trigger.getCondition();
					if(mcond!=null)
					{
						Rule rule = new Rule("create_plan_condition_"+mplan.getName(), new CombinedCondition(new ICondition[]{new NotInShutdownCondition(component), new ICondition()
						{
							public IFuture> evaluate(IEvent event)
							{
								UnparsedExpression uexp = mcond.getExpression();
								Boolean ret = (Boolean)SJavaParser.parseExpression(uexp, component.getModel().getAllImports(), component.getClassLoader()).getValue(CapabilityWrapper.getFetcher(component, uexp.getLanguage()));
								return new Future>(ret!=null && ret.booleanValue()? TRUE: FALSE);
							}
						}}), createplan);
						rule.setEvents(mcond.getEvents());
						rulesystem.getRulebase().addRule(rule);
					}
				}
				
				// context condition
								
//				final MethodInfo mi = mplan.getBody().getContextConditionMethod(component.getClassLoader());
//				if(mi!=null)
//				{
//					PlanContextCondition pcc = mi.getMethod(component.getClassLoader()).getAnnotation(PlanContextCondition.class);
//					String[] evs = pcc.beliefs();
//					RawEvent[] rawevs = pcc.rawevents();
//					List events = new ArrayList();
//					for(String ev: evs)
//					{
//						BDIAgentFeature.addBeliefEvents(component, events, ev);
//					}
//					for(RawEvent rawev: rawevs)
//					{
//						events.add(BDIAgentFeature.createEventType(rawev));
//					}f
//				
//					IAction abortplans = new IAction()
//					{
//						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
//						{
//							Collection coll = rcapa.getPlans(mplan);
//							
//							for(final RPlan plan: coll)
//							{
//								invokeBooleanMethod(plan.getBody().getBody(), mi.getMethod(component.getClassLoader()), plan.getModelElement(), event, plan, component)
//									.addResultListener(new IResultListener()
//								{
//									public void resultAvailable(Boolean result)
//									{
//										if(!result.booleanValue())
//										{
//											plan.abort();
//										}
//									}
//									
//									public void exceptionOccurred(Exception exception)
//									{
//									}
//								});
//							}
//							return IFuture.DONE;
//						}
//					};
//					
//					Rule rule = new Rule("plan_context_abort_"+mplan.getName(), 
//						new PlansExistCondition(mplan, rcapa), abortplans);
//					rule.setEvents(events);
//					rulesystem.getRulebase().addRule(rule);
//				}
//				else 
					
				if(mplan.getContextCondition()!=null)
				{
					final MethodInfo mi = mplan.getBody().getContextConditionMethod(component.getClassLoader());
					final Method m = mi!=null? mi.getMethod(component.getClassLoader()): null;
					final MCondition mcond = mplan.getContextCondition();
					
					IAction abortplans = new IAction()
					{
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
							Collection coll = rcapa.getPlans(mplan);
							
							for(final RPlan plan: coll)
							{
								if(m!=null)
								{
									invokeBooleanMethod(plan.getBody().getBody(), mi.getMethod(component.getClassLoader()), plan.getModelElement(), event, plan, component)
										.addResultListener(new IResultListener()
									{
										public void resultAvailable(Boolean result)
										{
											if(!result.booleanValue())
											{
												plan.abort();
											}
										}
										
										public void exceptionOccurred(Exception exception)
										{
										}
									});
								}
								else
								{
									if(!evaluateCondition(component, mcond, plan.getModelElement(), Collections.singletonMap(plan.getFetcherName(), (Object)plan)))
									{
										plan.abort();
									}
								}
							}
							return IFuture.DONE;
						}
					};
					
					Rule rule = new Rule("plan_context_condition_"+mplan.getName(), new PlansExistCondition(mplan, rcapa), abortplans);
					rule.setEvents(mcond.getEvents());
					rulesystem.getRulebase().addRule(rule);
				}
			}
			
			// add/rem goal inhibitor rules
			if(!goals.isEmpty())
			{
				boolean	usedelib	= false;
				for(int i=0; !usedelib && i events = new ArrayList();
					events.add(new EventType(new String[]{ChangeEvent.GOALADOPTED, EventType.MATCHALL}));
					Rule rule = new Rule("goal_addinitialinhibitors", 
						ICondition.TRUE_CONDITION, new IAction()
					{
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
							// create the complete inhibitorset for a newly adopted goal
							RGoal goal = (RGoal)event.getContent();
							return delstr.goalIsAdopted(goal);
						}
					});
					rule.setEvents(events);
					rulesystem.getRulebase().addRule(rule);
					
					events = new ArrayList();
					events.add(new EventType(new String[]{ChangeEvent.GOALDROPPED, EventType.MATCHALL}));
					rule = new Rule("goal_removegoalfromdelib", 
						ICondition.TRUE_CONDITION, new IAction()
					{
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
							// Remove a goal completely from 
							RGoal goal = (RGoal)event.getContent();
							return delstr.goalIsDropped(goal);
						}
					});
					rule.setEvents(events);
					rulesystem.getRulebase().addRule(rule);
					
					events = BDIAgentFeature.getGoalEvents(null);
					rule = new Rule("goal_addinhibitor", 
						new ICondition()
						{
							public IFuture> evaluate(IEvent event)
							{
								// return true when other goal is active and inprocess
								boolean ret = false;
								EventType type = event.getType();
								RGoal goal = (RGoal)event.getContent();
								ret = ChangeEvent.GOALACTIVE.equals(type.getType(0)) && RGoal.GoalProcessingState.INPROCESS.equals(goal.getProcessingState())
									|| (ChangeEvent.GOALINPROCESS.equals(type.getType(0)) && RGoal.GoalLifecycleState.ACTIVE.equals(goal.getLifecycleState()));
//									return ret? ICondition.TRUE: ICondition.FALSE;
								return new Future>(ret? ICondition.TRUE: ICondition.FALSE);
							}
						}, new IAction()
					{
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
							RGoal goal = (RGoal)event.getContent();
							return delstr.goalIsActive(goal);
						}
					});
					rule.setEvents(events);
					rulesystem.getRulebase().addRule(rule);
					
					rule = new Rule("goal_removeinhibitor", 
						new ICondition()
						{
							public IFuture> evaluate(IEvent event)
							{
//								if(getComponentIdentifier().getName().indexOf("Ambu")!=-1)
//									System.out.println("remin");
								
								// return true when other goal is active and inprocess
								boolean ret = false;
								EventType type = event.getType();
								if(event.getContent() instanceof RGoal)
								{
									RGoal goal = (RGoal)event.getContent();
									ret = ChangeEvent.GOALSUSPENDED.equals(type.getType(0)) 
										|| ChangeEvent.GOALOPTION.equals(type.getType(0))
//										|| ChangeEvent.GOALDROPPED.equals(type.getType(0)) 
										|| !RGoal.GoalProcessingState.INPROCESS.equals(goal.getProcessingState());
								}
//									return ret? ICondition.TRUE: ICondition.FALSE;
								return new Future>(ret? ICondition.TRUE: ICondition.FALSE);
							}
						}, new IAction()
					{
						public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
						{
							// Remove inhibitions of this goal 
							RGoal goal = (RGoal)event.getContent();
							return delstr.goalIsNotActive(goal);
						}
					});
					rule.setEvents(events);
					rulesystem.getRulebase().addRule(rule);
				}
				
				Rule rule = new Rule("goal_activate", 
					new LifecycleStateCondition(RGoal.GoalLifecycleState.OPTION),
					new IAction()
				{
					public IFuture execute(IEvent event, IRule rule, Object context, Object condresult)
					{
						RGoal goal = (RGoal)event.getContent();
						return delstr.goalIsOption(goal);
					}
				});
//				rule.addEvent(new EventType(new String[]{ChangeEvent.GOALNOTINHIBITED, EventType.MATCHALL}));
				rule.addEvent(new EventType(new String[]{ChangeEvent.GOALOPTION, EventType.MATCHALL}));
//				rule.setEvents(SUtil.createArrayList(new String[]{ChangeEvent.GOALNOTINHIBITED, ChangeEvent.GOALOPTION}));
				rulesystem.getRulebase().addRule(rule);
			}
			
			
			// Init must be set to true before init writes to ensure that new events
			// are executed and not processed as init writes
			IInternalBDILifecycleFeature bdil = (IInternalBDILifecycleFeature)component.getComponentFeature(ILifecycleComponentFeature.class);
			bdil.setInited(true);
			
			// After init rule execution mode to direct
			rulesystem.setQueueEvents(false);
			
//			System.out.println("inited: "+component.getComponentIdentifier());
			
			// perform init write fields (after injection of bdiagent)
			BDIAgentFeature.performInitWrites(component, component);
			
			// Start rule system
//				if(getComponentIdentifier().getName().indexOf("Cleaner")!=-1)// && getComponentIdentifier().getName().indexOf("Burner")==-1)
//					getCapability().dumpPlansPeriodically(getInternalAccess());
//				if(getComponentIdentifier().getName().indexOf("Ambulance")!=-1)
//				{
//					getCapability().dumpGoalsPeriodically(getInternalAccess());
//					getCapability().dumpPlansPeriodically(getInternalAccess());
//				}
			
//				}
//				catch(Exception e)
//				{
//					e.printStackTrace();
//				}
			
//				throw new RuntimeException();
		}
	}
	
	/**
	 *  Extracted start behavior. 
	 */
	public static class EndBehavior extends LifecycleBehavior
	{
		/**
		 *  Create a new start behavior.
		 */
		public EndBehavior(IInternalAccess component)
		{
			super(component);
		}
		
		/**
		 *  Start the end behavior.
		 *  
		 *  todo: problem with events
		 *  it is unclear how to wait for processing end of internal/end events 
		 *  solution: do not allow posting end events?!
		 */
		public IFuture startEndBehavior(final IBDIModel bdimodel, final RuleSystem rulesystem, final RCapability rcapa)
		{
			final Future	ret	= new Future();
			final IInternalBDIAgentFeature bdif = component.getComponentFeature(IInternalBDIAgentFeature.class);
			
			// Barrier to wait for all body processing.
			FutureBarrier	bodyend	= new FutureBarrier();
						
			// Abort running goals.
			Collection goals = bdif.getCapability().getGoals();
//			System.out.println(component.getComponentIdentifier()+" dropping body goals: "+goals);
			for(final RGoal goal: goals)
			{
				IFuture	fut	= goal.drop();
				bodyend.addFuture(fut);
//				fut.addResultListener(new IResultListener()
//				{
//					@Override
//					public void resultAvailable(Void result)
//					{
//						System.out.println(component.getComponentIdentifier()+" dropped body goal: "+goal);
//					}
//					
//					@Override
//					public void exceptionOccurred(Exception exception)
//					{
//						System.out.println(component.getComponentIdentifier()+" dropped body goal: "+goal+", "+exception);
//					}
//				});
			}
			
			// Abort running plans.
			Collection plans = bdif.getCapability().getPlans();
//			System.out.println(component.getComponentIdentifier()+" dropping body plans: "+plans);
			for(final RPlan plan: plans)
			{
				IFuture	fut	= plan.abort();
				bodyend.addFuture(fut);
//				fut.addResultListener(new IResultListener()
//				{
//					@Override
//					public void resultAvailable(Void result)
//					{
//						System.out.println(component.getComponentIdentifier()+" dropped body plan: "+plan);
//					}
//					
//					@Override
//					public void exceptionOccurred(Exception exception)
//					{
//						System.out.println(component.getComponentIdentifier()+" dropped body plan: "+plan+", "+exception);
//					}
//				});
			}
			
			bodyend.waitFor().addResultListener(new DelegationResultListener(ret)
			{
				public void customResultAvailable(Void result)
				{
//					System.out.println(component.getComponentIdentifier()+" body end");
					String confname = component.getConfiguration();
					if(confname!=null)
					{
						MConfiguration mconf = bdimodel.getCapability().getConfiguration(confname);
						
						if(mconf!=null)
						{
							final CounterResultListener lis = new CounterResultListener(3, new DelegationResultListener(ret));
								
							// Create end plans
							final List iplans = mconf.getEndPlans();
							dispatchConfigPlans(component, iplans, bdimodel).addResultListener(lis);
							
							// Create end goals
							final List igoals = mconf.getEndGoals();
							dispatchConfigGoals(component, igoals, bdimodel).addResultListener(lis);
							
							// Create end events
							final List ievents = mconf.getEndEvents();
							dispatchConfigEvents(component, ievents, bdimodel).addResultListener(lis);
						}
						else
						{
							ret.setResult(null);
						}
					}
					else
					{
						ret.setResult(null);
					}
				}
			});
			
			return ret;
		}
	}

}