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

jadex.bridge.component.impl.ExecutionComponentFeature Maven / Gradle / Ivy

Go to download

Jadex bridge is a base package for kernels and platforms, i.e., it is used by both and provides commonly used interfaces and classes for active components and their management.

There is a newer version: 4.0.267
Show newest version
package jadex.bridge.component.impl;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.logging.Logger;

import jadex.base.Starter;
import jadex.bridge.ComponentResultListener;
import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentStep;
import jadex.bridge.IConditionalComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.IPriorityComponentStep;
import jadex.bridge.ITransferableStep;
import jadex.bridge.ITypedComponentStep;
import jadex.bridge.IntermediateComponentResultListener;
import jadex.bridge.StepAborted;
import jadex.bridge.StepAbortedException;
import jadex.bridge.StepInvalidException;
import jadex.bridge.component.ComponentCreationInfo;
import jadex.bridge.component.IArgumentsResultsFeature;
import jadex.bridge.component.IComponentFeature;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.IMonitoringComponentFeature;
import jadex.bridge.service.IService;
import jadex.bridge.service.annotation.Timeout;
import jadex.bridge.service.component.Breakpoint;
import jadex.bridge.service.component.ComponentSuspendable;
import jadex.bridge.service.component.interceptors.CallAccess;
import jadex.bridge.service.component.interceptors.FutureFunctionality;
import jadex.bridge.service.search.ServiceNotFoundException;
import jadex.bridge.service.types.clock.IClockService;
import jadex.bridge.service.types.clock.ITimedObject;
import jadex.bridge.service.types.clock.ITimer;
import jadex.bridge.service.types.cms.CMSStatusEvent;
import jadex.bridge.service.types.cms.IComponentDescription;
import jadex.bridge.service.types.cms.SComponentManagementService;
import jadex.bridge.service.types.execution.IExecutionService;
import jadex.bridge.service.types.factory.IPlatformComponentAccess;
import jadex.bridge.service.types.monitoring.IMonitoringEvent;
import jadex.bridge.service.types.monitoring.IMonitoringService.PublishEventLevel;
import jadex.bridge.service.types.monitoring.IMonitoringService.PublishTarget;
import jadex.bridge.service.types.monitoring.MonitoringEvent;
import jadex.commons.SAccess;
import jadex.commons.DebugException;
import jadex.commons.IResultCommand;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.TimeoutException;
import jadex.commons.concurrent.Executor;
import jadex.commons.concurrent.IExecutable;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.FutureHelper;
import jadex.commons.future.FutureTerminatedException;
import jadex.commons.future.IFuture;
import jadex.commons.future.IIntermediateResultListener;
import jadex.commons.future.IResultListener;
import jadex.commons.future.ISubscriptionIntermediateFuture;
import jadex.commons.future.ISuspendable;
import jadex.commons.future.IntermediateExceptionDelegationResultListener;
import jadex.commons.future.SubscriptionIntermediateFuture;
import jadex.commons.future.TerminationCommand;
import jadex.commons.future.ThreadLocalTransferHelper;

/**
 *  This feature provides component step execution.
 */
public class ExecutionComponentFeature	extends	AbstractComponentFeature implements IExecutionFeature, IInternalExecutionFeature, IExecutable
{
	//-------- constants --------
	
	/** Debug flag. */
	// Hack!!! Non-final to be setable from Starter 
	public static boolean DEBUG = false;
	
	/** Constant for step event. */
	public static final String TYPE_STEP = "step";
	
	//-------- attributes --------
	
	/** The component steps. */
	protected TreeSet steps;
	
	/** The stepcnt - used to keep insertion order of same priority elements in the queue. */
	protected int stepcnt;
	
	/** The id of the step at which the execution was stopped because of a breakpoint. */
	protected int bpstepid = -1;
	
	/** The step at which the endstate begins. */
	protected int endstepcnt = -1;
	
	/** The current timer. */
	protected List timers = new ArrayList();
	
//	/** Retained listener notifications when switching threads due to blocking. */
//	protected Set>	notifications;
	
	/** Flag for testing double execution. */
	protected volatile boolean executing;
	
	/** Exception for debugging double execution. */
	protected volatile Throwable stacktrace;
	
	/** The thread currently executing the component (null for none). */
	protected Thread componentthread;
	
	/** The blocked threads by monitor. */
	protected Map	blocked; 
	
	/** The flag for a requested step (true when a step is allowed in stepwise execution). */
	protected String stepinfo;
	
	/** The future to be informed, when the requested step is finished. */
	protected Future stepfuture;
	
	/** The parent adapter (cached for speed). */
	protected IInternalExecutionFeature parenta;

	/** The synchronous subcomponents that want to be executed (if any). */
	protected Set subcomponents;

	/** Future for signalling that end of agenda execution has been reached. */
	protected Future endagenda;
	
	/** The termination future (used in noplatform case). */
	protected Future> termfuture;
	
	/** Heisenbug debug flag cached for speed. */
	protected boolean debug;
	
	//-------- constructors --------
	
	/**
	 *  Create the feature.
	 */
	public ExecutionComponentFeature(IInternalAccess component, ComponentCreationInfo cinfo)
	{
		super(component, cinfo);
		this.endagenda = new Future();
		this.debug	= component instanceof IPlatformComponentAccess && ((IPlatformComponentAccess) component).getPlatformComponent().debug;
		if(debug)
		{
			component.getLogger().severe("Enabled ExecutionComponentFeature debugging for "+component);
		}
	}
	
	/**
	 *  Shutdown the feature.
	 */
	public IFuture shutdown()
	{
		Future ret = new Future();
		
		// remember cnt when endstate starts
		this.endstepcnt = stepcnt;
		
//		if(getComponent().getComponentIdentifier().equals(getComponent().getComponentIdentifier().getRoot()))
//			System.out.println("shut platform");
		
//		System.out.println("shutdown start: "+getComponent().getComponentIdentifier());
		if(debug)
			getComponent().getLogger().severe("shutdown0: "+this);
		
		endagenda.addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
				if(debug)
					getComponent().getLogger().severe("shutdown1: "+this);
				
				doCleanup(new StepAborted(getComponent().getId()));
				
				if(debug)
					getComponent().getLogger().severe("shutdown2: "+this);
				
				super.customResultAvailable(result);
			}
		});
		
		// ensure that agenda is cleaned up
		wakeup();
		
		// notify waitForTermination calls (in noplatform mode)
		if(termfuture!=null)
		{
			IArgumentsResultsFeature arf = getComponent().getFeature0(IArgumentsResultsFeature.class);
			termfuture.setResult(arf!=null? arf.getResults(): Collections.emptyMap());
		}
		
		return ret;
