Skip to content

Commit

Permalink
Add shutdown hooks to Timer and DEECoContainer
Browse files Browse the repository at this point in the history
Now plugins can deinitialize themselfs when simualtion is finished
  • Loading branch information
vladamatena committed Nov 6, 2015
1 parent 39197a7 commit ac6fd83
Show file tree
Hide file tree
Showing 15 changed files with 169 additions and 47 deletions.
13 changes: 13 additions & 0 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/runtime/DEECoContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
* @author Ilias Gerostathopoulos <iliasg@d3s.mff.cuni.cz>
*/
public interface DEECoContainer {
/**
* Interface for container shutdown listener
*/
public static interface ShutdownListener {
public void onShutdown();
}

/**
* Returns the instance of the initialized plugin of type <code>pluginClass</code>.
Expand Down Expand Up @@ -75,4 +81,11 @@ public interface DEECoContainer {
* @return Container identification
*/
public int getId();

/**
* Registers handler for container shutdown
*
* Handler execution order is not guaranteed.
*/
public void addShutdownListener(ShutdownListener listener);
}
29 changes: 27 additions & 2 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/runtime/DEECoNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@ public class DEECoNode implements DEECoContainer {
KnowledgeManagerFactory knowledgeManagerFactory;

/**
* Contains the initialized plugins for this deeco object.
* Contains the initialized plugins for this DEECo object.
*/
Set<DEECoPlugin> pluginsSet;

/**
* Contains node shutdown handlers
*/
Set<DEECoContainer.ShutdownListener> shutdownListeners = new HashSet<>();

/**
* Creates new instance of {@link DEECoNode}.
* @param timer is the {@link Timer} that will be used in the created {@link DEECoNode} instance.
Expand Down Expand Up @@ -157,6 +162,12 @@ private void initializeRuntime(Timer timer) throws DEECoException {
executor.setExecutionListener(scheduler);
runtime = new RuntimeFrameworkImpl(model, scheduler, executor, kmContainer, null);
runtime.init(this);
timer.addShutdownListener(new Timer.ShutdownListener() {
@Override
public void onShutdown() {
shutdownPlugins();
}
});
}

/**
Expand Down Expand Up @@ -212,6 +223,15 @@ void initializePlugins(DEECoPlugin[] plugins) throws PluginDependencyException,
}
}

/**
* Shutdowns all plugins once simulation is over
*/
private void shutdownPlugins() {
for(ShutdownListener listener: shutdownListeners) {
listener.onShutdown();
}
}

@Override
public int getId() {
return nodeId;
Expand Down Expand Up @@ -319,5 +339,10 @@ List<DependencyNode> constructDependencyNodes(DEECoPlugin[] plugins) throws Plug
}

return dependencyNodes;
}
}

@Override
public void addShutdownListener(ShutdownListener listener) {
shutdownListeners.add(listener);
}
}
27 changes: 14 additions & 13 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/runtime/DEECoPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,35 @@
import cz.cuni.mff.d3s.deeco.annotations.processor.AnnotationProcessor;

/**
* Contains the specification of a DEECo plugin.
* The core is itself a plugin of type <code>RuntimeFramework</code>, only it is always present.
* Every plugin that has no explicit dependencies implicitly depends on the core plugin.
* Contains the specification of a DEECo plugin. The core is itself a plugin of type <code>RuntimeFramework</code>, only
* it is always present. Every plugin that has no explicit dependencies implicitly depends on the core plugin.
*
* @author Ilias Gerostathopoulos <iliasg@d3s.mff.cuni.cz>
* @author Filip Krijt <krijt@d3s.mff.cuni.cz>
*/
public interface DEECoPlugin {

/**
* The other plugins that this plugin depends on.
* If its dependencies are not provided, the plugin will not be initialized and used.
* The other plugins that this plugin depends on. If its dependencies are not provided, the plugin will not be
* initialized and used.
*/
public List<Class<? extends DEECoPlugin>> getDependencies();

/**
* Method through which a plugin extends the plugins it depends on (or the DEECo core plugin, if it has no explicit dependencies).
* Method through which a plugin extends the plugins it depends on (or the DEECo core plugin, if it has no explicit
* dependencies).
* <p>
* It should be used to do one or more of the following:
* <ul>
* <li>Register an extension via {@link AnnotationProcessor#addExtension(AnnotationProcessorExtensionPoint)}.</li>
* <li>Register any other extension to different points of the runtime (similarly to the annotation processor)</li>
* <li>Deploy any "system" components or ensembles</li>
* <li>Connect the metadata model to its plugin-related extensions (other EMF models)</li>
* <li>Register an extension via {@link AnnotationProcessor#addExtension(AnnotationProcessorExtensionPoint)}.</li>
* <li>Register any other extension to different points of the runtime (similarly to the annotation processor)</li>
* <li>Deploy any "system" components or ensembles</li>
* <li>Connect the metadata model to its plugin-related extensions (other EMF models)</li>
* </ul>
* </p>
*
* @param container main DEECo container that provides the necessary hooks to achieve the above extensions
*
* @param container
* main DEECo container that provides the necessary hooks to achieve the above extensions
*/
public void init(DEECoContainer container) throws PluginInitFailedException;
public void init(DEECoContainer container) throws PluginInitFailedException;
}
35 changes: 35 additions & 0 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/timer/BaseTimer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cz.cuni.mff.d3s.deeco.timer;

