Class SimulationEngine
This engine is MDI-agnostic: it has no dependency on any MDI view class.
Views and other UI components participate by subscribing as
SimulationListeners.
Threading model
- The simulation thread runs
Simulation.init(edu.cnu.mdi.sim.SimulationContext),Simulation.step(edu.cnu.mdi.sim.SimulationContext),Simulation.cancel(edu.cnu.mdi.sim.SimulationContext), andSimulation.shutdown(edu.cnu.mdi.sim.SimulationContext)— all computation stays on this thread. - Every
SimulationListenercallback is posted to the EDT viaSwingUtilities.invokeLater(java.lang.Runnable). It is therefore safe to update Swing components directly inside listener methods. - EDT-to-engine control signals (
requestPause,requestStop, etc.) are written asvolatileflags and observed on the simulation thread without further synchronization.
State machine
The engine progresses through SimulationState values in order.
The normal-completion path is:
NEW → INITIALIZING → READY → RUNNING → TERMINATING → TERMINATED
Pause/resume loops inside RUNNING without changing the path.
Cancellation reaches TERMINATED via the same terminal steps, but
SimulationListener.onDone(edu.cnu.mdi.sim.SimulationContext) is not fired — only
SimulationListener.onCancelRequested(edu.cnu.mdi.sim.SimulationContext) and the TERMINATED
state-change callback are delivered.
EDT coalescing
High-frequency data (refresh, progress, messages) is coalesced so that at most one pending task of each type is queued on the EDT at any moment. This prevents the EDT queue from backing up when the simulation thread runs faster than the UI can drain it.
Control
Supports pause/resume, stop, and cooperative cancel. Cancellation is
observed by the simulation via
SimulationContext.isCancelRequested().
-
Constructor Summary
ConstructorsConstructorDescriptionSimulationEngine(Simulation simulation, SimulationEngineConfig config) Create a new engine for the given simulation and configuration. -
Method Summary
Modifier and TypeMethodDescriptionvoidaddListener(SimulationListener listener) Add a simulation listener.booleanawaitTermination(long timeoutMillis) Wait for the engine thread to finish.Return the immutable engine configuration.Return theSimulationContextshared with the simulation.Return theSimulationplugin running inside this engine.getState()Return the current engine state.voidpostMessage(String message) Post a status message to listeners (coalesced).voidpostProgress(ProgressInfo info) Post a progress update to listeners (coalesced).voidremoveListener(SimulationListener listener) Remove a simulation listener.voidRequest cooperative cancellation.voidRequest that the engine pause at the next safe point.voidRequest a UI refresh (coalesced).voidRequest that the engine resume fromSimulationState.PAUSED, or begin running fromSimulationState.READYwhenautoRun == false.voidAlias forrequestResume().voidRequest a normal stop.voidstart()Start the simulation engine on a dedicated daemon thread.
-
Constructor Details
-
SimulationEngine
Create a new engine for the given simulation and configuration.- Parameters:
simulation- the computation plugin; must not benullconfig- engine configuration; must not benull- Throws:
NullPointerException- if either argument isnull
-
-
Method Details
-
addListener
Add a simulation listener.Safe to call from any thread. If
listenerisnullit is silently ignored. Registering the same listener instance more than once has no additional effect.- Parameters:
listener- the listener to add
-
removeListener
Remove a simulation listener.Safe to call from any thread. If
listeneris not currently registered this is a no-op.- Parameters:
listener- the listener to remove
-
getState
Return the current engine state.The state is written on the simulation thread and read here without a lock; the
volatilefield guarantees visibility. Treat the returned value as a snapshot — it may change immediately after this call returns.- Returns:
- the current
SimulationState; nevernull
-
start
public void start()Start the simulation engine on a dedicated daemon thread.This method is idempotent: if the engine has already been started, the call is a no-op. The engine thread is a daemon so that it does not prevent JVM shutdown if the application exits while a simulation is running.
-
requestPause
public void requestPause()Request that the engine pause at the next safe point.The simulation thread observes this flag at the top of each loop iteration and transitions to
SimulationState.PAUSED. This method returns immediately; callers that need to know when the pause has taken effect should observeSimulationListener.onPause(edu.cnu.mdi.sim.SimulationContext). -
requestResume
public void requestResume()Request that the engine resume fromSimulationState.PAUSED, or begin running fromSimulationState.READYwhenautoRun == false. -
requestRun
public void requestRun()Alias forrequestResume().Provided so that call sites that conceptually "start running" read more naturally than those that "resume".
-
requestStop
public void requestStop()Request a normal stop.The engine exits its step loop at the next iteration boundary, calls
Simulation.shutdown(edu.cnu.mdi.sim.SimulationContext), transitions toSimulationState.TERMINATED, and firesSimulationListener.onDone(edu.cnu.mdi.sim.SimulationContext). -
requestCancel
public void requestCancel()Request cooperative cancellation.Sets the cancellation flag in the
SimulationContext(observable viaSimulationContext.isCancelRequested()) and firesSimulationListener.onCancelRequested(edu.cnu.mdi.sim.SimulationContext)on the EDT immediately. The simulation thread observes the flag at the top of its next loop iteration, callsSimulation.cancel(edu.cnu.mdi.sim.SimulationContext)and thenSimulation.shutdown(edu.cnu.mdi.sim.SimulationContext), and transitions toSimulationState.TERMINATED.Note:
SimulationListener.onDone(edu.cnu.mdi.sim.SimulationContext)is not fired after a cancel. Cancellation is communicated solely viaonCancelRequestedand theTERMINATEDstate-change callback (withreason="cancelled"). -
requestRefresh
public void requestRefresh()Request a UI refresh (coalesced).If a refresh is already pending on the EDT this call is a no-op, preventing the EDT queue from accumulating stale refresh tasks when the simulation thread runs faster than the UI.
-
postProgress
Post a progress update to listeners (coalesced).If a progress event is already pending the new
inforeplaces the queued payload — the EDT will deliver the most recent value rather than every intermediate one. This is appropriate for smooth progress bars where skipping intermediate percentages is acceptable.- Parameters:
info- the non-null progress payload- Throws:
NullPointerException- ifinfois null
-
postMessage
Post a status message to listeners (coalesced).If a message event is already pending the new message replaces the queued one. This is appropriate for transient status text where only the most recent value matters.
- Parameters:
message- the non-null message text- Throws:
NullPointerException- ifmessageis null
-
getSimulation
Return theSimulationplugin running inside this engine.- Returns:
- the simulation; never
null
-
getConfig
Return the immutable engine configuration.- Returns:
- the configuration; never
null
-
getContext
Return theSimulationContextshared with the simulation.- Returns:
- the context; never
null
-
awaitTermination
Wait for the engine thread to finish.- Parameters:
timeoutMillis- maximum time to wait; zero waits indefinitely- Returns:
trueif the thread has finished (or was never started)- Throws:
InterruptedException- if the waiting thread is interruptedIllegalArgumentException- iftimeoutMillisis negative
-