Module RelayOSGi runtime fieldbook
OSGi · Dynamic Module SystemsView Markdown source

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:

  1. DS unbinds the connector from the coordinator.
  2. New OCPP work is rejected or queued within a fixed site quota.
  3. Existing calls reach a deadline; no lock spans the network.
  4. Idempotency makes a later retry safe.
  5. Health shows the affected protocol and site count.
  6. 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.

Module RelayIndependent study material · verify runtime details in official project documentation