import java.util.HashSet;
import java.util.Set;

/**
* Shared base for common timer types. Implements basic timer behavior such as registering shutdown listeners.
*
* @author Vladimir Matena <matena@d3s.mff.cuni.cz>
*/
public abstract class BaseTimer implements Timer {
/**
* Timer shutdown listener
*/
private Set<ShutdownListener> shutdownListeners = new HashSet<>();

/**
* Registers new shutdown listener
*
* @param listener
* Shutdown listener to register
*/
public void addShutdownListener(ShutdownListener listener) {
shutdownListeners.add(listener);
}

/**
* Runs registered shutdown listeners
*/
public void runShutdownListeners() {
for (ShutdownListener listener : shutdownListeners) {
listener.onShutdown();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import cz.cuni.mff.d3s.deeco.runtime.DEECoContainer;

public class DiscreteEventTimer implements SimulationTimer {
public class DiscreteEventTimer extends BaseTimer implements SimulationTimer {

private static final String TERMINATION_EVENT_NAME = "termination_event";

Expand Down Expand Up @@ -41,6 +41,8 @@ public void at(long time) {
currentTime = eventTime.getTimePoint();
eventTime.getListener().at(currentTime);
}

runShutdownListeners();
}

/**
Expand Down
15 changes: 15 additions & 0 deletions jdeeco-core/src/cz/cuni/mff/d3s/deeco/timer/Timer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
import cz.cuni.mff.d3s.deeco.runtime.DEECoContainer;

public interface Timer extends CurrentTimeProvider {
/**
* Interface for timer shutdown listeners
*/
interface ShutdownListener {
void onShutdown();
}

/**
* Set next notification time for node
*
Expand Down Expand Up @@ -38,4 +45,12 @@ void notifyAt(long time, TimerEventListener listener, String eventName,
*/
void interruptionEvent(TimerEventListener listener, String eventName,
DEECoContainer node);

/**
* Adds timer shutdown listener
*
* Shutdown listeners are executed when the timer reaches its time limit
* or is stopped from some other reason.
*/
void addShutdownListener(ShutdownListener listener);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* @author Ilias Gerostathopoulos <iliasg@d3s.mff.cuni.cz>
* @author Dominik Skoda <skoda@d3s.mff.cuni.cz>
*/
public class WallTimeTimer implements RunnerTimer {
public class WallTimeTimer extends BaseTimer implements RunnerTimer {

protected final Queue<EventTime> eventTimes;
protected final Map<DEECoContainer, EventTime> containerEvents;
Expand Down Expand Up @@ -99,6 +99,8 @@ else if (nextTime != currentTime){
// Adjust the current time after the event execution
adjustCurrentTime();
}

runShutdownListeners();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import cz.cuni.mff.d3s.deeco.runtime.DEECoPlugin;
import cz.cuni.mff.d3s.deeco.scheduler.Scheduler;
import cz.cuni.mff.d3s.deeco.task.TimerTaskListener;
import cz.cuni.mff.d3s.deeco.timer.BaseTimer;
import cz.cuni.mff.d3s.deeco.timer.SimulationTimer;
import cz.cuni.mff.d3s.deeco.timer.TimerEventListener;
import cz.cuni.mff.d3s.jdeeco.matsim.dataaccess.MATSimDataProviderReceiver;
Expand Down Expand Up @@ -47,7 +48,7 @@ public OMNeTMATSimSimulation(String matsimConfig, AdditionAwareAgentSource... ag
}

/**
* Gets MATSim and OMNet dependencies
* Gets MATSim and OMNet dependencies
*/
@Override
public List<Class<? extends DEECoPlugin>> getDependencies() {
Expand Down Expand Up @@ -87,10 +88,10 @@ public Timer getTimer() {
* @author Vladimir Matena <matena@d3s.mff.cuni.cz>
*
*/
class Timer implements SimulationTimer {
class Timer extends BaseTimer implements SimulationTimer {
@Override
public void notifyAt(long time, TimerEventListener listener, DEECoContainer node) {
omnet.getTimer().notifyAt(time, listener, node);
public void notifyAt(long time, TimerEventListener listener, String eventName, DEECoContainer node) {
omnet.getTimer().notifyAt(time, listener, eventName, node);
}

@Override
Expand All @@ -102,6 +103,12 @@ public long getCurrentMilliseconds() {
public void start(long duration) {
OMNeTMATSimSimulation.this.runMATSim(duration);
omnet.getTimer().start(duration);
runShutdownListeners();
}

@Override
public void interruptionEvent(TimerEventListener listener, String eventName, DEECoContainer node) {
throw new UnsupportedOperationException("Interruption events are not supported");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
import cz.cuni.mff.d3s.deeco.task.TimerTaskListener;

public class SimulationStepTask extends TimerTask {

public SimulationStepTask(Scheduler scheduler, TimerTaskListener taskListener) {
this(scheduler, taskListener, 1);
}

public SimulationStepTask(Scheduler scheduler, TimerTaskListener taskListener, long delay) {
super(scheduler, taskListener, delay);
super(scheduler, taskListener, "StepTask", delay);
((TimeTrigger) this.trigger).setOrder(Integer.MIN_VALUE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import cz.cuni.mff.d3s.deeco.logging.Log;
import cz.cuni.mff.d3s.deeco.runtime.DEECoContainer;
import cz.cuni.mff.d3s.deeco.runtime.DEECoPlugin;
import cz.cuni.mff.d3s.deeco.timer.BaseTimer;
import cz.cuni.mff.d3s.deeco.timer.SimulationTimer;
import cz.cuni.mff.d3s.deeco.timer.TimerEventListener;
import cz.cuni.mff.d3s.jdeeco.matsim.dataaccess.MATSimDataProviderReceiver;
Expand All @@ -41,7 +42,7 @@
import cz.cuni.mff.d3s.jdeeco.matsim.simulation.MATSimPreloadingControler;
import cz.cuni.mff.d3s.jdeeco.matsim.simulation.MATSimRouter;
import cz.cuni.mff.d3s.jdeeco.matsim.simulation.MATSimSimulationStepListener;
import cz.cuni.mff.d3s.jdeeco.matsim.simulation.Simulation;
import cz.cuni.mff.d3s.jdeeco.matsim.simulation.SimulationUtils;

/**
* Plug-in providing MATSim simulation
Expand Down Expand Up @@ -120,8 +121,8 @@ public void notifyStartup(StartupEvent event) {
}
}

simulationStep = Timer.secondsToMilliseconds(step);
currentMilliseconds = Timer.secondsToMilliseconds(controler.getConfig().getQSimConfigGroup().getStartTime());
simulationStep = SimulationUtils.secondsToMilliseconds(step);
currentMilliseconds = SimulationUtils.secondsToMilliseconds(controler.getConfig().getQSimConfigGroup().getStartTime());

router = new MATSimRouter(controler, travelTime, 10 /* TODO: FAKE VALUE */);
}
Expand Down Expand Up @@ -179,7 +180,7 @@ private void run(long duration) {
* @author Vladimir Matena <matena@d3s.mff.cuni.cz>
*
*/
public class Timer extends Simulation implements SimulationTimer, MATSimSimulationStepListener {
public class Timer extends BaseTimer implements SimulationUtils, SimulationTimer, MATSimSimulationStepListener {
private final TreeSet<Callback> callbacks = new TreeSet<>();
private final Map<Integer, Callback> hostIdToCallback = new HashMap<>();

Expand Down Expand Up @@ -214,12 +215,13 @@ public long getCurrentMilliseconds() {
@Override
public void start(long duration) {
MATSimSimulation.this.run(duration);
runShutdownListeners();
}

@Override
public void at(double seconds, Mobsim mobsim) {
// Exchange data with MATSim
long milliseconds = secondsToMilliseconds(seconds);
long milliseconds = SimulationUtils.secondsToMilliseconds(seconds);
matSimReceiver.setMATSimData(extractor.extractFromMATSim(listener.getAllJDEECoAgents(), mobsim));
listener.updateJDEECoAgents(matSimProvider.getMATSimData());
// Add callback for the MATSim step
Expand All @@ -235,7 +237,7 @@ public void at(double seconds, Mobsim mobsim) {
currentMilliseconds = callback.getAbsoluteTime();
// System.out.println("At: " + currentMilliseconds);
host = hosts.get(callback.hostId);
host.at(millisecondsToSeconds(currentMilliseconds));
host.at(SimulationUtils.millisecondsToSeconds(currentMilliseconds));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import cz.cuni.mff.d3s.deeco.timer.CurrentTimeProvider;

public abstract class Simulation implements CurrentTimeProvider,
public abstract interface SimulationUtils extends CurrentTimeProvider,
CallbackProvider {

protected static final int MILLIS_IN_SECOND = 1000;
static final int MILLIS_IN_SECOND = 1000;

public static double millisecondsToSeconds(long time) {
return time * 1.0 / MILLIS_IN_SECOND;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public void interruptionEvent(TimerEventListener listener, String eventName,
DEECoContainer node) {
throw new UnsupportedOperationException("Fake timer does not support interruptionEvent");
}

@Override
public void addShutdownListener(ShutdownListener listener) {
throw new UnsupportedOperationException("Fake timer does not support shutdown");
}
};
}

Expand Down
Loading

0 comments on commit ac6fd83

Please sign in to comment.