Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
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.
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()+")";
}
}