Module SDK
The Module SDK is the Java API surface modules use to participate
in the cluster. A module is shipped as a single shaded jar plus a
module.yaml manifest; the controller (and optionally each daemon)
loads it inside its own JVM and hands the entrypoint a
ModuleContext covering
storage, the event bus, capabilities, scheduling, HTTP, and JSON.
What you’ll learn
- The two entrypoint contracts:
PlatformModuleandDaemonModule. - The shared
ModuleContextsurface. - The orthogonal subsystems — events, capabilities, storage, REST.
- The on-disk
module.yamlschema.
SDK pages
| Page | Surface |
|---|---|
| PlatformModule | Controller-side lifecycle + REST + capability handles. |
| DaemonModule | Daemon-side lifecycle + per-instance hooks. |
| ModuleContext | Shared context: storage, events, scheduler, HTTP, JSON, capabilities. |
| EventBus | Subscribing to and publishing cluster events. |
| Capability API | The provides / requires graph and CapabilityHandle. |
| Storage API | Mongo ModuleDataStore + Redis PlatformRedisStorage. |
| REST Routes | onRegisterRoutes and the per-module wildcard dispatcher. |
| module.yaml | Manifest schema. |
Hello-world platform module
Minimum viable module that owns one Mongo collection, registers one GET route, and uses SLF4J for logging:
package com.example.hello;
import java.util.Map;
import me.prexorjustin.prexorcloud.api.module.platform.ModuleContext;import me.prexorjustin.prexorcloud.api.module.platform.PlatformModule;import me.prexorjustin.prexorcloud.api.module.rest.RouteRegistrar;
public final class HelloModule implements PlatformModule {
private ModuleContext context;
@Override public void onLoad(ModuleContext context) { this.context = context; context.requireMongoStorage().ensureCollection("greetings"); }
@Override public void onRegisterRoutes(RouteRegistrar routes) { routes.get("/greetings", (req, res) -> { long count = context.requireMongoStorage() .count("greetings", null); res.json(Map.of("count", count)); }); }
@Override public void onStart(ModuleContext context) { context.logger().info("hello module started"); }}manifestVersion: 1id: helloversion: 1.0.0hosts: [controller]backend: controller: entrypoint: com.example.hello.HelloModulestorage: mongo: trueThe route lives at /api/v1/modules/hello/greetings; the collection is
namespaced as mod_hello_greetings under the hood.
Conventions
- Logging: SLF4J only (
org.slf4j.Logger). The context exposes a pre-namespaced logger viacontext.logger(). - JSON: use
context.json()(Jackson, configured for ISO-8601 +NON_NULL). No Gson, no manual serialisation. - Persistence: Mongo via
ModuleDataStoreand Redis viaPlatformRedisStorage. JDBC is acceptable for advanced cases but not exposed by the SDK; ORMs are out of scope. - DI: constructor injection only — pass dependencies into your
service classes from the entrypoint’s
onLoad.
Reference module
cloud-module-stats-aggregator
ships in the repo and exercises every surface listed here. Code
samples on the SDK pages are drawn from it.
Next up
- PlatformModule — start here if you’re writing controller-side logic.
- Concepts → Modules — the architectural picture behind these contracts.