The current Nenjim runtime contains several JavaFX-based applications:
EvelynMissionControlImpl
NenjimProcessManagerImpl
NenjimComposerImpl
NenjimTestToolImpl
SodaTaskManagerImpl
SuwimoClientImpl
They currently depend on the static utility:
com.r35157.libs.javafx.JavaFxRuntime
Calling:
JavaFxRuntime.runLater(runnable);
implicitly initializes the JVM-wide JavaFX toolkit on first use and then submits the task to the JavaFX Application Thread.
This hides an active shared lifecycle behind a static helper. A JavaFX application can therefore start the common JavaFX runtime merely by attempting to submit a UI task, without the runtime being represented as a component, registered in the Nenjim Registry, started by NenjimHub, or visible through the Hub's started-process snapshot.
Issues #77 through #79 established the opposite architectural direction:
NenjimHub owns the runtime object graph and process lifecycle.
Active components implement the canonical NenjimProcess.
Shared dependencies are represented explicitly and supplied through constructor injection.
The Registry describes constructed components.
The Hub's started-process snapshot describes successful startup milestones.
The shared JavaFX runtime shall follow the same model.
Goal
Replace the implicitly initialized static JavaFX helper with one explicit JavaFxRuntimeService.
The service shall:
Represent the single JavaFX toolkit shared by JavaFX applications in the JVM.
Be constructed, registered, and started by NenjimHub.
Initialize JavaFX only through its Hub-managed NenjimProcess.start() lifecycle.
Provide JavaFX applications with access to the JavaFX Application Thread.
Reject task submission until startup has completed successfully.
Be injected explicitly into every modern consumer that currently uses JavaFxRuntime.
Appear in the Hub's started-process snapshot after successful startup.
This issue shall remove the hidden JavaFX startup path completely.
Terminology
The JVM-wide facility initialized through javafx.application.Platform is referred to as the JavaFX runtime or JavaFX toolkit.
JavaFX UI work executes on the JavaFX Application Thread.
JavaFxRuntimeService owns initialization of the shared runtime and submission of work to the JavaFX Application Thread. It does not abstract or replace the JavaFX UI APIs themselves.
The service interface shall not extend NenjimProcess.
Ordinary consumers receive only the service view and can submit JavaFX work after the service is active. They shall not receive lifecycle control through the service API.
The API shall expose no initialization, shutdown, restart, status, window-management, event, or configuration operations.
The reference implementation shall implement both:
JavaFxRuntimeServiceNenjimProcess
The same object shall therefore provide:
A registered service view for JavaFX consumers.
A Hub-owned process view for lifecycle startup.
No separate service-manager or administration interface is required.
Lifecycle
The reference implementation's start() operation shall be the only operation that initializes the JavaFX runtime.
Successful startup shall:
Initialize the JavaFX toolkit through Platform.startup(...).
Configure Platform.setImplicitExit(false).
Ensure the toolkit is ready to accept submitted work before start() returns.
Return only after the JavaFX runtime has reached its successful startup milestone.
The first startup attempt shall be the only accepted attempt.
A repeated start() call shall fail with IllegalStateException, including when the first startup attempt failed.
If JavaFX initialization fails, start() shall propagate a clear failure to the Hub. The service shall remain unusable and shall not expose a partially successful state.
The service shall not attempt to recover, restart JavaFX, or silently accept a JavaFX toolkit initialized outside the service.
This issue assumes one successfully started JavaFX runtime service per JVM.
Task submission
After successful startup:
javaFxRuntimeService.runLater(runnable);
shall submit the supplied task to the JavaFX Application Thread through Platform.runLater(...).
runLater(...) shall:
Reject null with a clear NullPointerException.
Fail with IllegalStateException before successful service startup.
Fail with IllegalStateException after a failed startup attempt.
Never initialize JavaFX implicitly.
Never start or retry the service.
Never execute the supplied task synchronously on the caller's thread.
Acceptance of a task for submission does not guarantee that the task itself will complete successfully. Exceptions raised by application UI work remain application failures and shall not be converted into JavaFX runtime startup failures.
Hub integration
NenjimHubImpl shall construct exactly one JavaFxRuntimeServiceImpl for its current runtime graph.
The Hub shall register the service under:
nenjim.javafx-runtime.service
The registration shall expose the same object through both JavaFxRuntimeService and NenjimProcess, following the existing Registry interface-indexing rules.
The Hub shall start the service through the same process-start mechanism used for other registered NenjimProcess instances.
The JavaFX runtime service shall be started before every currently enabled JavaFX application, including:
evelyn.mission-control.default
nenjim.process-manager.default
The Hub shall record:
nenjim.javafx-runtime.service
in its started-process snapshot only after the service's start() operation returns successfully.
If JavaFX runtime startup fails, Hub startup shall remain fail-fast and no dependent JavaFX process shall be started.
The current hardcoded Hub startup sequence remains in use in this issue. NenjimHub.conf and configurable autorun are separate future work.
Consumer migration
Every modern class that currently uses the static JavaFxRuntime utility shall receive a non-null JavaFxRuntimeService through constructor injection.
This applies to:
EvelynMissionControlImpl
NenjimProcessManagerImpl
NenjimComposerImpl
NenjimTestToolImpl
SodaTaskManagerImpl
SuwimoClientImpl
Each consumer shall:
Require the service through its constructor.
Validate the dependency as non-null.
Retain the supplied service.
Use that service for JavaFX Application Thread submission.
Never initialize the JavaFX toolkit itself.
Never use a static fallback when the dependency is absent or inactive.
The Hub shall inject the same JavaFxRuntimeService instance into the active Mission Control and Process Manager instances.
Dormant modern JavaFX classes shall also be migrated so that the repository contains one coherent JavaFX runtime model even when those classes are not currently constructed by the active Hub.
No backward-compatible constructor that recreates or hides the old static behaviour shall be retained.
Direct use of ordinary JavaFX UI types remains valid inside JavaFX applications. This issue centralizes runtime initialization and Application Thread submission; it does not attempt to wrap the complete JavaFX API.
Removal of the static utility
Remove:
com.r35157.libs.javafx.JavaFxRuntime
after all modern consumers have been migrated.
No modern source shall continue to:
Import JavaFxRuntime.
Call its static runLater(...).
Call Platform.startup(...) directly.
Lazily initialize the JavaFX toolkit through another helper.
Maintain a competing JavaFX initialization flag.
Legacy prototype code outside the modern component graph shall not be broadly refactored unless required for the repository to build after removal of the static utility.
Dependency ordering
The JavaFX runtime service is an explicit prerequisite for JavaFX application processes.
This issue shall express that dependency through:
Constructor injection of JavaFxRuntimeService.
Hub-controlled startup ordering.
Clear rejection of runLater(...) before successful service startup.
The Hub shall not automatically discover or recursively start process dependencies.
A later NenjimHub.conf change can express the JavaFX runtime service before selected JavaFX applications in its ordered autorun list. That configuration functionality is not implemented by this issue.
Documentation
Update the relevant Nenjim documentation to explain:
That JavaFX applications share one JVM-wide JavaFX runtime.
That the runtime is represented by JavaFxRuntimeService.
That the Hub constructs, registers, and starts it.
That JavaFX applications receive it through constructor injection.
That JavaFX runtime startup is no longer hidden inside runLater(...).
That the service must be started before dependent JavaFX processes.
That the service appears in the Hub's started-process snapshot.
That Platform.setImplicitExit(false) keeps the shared runtime alive when the last window closes.
Documentation must describe only the behaviour implemented by this issue and must not describe NenjimHub.conf or Hub events as already available.
The separation between the public service view and Hub-owned process lifecycle.
Strict single-attempt startup.
Successful JavaFX toolkit initialization before start() returns.
Platform.setImplicitExit(false).
Rejection of task submission before successful startup.
Non-null asynchronous task submission through the JavaFX Application Thread.
Hub construction, registration, startup ordering, and process-status tracking.
Constructor injection into all modern JavaFX consumers.
Removal of the static JavaFX initialization path.
Fail-fast Hub behaviour when JavaFX startup fails.
The absence of stop, restart, events, configuration, and automatic dependency startup.
Update only the canonical specifications affected by this vertical slice. Introduce a focused JavaFX runtime service capability rather than placing all JavaFX behaviour into an unrelated existing specification.
Keep the OpenSpec change active after implementation. Do not synchronize or archive it until the implementation has been reviewed and accepted.
Scope
This issue includes:
Introducing JavaFxRuntimeService.
Introducing its reference implementation.
Making the implementation a NenjimProcess.
Strict one-attempt JavaFX runtime startup.
Ensuring JavaFX is ready before successful start() completion.
No NenjimHub.conf, events, stop lifecycle, health monitoring, or automatic dependency startup is added.
No general unit tests or new NenjimTestTool functionality are added.
Relevant documentation describes the implemented JavaFX runtime ownership accurately.
The repository builds successfully.
The OpenSpec change describes only the functionality delivered by this issue.
The OpenSpec change remains active pending review and acceptance.
## Background
The current Nenjim runtime contains several JavaFX-based applications:
- `EvelynMissionControlImpl`
- `NenjimProcessManagerImpl`
- `NenjimComposerImpl`
- `NenjimTestToolImpl`
- `SodaTaskManagerImpl`
- `SuwimoClientImpl`
They currently depend on the static utility:
```java
com.r35157.libs.javafx.JavaFxRuntime
```
Calling:
```java
JavaFxRuntime.runLater(runnable);
```
implicitly initializes the JVM-wide JavaFX toolkit on first use and then submits the task to the JavaFX Application Thread.
This hides an active shared lifecycle behind a static helper. A JavaFX application can therefore start the common JavaFX runtime merely by attempting to submit a UI task, without the runtime being represented as a component, registered in the Nenjim Registry, started by `NenjimHub`, or visible through the Hub's started-process snapshot.
Issues #77 through #79 established the opposite architectural direction:
- `NenjimHub` owns the runtime object graph and process lifecycle.
- Active components implement the canonical `NenjimProcess`.
- Shared dependencies are represented explicitly and supplied through constructor injection.
- The Registry describes constructed components.
- The Hub's started-process snapshot describes successful startup milestones.
The shared JavaFX runtime shall follow the same model.
## Goal
Replace the implicitly initialized static JavaFX helper with one explicit `JavaFxRuntimeService`.
The service shall:
- Represent the single JavaFX toolkit shared by JavaFX applications in the JVM.
- Be constructed, registered, and started by `NenjimHub`.
- Initialize JavaFX only through its Hub-managed `NenjimProcess.start()` lifecycle.
- Provide JavaFX applications with access to the JavaFX Application Thread.
- Reject task submission until startup has completed successfully.
- Be injected explicitly into every modern consumer that currently uses `JavaFxRuntime`.
- Appear in the Hub's started-process snapshot after successful startup.
This issue shall remove the hidden JavaFX startup path completely.
## Terminology
The JVM-wide facility initialized through `javafx.application.Platform` is referred to as the JavaFX runtime or JavaFX toolkit.
JavaFX UI work executes on the JavaFX Application Thread.
`JavaFxRuntimeService` owns initialization of the shared runtime and submission of work to the JavaFX Application Thread. It does not abstract or replace the JavaFX UI APIs themselves.
## Public service API
Introduce the public service interface:
```java
package com.r35157.service.javafx;
import com.r35157.nenjim.component.NenjimComponent;
import org.jetbrains.annotations.NotNull;
public interface JavaFxRuntimeService extends NenjimComponent {
void runLater(@NotNull Runnable runnable);
}
```
The service interface shall not extend `NenjimProcess`.
Ordinary consumers receive only the service view and can submit JavaFX work after the service is active. They shall not receive lifecycle control through the service API.
The API shall expose no initialization, shutdown, restart, status, window-management, event, or configuration operations.
## Reference implementation
Introduce:
```java
com.r35157.service.javafx.impl.ref.JavaFxRuntimeServiceImpl
```
The reference implementation shall implement both:
```java
JavaFxRuntimeService
NenjimProcess
```
The same object shall therefore provide:
- A registered service view for JavaFX consumers.
- A Hub-owned process view for lifecycle startup.
No separate service-manager or administration interface is required.
## Lifecycle
The reference implementation's `start()` operation shall be the only operation that initializes the JavaFX runtime.
Successful startup shall:
1. Initialize the JavaFX toolkit through `Platform.startup(...)`.
2. Configure `Platform.setImplicitExit(false)`.
3. Ensure the toolkit is ready to accept submitted work before `start()` returns.
4. Return only after the JavaFX runtime has reached its successful startup milestone.
The first startup attempt shall be the only accepted attempt.
A repeated `start()` call shall fail with `IllegalStateException`, including when the first startup attempt failed.
If JavaFX initialization fails, `start()` shall propagate a clear failure to the Hub. The service shall remain unusable and shall not expose a partially successful state.
The service shall not attempt to recover, restart JavaFX, or silently accept a JavaFX toolkit initialized outside the service.
This issue assumes one successfully started JavaFX runtime service per JVM.
## Task submission
After successful startup:
```java
javaFxRuntimeService.runLater(runnable);
```
shall submit the supplied task to the JavaFX Application Thread through `Platform.runLater(...)`.
`runLater(...)` shall:
- Reject `null` with a clear `NullPointerException`.
- Fail with `IllegalStateException` before successful service startup.
- Fail with `IllegalStateException` after a failed startup attempt.
- Never initialize JavaFX implicitly.
- Never start or retry the service.
- Never execute the supplied task synchronously on the caller's thread.
Acceptance of a task for submission does not guarantee that the task itself will complete successfully. Exceptions raised by application UI work remain application failures and shall not be converted into JavaFX runtime startup failures.
## Hub integration
`NenjimHubImpl` shall construct exactly one `JavaFxRuntimeServiceImpl` for its current runtime graph.
The Hub shall register the service under:
```text
nenjim.javafx-runtime.service
```
The registration shall expose the same object through both `JavaFxRuntimeService` and `NenjimProcess`, following the existing Registry interface-indexing rules.
The Hub shall start the service through the same process-start mechanism used for other registered `NenjimProcess` instances.
The JavaFX runtime service shall be started before every currently enabled JavaFX application, including:
- `evelyn.mission-control.default`
- `nenjim.process-manager.default`
The Hub shall record:
```text
nenjim.javafx-runtime.service
```
in its started-process snapshot only after the service's `start()` operation returns successfully.
If JavaFX runtime startup fails, Hub startup shall remain fail-fast and no dependent JavaFX process shall be started.
The current hardcoded Hub startup sequence remains in use in this issue. `NenjimHub.conf` and configurable autorun are separate future work.
## Consumer migration
Every modern class that currently uses the static `JavaFxRuntime` utility shall receive a non-null `JavaFxRuntimeService` through constructor injection.
This applies to:
- `EvelynMissionControlImpl`
- `NenjimProcessManagerImpl`
- `NenjimComposerImpl`
- `NenjimTestToolImpl`
- `SodaTaskManagerImpl`
- `SuwimoClientImpl`
Each consumer shall:
- Require the service through its constructor.
- Validate the dependency as non-null.
- Retain the supplied service.
- Use that service for JavaFX Application Thread submission.
- Never initialize the JavaFX toolkit itself.
- Never use a static fallback when the dependency is absent or inactive.
The Hub shall inject the same `JavaFxRuntimeService` instance into the active Mission Control and Process Manager instances.
Dormant modern JavaFX classes shall also be migrated so that the repository contains one coherent JavaFX runtime model even when those classes are not currently constructed by the active Hub.
No backward-compatible constructor that recreates or hides the old static behaviour shall be retained.
Direct use of ordinary JavaFX UI types remains valid inside JavaFX applications. This issue centralizes runtime initialization and Application Thread submission; it does not attempt to wrap the complete JavaFX API.
## Removal of the static utility
Remove:
```java
com.r35157.libs.javafx.JavaFxRuntime
```
after all modern consumers have been migrated.
No modern source shall continue to:
- Import `JavaFxRuntime`.
- Call its static `runLater(...)`.
- Call `Platform.startup(...)` directly.
- Lazily initialize the JavaFX toolkit through another helper.
- Maintain a competing JavaFX initialization flag.
Legacy prototype code outside the modern component graph shall not be broadly refactored unless required for the repository to build after removal of the static utility.
## Dependency ordering
The JavaFX runtime service is an explicit prerequisite for JavaFX application processes.
This issue shall express that dependency through:
- Constructor injection of `JavaFxRuntimeService`.
- Hub-controlled startup ordering.
- Clear rejection of `runLater(...)` before successful service startup.
The Hub shall not automatically discover or recursively start process dependencies.
A later `NenjimHub.conf` change can express the JavaFX runtime service before selected JavaFX applications in its ordered autorun list. That configuration functionality is not implemented by this issue.
## Documentation
Update the relevant Nenjim documentation to explain:
- That JavaFX applications share one JVM-wide JavaFX runtime.
- That the runtime is represented by `JavaFxRuntimeService`.
- That the Hub constructs, registers, and starts it.
- That JavaFX applications receive it through constructor injection.
- That JavaFX runtime startup is no longer hidden inside `runLater(...)`.
- That the service must be started before dependent JavaFX processes.
- That the service appears in the Hub's started-process snapshot.
- That `Platform.setImplicitExit(false)` keeps the shared runtime alive when the last window closes.
Documentation must describe only the behaviour implemented by this issue and must not describe `NenjimHub.conf` or Hub events as already available.
## OpenSpec requirements
Create a new OpenSpec change for issue #80.
Suggested change ID:
```text
80-introduce-javafx-runtime-service
```
The OpenSpec artifacts shall specify:
- The `JavaFxRuntimeService` API.
- The separation between the public service view and Hub-owned process lifecycle.
- Strict single-attempt startup.
- Successful JavaFX toolkit initialization before `start()` returns.
- `Platform.setImplicitExit(false)`.
- Rejection of task submission before successful startup.
- Non-null asynchronous task submission through the JavaFX Application Thread.
- Hub construction, registration, startup ordering, and process-status tracking.
- Constructor injection into all modern JavaFX consumers.
- Removal of the static JavaFX initialization path.
- Fail-fast Hub behaviour when JavaFX startup fails.
- The absence of stop, restart, events, configuration, and automatic dependency startup.
Update only the canonical specifications affected by this vertical slice. Introduce a focused JavaFX runtime service capability rather than placing all JavaFX behaviour into an unrelated existing specification.
Keep the OpenSpec change active after implementation. Do not synchronize or archive it until the implementation has been reviewed and accepted.
## Scope
This issue includes:
- Introducing `JavaFxRuntimeService`.
- Introducing its reference implementation.
- Making the implementation a `NenjimProcess`.
- Strict one-attempt JavaFX runtime startup.
- Ensuring JavaFX is ready before successful `start()` completion.
- Disabling implicit JavaFX exit.
- Explicit asynchronous JavaFX Application Thread submission.
- Registering the service as `nenjim.javafx-runtime.service`.
- Starting it through the Hub before JavaFX applications.
- Recording it through the existing started-process mechanism.
- Constructor-injecting it into all modern JavaFX consumers.
- Removing the static `JavaFxRuntime` utility.
- Updating applicable documentation and OpenSpec artifacts.
- Building the complete repository successfully.
## Out of scope
This issue does not implement:
- `NenjimHub.conf`.
- Configurable autorun.
- Context resolution.
- Implementation-version selection.
- Classloader changes.
- Automatic dependency discovery.
- Automatic dependency startup.
- Hub lifecycle events.
- Event subscriptions.
- JavaFX window discovery or management.
- Process start, stop, or restart controls.
- JavaFX runtime shutdown or restart.
- Runtime process unloading.
- Health monitoring.
- Recovery or supervision.
- Multiple independent JavaFX toolkits in one JVM.
- Headless JavaFX emulation.
- Replacement of JavaFX with another GUI toolkit.
- Wrapping the complete JavaFX API.
- Migration of unrelated legacy prototype code.
- A general unit-test framework.
- NenjimTestTool functionality beyond constructor migration.
- Production deployment changes.
## Acceptance criteria
- [ ] `com.r35157.service.javafx.JavaFxRuntimeService` exists as a public `NenjimComponent`.
- [ ] The service API exposes only non-null `runLater(Runnable)` task submission.
- [ ] `JavaFxRuntimeServiceImpl` implements both `JavaFxRuntimeService` and the canonical `NenjimProcess`.
- [ ] The same implementation object supplies both the service and process views.
- [ ] Only `start()` initializes the JavaFX toolkit.
- [ ] Successful `start()` configures `Platform.setImplicitExit(false)`.
- [ ] Successful `start()` does not return before the JavaFX runtime is ready.
- [ ] Only the first startup attempt is accepted.
- [ ] Repeated startup fails with `IllegalStateException`.
- [ ] A failed first startup attempt cannot be retried.
- [ ] Failed startup leaves the service unusable.
- [ ] A null submitted task is rejected clearly.
- [ ] Task submission before successful startup fails with `IllegalStateException`.
- [ ] `runLater(...)` never initializes or starts JavaFX.
- [ ] Accepted tasks are submitted asynchronously to the JavaFX Application Thread.
- [ ] The Hub constructs one JavaFX runtime service instance.
- [ ] The Hub registers it as `nenjim.javafx-runtime.service`.
- [ ] The registered object is discoverable through both `JavaFxRuntimeService` and `NenjimProcess`.
- [ ] The Hub starts the JavaFX runtime service through its normal process-start mechanism.
- [ ] The JavaFX runtime service is started before Mission Control and Process Manager.
- [ ] Its ID is recorded only after successful startup.
- [ ] A JavaFX runtime startup failure prevents dependent JavaFX processes from starting.
- [ ] Mission Control and Process Manager receive the same service instance.
- [ ] All six modern `JavaFxRuntime` consumers use constructor-injected `JavaFxRuntimeService`.
- [ ] No compatibility constructor preserves hidden static initialization.
- [ ] The static `com.r35157.libs.javafx.JavaFxRuntime` utility is removed.
- [ ] No modern JavaFX consumer calls `Platform.startup(...)` directly.
- [ ] No competing lazy JavaFX initialization path remains in the modern component graph.
- [ ] Existing JavaFX window behaviour remains otherwise unchanged.
- [ ] No `NenjimHub.conf`, events, stop lifecycle, health monitoring, or automatic dependency startup is added.
- [ ] No general unit tests or new NenjimTestTool functionality are added.
- [ ] Relevant documentation describes the implemented JavaFX runtime ownership accurately.
- [ ] The repository builds successfully.
- [ ] The OpenSpec change describes only the functionality delivered by this issue.
- [ ] The OpenSpec change remains active pending review and acceptance.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Background
The current Nenjim runtime contains several JavaFX-based applications:
EvelynMissionControlImplNenjimProcessManagerImplNenjimComposerImplNenjimTestToolImplSodaTaskManagerImplSuwimoClientImplThey currently depend on the static utility:
Calling:
implicitly initializes the JVM-wide JavaFX toolkit on first use and then submits the task to the JavaFX Application Thread.
This hides an active shared lifecycle behind a static helper. A JavaFX application can therefore start the common JavaFX runtime merely by attempting to submit a UI task, without the runtime being represented as a component, registered in the Nenjim Registry, started by
NenjimHub, or visible through the Hub's started-process snapshot.Issues #77 through #79 established the opposite architectural direction:
NenjimHubowns the runtime object graph and process lifecycle.NenjimProcess.The shared JavaFX runtime shall follow the same model.
Goal
Replace the implicitly initialized static JavaFX helper with one explicit
JavaFxRuntimeService.The service shall:
NenjimHub.NenjimProcess.start()lifecycle.JavaFxRuntime.This issue shall remove the hidden JavaFX startup path completely.
Terminology
The JVM-wide facility initialized through
javafx.application.Platformis referred to as the JavaFX runtime or JavaFX toolkit.JavaFX UI work executes on the JavaFX Application Thread.
JavaFxRuntimeServiceowns initialization of the shared runtime and submission of work to the JavaFX Application Thread. It does not abstract or replace the JavaFX UI APIs themselves.Public service API
Introduce the public service interface:
The service interface shall not extend
NenjimProcess.Ordinary consumers receive only the service view and can submit JavaFX work after the service is active. They shall not receive lifecycle control through the service API.
The API shall expose no initialization, shutdown, restart, status, window-management, event, or configuration operations.
Reference implementation
Introduce:
The reference implementation shall implement both:
The same object shall therefore provide:
No separate service-manager or administration interface is required.
Lifecycle
The reference implementation's
start()operation shall be the only operation that initializes the JavaFX runtime.Successful startup shall:
Platform.startup(...).Platform.setImplicitExit(false).start()returns.The first startup attempt shall be the only accepted attempt.
A repeated
start()call shall fail withIllegalStateException, including when the first startup attempt failed.If JavaFX initialization fails,
start()shall propagate a clear failure to the Hub. The service shall remain unusable and shall not expose a partially successful state.The service shall not attempt to recover, restart JavaFX, or silently accept a JavaFX toolkit initialized outside the service.
This issue assumes one successfully started JavaFX runtime service per JVM.
Task submission
After successful startup:
shall submit the supplied task to the JavaFX Application Thread through
Platform.runLater(...).runLater(...)shall:nullwith a clearNullPointerException.IllegalStateExceptionbefore successful service startup.IllegalStateExceptionafter a failed startup attempt.Acceptance of a task for submission does not guarantee that the task itself will complete successfully. Exceptions raised by application UI work remain application failures and shall not be converted into JavaFX runtime startup failures.
Hub integration
NenjimHubImplshall construct exactly oneJavaFxRuntimeServiceImplfor its current runtime graph.The Hub shall register the service under:
The registration shall expose the same object through both
JavaFxRuntimeServiceandNenjimProcess, following the existing Registry interface-indexing rules.The Hub shall start the service through the same process-start mechanism used for other registered
NenjimProcessinstances.The JavaFX runtime service shall be started before every currently enabled JavaFX application, including:
evelyn.mission-control.defaultnenjim.process-manager.defaultThe Hub shall record:
in its started-process snapshot only after the service's
start()operation returns successfully.If JavaFX runtime startup fails, Hub startup shall remain fail-fast and no dependent JavaFX process shall be started.
The current hardcoded Hub startup sequence remains in use in this issue.
NenjimHub.confand configurable autorun are separate future work.Consumer migration
Every modern class that currently uses the static
JavaFxRuntimeutility shall receive a non-nullJavaFxRuntimeServicethrough constructor injection.This applies to:
EvelynMissionControlImplNenjimProcessManagerImplNenjimComposerImplNenjimTestToolImplSodaTaskManagerImplSuwimoClientImplEach consumer shall:
The Hub shall inject the same
JavaFxRuntimeServiceinstance into the active Mission Control and Process Manager instances.Dormant modern JavaFX classes shall also be migrated so that the repository contains one coherent JavaFX runtime model even when those classes are not currently constructed by the active Hub.
No backward-compatible constructor that recreates or hides the old static behaviour shall be retained.
Direct use of ordinary JavaFX UI types remains valid inside JavaFX applications. This issue centralizes runtime initialization and Application Thread submission; it does not attempt to wrap the complete JavaFX API.
Removal of the static utility
Remove:
after all modern consumers have been migrated.
No modern source shall continue to:
JavaFxRuntime.runLater(...).Platform.startup(...)directly.Legacy prototype code outside the modern component graph shall not be broadly refactored unless required for the repository to build after removal of the static utility.
Dependency ordering
The JavaFX runtime service is an explicit prerequisite for JavaFX application processes.
This issue shall express that dependency through:
JavaFxRuntimeService.runLater(...)before successful service startup.The Hub shall not automatically discover or recursively start process dependencies.
A later
NenjimHub.confchange can express the JavaFX runtime service before selected JavaFX applications in its ordered autorun list. That configuration functionality is not implemented by this issue.Documentation
Update the relevant Nenjim documentation to explain:
JavaFxRuntimeService.runLater(...).Platform.setImplicitExit(false)keeps the shared runtime alive when the last window closes.Documentation must describe only the behaviour implemented by this issue and must not describe
NenjimHub.confor Hub events as already available.OpenSpec requirements
Create a new OpenSpec change for issue #80.
Suggested change ID:
The OpenSpec artifacts shall specify:
JavaFxRuntimeServiceAPI.start()returns.Platform.setImplicitExit(false).Update only the canonical specifications affected by this vertical slice. Introduce a focused JavaFX runtime service capability rather than placing all JavaFX behaviour into an unrelated existing specification.
Keep the OpenSpec change active after implementation. Do not synchronize or archive it until the implementation has been reviewed and accepted.
Scope
This issue includes:
JavaFxRuntimeService.NenjimProcess.start()completion.nenjim.javafx-runtime.service.JavaFxRuntimeutility.Out of scope
This issue does not implement:
NenjimHub.conf.Acceptance criteria
com.r35157.service.javafx.JavaFxRuntimeServiceexists as a publicNenjimComponent.runLater(Runnable)task submission.JavaFxRuntimeServiceImplimplements bothJavaFxRuntimeServiceand the canonicalNenjimProcess.start()initializes the JavaFX toolkit.start()configuresPlatform.setImplicitExit(false).start()does not return before the JavaFX runtime is ready.IllegalStateException.IllegalStateException.runLater(...)never initializes or starts JavaFX.nenjim.javafx-runtime.service.JavaFxRuntimeServiceandNenjimProcess.JavaFxRuntimeconsumers use constructor-injectedJavaFxRuntimeService.com.r35157.libs.javafx.JavaFxRuntimeutility is removed.Platform.startup(...)directly.NenjimHub.conf, events, stop lifecycle, health monitoring, or automatic dependency startup is added.