//		return IFuture.DONE;
	}
	
	/**
	 *  Check if the feature potentially executed user code in body.
	 *  Allows blocking operations in user bodies by using separate steps for each feature.
	 *  Non-user-body-features are directly executed for speed.
	 *  If unsure just return true. ;-)
	 */
	public boolean	hasUserBody()
	{
		return false;
	}
	
	/**
	 *  Kill is only invoked, when shutdown of some (e.g. other) feature does not return due to timeout.
	 *  The feature should do any kind of possible cleanup, but no asynchronous operations.
	 */
	@Override
	public void kill()
	{
		doCleanup(new ThreadDeath());
	}
	
	/**
	 *  Shared cleanup code for shutdown and kill.
	 */
	protected void doCleanup(Error e)
	{
//		System.err.println("shutdown end: "+getComponent().getDescription()+", "+steps.size());
		
		// Should not wake up all blocked threads at the same time?!
		// Could theoretically catch the threaddeath and do sth what is not guarded against concurrent access
//		if(blocked!=null && blocked.size()>0)
//			System.out.println("blocked: "+blocked.size());
		while(blocked!=null && !blocked.isEmpty())
		{
			// Unblock throwing thread death as component already has been terminated.
			unblock(blocked.keySet().iterator().next(), e);
//			unblock(blocked.keySet().iterator().next(), null);
		}
//		
		if(parenta!=null)
			parenta.removeSubcomponent(ExecutionComponentFeature.this);
	}
	
	//-------- IComponentFeature interface --------
	
	/**
	 *  Get the user interface type of the feature.
	 */
	public Class	getType()
	{
		return IExecutionFeature.class;
	}
	
	/**
	 *  Create an instance of the feature.
	 */
	public IComponentFeature createInstance(IInternalAccess access, ComponentCreationInfo info)
	{
		return new ExecutionComponentFeature(access, info);
	}
	
	//-------- IExecutionFeature interface --------
	
	// for debugging: remember stack trace of stack addition
	protected Map, Exception>	stepadditions;
	
	/**
	 *  Get the component description.
	 *  @return	The component description.
	 */
	// Todo: hack??? should be internal to CMS!?
	public IComponentDescription getDescription()
	{
		return getComponent().getDescription();
	}
	
	/**
	 *  Schedule a component step but don't wait for its execution.
	 *  Scheduling a decoupled step is useful to indicate that exceptions in the
	 *  step are not handled by the caller, e.g., to have them printed to the console instead of discarded.
	 *  @param step The component step.
	 *  @return A future indicating that the step has been scheduled (but maybe not yet executed).
	 */
	public IFuture scheduleDecoupledStep(IComponentStep step)
	{
		IFuture	fut	= scheduleStep(step);
		if(fut.getException()!=null)
		{
			return new Future<>(fut.getException());
		}
		else
		{
			return IFuture.DONE;
		}
	}
	
	/**
	 *  Execute a component step.
	 */
	public 	IFuture scheduleStep(IComponentStep step)
	{
		return scheduleStep(IExecutionFeature.STEP_PRIORITY_NORMAL, step);
	}
	
	/**
	 *  Execute a component step.
	 *  @param step The component step.
	 *  @param priority The step priority (0 is default).
	 */
	public 	IFuture scheduleStep(int priority, IComponentStep step)
	{
		final Future ret = createStepFuture(step);
		
		synchronized(this)
		{
			// Todo: synchronize with last step!
			int prio = step instanceof IPriorityComponentStep? ((IPriorityComponentStep)step).getPriority(): priority;
//			if(IComponentDescription.STATE_TERMINATED.equals(getComponent().getDescription().getState()))
			if(endagenda.isDone() && prio)step).getPriority(): priority;
				// Reject non-priority steps if we are already terminating.
				// Otherwise this leads to a bad interaction with the monitoring:
				// The step creation/dispose gets reported to the monitoring agent
				// the return path then decouples onto the external access, which
				// creates, schedule and aborts a step, creating two more create/dispose
				// events to be reported etc...
				if((STEP_PRIORITY_IMMEDIATE > prio && endstepcnt != -1))
				{
					ret.setException(new ComponentTerminatedException(getComponent().getId()));
					return ret;
				}
				addStep(new StepInfo(step, ret, new ThreadLocalTransferHelper(true), prio, stepcnt++));
				
//				System.out.println("steps: "+steps);
				
				if(DEBUG)
				{
					if(stepadditions==null)
						stepadditions	= new HashMap, Exception>();
					stepadditions.put(step, new DebugException(step.toString()));
				}
			}
		}

		try
		{
			if(!ret.isDone())
				wakeup();
		}
		catch(Exception e)
		{
			// rare racecondition that component is terminated after synchronized block but before wakeup() call.
			ret.setExceptionIfUndone(e);
		}
		
		return ret;
	}
	
	/**
	 * Repeats a ComponentStep periodically, until terminate() is called on result future or a failure occurs in a step.
	 * @param initialdelay delay before first execution in milliseconds
	 * @param delay delay between scheduled executions of the step in milliseconds
	 * @param step The component step
	 * @return The intermediate results
	 */
	@Override
	public  ISubscriptionIntermediateFuture repeatStep(long initialdelay, long delay, IComponentStep step)
	{
		return repeatStep(initialdelay, delay, step, false);
	}
	
	/**
	 * Repeats a ComponentStep periodically, until terminate() is called on result future.
	 * 
	 * Warning: In order to avoid memory leaks, the returned subscription future does NOT store
	 * values, requiring the addition of a listener within the same step the repeat
	 * step was schedule.
	 * 
	 * @param initialdelay delay before first execution in milliseconds
	 * @param delay delay between scheduled executions of the step in milliseconds
	 * @param step The component step
	 * @param ignorefailures Don't terminate repeating after a failed step.
	 * @return The intermediate results
	 */
	@Override
	public  ISubscriptionIntermediateFuture repeatStep(long initialdelay, final long delay, final IComponentStep step, final boolean ignorefailures)
	{
		final boolean[] stillrepeating	= new boolean[1];
		stillrepeating[0] = true;
		
		final SubscriptionIntermediateFuture	ret	= new SubscriptionIntermediateFuture(new TerminationCommand()
		{
			@Override
			public void terminated(Exception reason)
			{
				stillrepeating[0] = false;
			}
		}, true);
		
		// schedule the initial step
		waitForDelay(initialdelay, step)
			.addResultListener(new IResultListener()
		{
			@Override
			public void resultAvailable(T result)
			{
				if(!ret.isDone())
				{
					ret.addIntermediateResult(result);
					proceed();
				}
			}
			
			@Override
			public void exceptionOccurred(Exception exception)
			{
				if(!ret.isDone())
				{
					if(exception instanceof StepInvalidException || exception instanceof FutureTerminatedException)
					{
						stillrepeating[0] = false;
						proceed();
					}
					else if(ignorefailures)
					{
						proceed();
					}
					else
					{
						ret.setException(exception);
					}
				}
			}
			
			private void proceed()
			{
				if(stillrepeating[0])
				{
					// reschedule this step if we're still repeating
					waitForDelay(delay, step)
						.addResultListener(this);
				}
				else
				{
					ret.setFinished();
				}
			}
		});
		
		return ret;
	}

	/**
	 *  Wait for some time and execute a component step afterwards.
	 */
	public  IFuture waitForDelay(final long delay, final IComponentStep step)
	{
		return waitForDelay(delay, step, false);
	}
	
	/**
	 *  Wait for some time and execute a component step afterwards.
	 */
	public  IFuture waitForDelay(final long delay, final IComponentStep step, final boolean realtime)
	{
		// todo: remember and cleanup timers in case of component removal.
		
		final Future ret = new Future();
		
		try
		{
			if(delay>=0)
			{
				// OK to fetch sync even from external access because everything thread safe.
				//IClockService cs = ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IClockService.class);
				IClockService cs = getClockService();
				if(cs!=null)
				{
					ITimedObject to	= new ITimedObject()
					{
						public void timeEventOccurred(long currenttime)
						{
							//if(getComponent().getId().toString().indexOf("Sokrates")!=-1)
							//	System.out.println("before scheduleStep: "+getComponent().getId());
		//					System.out.println("step: "+step);
							IFuture	stepfut	= scheduleStep(step);
							
							// Immediate future fail due to component terminated before timer occurred.
							if(stepfut.getException() instanceof ComponentTerminatedException
								&& ((ComponentTerminatedException)stepfut.getException()).getComponentIdentifier().equals(component.getId()))
							{
								// TODO: handle or just ignore?
								getComponent().getLogger().info("Timer after termination: "+component+", "+step);
							}
							else
							{
								stepfut.addResultListener(createResultListener(new DelegationResultListener(ret)
								{
									@Override
									public void customResultAvailable(T result)
									{
										//if(getComponent().getId().toString().indexOf("Sokrates")!=-1)
										//	System.out.println("after scheduleStep: "+getComponent().getId());
										super.customResultAvailable(result);
									}
									@Override
									public void exceptionOccurred(Exception exception)
									{
										//if(getComponent().getId().toString().indexOf("Sokrates")!=-1)
										//	System.out.println("after scheduleStep: "+getComponent().getId()+" "+exception);
										super.exceptionOccurred(exception);
									}
								}));
							}
						}
						
						public String toString()
						{
							return "waitForDelay["+step+"]("+getComponent().getId()+")";
						}
					};
					if(realtime)
					{
						cs.createRealtimeTimer(delay, to);
					}
					else
					{
						cs.createTimer(delay, to);					
					}
				}
				else
				{
					ret.setException(new ServiceNotFoundException("Clock service not found."));
				}
			}
			else
			{
				getComponent().getLogger().warning("WaitFor will never complete: "+step);
			}
		}
		catch(Exception e)
		{
			ret.setExceptionIfUndone(new RuntimeException(e)
			{
				@Override
				public void printStackTrace()
				{
					Thread.dumpStack();
					super.printStackTrace();
				}
			});
		}
		
		return ret;
	}
	
	/**
	 *  Wait for some time.
	 */
	public IFuture waitForDelay(final long delay)
	{
		return waitForDelay(delay, false);
	}

	/**
	 *  Wait for some time.
	 */
	public IFuture waitForDelay(final long delay, final boolean realtime)
	{
		final Future ret = new Future();
		
		//IClockService cs = ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IClockService.class);
		IClockService cs = getClockService();
		if(cs!=null)
		{
			ITimedObject to	= new ITimedObject()
			{
				public void timeEventOccurred(long currenttime)
				{
					//if(getComponent().getId().toString().indexOf("Sokrates")!=-1)
					//	System.out.println("before scheduleStep: "+getComponent().getId());
					scheduleStep(new IComponentStep()
					{
						public IFuture execute(IInternalAccess ia)
						{
						//	if(getComponent().getId().toString().indexOf("Sokrates")!=-1)
						//		System.out.println("after scheduleStep: "+getComponent().getId());
							
							ret.setResult(null);
							return IFuture.DONE;
						}
						
						public String toString()
						{
							return "waitForDelay("+getComponent().getId()+")";
						}
					}).addResultListener(new IResultListener()
					{
						public void resultAvailable(Void result)
						{
						}
						
						public void exceptionOccurred(Exception exception)
						{
//							exception.printStackTrace();
							// Ignore outdated timer entries when component is already dead.
							// propblem this can occur on clock thread
	//						if(!(exception instanceof ComponentTerminatedException) || !((ComponentTerminatedException)exception).getComponentIdentifier().equals(getComponent().getComponentIdentifier()))
								ret.setExceptionIfUndone(exception);									
						}
					});
				}
				
				public String toString()
				{
					return "waitForDelay("+getComponent().getId()+")";
				}
			};
			
			if(realtime)
			{
				cs.createRealtimeTimer(delay, to);
			}
			else
			{
				cs.createTimer(delay, to);
			}
		}
		else
		{
			ret.setException(new IllegalStateException("No clockservice found"));
		}
		
		return ret;
	}
	
