Class SimulationEngine

java.lang.Object
edu.cnu.mdi.sim.SimulationEngine

public final class SimulationEngine extends Object
A state-machine-driven simulation engine that runs computation on a dedicated background thread and delivers all UI callbacks on the Swing/AWT Event Dispatch Thread (EDT).

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

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 Details

    • SimulationEngine

      public SimulationEngine(Simulation simulation, SimulationEngineConfig config)
      Create a new engine for the given simulation and configuration.
      Parameters:
      simulation - the computation plugin; must not be null
      config - engine configuration; must not be null
      Throws:
      NullPointerException - if either argument is null
  • Method Details

    • addListener

      public void addListener(SimulationListener listener)
      Add a simulation listener.

      Safe to call from any thread. If listener is null it is silently ignored. Registering the same listener instance more than once has no additional effect.

      Parameters:
      listener - the listener to add
    • removeListener

      public void removeListener(SimulationListener listener)
      Remove a simulation listener.

      Safe to call from any thread. If listener is not currently registered this is a no-op.

      Parameters:
      listener - the listener to remove
    • getState

      public SimulationState getState()
      Return the current engine state.

      The state is written on the simulation thread and read here without a lock; the volatile field guarantees visibility. Treat the returned value as a snapshot — it may change immediately after this call returns.

      Returns:
      the current SimulationState; never null
    • 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 observe SimulationListener.onPause(edu.cnu.mdi.sim.SimulationContext).

    • requestResume

      public void requestResume()
      Request that the engine resume from SimulationState.PAUSED, or begin running from SimulationState.READY when autoRun == false.
    • requestRun

      public void requestRun()
      Alias for requestResume().

      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 to SimulationState.TERMINATED, and fires SimulationListener.onDone(edu.cnu.mdi.sim.SimulationContext).

    • requestCancel

      public void requestCancel()
      Request cooperative cancellation.

      Sets the cancellation flag in the SimulationContext (observable via SimulationContext.isCancelRequested()) and fires SimulationListener.onCancelRequested(edu.cnu.mdi.sim.SimulationContext) on the EDT immediately. The simulation thread observes the flag at the top of its next loop iteration, calls Simulation.cancel(edu.cnu.mdi.sim.SimulationContext) and then Simulation.shutdown(edu.cnu.mdi.sim.SimulationContext), and transitions to SimulationState.TERMINATED.

      Note: SimulationListener.onDone(edu.cnu.mdi.sim.SimulationContext) is not fired after a cancel. Cancellation is communicated solely via onCancelRequested and the TERMINATED state-change callback (with reason="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

      public void postProgress(ProgressInfo info)
      Post a progress update to listeners (coalesced).

      If a progress event is already pending the new info replaces 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 - if info is null
    • postMessage

      public void postMessage(String message)
      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 - if message is null
    • getSimulation

      public Simulation getSimulation()
      Return the Simulation plugin running inside this engine.
      Returns:
      the simulation; never null
    • getConfig

      public SimulationEngineConfig getConfig()
      Return the immutable engine configuration.
      Returns:
      the configuration; never null
    • getContext

      public SimulationContext getContext()
      Return the SimulationContext shared with the simulation.
      Returns:
      the context; never null
    • awaitTermination

      public boolean awaitTermination(long timeoutMillis) throws InterruptedException
      Wait for the engine thread to finish.
      Parameters:
      timeoutMillis - maximum time to wait; zero waits indefinitely
      Returns:
      true if the thread has finished (or was never started)
      Throws:
      InterruptedException - if the waiting thread is interrupted
      IllegalArgumentException - if timeoutMillis is negative