7.5 KiB
javafx-runtime-service Specification
Purpose
TBD - created by archiving change 80-introduce-javafx-runtime-service. Update Purpose after archive.
Requirements
Requirement: JavaFX runtime service separates use from lifecycle
com.r35157.service.javafx.JavaFxRuntimeService SHALL be a public NenjimComponent interface exposing exactly void runLater(@NotNull Runnable runnable) and no initialization, shutdown, restart, status, configuration, window-management, event, or lifecycle operation. com.r35157.service.javafx.impl.ref.JavaFxRuntimeServiceImpl SHALL implement both that service and the canonical NenjimProcess, so one object supplies the ordinary service view and the Hub-owned process view without a separate manager or administration interface.
Scenario: Consumer receives only the service view
- WHEN an ordinary JavaFX application receives a
JavaFxRuntimeService - THEN it can submit non-null JavaFX work but cannot start, stop, restart, configure, inspect, or administer the runtime through that API
Scenario: One implementation supplies both views
- WHEN one
JavaFxRuntimeServiceImplis registered once - THEN Registry lookup through
JavaFxRuntimeServiceandNenjimProcessreturns the identical object reference
Requirement: JavaFX runtime startup is one-attempt and complete
The implementation's start() SHALL be the only operation that calls Platform.startup(...). It SHALL accept only the first attempt, configure Platform.setImplicitExit(false) on the JavaFX startup callback, wait for that callback to complete successfully, and open service availability only before returning successfully. Every repeated attempt SHALL fail with IllegalStateException, including after first-attempt failure or interruption. A synchronous or callback initialization failure SHALL propagate with a clear service-startup diagnostic, leave the service unavailable, and SHALL not be retried, recovered, restarted, rolled back, or silently accepted as an externally initialized toolkit.
Scenario: First startup succeeds
- WHEN JavaFX startup invokes its callback and implicit exit is disabled successfully
- THEN
start()returns only after that callback completes and the service becomes available
Scenario: Startup callback has not completed
- WHEN
Platform.startup(...)has accepted initialization but its callback has not completed - THEN
start()has not returned successfully and task submission remains unavailable
Scenario: Startup fails
- WHEN toolkit initialization or callback configuration fails
- THEN
start()propagates a clear failure and the service remains unavailable without partial success
Scenario: Startup is repeated
- WHEN
start()is called after any earlier attempt began - THEN it fails with
IllegalStateExceptionwithout callingPlatform.startup(...)again
Scenario: Last window closes
- WHEN the last JavaFX window closes after successful service startup
- THEN disabled implicit exit keeps the shared JavaFX runtime alive for later submitted work
Requirement: JavaFX task submission is non-null gated and asynchronous
runLater(...) SHALL reject null with NullPointerException. Before successful startup and after failed startup it SHALL reject every non-null task with IllegalStateException without initializing, starting, or retrying JavaFX and without executing the task. After successful startup it SHALL submit the exact task through Platform.runLater(...) and SHALL never execute it synchronously on the caller's thread. Acceptance SHALL make no guarantee that application UI work completes successfully, and exceptions raised by that work SHALL not change the completed runtime startup milestone.
Scenario: Null task is submitted
- WHEN
runLater(null)is called in any service state - THEN it fails with
NullPointerExceptionidentifying the null task
Scenario: Task is submitted before successful startup
- WHEN a caller submits a non-null task before
start()succeeds or after its failure - THEN submission fails with
IllegalStateExceptionwithout any JavaFX initialization or synchronous task execution
Scenario: Task is accepted after startup
- WHEN a non-null task is submitted after successful startup
- THEN the service passes it to
Platform.runLater(...)for asynchronous execution on the JavaFX Application Thread
Scenario: Application task fails
- WHEN accepted UI work later throws on the JavaFX Application Thread
- THEN that remains an application failure and does not convert the service's successful startup into a runtime startup failure
Requirement: Modern JavaFX consumers require the shared service
EvelynMissionControlImpl, NenjimProcessManagerImpl, NenjimComposerImpl, NenjimTestToolImpl, SodaTaskManagerImpl, and SuwimoClientImpl SHALL each require, reject null for, retain, and use a constructor-injected JavaFxRuntimeService for JavaFX Application Thread submission. No compatibility constructor, static fallback, direct Platform.startup(...), lazy initialization helper, or competing initialization flag SHALL remain in the modern component graph. Direct ordinary JavaFX UI API use inside application code SHALL remain valid.
Scenario: Consumer dependency is null
- WHEN any modern JavaFX implementation is constructed with a null runtime service
- THEN construction fails with
NullPointerException
Scenario: Consumer starts UI work
- WHEN any modern JavaFX consumer requests window creation or JavaFX publication
- THEN it submits through its retained service and neither initializes JavaFX nor falls back to static behavior
Scenario: Static initialization path is inspected
- WHEN modern source is searched after migration
- THEN
com.r35157.libs.javafx.JavaFxRuntimeis absent and onlyJavaFxRuntimeServiceImpl.start()callsPlatform.startup(...)
Requirement: Deferred JavaFX runtime features remain absent
The JavaFX runtime service SHALL represent one JVM-wide toolkit and SHALL not implement multiple toolkits, headless emulation, toolkit replacement, shutdown, stop, restart, recovery, supervision, health monitoring, runtime status queries, window discovery or management, configuration, Context resolution, automatic dependency discovery/startup, lifecycle events, or subscriptions. Hub configuration MAY select the JavaFX runtime and applications only through explicit known process IDs in dependency-safe order; it SHALL not add configuration to the JavaFX service API. A valid headless Hub configuration MAY omit the runtime and every JavaFX application, in which case the Hub SHALL not construct or initialize the JavaFX runtime.
Scenario: Configured JavaFX consumers follow runtime startup
- WHEN a valid Hub configuration selects JavaFX applications
- THEN it lists
nenjim.javafx-runtime.servicebefore those applications and the shared runtime is started before they submit UI work
Scenario: Headless configuration omits JavaFX
- WHEN a valid Hub configuration omits the JavaFX runtime and all JavaFX applications
- THEN no JavaFX runtime or application process is constructed and the JavaFX toolkit remains uninitialized by Hub startup
Scenario: Runtime boundary is inspected
- WHEN the delivered service, process implementation, Hub integration, and application constructors are examined
- THEN only explicit one-time runtime startup, asynchronous task submission, configuration-ordered dependency injection, and optional omission are present