//	/**
//	 *  Wait for some time.
//	 */
//	public IFuture waitForDelayWithTimer(final long delay, final IComponentStep step)
//	{
//		final Future ret = new Future();
//		
//		IClockService	cs	= getRawService(new ServiceQuery<>(IClockService.class));
//		ITimedObject	to	=  	new ITimedObject()
//		{
//			public void timeEventOccurred(long currenttime)
//			{
//				scheduleStep(step);
//			}
//			
//			public String toString()
//			{
//				return "waitForDelay("+getComponent().getComponentIdentifier()+")";
//			}
//		};
//		
//		ITimer timer = cs.createTimer(delay, to);
//		ret.setResult(timer);
//		
//		return ret;
//	}
	
	/**
	 *  Wait for the next tick.
	 *  @param time The time.
	 */
	public IFuture waitForTick(final IComponentStep run)
	{
//		final Future ret = new Future();
		final Future ret = new Future();
		
		//IClockService	cs	= ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IClockService.class);
		IClockService cs = getClockService();
		final ITimer[] ts = new ITimer[1];
		ts[0] = cs.createTickTimer(new ITimedObject()
		{
			public void timeEventOccurred(final long currenttime)
			{
				try
				{
					scheduleStep(new ExecuteWaitForStep(ts[0], run));
				}
				catch(ComponentTerminatedException e)
				{
				}
			}
		});
		if(timers==null)
			timers	= new ArrayList();
		timers.add(ts[0]);
//		ret.setResult(new TimerWrapper(ts[0]));
		ret.setResult(null);
		
		return ret;
	}
	
	/**
	 *  Wait for the next tick.
	 *  @param time The time.
	 */
	public IFuture waitForTick()
	{
		final Future ret = new Future();
		
		//IClockService	cs	= ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IClockService.class);
		IClockService cs = getClockService();
		final ITimer[] ts = new ITimer[1];
		ts[0] = cs.createTickTimer(new ITimedObject()
		{
			public void timeEventOccurred(final long currenttime)
			{
				ret.setResult(null);
			}
		});
		if(timers==null)
			timers	= new ArrayList();
		timers.add(ts[0]);
		
		return ret;
	}
	
	/**
	 *  Waits for the components to finish.
	 * 
	 *  @return Component results.
	 */
	public IFuture> waitForTermination()
	{
		if(!Starter.isNoPlatformMode(getInternalAccess()))
		{
			//System.out.println("adding termination listener for: "+component.getId());
			final Future> ret = new Future<>();
			SComponentManagementService.listenToComponent(component.getId(), component).addResultListener(new IntermediateExceptionDelegationResultListener>(ret)
			{
				public void intermediateResultAvailable(CMSStatusEvent result)
				{
					if(result instanceof CMSStatusEvent.CMSTerminatedEvent)
					{
						CMSStatusEvent.CMSTerminatedEvent termev = (CMSStatusEvent.CMSTerminatedEvent)result;
						if(termev.getException() != null)
							ret.setException(termev.getException());
						else
							ret.setResult(termev.getResults());
					}
				}
				
				@Override
				public void exceptionOccurred(Exception exception)
				{
					if(exception instanceof IllegalStateException)
					{
						exception 	= (Exception)new ComponentTerminatedException(getInternalAccess().getId(),
							"Component probably already terminated. Consider starting the component in suspended state and only resume after waitForTermination() was called.")
								.initCause(exception);
					}
					super.exceptionOccurred(exception);
				}
			});
			return ret;
		}
		else
		{
			if(termfuture==null)
				termfuture = new Future<>();
			return termfuture;
		}
	}
	
	// todo:?
