jadex.platform.service.simulation.SimulationService Maven / Gradle / Ivy
package jadex.platform.service.simulation;
import java.util.List;
import jadex.bridge.IComponentStep;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ImmediateComponentStep;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.annotation.ServiceComponent;
import jadex.bridge.service.annotation.ServiceShutdown;
import jadex.bridge.service.annotation.ServiceStart;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.clock.IClock;
import jadex.bridge.service.types.clock.IClockService;
import jadex.bridge.service.types.clock.ITimer;
import jadex.bridge.service.types.execution.IExecutionService;
import jadex.bridge.service.types.settings.ISettingsService;
import jadex.bridge.service.types.simulation.ISimulationService;
import jadex.bridge.service.types.threadpool.IThreadPoolService;
import jadex.commons.ChangeEvent;
import jadex.commons.IChangeListener;
import jadex.commons.IPropertiesProvider;
import jadex.commons.Properties;
import jadex.commons.Property;
import jadex.commons.collection.SCollection;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
/**
* The execution control is the access point for controlling the
* execution of one application. It provides basic features for
* starting, stopping and stepwise execution.
*/
@Service
public class SimulationService implements ISimulationService, IPropertiesProvider
{
//-------- attributes --------
/** The containing component. */
@ServiceComponent
protected IInternalAccess access;
/** The execution mode. */
protected String mode;
/** The executing flag. */
protected boolean executing;
/** The listeners. */
protected List listeners;
/** The time of a time step. */
protected long timesteptime;
/** The clock service. */
protected IClockService clockservice;
/** The execution service. */
protected IExecutionService exeservice;
/** The future (if any) indicating when a step is finished. */
protected Future stepfuture;
/** The idle future listener. */
protected IdleListener idlelistener;
/** Flag to indicate that simulation should be started after service is inited. */
protected boolean startoninit;
//-------- constructors --------
/**
* Create a new execution control.
*/
public SimulationService()
{
this.mode = MODE_NORMAL;
this.startoninit = true;
this.listeners = SCollection.createArrayList();
}
//-------- service methods --------
/**
* Shutdown the service.
* @param listener The listener.
*/
@ServiceShutdown
public IFuture shutdownService()
{
final Future deregistered = new Future();
SServiceProvider.getService(access, ISettingsService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new IResultListener()
{
public void resultAvailable(Object result)
{
ISettingsService settings = (ISettingsService)result;
settings.deregisterPropertiesProvider("simulationservice")
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(deregistered)));
}
public void exceptionOccurred(Exception exception)
{
// No settings service: ignore.
deregistered.setResult(null);
}
}));
final Future ret = new Future();
deregistered.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object result)
{
IFuture stopped;
if(executing)
{
stopped = pause();
}
else
{
stopped = IFuture.DONE;
}
stopped.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)));
}
}));
return ret;
}
//-------- methods --------
/**
* Start (and run) the execution.
*/
@ServiceStart
public IFuture startService()
{
final Future ret = new Future();
SServiceProvider.getService(access, ISettingsService.class, RequiredServiceInfo.SCOPE_PLATFORM)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new IResultListener()
{
public void resultAvailable(Object result)
{
ISettingsService settings = (ISettingsService)result;
settings.registerPropertiesProvider("simulationservice", SimulationService.this)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object result)
{
proceed();
}
public void exceptionOccurred(Exception exception)
{
super.exceptionOccurred(exception);
}
}));
}
public void exceptionOccurred(Exception exception)
{
// No settings service: ignore.
proceed();
}
public void proceed()
{
final boolean[] services = new boolean[2];
SServiceProvider.getService(access, IExecutionService.class, RequiredServiceInfo.SCOPE_PLATFORM, false)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object result)
{
exeservice = (IExecutionService)result;
services[0] = true;
if(services[0] && services[1])
{
if(startoninit)
{
startoninit = false;
start().addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)));
}
else
{
ret.setResult(null);
// ret.setResult(getServiceIdentifier());
}
}
}
}));
SServiceProvider.getService(access, IClockService.class, RequiredServiceInfo.SCOPE_PLATFORM, false)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)
{
public void customResultAvailable(Object result)
{
clockservice = (IClockService)result;
services[1] = true;
if(services[0] && services[1])
{
if(startoninit)
{
startoninit = false;
start().addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)));
}
else
{
ret.setResult(null);
// ret.setResult(getServiceIdentifier());
}
}
}
}));
}
}));
return ret;
}
/**
* Pause the execution (can be resumed via start or step).
*/
public IFuture pause()
{
IFuture ret;
if(!executing)
{
// System.out.println("Not pausing");
ret = new Future(new IllegalStateException("Simulation not running."));
}
else
{
// System.out.println("Pausing");
setExecuting(false);
getClockService().stop();
ret = IFuture.DONE;
if(idlelistener!=null)
{
idlelistener.outdated = true;
idlelistener = null;
}
}
return ret;
}
/**
* Restart the execution after pause.
*/
public IFuture start()
{
IFuture ret;
if(executing)
{
// System.out.println("Not starting");
ret = new Future(new IllegalStateException("Simulation already running."));
}
else
{
// System.out.println("Starting");
setMode(MODE_NORMAL);
getClockService().start();
setExecuting(true);
scheduleAdvanceClock();
ret = IFuture.DONE;
}
return ret;
}
/**
* Perform one event.
*/
public IFuture stepEvent()
{
IFuture ret;
if(executing)
{
// System.out.println("Not stepping");
ret = new Future(new IllegalStateException("Simulation already running."));
}
else if(IClock.TYPE_CONTINUOUS.equals(getClockService().getClockType())
|| IClock.TYPE_SYSTEM.equals(getClockService().getClockType()))
{
// System.out.println("Not stepping");
ret = new Future(new IllegalStateException("Step only possible in simulation mode."));
}
else
{
// System.out.println("Stepping");
setMode(MODE_ACTION_STEP);
getClockService().start();
setExecuting(true);
assert stepfuture==null;
stepfuture = new Future();
ret = stepfuture;
scheduleAdvanceClock();
}
return ret;
}
/**
* Perform all actions belonging to one time point.
*/
public IFuture stepTime()
{
IFuture ret;
if(executing)
{
// System.out.println("Not stepping");
ret = new Future(new IllegalStateException("Simulation already running."));
}
else if(IClock.TYPE_CONTINUOUS.equals(getClockService().getClockType())
|| IClock.TYPE_SYSTEM.equals(getClockService().getClockType()))
{
// System.out.println("Not stepping");
ret = new Future(new IllegalStateException("Step only possible in simulation mode."));
}
else
{
// System.out.println("Stepping");
setMode(MODE_TIME_STEP);
ITimer next = getClockService().getNextTimer();
if(next!=null)
{
timesteptime = next.getNotificationTime();
// System.out.println("time step: "+timesteptime);
getClockService().start();
setExecuting(true);
assert stepfuture==null;
stepfuture = new Future();
ret = stepfuture;
scheduleAdvanceClock();
}
else
{
ret = IFuture.DONE;
}
}
return ret;
}
/**
* Get the execution mode.
* @return The mode.
*/
public IFuture getMode()
{
return new Future(mode);
}
/**
* Set the execution mode.
* @param mode The mode.
*/
public void setMode(String mode)
{
this.mode = mode;
}
/**
* Set the clock type.
* @param type The clock type.
*/
public IFuture setClockType(final String type)
{
IFuture ret;
if(executing)
{
// System.out.println("Not setting clock");
ret = new Future(new IllegalStateException("Change clock not allowed during execution."));
}
else
{
String oldtype = clockservice.getClockType();
if(!type.equals(oldtype))
{
// System.out.println("Setting clock");
final Future fut = new Future();
ret = fut;
SServiceProvider.getService(access, IThreadPoolService.class, RequiredServiceInfo.SCOPE_PLATFORM, false)
.addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(fut)
{
public void customResultAvailable(Object result)
{
IThreadPoolService tps = (IThreadPoolService)result;
clockservice.setClock(type, tps);
notifyListeners(new ChangeEvent(this, "clock_type", type));
fut.setResult(null);
}
}));
}
else
{
// System.out.println("Not setting clock");
ret = IFuture.DONE;
}
}
return ret;
}
/**
* Test if context is executing.
*/
public IFuture isExecuting()
{
return new Future(executing ? Boolean.TRUE : Boolean.FALSE);
}
/**
* Add a change listener.
* @param listener The change listener.
*/
public void addChangeListener(IChangeListener listener)
{
listeners.add(listener);
}
/**
* Remove a change listener.
* @param listener The change listener.
*/
public void removeChangeListener(IChangeListener listener)
{
listeners.remove(listener);
}
/**
* Set the executing state.
*/
public void setExecuting(boolean executing)
{
// System.out.println("Set executing: "+executing);
assert executing!=this.executing;
this.executing = executing;
notifyListeners(new ChangeEvent(this, "executing", executing? Boolean.TRUE: Boolean.FALSE));
}
/**
* Notify the listeners.
*/
protected void notifyListeners(ChangeEvent event)
{
IChangeListener[] alisteners = listeners.isEmpty() ? null
: (IChangeListener[])listeners.toArray(new IChangeListener[listeners.size()]);
for(int i=0; alisteners!=null && itimesteptime))
{
// System.out.println("Not advancing clock");
setIdle();
}
else
{
// System.out.println("Advancing clock");
if(getClockService().advanceEvent())
{
if(idlelistener==null)
idlelistener = new IdleListener();
getExecutorService().getNextIdleFuture().addResultListener(access.getComponentFeature(IExecutionFeature.class).createResultListener(idlelistener));
}
else
{
// System.out.println("Clock not advanced");
// Simulation stopped due to no more entries
// -> listen on clock until new entries available.
if(MODE_NORMAL.equals(mode))
{
getClockService().addChangeListener(new IChangeListener()
{
public void changeOccurred(ChangeEvent event)
{
if(IClock.EVENT_TYPE_TIMER_ADDED.equals(event.getType()))
{
getClockService().removeChangeListener(this);
access.getExternalAccess().scheduleStep(new IComponentStep()
{
public IFuture execute(IInternalAccess ia)
{
// Resume execution if still executing.
if(MODE_NORMAL.equals(mode) && executing)
{
scheduleAdvanceClock();
}
return IFuture.DONE;
}
});
}
}
});
}
// Step finished.
else
{
setIdle();
}
}
}
}
// else do nothing for continuous clock as it executes itself.
// else
// {
// System.out.println("Not advancing clock");
// }
}
//-------- helper classes --------
/**
* Listener on the execution service.
*/
public class IdleListener implements IResultListener
{
//-------- attributes --------
/** Flag to indicate an outdated listener that should not do anything.
* Required, because future does not support remove listener. */
protected boolean outdated;
/** Flag indicating an a continued execution.
* If in action step mode, clock must not be advanced. */
protected boolean continued;
//-------- IResultListener interface --------
/**
* Called when an exception occurs.
*/
public void exceptionOccurred(Exception exception)
{
// ignore (happens when execution service terminates).
}
/**
* Called when the execution service is idle.
*/
public void resultAvailable(Object result)
{
// System.out.println("Executor idle");
if(executing && !outdated)
{
if(MODE_NORMAL.equals(mode) || MODE_TIME_STEP.equals(mode) || !continued)
{
continued = true;
advanceClock();
}
else if(MODE_ACTION_STEP.equals(mode))
{
setIdle();
}
}
}
}
//-------- IPropertiesProvider interface --------
/**
* Update from given properties.
*/
public IFuture setProperties(Properties props)
{
final boolean exe = props.getBooleanProperty("executing");
return access.getExternalAccess().scheduleStep(new ImmediateComponentStep()
{
public IFuture execute(IInternalAccess ia)
{
// startoninit==false means service already running
if(exe && !executing && !startoninit)
{
start();
}
else if(!exe && executing)
{
pause();
}
else if(!exe)
{
startoninit = false;
}
return IFuture.DONE;
}
});
}
/**
* Write current state into properties.
*/
public IFuture getProperties()
{
Properties props = new Properties();
// Only save as executing when in normal mode.
props.addProperty(new Property("executing", ""+(executing && MODE_NORMAL.equals(mode))));
return new Future(props);
}
}