Covalent

A lightweight Java component model and runtime container.

View the Project on GitHub opales-org/covalent

Home | Previous: Covalent HMI Guide | Next: Solar System Simulation - Architecture

Table of Contents

Covalent Examples

A note on the examples. The examples are there to show how Covalent is used. They, and the algorithms they run (the training, the solver, the simulations), were written with the help of an AI assistant, and are not meant as reference implementations of those algorithms. The component structure, the ports and the use of the container are what they illustrate.

covalent-examples hosts a handful of small, runnable JavaFX applications built entirely on Covalent. Each one leans into a different subset of the framework’s mechanisms rather than showcasing every feature at once, and each is launched from a single entry point, LauncherApplication:

mvn -f covalent-examples/pom.xml -am -DskipTests javafx:run

With the Maven Wrapper (see Building And Testing The Repository for it and for the required JDK version), use .\mvnw.cmd on Windows and ./mvnw elsewhere in place of mvn. Add -Pjmx to let a JMX tool connect to the JVM that runs the examples (localhost:9010, or the next free port; see Connecting a JMX Tool to the Application).

This opens a small launcher window with one button per demo. Each demo runs in its own, independently started and stopped CovalentContainer, obtained through Covalent.managedContainer(name), so several can run side by side without interfering with one another, and stopping one leaves the others untouched. The supervisor is available alongside every demo: press Ctrl+Shift+F12 in any demo window to open it and inspect the live component graph while the demo runs (see Summoning the Supervisor).

The Covalent Demos launcher, with every demo started

Every demo window also carries its own “Help” menu, with “About” and “Using” entries that each open a small, non-modal, read-only panel - one summarizing what that demo illustrates and which Covalent mechanisms it uses, the other describing how to drive its controls. Built by each demo’s own HmiBuilder alongside everything else it assembles, this is the one piece of HMI code in every demo that is not itself an MVIC.

The MVIC Pattern

Every demo function is built the same way: Model / Controller / Interaction Controller / View (MVIC), one instance per function, as a single composite grouping the four.

This keeps all four genuinely independent: the Model doesn’t know a View exists, and the View doesn’t know which component ends up handling an action it triggers.

Capability Matrix

Four demos make up this module, each leaning into a different subset of Covalent’s mechanisms. The matrix shows which of them each one actually demonstrates - not which ones it merely could.

Capability Neural Network Trainer Solar System Simulation Ecosystem Rubik’s Cube Solver
Services ✅ ✅ ✅ ✅
Extending Services - - - ✅
Parameters ✅ ✅ ✅ ✅
Events ✅ ✅ ✅ ✅
Generic Subscribe (GenericSubscribe) ✅ - - -
Object Observers - - ✅ -
Event Filters - ✅ ✅ -
Event Subscription Delegation ✅ - ✅ ✅
Custom Event Subscription (extra subscribe arguments) - - ✅ -
Event Cloning (@Cloned) - - - ✅
Composition ✅ ✅ ✅ ✅
Recursive Decomposition (composites nested in composites) - - ✅ -
Root Composite ✅ ✅ ✅ -
Items (@Item) ✅ - ✅ -
Raw Components - - ✅ -
HMI / ActionManager ✅ ✅ ✅ ✅
Asynchronous Services (AsyncServices) - - - ✅

A root composite deploys the whole application as a single top-level component containing every function as a sub-component, rather than several independent root components side by side - the alternative Rubik’s Cube Solver demonstrates explicitly instead (see its architecture page’s Top-Level Composites section).

Neural Network Trainer

What NNTrainer Does

NNTrainer trains a small feed-forward neural network, in real time, on a toy two-dimensional classification problem whose shape is chosen among two moons, ring, cross, star, spiral and checkerboard: the dataset, the network’s layer/weight structure, and the training loss all update live as the controls are used.

Neural Network Trainer

Using NNTrainer

The window has three columns.

Covalent Capabilities In NNTrainer

Every user-triggered control - “Start”, “Predict”, the sliders in User Configuration - is registered by its Interaction Controller against an ActionKey through ActionProviderServices, and executed by its View through ActionConsumerServices, rather than a View holding a direct reference to the Interaction Controller behind it (see ActionManager). Concretely, a View never knows which component implements “Start training”; it only knows the action’s key. This is what keeps the View, Controller, Interaction Controller and Model genuinely independent: any of them can be reworked, or a control re-labeled and moved to a different panel, without touching the others’ code.

The demo also uses @Item for its gradient-descent optimizer: an internal sub-part of the network’s Controller with no component identity, lifecycle or wiring of its own - the right tool when a piece of state needs to be owned and encapsulated, but never looked up or activated independently.

“Freeze charts” is this demo’s illustration of manual subscription without a specific subscribe interface: TrainingView consumes TrainingEvents, which declares no @EventsSubscribe interface of its own, so it is free to subscribe to (and unsubscribe from) it manually through GenericSubscribe instead of Covalent’s ordinary automatic autowiring - exactly the partial-lifecycle case that mechanism exists for. TrainingInteraction consumes the same TrainingEvents independently, still automatically, so freezing the charts never affects its own reaction to convergence and reset.

Each function (Dataset, Network, Training) is a composite @Implementation grouping its own Model/Controller/View/Interaction Controller as child components; a late-joining subscriber catches up on already-in-progress state through event subscription delegation rather than missing whatever happened before it subscribed.

The whole demo also deploys as a single root composite, NeuralNetworkDemoImpl: the launcher starts and stops it with one deployComponents(...)/start() call pair, and the container resolves every function’s activation order from its field declarations - rather than the launcher constructing and wiring five functions by hand.