//	/**
//	 *  Wait for some time and execute a component step afterwards.
//	 */
//	public IFuture waitForImmediate(long delay, IComponentStep step);
	
	/** Flag to indicate bootstrapping execution of main thread (only for platform, hack???). */
	protected volatile boolean manual;
	
	/**
	 *  Set manual execution mode, e.g. for bootstrapping at platform startup.
	 *  @param manual Ignore wake up calls, if true.
	 */
	public void	setManual(boolean manual)
	{
		this.manual	= manual;
	}
	
	/**
	 *  Trigger component execution.
	 */
	public void	wakeup()
	{
		if(manual)
			return;
		
		if(getComponent().getDescription().isSynchronous())
		{
			// Add to parent and wake up parent.
			if(parenta==null)
			{
				// Todo w/o proxy???
//				IComponentManagementService cms = getComponent().getFeature(IRequiredServicesFeature.class).getLocalService(new ServiceQuery<>(IComponentManagementService.class));
				IExternalAccess exta = getComponent().getExternalAccess(getComponent().getId().getParent());
				// raw because called from scheduleStep also on external thread.
				exta.scheduleStep(new IComponentStep()
				{
					public IFuture execute(IInternalAccess ia)
					{
						parenta	= (IInternalExecutionFeature)ia.getFeature(IExecutionFeature.class);
						parenta.addSubcomponent(ExecutionComponentFeature.this);
						parenta.wakeup();
						return IFuture.DONE;
					}
				});
			}
			else
			{
				parenta.addSubcomponent(this);
				parenta.wakeup();
			}
		}
		else
		{
			if(endstepcnt!=-1 && debug)
				getComponent().getLogger().severe("wakeup0: "+this);

			IExecutionService exe = getExecutionService();
			//IExecutionService exe = ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IExecutionService.class);
			
			if(endstepcnt!=-1 && debug)
				getComponent().getLogger().severe("wakeup2: "+this+", "+exe);

			if(exe!=null && ((IService)exe).isValid().get().booleanValue())	// Hack!!! service is raw
			{
				if(endstepcnt!=-1 && debug)
					getComponent().getLogger().severe("wakeup4: "+this);
				exe.execute(ExecutionComponentFeature.this);
			}
			
			// Exe service gone -> component is platform during last steps of shutdown
			else
			{
				switchToRescueThread();
			}
		}
	}
	
	/** Should switch to rescue thread after next step? */
	protected boolean	switchtorescue	= false;
	
	/** Running on rescue thread? */
	protected boolean	isonrescue	= false;
	
	/** Is the current thread the rescue thread? */
	protected Thread	rescuethread	= null;	
	
	/**
	 *  Switch to rescue thread when execution service is gone.
	 */
	protected void	switchToRescueThread()
	{
		// robust handshake exe service vs rescue thread to avoid double executions vs hang
		boolean	run	= false;
		synchronized(this)
		{
			if(executing || isonrescue)
			{
				switchtorescue	= true;
			}
			else
			{
				run	= true;
				isonrescue	= true;
				switchtorescue	= false;
			}
		}
		
		if(run)
		{
//			System.err.println(getComponent() + ": starting rescue thread");
//			Thread.dumpStack();
			Starter.scheduleRescueStep(getComponent().getId(), () ->
			{
				// Hack to avoid double execution if execution service triggered in mean time
				
//				System.out.println(getComponent() + ": starting rescue thread 1");
				try
				{
					rescuethread	= Thread.currentThread();
					while(execute());
				}
				finally
				{
//					System.err.println(getComponent() + ": finished rescue thread");
					boolean	run1;
					synchronized(ExecutionComponentFeature.this)
					{
						run1	= switchtorescue;
						isonrescue	= false;
					}
					if(run1)
						switchToRescueThread();
				}
			} );
		}
	}
	
	/**
	 *  Do a step of a suspended component.
	 */
	public IFuture doStep(String stepinfo)
	{
		Future ret = new Future();
		synchronized(this)
		{
//			System.out.println("is sus: "+getComponent().getDescription().getState()+" "+getComponent());
			if(!IComponentDescription.STATE_SUSPENDED.equals(getComponent().getDescription().getState()))
			{
				ret.setException(new IllegalStateException("Component not suspended: "+getComponent().getId()));
			}
			else if(this.stepinfo!=null || stepfuture!=null)
			{
				ret.setException(new RuntimeException("Only one step allowed at a time."));
			}
			else
			{
//				this.dostep	= true;		
				this.stepfuture = ret; // stepfuture!=null signals that step mode is active
				this.stepinfo = stepinfo; // stepinfo is name id of the step to perform (if not simply next)
				//System.out.println("stepfuture set");
			}
		}
		
		wakeup();
		
		return ret;
	}

	/**
	 *  Test if current thread is the component thread.
	 *  @return True if the current thread is the component thread.
	 */
	public boolean isComponentThread()
	{
		return Thread.currentThread()==getComponentThread() || 
//			IComponentDescription.STATE_TERMINATED.equals(getComponent().getDescription().getState())
			endagenda.isDone()
				&& Starter.isRescueThread(getComponent().getId());
	}
	
	/**
	 *  Create a result listener that is executed on the
	 *  component thread.
	 */
	public  IResultListener createResultListener(IResultListener listener)
	{
		return new ComponentResultListener(listener, component);
	}
	
	/**
	 *  Create a result listener that is executed on the
	 *  component thread.
	 */
	public  IIntermediateResultListener createResultListener(IIntermediateResultListener listener)
	{
		return new IntermediateComponentResultListener(listener, component);
	}
	
	//-------- IInternalExecutionFeature --------
	
	/**
	 *  Add a synchronous subcomponent that will run on its parent's thread.
	 */
	public void	addSubcomponent(IInternalExecutionFeature sub)
	{
		synchronized(this)
		{
			if(subcomponents==null)
				subcomponents	= new HashSet();
			subcomponents.add(sub);
		}
	}

	/**
	 *  Remove a synchronous subcomponent.
	 */
	public void	removeSubcomponent(IInternalExecutionFeature sub)
	{
		synchronized(this)
		{
			if(subcomponents!=null)
				subcomponents.remove(sub);
		}
	}
	
	
	/**
	 *  Block the current thread and allow execution on other threads.
	 *  @param monitor	The monitor to wait for.
	 *  @param realtime Flag if timeout is realtime (in contrast to simulation time).
	 */
 	public void	block(final Object monitor, long timeout, boolean realtime)
	{
		if(!isComponentThread())
		{
			throw new RuntimeException("Can only block current component thread: "+getComponentThread()+", "+Thread.currentThread());
		}
		
		if(parenta!=null)
		{
			parenta.block(monitor, timeout, realtime);
		}
		else
		{
			// Perform scheduled notifications before blocking thread.
			FutureHelper.notifyStackedListeners();
			
//			// Retain listener notifications for new component thread.
//			assert notifications==null : getComponent()+", "+IComponentIdentifier.LOCAL.get();
//			notifications	= FutureHelper.removeStackedListeners();
//			if(notifications!=null && getComponent().toString().indexOf("IntermediateBlockingTest@")!=-1)
//				System.err.println("setting notifications: "+getComponent());
			
			Executor	exe	= Executor.EXECUTOR.get();
			if(exe==null)
			{
				throw new RuntimeException("Cannot block: no executor");
			}
			
			beforeBlock();
			
			this.executing	= false;
			this.stacktrace	= null;
			setComponentThread(null);
//			this.componentthread	= null;
			
			if(blocked==null)
			{
				blocked	= new HashMap();
			}
			blocked.put(monitor, exe);
			
			// Flag to check if unblocked before timeout
			final boolean[]	unblocked	= new boolean[1];
			
			if(timeout!=Timeout.NONE)
			{
				final Exception ex	= Future.DEBUG ? new DebugException("Timeout: "+timeout) : null;
				waitForDelay(timeout, realtime)
					.addResultListener(new IResultListener()
				{
					public void resultAvailable(Void result)
					{
						if(!unblocked[0])
						{
							unblock(monitor, new TimeoutException(Future.DEBUG ? ""+timeout : timeout+": Use PlatformConfiguration.getExtendedPlatformConfiguration().setDebugFutures(true) for timeout cause.", ex));
						}
					}
					
					public void exceptionOccurred(Exception exception)
					{
					}
				});
			}
			
			
			boolean	threaddeath	= false;
			try
			{
				wakeup();
				exe.blockThread(monitor);
				// Todo: wait for blocked threads to be resumed before terminating component
//				if(IComponentDescription.STATE_TERMINATED.equals(getComponent().getDescription().getState()))
				if(endagenda.isDone())
				{
					throw new ThreadDeath()
					{
						@Override
						public String toString()
						{
							return "java.lang.ThreadDeath("+component+")";
						}
					};
				}
			}
			catch(ThreadDeath e)
			{
				threaddeath	= true;
				throw e;
			}
			finally
			{
//				if(getComponent().toString().indexOf("Leaker")!=-1)
//				{
//					System.out.println("block done "+Thread.currentThread());
//				}
				
				unblocked[0]	= true;
				
				// Todo: should also work for thread death (i.e. blocked threads terminated before component is gone).
				assert threaddeath || !endagenda.isDone();
				
				synchronized(this)
				{
					if(executing)
					{
						System.err.println(getComponent().getId()+": double execution (unblock)");
						if(debug)
							new RuntimeException("executing: "+getComponent().getId()).initCause(stacktrace).printStackTrace();
						else
							new RuntimeException("executing: "+getComponent().getId()).printStackTrace();
					}
					this.executing	= true;
					if(debug)
						this.stacktrace	= new Exception("First execution").fillInStackTrace();
				}
		
				setComponentThread(Thread.currentThread());
//				this.componentthread	= Thread.currentThread();
				
				afterBlock();
				
//				// If no other thread for component in mean time, maybe there are notifications left -> readd
//				if(notifications!=null)
//				{
////					if(getComponent().toString().indexOf("IntermediateBlockingTest@")!=-1)
////						System.err.println("unsetting notifications2: "+getComponent());
//					FutureHelper.addStackedListeners(notifications);
//					notifications	= null;
//				}
			}
		}
	}
	
	/**
	 *  Unblock the thread waiting for the given monitor
	 *  and cease execution on the current thread.
	 *  @param monitor	The monitor to notify.
	 */
	public void	unblock(Object monitor, Throwable exception)
	{
		if(!isComponentThread())
		{
			throw new RuntimeException("Can only unblock from component thread: "+getComponentThread()+", "+Thread.currentThread());
		}
		
		if(parenta!=null)
		{
			parenta.unblock(monitor, exception);
		}
		else if(blocked!=null) // can be null when rescue thread
		{
//			System.out.println("unblock: "+monitor);
			Executor exe = blocked.remove(monitor);
			if(blocked.isEmpty())
				blocked	= null;
					
			exe.switchThread(monitor, exception);
		}
	}
	
	/**
	 *  Called before blocking the component thread.
	 */
	protected void	beforeBlock()
	{
//		System.out.println("beforeBlock: "+(ComponentSuspendable)ISuspendable.SUSPENDABLE.get()+", "+((ComponentSuspendable)ISuspendable.SUSPENDABLE.get()).getFuture());
	}
	
	/**
	 *  Called after unblocking the component thread.
	 */
	protected void	afterBlock()
	{
//		System.out.println("afterBlock: "+(ComponentSuspendable)ISuspendable.SUSPENDABLE.get()+", "+((ComponentSuspendable)ISuspendable.SUSPENDABLE.get()).getFuture());
	}
	
	//-------- IExecutable interface --------
	
	/**
	 *  Execute the executable.
	 *  @return True, if the object wants to be executed again.
	 */
	public boolean execute()
	{
		try {
		
		if(endstepcnt!=-1 && debug)
			getComponent().getLogger().severe("execute()0: "+getComponent().getId()+", "+IComponentIdentifier.LOCAL.get()+", endstepcnt="+endstepcnt+", stepcnt="+stepcnt);

		synchronized(this)
		{
			// Abort execution service step when already on rescue thread
			if(isonrescue && !(Thread.currentThread()==rescuethread))
				return false;
			
			if(executing)
			{
				System.err.println(getComponent().getId()+": double execution "+isonrescue);
				if(debug)
					new RuntimeException("executing: "+getComponent().getId()).initCause(stacktrace).printStackTrace();
				else
					new RuntimeException("executing: "+getComponent().getId()).printStackTrace();
			}
			this.executing	= true;
			if(debug)
				this.stacktrace	= new Exception("First execution").fillInStackTrace();
		}

		if(endstepcnt!=-1 && debug)
			getComponent().getLogger().severe("execute()1: "+getComponent().getId()+", "+IComponentIdentifier.LOCAL.get()+", endstepcnt="+endstepcnt+", stepcnt="+stepcnt);
		// Todo: termination and exception!?
//		// Note: wakeup() can be called from arbitrary threads (even when the
//		// component itself is currently running. I.e. it cannot be ensured easily
//		// that an execution task is enqueued and the component has terminated
//		// meanwhile.
//		if(!IComponentDescription.STATE_TERMINATED.equals(getComponent().getComponentDescription().getState()))
//		{
//			if(exception!=null)
//			{
//				this.executing	= false;
//				return false;	// Component already failed: tell executor not to call again. (can happen during failed init)
//			}
	
			ClassLoader cl = setExecutionState();
			
//			// Process listener notifications from old component thread.
////			boolean notifexecuted	= false;
//			if(notifications!=null)
//			{
////				if(getComponent().toString().indexOf("IntermediateBlockingTest@")!=-1)
////					System.err.println("unsetting notifications: "+getComponent());
//				FutureHelper.addStackedListeners(notifications);
//				notifications	= null;
//				
//				// Todo: termination and exception!?
////				try
////				{
//					FutureHelper.notifyStackedListeners();
////					notifexecuted	= true;
////				}
////				catch(Exception e)
////				{
////					fatalError(e);
////				}
////				catch(StepAborted sa)
////				{
////				}
////				catch(Throwable t)
////				{
////					fatalError(new RuntimeException(t));
////				}
//
//			}
			if(endstepcnt!=-1 && debug)
				getComponent().getLogger().severe("execute()2: "+getComponent().getId()+", "+IComponentIdentifier.LOCAL.get()+", endstepcnt="+endstepcnt+", stepcnt="+stepcnt);
			
//			boolean	again	= false;
//			if(!breakpoint_triggered && !extexecuted  && !notifexecuted && (!IComponentDescription.STATE_SUSPENDED.equals(desc.getState()) || dostep))
//			{
//				try
//				{
////					if(getComponentIdentifier()!=null && getComponentIdentifier().getParent()==null)
////						System.out.println("Executing: "+getComponentIdentifier()+", "+Thread.currentThread());
//					again	= component.executeStep();
////					if(getComponentIdentifier()!=null && getComponentIdentifier().getParent()==null)
////						System.out.println("Not Executing: "+getComponentIdentifier()+", "+Thread.currentThread());
//				}
//				catch(Exception e)
//				{
//					fatalError(e);
//				}
//				catch(StepAborted sa)
//				{
//				}
//				catch(Throwable t)
//				{
//					fatalError(new RuntimeException(t));
//				}
//				if(dostep)
//				{
//					dostep	= false;
//					if(stepfuture!=null)
//					{
//						stepfuture.setResult(null);
//					}
//				}
//				
//				// Suspend when breakpoint is triggered.
//				if(!IComponentDescription.STATE_SUSPENDED.equals(desc.getState()))
//				{
//					if(component.isAtBreakpoint(desc.getBreakpoints()))
//					{
//						breakpoint_triggered	= true;
//						getCMS().addResultListener(new DefaultResultListener(logger)
//						{
//							public void resultAvailable(IComponentManagementService cms)
//							{
//								cms.suspendComponent(desc.getName());
//							}
//							
//							public void exceptionOccurred(Exception exception)
//							{
//								if(!(exception instanceof ComponentTerminatedException))
//								{
//									super.exceptionOccurred(exception);
//								}
//							}
//						});
//					}
//				}
//			}
			
//		boolean	cycle	= false;
//		if(IComponentDescription.STATE_ACTIVE.equals(getComponent().getComponentDescription().getState()) || dostep || stepfuture!=null)
//		{
//			try
//			{
//				dostep	= false;
//				cycle	= executeCycle();
//			}
//			catch(Exception e)
//			{
//				// Todo: fail fast vs robust components.
//				
//				StringWriter	sw	= new StringWriter();
//				e.printStackTrace(new PrintWriter(sw));
//				getComponent().getLogger().severe("Component cycle failed:\n"+sw);
//			}				
//		}	
			
		StepInfo stepi = null;
		boolean priostep = false;
		boolean	breakpoint_triggered = false;
		
		synchronized(this)
		{			
			if(steps!=null && steps.size()>0) 
			{				
//				if(getComponent().getComponentIdentifier().getName().indexOf("Hello")!=-1)
//					System.out.println("executing");
				StepInfo si = steps.first();
				priostep = si.getPriority()>=STEP_PRIORITY_IMMEDIATE;
		
				// Suspend when breakpoint is triggered.
				// Necessary because component wakeup could be called anytime even if is at breakpoint..
				if(!priostep && stepfuture==null && !IComponentDescription.STATE_SUSPENDED.equals(getComponent().getDescription().getState())
					&& getComponent().getDescription().getBreakpoints().length>0)
				{
					if(isAtBreakpoint(getComponent().getDescription().getBreakpoints()))
					{
						breakpoint_triggered = true;
					}
				}		
		
//				if(getComponent().getId().getName().indexOf("Hello")!=-1)
//					System.out.println("executing");
				if(priostep)
				{
					// remove the element
					stepi = removeStep();
				}
				else if(!breakpoint_triggered)
				{
					if((IComponentDescription.STATE_ACTIVE.equals(getComponent().getDescription().getState())))
					{
						stepi = removeStep();
					}
					else if(stepfuture!=null)
					{
						boolean found = false;
						if(stepinfo!=null)
						{
							// search for right step via stepinfo
							for(StepInfo sti: steps)
							{
								if(stepinfo.equals(""+sti.getStepCount()))
								{
									stepi = sti;
									steps.remove(sti);
									publishStepEvent(sti, IMonitoringEvent.EVENT_TYPE_DISPOSAL);
									found = true;
									break;
								}
							}
							if(!found)
								getComponent().getLogger().warning("Step not found with id: "+stepinfo+"\n");
							
							stepinfo = null;
						}
						
						if(!found)
							stepi = removeStep();
					}
				}
			}
		}
		final StepInfo step = stepi;
		
		if(breakpoint_triggered)
		{
//			IComponentManagementService	cms	= ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IComponentManagementService.class);
			getComponent().suspendComponent(getComponent().getDescription().getName());
		}
		
		if(endstepcnt!=-1 && debug)
			getComponent().getLogger().severe("execute()3: "+getComponent().getId()+", "+IComponentIdentifier.LOCAL.get()+", endstepcnt="+endstepcnt+", stepcnt="+stepcnt+", "+step);

		boolean	hasstep;
		if(step!=null)
		{
//			if(step.getPriority()	stepfut	= null;
			Throwable ex = null;
			boolean	hardex	= false;
			try
			{
				boolean valid = true;
				if(step.getStep() instanceof IConditionalComponentStep)
					valid = ((IConditionalComponentStep)step.getStep()).isValid();
				
				// Prio steps are always ok?!
				int endstart = ((IInternalExecutionFeature)getComponent().getFeature(IExecutionFeature.class)).getEndstateStart();
				boolean stateok  = priostep || endstart==-1 || step.getStepCount()<=endstart;
//				if (Math.random() < 0.01)
//				{
//					if (priostep)
//						System.out.println(step.getStep());
//					System.out.println("stateok " + component + " " + priostep + " " + (endstart==-1) + " " + (step.getStepCount()<= endstart) + " " + + step.getStepCount() + " " + endstart);
//				}
				// for test execution to ensure that not dropped steps cause problems
//				stateok = true;
				
				if(valid && stateok) 
				{
					step.getTransfer().afterSwitch();
					
					if(endstepcnt!=-1 && debug)
						getComponent().getLogger().severe("execute()4: "+step.getStep()+" "+step.getPriority()+" "+getComponent().getDescription().getState());
					
					try
					{
						stepfut	= step.getStep().execute(component);

						
						if(endstepcnt!=-1 && debug)
							getComponent().getLogger().severe("execute()5: "+step.getStep()+" "+step.getPriority()+" "+getComponent().getDescription().getState());
					}
					catch(Throwable dummy)
					{
						if(endstepcnt!=-1 && debug)
							getComponent().getLogger().severe("execute()6: "+step.getStep()+" "+step.getPriority()+" "+getComponent().getDescription().getState()+"\n"+SUtil.getExceptionStacktrace(dummy));
						
						throw dummy;
					}
				}
				else
				{
					if(valid)
					{
						getComponent().getLogger().warning("Step aborted due to endstate:"+" "+step.getStep());
						ex = new StepAbortedException(step.getStep());
//						{
//							@Override
//							public void printStackTrace(PrintStream s)
//							{
//								Thread.dumpStack();
//								super.printStackTrace(s);
//							}
//							
//							@Override
//							public void printStackTrace(PrintWriter s)
//							{
//								Thread.dumpStack();
//								super.printStackTrace(s);
//							}
//						};
					}
					else
					{
						getComponent().getLogger().info("Step invalid "+" "+step.getStep());
						ex = new StepInvalidException(step.getStep());
					}
				}
			}
			catch(Throwable t)
			{
				ex = t;
				hardex	= true;
			}
			
			if(ex!=null)
			{
				// "Soft" cleanup using endagenda
				if(ex instanceof StepAborted)
				{
					// Todo: plan for other uses of step aborted= -> step terminated exception in addition to step aborted error?
					ex	= new ComponentTerminatedException(component.getId());
					System.err.println(component.getId()+": step after termination: "+step);
				}
				
				// Hard thread cleanup after endagenda is done
				else if(ex instanceof ThreadDeath)
				{
					getComponent().getLogger().info("Cleaning up blocked thread of terminated component: "+component
						+ (Future.DEBUG ? "\n"+SUtil.getExceptionStacktrace(ex)	: ", "+ex));
					
					// Hard cleanup during kill.
					resetExecutionState(cl);
					throw (ThreadDeath)ex;
				}
				
				step.getFuture().setExceptionIfUndone(ex instanceof Exception? (Exception)ex: new RuntimeException(ex));

				// If no listener, print failed step to console for developer.
				if(!step.getFuture().isNotified() &&
					(!(ex instanceof ComponentTerminatedException)
					|| !((ComponentTerminatedException)ex).getComponentIdentifier().equals(component.getId()))
					&& !(ex instanceof StepInvalidException) && !(ex instanceof StepAbortedException))
				{
//					final Throwable fex = ex;
//					// No wait for delayed listener addition for hard failures to print errors immediately.
//					waitForDelay(3000, true)
//						.addResultListener(new IResultListener()
//					{
//						public void resultAvailable(Void result)
//						{
//							if(!step.getSecondEntity().hasResultListener())
//							{
								// Todo: fail fast vs robust components.
								getComponent().getLogger().severe("Component step failed: "+step.getStep()+"\n"+SUtil.getExceptionStacktrace(ex));
								
								if(DEBUG && stepadditions!=null && stepadditions.containsKey(step.getStep()))
								{
									stepadditions.get(step.getStep()).printStackTrace();
								}
//							}
//						}
//						
//						public void exceptionOccurred(Exception exception)
//						{
//							// shouldn't happen:
//							exception.printStackTrace();
//						}
//					});
				}
				// Hard step failure with uncatched exception is shown also when no debug.
				else if(hardex)
				{
					getComponent().getLogger().warning("Component step threw hard exception: "+step.getStep()+"\n"+SUtil.getExceptionStacktrace(ex));
				}
			}
			
			if(stepfut!=null)
			{
				try
				{
					// Use generic connection method to avoid issues with different future types.
					FutureFunctionality.connectDelegationFuture(step.getFuture(), stepfut);
					
					// Monitoring only when active after step started (outer check) and step completed (inner check).
					if(step.getPriority()()
						{
							@Override
							public void accept(Object t)
							{
								if(step.getPriority()()
						{
							public void resultAvailable(Void result)
							{
								if(!step.getFuture().isNotified())
								{
									((Future)step.getFuture()).addResultListener(new IResultListener()
									{
										public void resultAvailable(Object result)
										{
											getComponent().getLogger().warning("No listener for component step: "+step.getFuture());
											
											if(DEBUG && stepadditions!=null && stepadditions.containsKey(step.getFuture()))
											{
												stepadditions.get(step.getStep()).printStackTrace();
											}
										}
										
										public void exceptionOccurred(Exception exception)
										{
											// Todo: fail fast vs robust components.
											
											// TODO: why is this code here???
//											IExecutionService	exe	= ((IInternalRequiredServicesFeature)getComponent().getFeature(IRequiredServicesFeature.class)).getRawService(IExecutionService.class);
//											// Hack!!! service is foudn before it is started, grrr.
//											if(((IService)exe).isValid().get().booleanValue())	// Hack!!! service is raw
//											{
//												if(bootstrap)
//												{
//													// Execution service found during bootstrapping execution -> stop bootstrapping as soon as possible.
//													available	= true;
//												}
//												else
//												{
//													exe.execute(ExecutionComponentFeature.this);
//												}
//											}
//											else
//											{
//												// Happens during platform bootstrapping -> execute on platform rescue thread.
//												if(!bootstrap)
//												{
//													bootstrap	= true;
//													Starter.scheduleRescueStep(getComponent().getId().getRoot(), new Runnable()
//													{
//														public void run()
//														{
//															boolean	again	= true;
//															while(!available && again)
//															{
//																again	= execute();
//															}
//															bootstrap	= false;
//															
//															if(again)
//															{					
//																// Bootstrapping finished -> do real kickoff
//																wakeup();
//															}
//														}
//													});
//												}
//											}
											
											StringWriter	sw	= new StringWriter();
											exception.printStackTrace(new PrintWriter(sw));
											getComponent().getLogger().severe("No listener for component step exception: "+step.getStep()+"\n"+sw);
											
											if(DEBUG && stepadditions!=null && stepadditions.containsKey(step.getStep()))
											{
												stepadditions.get(step.getStep()).printStackTrace();
											}
										}
									});
								}
							}
							
							public void exceptionOccurred(Exception exception)
							{
								// shouldn't happen:
								exception.printStackTrace();
							}
						});
					}
				}
				catch(Throwable e)
				{
					// Todo: fail fast vs robust components.
					if(!(e instanceof ThreadDeath))
					{
						StringWriter	sw	= new StringWriter();
						e.printStackTrace(new PrintWriter(sw));
						getComponent().getLogger().severe("Component step listener failed: "+step.getStep()+"\n"+sw);
						
						if(DEBUG && stepadditions!=null && stepadditions.containsKey(step.getStep()))
						{
							stepadditions.get(step.getStep()).printStackTrace();
						}
					}
				}
			}
			
			synchronized(this)
			{
				hasstep	= steps!=null && steps.size()>0;
			}
		}
		else
		{
			hasstep	= false;
		}
		
		boolean	cycle	= false;
		if(IComponentDescription.STATE_ACTIVE.equals(getComponent().getDescription().getState()) || stepfuture!=null)
		{
			try
			{
				cycle	= executeCycle();
			}
			catch(Exception e)
			{
				// Todo: fail fast vs robust components.
				
				StringWriter	sw	= new StringWriter();
				e.printStackTrace(new PrintWriter(sw));
				getComponent().getLogger().severe("Component cycle failed:\n"+sw);
			}				
		}
		
		if(!priostep)
		{
			// In step mode, notify done step, if any.
			Future stepfut = null;
			synchronized(this)
			{
				
				if(stepfuture!=null && stepinfo==null)
				{
					stepfut	= stepfuture;
					stepfuture = null;
					//System.out.println("stepfuture null");
				}
			}
			if(stepfut!=null)
			{
				stepfut.setResult(null);
			}
		}

		resetExecutionState(cl);

		// Execute the subcomponents
		boolean ret = hasstep || cycle;
		IInternalExecutionFeature[] subs = null;
		synchronized(this)
		{
			if(subcomponents!=null)
			{
				subs = subcomponents.toArray(new IInternalExecutionFeature[subcomponents.size()]);
				subcomponents	= null;
			}
		}
		if(subs!=null)
		{
			for(IInternalExecutionFeature sub: subs)
			{
//				System.out.println("execute1: "+sub.getComponentIdentifier());
				setComponentThread(Thread.currentThread());
//				this.componentthread = Thread.currentThread();
				boolean	again = ((IInternalExecutionFeature)sub).execute();
				setComponentThread(null);
//				this.componentthread = null;
				if(again)
				{
					addSubcomponent(sub);
				}
				ret	= again || ret;
			}
		}
		
		if(endstepcnt!=-1 && debug)
			getComponent().getLogger().severe("execute()7: endstepcnt="+endstepcnt+", ret="+ret+", endagenda.isDone()="+endagenda.isDone());
		
		if(endstepcnt!=-1 && !ret && !endagenda.isDone())
		{
			cl	= setExecutionState();
			
			endagenda.setResult(null);

			resetExecutionState(cl);
		}
		
//		if(endstepcnt!=-1 && getComponent().getComponentIdentifier().equals(getComponent().getComponentIdentifier().getRoot()))
//			System.out.println("platform: "+steps.size());
		
		// Stop executing again on exe service when switched to rescue thread in mean time.
		return ret && (!isonrescue || Thread.currentThread()==rescuethread);
		
		} catch(Throwable t) {
			if(executing)
				new RuntimeException("dreck").initCause(t).printStackTrace();
			throw SUtil.throwUnchecked(t);
		}
	}

	
	/**
	 *  Get the component thread.
	 *  @return The component thread.
	 */
	public Thread getComponentThread()
	{
		return componentthread;
	}

	/**
	 *  Set the component thread.
	 *  @param componentthread The component thread.
	 */
	public void setComponentThread(Thread componentthread)
	{
//		System.out.println(getComponent().getComponentIdentifier().getLocalName()+" "+componentthread);
//		if("clock".equals(getComponent().getComponentIdentifier().getLocalName()) && componentthread==null)
//			System.out.println("clock thread to null");
		this.componentthread = componentthread;
	}

	/**
	 *  Set flags when entering thread.
	 *  @return	The previous context class loader.
	 */
	protected ClassLoader setExecutionState()
	{
		// Remember execution thread.
		setComponentThread(Thread.currentThread());
//		this.componentthread	= Thread.currentThread();
		IComponentIdentifier.LOCAL.set(getComponent().getId());
		IInternalExecutionFeature.LOCAL.set(getInternalAccess());
		ClassLoader	cl	= Thread.currentThread().getContextClassLoader();
		Thread.currentThread().setContextClassLoader(component.getClassLoader());
		ISuspendable.SUSPENDABLE.set(new ComponentSuspendable(getInternalAccess()));
		return cl;
	}
	
	/**
	 *  Reset flags when exiting thread.
	 *  @param cl	The previous context class loader.
	 */
	protected void resetExecutionState(ClassLoader cl)
	{
		// Switch to rescue thread?
		boolean	run	= false;
		synchronized(this)
		{
			run	= switchtorescue && !isonrescue;
		}
		
		// Reset execution state.
		IComponentIdentifier.LOCAL.set(null);
		IInternalExecutionFeature.LOCAL.set(null);
		// Must reset service call settings when thread retreats from components
		CallAccess.resetCurrentInvocation();
		CallAccess.resetNextInvocation();
		Thread.currentThread().setContextClassLoader(cl);
		setComponentThread(null);
//		this.componentthread = null;
		executing	= false;
		stacktrace	= null;
		ISuspendable.SUSPENDABLE.set(null);
		
		if(run)
		{
			switchToRescueThread();
		}
	}

	/**
	 *  Components with autonomous behavior may override this method
	 *  to implement a recurring execution cycle.
	 *  @return true, if the execution should continue, false, if the component may become idle. 
	 */
	protected boolean	executeCycle()
	{
		return false;
	}
	
	/**
	 *  Create intermediate of direct future.
	 */
	protected  Future createStepFuture(IComponentStep step)
	{
		Future ret;
		try
		{
			Class clazz;
			if(step instanceof ITypedComponentStep)
			{
				clazz	= ((ITypedComponentStep)step).getReturnType();
			}
			else
			{
				Method method = step.getClass().getMethod("execute", new Class[]{IInternalAccess.class});
				clazz = method.getReturnType();
			}
//			ret = FutureFunctionality.getDelegationFuture(clazz, new FutureFunctionality(getLogger()));
			// Must not be fetched before properties are available!
			ret = (Future)FutureFunctionality.getDelegationFuture(clazz, new FutureFunctionality(new IResultCommand()
			{
				public Logger execute(Void args)
				{
					return getComponent().getLogger();
				}
			}));
		}
		catch(Exception e)
		{
			throw new RuntimeException(e);
		}
		
		return ret;
	}
	
	/**
	 *  Add a new step.
	 */
	protected void addStep(StepInfo step)
	{
		if(steps==null)
			steps	= new TreeSet();
		steps.add(step);
		
		publishStepEvent(step, IMonitoringEvent.EVENT_TYPE_CREATION);
	}
	
	/**
	 *  Remove a new step.
	 */
	protected StepInfo removeStep()
	{
		assert steps!=null && !steps.isEmpty();
		StepInfo ret = steps.pollFirst();
		
		publishStepEvent(ret, IMonitoringEvent.EVENT_TYPE_DISPOSAL);
		
		return ret;
	}
	
	/**
	 *  Publish a step event.
	 */
	public void publishStepEvent(StepInfo step, String type)
	{
		if(step.getPriority() getStepDetails(StepInfo step)
	{
		Map	ret = new LinkedHashMap();
		
		ret.put("Class", step.getStep().getClass().getName());
		ret.put("Priority", ""+step.getPriority());
		ret.put("Id", ""+step.getStepCount());
		
		if(step.getStep() instanceof ITransferableStep)
		{
			Map det = ((ITransferableStep)step.getStep()).getTransferableObject();
			if(det!=null)
				ret.putAll(det);
		}
			
		Field[] fields = step.getStep().getClass().getDeclaredFields();
		for(int i = 0; i < fields.length; i++) 
		{
			String valtext = null;
			try 
			{
				SAccess.setAccessible(fields[i], true);
				Object val = fields[i].get(step.getStep());
				valtext = val == null ? "null" : val.toString();
			} 
			catch (Exception e) 
			{
				valtext = e.getMessage();
			}

			if(valtext != null) 
			{
				ret.put(fields[i].getName(), valtext);
			}
		}
		
//		StringBuffer buf = new StringBuffer();
//
//		buf.append("Class = ").append(step.getStep().getClass().getName()).append("\n");
//		buf.append("Priority = ").append(step.getPriority()).append("\n");
//		buf.append("Id = ").append(step.getStepCount()).append("\n");
//			
//		Field[] fields = step.getStep().getClass().getDeclaredFields();
//		for(int i = 0; i < fields.length; i++) 
//		{
//			String valtext = null;
//			try 
//			{
//				fields[i].setAccessible(true);
//				Object val = fields[i].get(step.getStep());
//				valtext = val == null ? "null" : val.toString();
//			} 
//			catch (Exception e) 
//			{
//				valtext = e.getMessage();
//			}
//
//			if(valtext != null) 
//			{
//				buf.append("\n");
//				buf.append(fields[i].getName()).append(" = ").append(valtext);
//			}
//		}
//
//		ret = buf.toString();
			
		return ret;
	}
	
	/**
	 *  Get the current steps.
	 *  @return The current steps.
	 */
	public synchronized List getCurrentSteps()
	{
		List ret = null;
		
		if(steps!=null && steps.size()>0)
		{
			ret = new ArrayList(steps);
		}
		
		return ret;
	}
	
	/**
	 *  Get the current state as events.
	 */
	public List getCurrentStateEvents()
	{
		List ret = null;
		
		IExecutionFeature exef = getComponent().getFeature0(IExecutionFeature.class);
		if(exef instanceof ExecutionComponentFeature)
		{
			List steps = ((ExecutionComponentFeature)exef).getCurrentSteps();
			if(steps!=null)
			{
				ret = new ArrayList();
				for(StepInfo step: steps)
				{
					if(step.getPriority()0)
		{
			
			if(steps.first().getStepCount()==bpstepid)
			{
				bpstepid = -1;
			}
			else
			{
				ret = testIfBreakpoint(breakpoints);
			}
		}
		return ret;
	}
	
	/**
	 *  Kernel specific test if the step is a breakpoint.
	 */
	public boolean testIfBreakpoint(String[] breakpoints)
	{
		boolean ret = false;
		try
		{
//			System.out.println("testing: "+steps.first().getStep().getClass());
			Method m = steps.first().getStep().getClass().getMethod("execute", new Class[]{IInternalAccess.class});
			Breakpoint bp = m.getAnnotation(Breakpoint.class);
			if(bp!=null)
			{
				Set	bps	= new HashSet(Arrays.asList(breakpoints));
				String bpname = bp.value();
				// todo: support wildcard matching
				ret = bps.contains(bpname);
				if(ret)
					bpstepid = steps.first().getStepCount();
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return ret;
	}
	
	/**
	 *  Add a component listener for a specific component.
	 *  The listener is registered for component changes.
	 *  @param cid	The component to be listened.
	 */
	public ISubscriptionIntermediateFuture listenToComponent()
	{
		return getComponent().listenToComponent(component.getId());
	}
	
	/**
	 *  Add a component listener for all components of a platform.
	 *  The listener is registered for component changes.
	 */
	public ISubscriptionIntermediateFuture listenToAll()
	{
		return getComponent().listenToComponent(null);
	}
	
	/**
	 *  Execute a step of a suspended component.
	 *  @param componentid The component identifier.
	 */
	public IFuture stepComponent(String stepinfo)
	{
		return getComponent().stepComponent(component.getId(), stepinfo);
	}
	
	/**
	 *  Set breakpoints for a component.
	 *  Replaces existing breakpoints.
	 *  To add/remove breakpoints, use current breakpoints from component description as a base.
	 *  @param componentid The component identifier.
	 *  @param breakpoints The new breakpoints (if any).
	 */
	public IFuture setComponentBreakpoints(String[] breakpoints)
	{
		return getComponent().setComponentBreakpoints(component.getId(), breakpoints);
	}
	
	/**
	 *  Suspend the execution of an component.
	 *  @param componentid The component identifier.
	 */
	public IFuture suspendComponent()
	{
		return getComponent().suspendComponent(component.getId());
	}
	
	/**
	 *  Resume the execution of an component.
	 *  @param componentid The component identifier.
	 */
	public IFuture resumeComponent()
	{
		return getComponent().resumeComponent(component.getId());
	}
	
//	/**
//	 *  Add a new component as subcomponent of this component.
//	 *  @param component The model or pojo of the component.
//	 */
//	public IFuture createComponent(CreationInfo info, IResultListener>> resultlistener)
//	{
//		return getComponent().createComponent(info, resultlistener);
//	}
//	
//	/**
//	 *  Add a new component as subcomponent of this component.
//	 *  @param component The model or pojo of the component.
//	 */
//	public ISubscriptionIntermediateFuture createComponentWithResults(CreationInfo info)
//	{
//		return getComponent().createComponentWithResults(info);
//	}
//	
//	/**
//	 *  Create a new component on the platform.
//	 *  @param name The component name or null for automatic generation.
//	 *  @param model The model identifier (e.g. file name).
//	 *  @param info Additional start information such as parent component or arguments (optional).
//	 *  @return The id of the component and the results after the component has been killed.
//	 */
//	public ITuple2Future> createComponent(CreationInfo info)
//	{
//		return getComponent().createComponent(info);
//	}
	
	/**
	 *  Kill the component.
	 */
	public IFuture> killComponent()
	{
		if(IComponentDescription.STATE_SUSPENDED.equals(getComponent().getDescription().getState()))
			getComponent().resumeComponent(component.getId());
		return getComponent().killComponent();
	}
	
	/**
	 *  Kill the component.
	 *  @param e The failure reason, if any.
	 */
	public IFuture> killComponent(Exception e)
	{
		if(IComponentDescription.STATE_SUSPENDED.equals(getComponent().getDescription().getState()))
			getComponent().resumeComponent(component.getId());
		return getComponent().killComponent(e);
	}
	
//	/**
//	 *  Kill the component.
//	 *  @param e The failure reason, if any.
//	 */
//	public IFuture> killComponent(IComponentIdentifier cid)
//	{
//		return getComponent().killComponent(cid);
//	}
	
	/**
	 *  Get the external access for a component id.
	 *  @param cid The component id.
	 *  @return The external access.
	 */
	public IExternalAccess getExternalAccess(IComponentIdentifier cid)
	{
		if (cid == null || component.getId().equals(cid))
			return getComponent().getExternalAccess();
		return SComponentManagementService.getExternalAccess(cid, component);
	}
	
	/**
	 *  Get the external access for a component id.
	 *  @param cid The component id.
	 *  @return The external access.
	 */
	public IFuture getExternalAccessAsync(IComponentIdentifier cid)
	{
		// TODO FIXME: REMOVE
		return new Future<>(getExternalAccess(cid));
	}
	
	/**
	 *  Get the component description.
	 *  @return	The component description.
	 */
	// Todo: hack??? should be internal to CMS!?
	public IFuture getDescriptionAsync()
	{
		return new Future<>(getComponent().getDescription());
	}
	
	/**
	 *  Get the component description.
	 *  @return	The component description.
	 */
	// Todo: hack??? should be internal to CMS!?
	public IFuture getDescription(IComponentIdentifier cid)
	{
 		// redirect remote calls 
		if(!getComponent().getId().hasSameRoot(cid))
			return getExternalAccess(cid).getDescription(cid);
		else
			return getComponent().getDescription(cid);
	}
	
	/**
	 *  Get the component description.
	 *  @return	The component description.
	 */
	// Todo: hack??? should be internal to CMS!?
	public IFuture getDescriptions()
	{
		return getComponent().getDescriptions();
	}
	
	/**
	 *  Get the step number when endstate began.
	 *  @return The step cnt.
	 */
	public int getEndstateStart()
	{
		return endstepcnt;
	}
	
	/**
	 *  Called when a child was terminated.
	 */
	public void childTerminated(IComponentDescription desc, Exception ex)
	{
		System.out.println("Child terminated: "+desc.getName());
		// does nothing per default
		// kernels need to override 
	}
	
	/**
	 *  Wrap a timer and remove it from the agent when it is cancelled.
	 */
	protected class TimerWrapper implements ITimer 
	{
		//-------- attributes --------
		
		/** The wrapped timer. */
		ITimer	timer;
		
		//-------- constructors--------
		
		/**
		 *  Wrap a timer.
		 */
		public TimerWrapper(ITimer timer)
		{
			this.timer	= timer;
		}
		
		//-------- ITimer interface --------
		
		public void cancel()
		{
			assert timers!=null;
			timers.remove(timer);
			timer.cancel();
		}

		public long getNotificationTime()
		{
			return timer.getNotificationTime();
		}

		public ITimedObject getTimedObject()
		{
			return timer.getTimedObject();
		}

		public void setNotificationTime(long time)
		{
			timer.setNotificationTime(time);
		}

		public boolean equals(Object obj)
		{
			return timer.equals(obj);
		}

		public int hashCode()
		{
			return timer.hashCode();
		}

		public String toString()
		{
			return timer.toString();
		}
	}
	
	/**
	 *  Step to execute a wait for entry.
	 */
	public static class ExecuteWaitForStep implements IComponentStep
	{
		//-------- attributes --------

		/** The timer. */
		private final ITimer ts;

		/** The component step. */
		private final IComponentStep run;

		//-------- constructors--------

		/**
		 * This class is constructed with an array of {@link ITimer}s and the {@link IComponentStep}
		 * which is scheduled for execution.
		 * @param ts an array of {@link ITimer}s
		 * @param run the {@link IComponentStep} which is scheduled for execution
		 */
		public ExecuteWaitForStep(ITimer ts, IComponentStep run)
		{
			this.ts = ts;
			this.run = run;
		}

		//-------- methods --------

		/**
		 * Removes the first entry from the {@link ITimer} array from the micro agents
		 * {@link MicroAgent#timers} {@link List} and executes the {@link IComponentStep}.
		 */
		public IFuture execute(IInternalAccess ia)
		{
			assert ((ExecutionComponentFeature)ia.getFeature(IExecutionFeature.class)).timers!=null;
			((ExecutionComponentFeature)ia.getFeature(IExecutionFeature.class)).timers.remove(ts);
			run.execute(ia);
			return IFuture.DONE;
		}

		/**
		 * @return "microagent.waitFor_#" plus the hash code of this class
		 */
		public String toString()
		{
			return ts==null? super.toString(): ts.getTimedObject()!=null? ts.getTimedObject().toString(): ts.toString();
		}
		
		/**
		 * Returns the {@link IComponentStep} that is scheduled for execution.
		 * @return The {@link IComponentStep} that is scheduled for execution
		 */
		public IComponentStep getComponentStep()
		{
			return run;
		}
	}
	
	/**
	 *  Info struct for steps.
	 */
	public static class StepInfo implements Comparable
	{
		/** The component step. */
		protected IComponentStep step; 
		
		/** The result future. */
		protected Future future; 
		
		/** The service call. */
		protected ThreadLocalTransferHelper transfer;
		
		/** The priority. */
		protected int priority;
		
		/** The number of the step (preserve insert order of same prio). */
		protected int stepcnt;
		
//		/** The component state (create, init, body, end). */
//		protected ComponentLifecycleState state;
		
//		/**
//		 *  Create a new StepInfo. 
//		 */
//		public StepInfo(IComponentStep step, Future future, ThreadLocalTransferHelper transfer, int stepcnt)
//		{
//			this(step, future, transfer, step instanceof IPriorityComponentStep? ((IPriorityComponentStep)step).getPriority(): 0, stepcnt);
//		}
		
		/**
		 *  Create a new StepInfo. 
		 */
		public StepInfo(IComponentStep step, Future future, ThreadLocalTransferHelper transfer, 
			int priority, int stepcnt)
		{
			this.step = step;
			this.future = future;
			this.transfer = transfer;
			this.priority = priority;
			this.stepcnt = stepcnt;
		}

		/**
		 *  Get the step.
		 *  @return The step.
		 */
		public IComponentStep getStep()
		{
			return step;
		}

		/**
		 *  Set the step.
		 *  @param step The step to set.
		 */
		public void setStep(IComponentStep step)
		{
			this.step = step;
		}

		/**
		 *  Get the future.
		 *  @return The future.
		 */
		public Future getFuture()
		{
			return future;
		}

		/**
		 *  Set the future.
		 *  @param future The future to set.
		 */
		public void setFuture(Future future)
		{
			this.future = future;
		}

		/**
		 *  Get the transfer.
		 *  @return The transfer
		 */
		public ThreadLocalTransferHelper getTransfer()
		{
			return transfer;
		}

		/**
		 *  The transfer to set.
		 *  @param transfer The transfer to set
		 */
		public void setTransfer(ThreadLocalTransferHelper transfer)
		{
			this.transfer = transfer;
		}

		/**
		 *  Get the priority.
		 *  @return The priority
		 */
		public int getPriority()
		{
			return priority;
		}

		/**
		 *  The priority to set.
		 *  @param priority The priority to set
		 */
		public void setPriority(int priority)
		{
			this.priority = priority;
		}
		
		/**
		 *  Get the stepcnt.
		 *  @return The stepcnt
		 */
		public int getStepCount()
		{
			return stepcnt;
		}

		/**
		 *  The stepcnt to set.
		 *  @param stepcnt The stepcnt to set
		 */
		public void setStepCount(int stepcnt)
		{
			this.stepcnt = stepcnt;
		}
		
//		/**
//		 *  Get the state. 
//		 *  @return The state
//		 */
//		public ComponentLifecycleState getState()
//		{
//			return state;
//		}
//
//		/**
//		 *  Set the state.
//		 *  @param state The state to set
//		 */
//		public void setState(ComponentLifecycleState state)
//		{
//			this.state = state;
//		}
		
		/**
		 *  Compare two steps.
		 */
		public int compareTo(StepInfo o)
		{
			int ret = o.getPriority()-getPriority();
			if(ret==0)
				ret = getStepCount()-o.getStepCount();
			return ret;
		}

		/**
		 *  Get the string representation.
		 */
		public String toString()
		{
			return "StepInfo(priority=" + priority + ", step=" + step + ")";
		}
	}

	/**
	 *  Get the string representation.
	 */
	public String toString()
	{
		return "ExecutionFeature("+getComponent().getId()+")";
	}
}