Real-life scenario: ChargeGrid
ChargeGrid operates 70,000 EV chargers from multiple vendors. Sites remain available during network loss, tariffs change by region, and operators deploy connector fixes without rebuilding the whole control station.
Requirements
- each vendor protocol is replaceable;
- core billing never imports vendor implementation packages;
- connector configuration can create one instance per site;
- offline commands queue with bounded storage;
- duplicated messages never create duplicate charges;
- operators can diagnose one site without exposing credentials;
- updates are signed, staged, observable, and reversible.
Bundle map
chargegrid.model.api records, IDs, money, states
chargegrid.connector.api ChargerConnector service contract
chargegrid.session.core charging-session state machine
chargegrid.tariff.api TariffService contract
chargegrid.vendor.ocpp OCPP connector implementation
chargegrid.vendor.legacy legacy serial connector
chargegrid.persistence checkpoint and idempotency store
chargegrid.http HTTP/Jakarta REST whiteboard resources
chargegrid.operations health, commands, support snapshot
API bundles export small packages. Implementation bundles export
nothing. session.core imports only model and service API
packages.
Dynamic services
Each vendor bundle publishes ChargerConnector with
properties:
protocol=ocpp
protocol.version=2.0.1
region=eu
secure=true
The station coordinator has a multiple DS reference and indexes connectors by declared protocol. Removing one connector stops new assignments, drains bounded work, checkpoints state, and then unbinds.
Configuration
A factory PID creates one SiteConnector component per
charging site. Typed Metatype declares endpoint, site ID, TLS profile,
timeout, and concurrency. Secrets are references to a vault-backed
CredentialService, not literal passwords in
ConfigAdmin.
Correctness
Every command has a durable (siteId, commandId)
idempotency key. Session state changes and outbound intent commit
together. A dispatcher retries safe commands with deadlines and jitter.
Reconciliation compares station counters, accepted events, and billed
energy.
Karaf assembly
Karaf 4.4.11 provides the managed runtime. A versioned ChargeGrid features repository installs SCR, ConfigAdmin, HTTP, logging, APIs, then implementations. Provisioning occurs from a signed internal repository with no public shell.
Failure walkthrough
When the OCPP service disappears:
- DS unbinds the connector from the coordinator.
- New OCPP work is rejected or queued within a fixed site quota.
- Existing calls reach a deadline; no lock spans the network.
- Idempotency makes a later retry safe.
- Health shows the affected protocol and site count.
- The legacy connector and core tariff services remain active.
Upgrade
A connector API addition passes bnd baseline as a minor-compatible change. The new provider is installed beside the old one with a higher service ranking only for a canary site filter. Metrics and reconciliation prove correctness before the remaining configurations move. Rollback restores ranking and config; the data format remains backward compatible.
Architecture verdict
OSGi fits because connector diversity, long-lived edge runtimes, controlled plugin boundaries, and partial updates are primary requirements. If ChargeGrid were one stateless cloud API redeployed as a unit, a plain modular Java service might be simpler.
Feynman check
Trace one “start charging” command through HTTP service, session core, connector selection, durable idempotency, vendor service, event result, and telemetry. Then explain what happens at every step if the connector vanishes.