For the full component-level architecture - root dependencies, the shared interfaces between functions, a per-function MVIC decomposition with full interface method signatures, and how the HMI is assembled from every function’s View - see Neural Network Trainer - Architecture.

Solar System Simulation

What Solar System Simulation Does

Solar System Simulation is a small 2D n-body gravitational demo: a Sun and a few planets attract each other and are integrated forward in time, animated live on an orrery view, with a hazard layer watching for close approaches between bodies.

Solar System Simulation

Using Solar System Simulation

The window has a left column (configuration, then run controls), the orrery in the center, the two event logs on the right, and the readout at the bottom.

Covalent Capabilities In Solar System Simulation

OrbitalWatch and HazardAlert both subscribe to the very same CloseApproachEvents interface, but in two contrasting ways (see Event Filters): OrbitalWatch subscribes to every notification through ordinary, automatic autowiring, while HazardAlert subscribes manually with a filter that re-reads its own live thresholds on every notification - moving a slider changes what qualifies from the next close approach on, with no re-subscription needed. This is the demo’s clearest illustration of a filter’s actual purpose: two independent consumers, each seeing a different subset of the same broadcast stream, without either one sorting events itself in its own callback.

As in the neural network demo, every control is routed through ActionProviderServices/ActionConsumerServices rather than a View calling an Interaction Controller directly (see ActionManager), and each function - OrbitalSystem, SimulationRunner, OrbitalWatch, HazardAlert - is its own composite @Implementation.

The whole demo also deploys as a single root composite, SolarSystemDemoImpl: the launcher starts and stops it with one deployComponents(...)/start() call pair, and the container resolves every function’s activation order from its field declarations - rather than the launcher constructing and wiring six functions by hand.

For the full component-level architecture - root dependencies, the shared interfaces between functions, a per-function MVIC decomposition with full interface method signatures, and how the HMI is assembled from every function’s View - see Solar System Simulation - Architecture.

Ecosystem

What Ecosystem Does

Ecosystem is a small population-dynamics simulation: Grass, Prey and Predator populations interact through a stochastic, tau-leaping generalized Lotka-Volterra model, with live population curves showing the resulting growth, decline and oscillation. Three watchers observe the same stream of birth/death/predation notifications, each scoped to its own concern, and a raw component mirrors the running population counts out to a CSV file.

Ecosystem Demo

Using Ecosystem

The window has three columns.

Covalent Capabilities In Ecosystem

One interface carries almost all of the cross-function work: PopulationEvents, produced once by Ecosystem and consumed independently by the three watchers inside Watchers, each with its own filter - the same broadcast stream partitioned three different ways. RoleWatcher combines its filter with subscribing an object instead of the consumer component: two small delegate instances, one per role, so its own callback never branches on which role a notification belongs to.

The chart’s own events, EcosystemStateEvents, show subscription with custom arguments: the View subscribes manually, and each subscription carries the simulation time of the last state it has and a history depth, which the Model uses to replay the missed states (event subscription delegation) when the display resumes from a pause.

A raw component pair, StatsExporter and StatsExportWidget, mirrors the running population counts to a CSV file from outside the managed component graph entirely, wired by the demo’s own launcher rather than deployComponents(...) - see Raw Components and the architecture page’s own section on it.

As in the other demos, every control is routed through ActionProviderServices/ActionConsumerServices (see ActionManager), each function is its own composite @Implementation, and the whole demo deploys as a single root composite, EcosystemDemoImpl. It is also the one demo that decomposes recursively: the Watchers function is a composite of three watcher composites, each grouping its own four MVIC components, so the tree is three levels deep (see the architecture page’s Top-Level Composites).

For the full component-level architecture - root dependencies, the shared interfaces between functions, a per-function MVIC decomposition with full interface method signatures, the raw component pair, and how the HMI is assembled from every function’s View - see Ecosystem - Architecture.

Rubik’s Cube Solver

What Rubik’s Cube Solver Does

Rubik’s Cube Solver is a cube model that two independent solving algorithms, Kociemba’s two-phase strategy and the layer-by-layer method a person follows, can each be set loose on: pick an algorithm, start a solve, and watch it run off the UI thread while its progress is reported live.

Rubik's Cube Solver

Using Rubik’s Cube Solver

Covalent Capabilities In Rubik’s Cube Solver

Unlike the other three demos, nothing here wraps the whole application in a single root composite: Cube, Solver, UserConfiguration and HmiBuilder are passed directly to deployComponents(...), several independent top-level composites side by side rather than one.

CubeServices extends CubeReadServices (extending services): the cube’s mutating operations (applyMove, scramble and resetToSolved) are reachable only through the wider interface, while UserConfiguration is written against the read-only one alone. SolverController drives each solve through AsyncServices, the container’s own Application Utility Service, off the UI thread, on a dedicated queue key that also makes cancellation meaningful. CubeEvents.stateChanged carries its CubeState argument @Cloned, since CubeState is mutable and the instance delivered is the one the Model holds, so each subscriber receives its own copy, and CubeModelImpl’s subscription delegation pushes a real catch-up snapshot to a late subscriber.

For the full component-level architecture - the no-root-composite deployment shape, the shared interfaces between functions, a per-function MVIC decomposition with full interface method signatures, and how the HMI is assembled from every function’s View - see Rubik’s Cube Solver - Architecture.

Home | Previous: Covalent HMI Guide | Next: Solar System Simulation - Architecture