/*
* Dateiname: SimulationTime.java
* Autor(en): Lukas König
* Java-Version: 6
* Erstellt (vor): 14.05.2009
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.simulation;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import eas.miscellaneous.StaticMethods;
import eas.miscellaneous.system.windowFrames.GeneralDialog;
import eas.plugins.Plugin;
import eas.plugins.masterScheduler.MasterScheduler;
import eas.simulation.event.ConstantEventFilterTrue;
import eas.simulation.event.EASEvent;
import eas.simulation.event.EventFilter;
import eas.startSetup.GlobalVariables;
import eas.startSetup.ParCollection;
/**
* Implementation of the simulation engine.
*
* Note that the terms 'plugin' and 'scheduler' are used synonymously. The
* master scheduler is a special type of plugin.
*
* @author Lukas König
*/
public class SimulationTime<RunnableType extends EASRunnable> implements Runnable, Serializable {
/**
* Serialization ID as of 27 May 2014.
*/
private static final long serialVersionUID = -5072984671932777494L;
/**
* The parameters of this simulation run.
*/
private ParCollection pars;
/**
* Simulation time passed so far.
*/
private Wink currentTime;
/**
* Flag that states if the simulation should stop at the next possible
* point.
*/
private boolean stopSim;
/**
* List of plugin objects to manipulate simulation. First plugin is master
* scheduler.
*/
private LinkedList<Plugin<?>> plugins;
/**
* The environment being simulated.
*/
private RunnableType runnable;
// /**
// * The thread for the simulation time to run in.
// */
// private Thread simThread;
/**
* If ticks are requested by any plugin.
*/
private boolean isRequestedTicks;
/**
* For every plugin the information if ticks are requested or not.
*/
private HashMap<Plugin<?>, Boolean> requestedTicks
= new HashMap<Plugin<?>, Boolean>();
/**
* For requested notification time the plugin that requested it.
* Keys are sorted.
*/
private TreeMap<Double, LinkedList<Plugin<?>>> requestedNotif
= new TreeMap<Double, LinkedList<Plugin<?>>>();
/**
* Set of plugins that are notified at all notifications that
* occur for any other plugin - NOT at events.
* This influences only the invokation of the method runDuringSim.
* The plugins in this set are invoked AFTER the invokation of other
* plugins at the same time step.
* Note: plugins that have already been invoked at a time step are not invoked
* in the same time step for a second time.
*/
private HashSet<Plugin<?>> toBeNotifiedAtAllNotifications
= new HashSet<Plugin<?>>();
/**
* A list of all plugins that are requesting events. Every plugin is
* assigned to an event filter deciding if the plugin should be notified
* for a specific event broadcast.
*/
private HashMap<Plugin<?>, EventFilter> eventRequestingPlugins;
/**
* Konstruktor, benutzt von Starterklasse während der Simulation.
*
* @param params Die Parameter für den Lauf.
* @param plug Plugin-Objekte, die in jedem Zyklus die Simulation
* beeinflussen können.
*/
public SimulationTime(
final RunnableType env,
final LinkedList<Plugin<?>> plug,
final ParCollection params) {
this.pars = params;
this.plugins = plug;
if (this.plugins != null) {
for (Plugin<?> p : this.plugins) {
this.requestTicks(p);
}
}
this.eventRequestingPlugins = new HashMap<Plugin<?>, EventFilter>();
this.runnable = env;
this.reset();
this.checkRequiredPlugins();
}
/**
* Resets the simulation time to the beginning.
*/
public void reset() {
this.stopSim = false;
// A negative currentTime indicates a simulation before the start of time.
this.currentTime = new Wink(-1, true, this);
StaticMethods.log(
StaticMethods.LOG_INFO,
"<SimulationTime> Simulation time has been set to the initial state.",
this.pars);
}
/**
* Runs the complete simulation cycle.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void run() {
StaticMethods.log(
StaticMethods.LOG_INFO,
"<SimulationTime> Course of time started for runnable " + this.runnable.id() + ".",
this.pars);
if (this.simulationResumed) {
// Starting the plugin method to resume simulation.
for (Plugin p : this.plugins) {
try {
this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> resuming plugin '" + p.id() + "'...");
if (!this.neverNotify.contains(p)) {
p.onSimulationResumed(this.runnable, this.currentTime, this.pars);
}
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
}
} else {
// Starting the plugin method before Simulation.
for (Plugin p : this.plugins) {
try {
if (!this.neverNotify.contains(p)) {
runBeforeSimulation(p);
}
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
}
}
boolean fortsetzen = this.setNextNotificationTime();
// Main loop generating time and event notifications for plugins.
while (fortsetzen) {
// while (this.globalPause) {
// try {Thread.sleep(100);} catch (InterruptedException e) {}
// }
this.step();
fortsetzen = this.setNextNotificationTime();
this.simulationResumed = false;
}
// Starting the plugin after Simulation.
for (Plugin p : this.plugins) {
try {
this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> finalizing plugin '" + p.id() + "'...");
if (!this.neverNotify.contains(p)) {
p.runAfterSimulation(this.runnable, this.pars);
}
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
}
StaticMethods.log(
StaticMethods.LOG_INFO,
"<SimulationTime> Course of time ended for runnable " + this.runnable.id() + ".",
this.pars);
this.timeTerminated = true;
}
@SuppressWarnings("unchecked")
public void runBeforeSimulation(@SuppressWarnings("rawtypes") Plugin p) {
this.pars.log(StaticMethods.LOG_INFO, "<SimulationTime> initializing plugin '" + p.id() + "'...");
p.runBeforeSimulation(this.runnable, this.pars);
}
private boolean timeTerminated = false;
/**
* @return Returns the timeFinished.
*/
public boolean isTimeTerminated() {
return this.timeTerminated;
}
/**
* Checks if all (by any plugin) required plugins are existing and throws
* a RuntimeException if some are missing.
*/
private void checkRequiredPlugins() {
boolean gefunden;
if (this.plugins == null) {
return;
}
for (Plugin<?> p : this.plugins) {
if (p.getRequiredPlugins() != null) {
for (String prStr : p.getRequiredPlugins()) {
gefunden = false;
for (Plugin<?> p2 : this.plugins) {
if (prStr.equals(p2.id())) {
gefunden = true;
break;
}
}
if (!gefunden) {
throw new RuntimeException(
"Plugin '" + p.id()
+ "' requires plugin(s) '" + prStr
+ "' which could not be found.");
}
}
}
}
}
/**
* Sets the current time to the next time step that is relevant for
* notifications if there exists such a time step within simulation
* time. If the flag stopSim is true, nothing is done and
* <code>false</code> is returned.
*
* @return Returns <code>true</code> as long as some plugin is still to
* be notified, <code>false</code> otherwise.
*/
private boolean setNextNotificationTime() {
if (!this.stopSim &&
(this.isRequestedTicks || this.requestedNotif.size() > 0)) {
long nextTick = this.currentTime.getLastTick() + 1;
double nextNot = Double.POSITIVE_INFINITY;
if (this.requestedNotif.size() > 0) {
nextNot = this.requestedNotif.firstKey();
}
// Do nothing if time is terminated.
if (this.getMasterScheduler().isTerminationRequested(this.runnable, this.currentTime, this.pars)) {
return false;
}
if (this.isRequestedTicks && nextTick < nextNot) {
// isTick wird automatisch gesetzt.
this.currentTime.nextTick();
} else {
this.currentTime.setCurrentTime(nextNot);
this.currentTime.setTick(false);
}
return true;
}
return false;
}
/**
* The plugins that have to be notified in the current time step are
* notified. If there are notifications left to do within simulation time,
* the current simulation time is set to the next time step that is
* associated to a notification; otherwise, <code>false</code> is returned
* meaning that the simulation should be stopped. Note that
*
* @return Returns <code>true</code> as long as some plugin is still to
* be notified, <code>false</code> otherwise.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void step() {
HashSet<Plugin<?>> invoked = new HashSet<Plugin<?>>();
if (this.currentTime.isTick()) {
for (Plugin p : this.plugins) {
if (this.requestedTicks.get(p)) {
try {
p.runDuringSimulation(
this.runnable,
this.currentTime,
this.pars);
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
invoked.add(p);
}
}
} else { // Time step is no tick, i.e. a requested notification.
for (Plugin p : this.requestedNotif.get(
this.currentTime.getCurrentTime())) {
try {
p.runDuringSimulation(
this.runnable,
this.currentTime,
this.pars);
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
invoked.add(p);
}
this.requestedNotif.remove(this.currentTime.getCurrentTime());
}
/*
* Invoke all plugins that want to be notified every time anything
* happens.
*/
if (invoked.size() > 0) {
for (Plugin p : this.toBeNotifiedAtAllNotifications) {
if (!invoked.contains(p)) {
try {
p.runDuringSimulation(
this.runnable,
this.currentTime,
this.pars);
} catch (Exception e) {
// Handle uncaught exception.
this.handleExceptionInMainLoop(e, p);
}
}
}
}
/*
* Register new waiting plugins.
*/
for (Plugin p : this.pluginsToRegisterAfterExecutionOfCurrentStep) {
registerPluginSynchronized(p);
}
this.plugins.addAll(this.pluginsToRegisterAfterExecutionOfCurrentStep);
this.pluginsToRegisterAfterExecutionOfCurrentStep.clear();
}
private boolean ignoreAllExceptions = false;
/**
* Handles cases where an uncaught exception occurred in a plugin
* / scheduler.
*
* @param e The uncaught exception.
* @param p The plugin / scheduler that caused the exception.
*/
private void handleExceptionInMainLoop(Exception e, Plugin<?> p) {
String time = "" + this.currentTime.getCurrentTime();
if (ignoreAllExceptions) {
return;
}
if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_ASK_WHAT_TO_DO)) {
ArrayList<String> buttons = new ArrayList<String>(10);
buttons.add("Ignore");
buttons.add("Ignore all");
buttons.add("Log and ignore all");
if (!this.getMasterScheduler().id().equals(p.id())) {
buttons.add("Remove Plugin '" + p.id() + "'");
}
buttons.add("Terminate");
buttons.add("Halt immediately!");
buttons.add("Throw exception!");
GeneralDialog dia = new GeneralDialog(
null,
null,
"Handle uncaught exception at time step " + time + ".",
buttons,
"The plugin \n'"
+ p.id()
+ "'\nhas caused an exception that has been raised to the main simulation loop.\n\nDetails:\n"
+ e.toString()
+ "\nat "
+ Arrays.deepToString(e.getStackTrace()).replace('[', '\n').replace(']', '\n').replace(',', '\n'));
dia.setVisible(true);
if (dia.getResult().equals("Throw exception!")) {
throw new RuntimeException(e);
}
if (dia.getResult().equals("Halt immediately!")) {
// Halt immediately.
StaticMethods.logInfo("User request: Simulation is being HALTED immediately. Goodbye!", this.pars);
System.exit(0);
} else if (dia.getResult().equals("Terminate")) {
// Terminate simulation immediately in a regular way.
StaticMethods.logInfo("User request: Simulation is being TERMINATED at end of current cycle.", this.pars);
this.timeTerminate();
} else if (dia.getResult().equals("Ignore all")) {
this.ignoreAllExceptions = true;
} else if (dia.getResult().equals("Log and ignore all")) {
this.pars.setActionOnUncaughtException(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_RECOVER);
} else if (dia.getResult().startsWith("Remove Plugin")) {
this.neverNotifyAgain(p);
StaticMethods.logInfo("User request: Scheduler '" + p.id() + "' has been removed from simulation.", this.pars);
} else {
StaticMethods.logInfo("User request: Course of time has recovered from an ancaught exception.", this.pars);
}
return;
}
// Do nothing.
if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_DO_NOTHING)) {
return;
}
String master = "";
if (p.id().equalsIgnoreCase(this.getMasterScheduler().id())) {
master = " (MASTER SCHEDULER)";
}
// Log message.
if (!this.pars.getActionOnUncaughtException().equalsIgnoreCase(ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_DO_NOTHING)) {
StaticMethods
.log(StaticMethods.LOG_ERROR,
"<SimulationTime> Main simulation loop caught at time step "
+ time
+ " an unhandled exception thrown by scheduler '"
+ p.id()
+ "'"
+ master
+ ": \n---\n"
+ e.toString()
+ "\nat "
+ Arrays.deepToString(e.getStackTrace())
.replace('[', '\n')
.replace(']', '\n')
.replace(',', '\n') + "---",
this.pars, "", e);
}
// Ignore plugin in future (except master scheduler).
if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_REMOVE_SCHEDULER_AND_RECOVER)) {
if (master.length() == 0) {
this.neverNotifyAgain(p);
StaticMethods.logInfo("<SimulationTime> Scheduler '" + p.id() + "' has been removed from simulation.", this.pars);
}
StaticMethods.logInfo("<SimulationTime> Course of time has recovered from an ancaught exception.", this.pars);
} else if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_TERMINATE)) {
// Terminate simulation immediately in a regular way.
StaticMethods.logInfo("<SimulationTime> Simulation is being TERMINATED at end of current cycle.", this.pars);
this.timeTerminate();
} else if (this.pars.getActionOnUncaughtException().equalsIgnoreCase(
ConstantsSimulation.ACTION_ON_UNCAUGHT_EXCEPTION_PRINT_AND_HALT)) {
// Halt immediately.
StaticMethods.logInfo("<SimulationTime> Simulation is being HALTED immediately. Goodbye!", this.pars);
System.exit(0);
} else {
StaticMethods.logInfo("<SimulationTime> Course of time has recovered from an ancaught exception.", this.pars);
}
}
/**
* @return Returns the environment.
*/
public EASRunnable getEnvironment() {
return this.runnable;
}
// /**
// * @return Returns the simThread.
// */
// public Thread getSimThread() {
// return this.simThread;
// }
private boolean simulationResumed = false;
public void resumeLoadedSimulation() {
this.pars.onSimulationResumed();
this.simulationResumed = true;
this.pars.logInfo("<SimulationTime> Resuming simulation '"
+ this.getEnvironment().getClass().getSimpleName().toString()
+ "' at time instant " + this.getCurrentTime() + ".");
this.timeStart();
}
/**
* Startet den Zeitablauf mit automatischem Weiterlaufen.
*/
public void timeStart() {
Thread simThread;
simThread = new Thread(this);
simThread.start();
}
/**
* Requests a termination of simulation time. This will occur in the next
*
*/
public void timeTerminate() {
this.stopSim = true;
}
/**
* @param id Der Name des Plugins.
*
* @return Das (erste) Plugin, das den Namen hat.
* null, falls es kein Plugin dieses Namens gibt.
*/
public Plugin<?> getPluginObject(final String id) {
if (this.plugins == null) {
return null;
}
for (Plugin<?> p : this.plugins) {
if (p.id().equals(id)) {
return p;
}
}
return null;
}
/**
* @return Returns the currentTime.
*/
public Wink getCurrentTime() {
return this.currentTime;
}
/**
* Gives a notification to the given Plugin at every tick from now on
* until the neglectTicks-method is called.
*
* @param requester The plugin that should be notified.
*/
public void requestTicks(final Plugin<?> requester) {
this.requestedTicks.put(requester, true);
this.isRequestedTicks = true;
}
/**
* Stops notifying the given plugin at every tick until the requestTicks-
* method is called.
*
* @param requester The plugin to ignore at ticks.
*/
public void neglectTicks(final Plugin<?> requester) {
this.requestedTicks.put(requester, false);
for (boolean b : this.requestedTicks.values()) {
if (b) {
return;
}
}
this.isRequestedTicks = false;
}
/**
* Requests a notification for the requesting plugin at a specific
* time step in the future. CAUTION! Note that time steps requested using
* this method are NOT CONSIDERED TICKS - even if they happen to point at
* a time simultaneous to a tick.
*
* @param requester The plugin to be notified.
* @param time The time of notification.
*/
public void requestNotification(
final Plugin<?> requester,
final double time) {
if (time <= this.currentTime.getCurrentTime()) {
return;
}
// if (time > this.pars.getExperimentLength()) {
// StaticMethods.log(
// StaticMethods.LOG_WARNING,
// "Requested notification time "
// + time + " (for " + requester.id() + ") "
// + "is greater than the total simulation time ("
// + this.pars.getExperimentLength() + ").",
// this.pars);
// }
if (time < 0) {
throw new RuntimeException("Requested notification time "
+ time + " (for " + requester.id()
+ ") is below 0.");
}
LinkedList<Plugin<?>> currList
= this.requestedNotif.get(time);
if (currList == null) {
currList = new LinkedList<Plugin<?>>();
this.requestedNotif.put(time, currList);
}
if (!currList.contains(requester)) {
currList.add(requester);
}
}
/**
* Gives a notification to this SimulationTime's master scheduler
* at every tick from now on until the neglectTicks-method is called.
*
* @param requester The plugin that should be notified.
*/
public void requestTicks() {
this.requestTicks(this.getMasterScheduler());
}
/**
* Stops notifying this SimulationTime's master scheduler
* at every tick until the requestTicks-method is called.
*
* @param requester The plugin to ignore at ticks.
*/
public void neglectTicks() {
this.neglectTicks(this.getMasterScheduler());
}
/**
* Requests a notification for this SimulationTime's master scheduler at
* a specific time step. CAUTION! Note that time steps requested using
* this method are NOT CONSIDERED TICKS - even if they happen to point at
* a time simultaneous to a tick.
*
* @param requester The plugin to be notified.
* @param time The time of notification.
*/
public void requestNotification(final double time) {
this.requestNotification(this.getMasterScheduler(), time);
}
/**
* Requests a notification for any time step a notification occurs in
* the simulation.
* This influences only the invokation of the method runDuringSim.
* The given plugin is invoked AFTER the invokation of other
* plugins at the same time step.
* Note: plugins that have been invoked at a time step are not invoked
* in the same time step a second time.
*
* @param requester The requesting plugin. Note that there is no separate
* method for the master scheduler as master schedulers
* typically will not need this functionality. If a
* master scheduler M should need this, the method can be
* invoked as requestAllNotifications(M).
*/
public void requestAllNotifications(final Plugin<?> requester) {
this.toBeNotifiedAtAllNotifications.add(requester);
}
/**
* Neglects notifications for all time steps a notification occurs in
* the simulation (cf. method requestAllNotifications).
*
* @param requester The neglecting plugin. Note that there is no separate
* method for the master scheduler as master schedulers
* typically will not need this functionality. If a
* master scheduler M should need this, the method can be
* invoked as requestAllNotifications(M).
*/
public void neglectAllNotifications(final Plugin<?> requester) {
this.toBeNotifiedAtAllNotifications.remove(requester);
}
public void requestAllNotifications() {
this.requestAllNotifications(this.getMasterScheduler());
}
public void neglectAllNotifications() {
this.neglectAllNotifications(this.getMasterScheduler());
}
private HashSet<Plugin<?>> neverNotify = new HashSet<Plugin<?>>();
/**
* Ignores the plugin for all future notifications including events. The
* plugin cannot recover by itself from this state. Another scheduler,
* however, can request future notifications for this scheduler.
*
* @param requester The scheduler (plugin) to be ignored.
*/
public void neverNotifyAgain(final Plugin<?> requester) {
this.neverNotify.add(requester);
this.neglectAllNotifications(requester);
this.neglectTicks(requester);
this.eventRequestingPlugins.remove(requester);
for (Double d : this.requestedNotif.keySet()) {
List<Plugin<?>> list = this.requestedNotif.get(d);
list.remove(requester);
}
}
/**
* @return This SimulationTime's master scheduler.
*/
@SuppressWarnings("unchecked")
public MasterScheduler<RunnableType> getMasterScheduler() {
return (MasterScheduler<RunnableType>) this.plugins.get(0);
}
/**
* Broadcasts the given event to all registered plugins.
*
* @param e The event causing the broadcast.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void broadcastEvent(final EASEvent e) {
for (Plugin p : this.eventRequestingPlugins.keySet()) {
if (eventRequestingPlugins.get(p).isAcceptable(e)) {
p.handleEvent(e, this.runnable, this.currentTime, this.pars);
}
}
}
/**
* Requests events for the specified plugin filtered by the specified
* event filter.
*
* @param plugin The plugin to be notified.
* @param filter The event filter.
*/
public void requestEvents(
final Plugin<?> plugin,
final EventFilter filter) {
this.eventRequestingPlugins.put(plugin, filter);
}
/**
* Requests events for the master scheduler filtered by the specified
* event filter.
*
* @param filter The event filter.
*/
public void requestEvents(final EventFilter filter) {
this.requestEvents(this.getMasterScheduler(), filter);
}
/**
* Requests ALL events for the specified plugin (filtered by the constant
* event filter <code>ConstantEventFilterTrue</code>).
*
* @param plugin The plugin to be notified.
*/
public void requestAllEvents(final Plugin<?> plugin) {
this.requestEvents(plugin, new ConstantEventFilterTrue());
}
/**
* Requests ALL events for the master scheduler (filtered by the constant
* event filter <code>ConstantEventFilterTrue</code>).
*/
public void requestAllEvents() {
this.requestEvents(new ConstantEventFilterTrue());
}
private LinkedList<Plugin<?>> pluginsToRegisterAfterExecutionOfCurrentStep = new LinkedList<>();
/**
* Add a plugin to the list of registered plugins. The plugin is put at
* the end of the list and therefore notified last. Ticks are automatically
* requested for the new plugin, and as a first action, the plugin's
* <code>runBeforeSimulation</code> method is called. Everything else has
* to be done from outside. (The complementary method to remove a plugin
* is called <code>neverNotifyAgain</code>.)
*
* @param plugin The plugin to register.
* @return If the plugin has been registered (if not, probably a required
* plugin is missing).
*/
public boolean registerPlugin(Plugin<?> plugin) {
if (plugin.getRequiredPlugins() != null) {
for (String pID : plugin.getRequiredPlugins()) {
boolean gefunden = false;
for (Plugin<?> p : this.plugins) {
if (pID.equals(p.id())) {
gefunden = true;
}
}
if (!gefunden) {
GlobalVariables.getPrematureParameters().logWarning(
"Plugin '" + plugin.id()
+ "' NOT registered as the required plugin '"
+ pID + "' is not registered.");
return false;
}
}
}
if (this.pluginsToRegisterAfterExecutionOfCurrentStep.size() == 0) {
this.pluginsToRegisterAfterExecutionOfCurrentStep.add(plugin);
return true;
} else {
GlobalVariables
.getPrematureParameters()
.logWarning(
"Plugin '"
+ plugin.id()
+ "' NOT registered because another plugin ('"
+ this.pluginsToRegisterAfterExecutionOfCurrentStep
.get(0).id()
+ "') is waiting to be registered.");
return false;
}
}
private void registerPluginSynchronized(@SuppressWarnings("rawtypes") Plugin plugin) {
this.pars.addPluginIncludingParameters(plugin.id());
this.requestTicks(plugin);
runBeforeSimulation(plugin);
}
/**
* Save the current simulation state to disc.
*
* @param f The path to store the simState.
*
* @return If the simState was successfully saved.
*/
public boolean serializeSimState(File f) {
try {
new SerializableSimulationState(this, f).save();
return true;
} catch (SimStateUnserializableException e) {
return false;
}
}
public LinkedList<Plugin<?>> getPlugins() {
return this.plugins;
}
public LinkedList<Plugin<?>> getAllSleepingPlugins() {
LinkedList<Plugin<?>> sleeping = new LinkedList<>();
for (Plugin<?> p : this.plugins) {
if (this.isPluginSleeping(p)) {
sleeping.add(p);
}
}
return sleeping;
}
private boolean isPluginSleeping(Plugin<?> p) {
return this.neverNotify.contains(p) && this.eventRequestingPlugins.get(p) == null;
}
// private boolean globalPause = false;
//
// /**
// * Pauses the simulation at the core of the main simulation cycle.
// *
// * @param globalPause Activate (true) or deactivate (false) global pause.
// */
// public void setGlobalPause(boolean globalPause) {
// this.globalPause = globalPause;
// }
}