Skip to content

Configuration API

This is the API reference for the configuration subsystem: the type you get back from the SDK facade, its read methods, the typed section accessors, template resolution, and the ConfigurationChangeListener interface. For a task-oriented walkthrough (choosing a source, the document layout, hot reload) see the Configuration guide; for the exhaustive field list see the configuration schema reference.

How you obtain config from the top-level SDK object is the first cross-language divergence. Java and Python hand you a rich manager object with getters; Rust and TypeScript hand you an immutable Config snapshot that is replaced atomically on hot reload.

Language Accessor Returns
Java gg.getConfigManager() ConfigManager (mutable manager, many getters)
Python gg.get_config_manager() ConfigManager
Rust gg.config() Arc<Config> (immutable snapshot)
TypeScript gg.config() Config (immutable snapshot)

The core read surface — global config, instance ids, and per-instance lookup — exists in every language. Note the divergence on a missing instance id.

Operation Java Python Rust TypeScript
Global config subtree getGlobalConfig() get_global_config() global() global()
Instance ids getInstanceIds() get_instance_ids() instance_ids() instanceIds()
One instance subtree getInstanceConfig(id) get_instance_config(id) instance(id) instance(id)
Full raw document getFullConfig() get_full_config() raw field raw field
Missing-instance result returns null raises KeyError returns None returns undefined

The return types mirror each language’s JSON value: Java JsonObject (Gson), Python dict, Rust &serde_json::Value / Option<&Value>, TypeScript unknown / unknown | undefined.

ConfigManager config = gg.getConfigManager();
JsonObject global = config.getGlobalConfig();
long timeout = global.has("timeout") ? global.get("timeout").getAsLong() : 5000L;
for (String id : config.getInstanceIds()) {
JsonObject inst = config.getInstanceConfig(id); // null if id absent
}

The well-known config sections (logging, heartbeat, metricEmission, health, tags) are exposed as strongly-typed objects rather than raw JSON. Java/Python expose them as getters on the ConfigManager; Rust/TypeScript expose them as fields on the snapshot’s parsed view (RawConfig).

Section Java getter Python getter Rust field (cfg.parsed.…) TS field (cfg.parsed.…)
Logging getLoggingConfig()LoggingConfiguration get_logging_config() logging: LoggingConfig logging: LoggingConfig
Heartbeat getHeartbeatConfig()HeartbeatConfiguration get_heartbeat_config() heartbeat: HeartbeatConfig heartbeat: HeartbeatConfig
Metric emission getMetricConfig()MetricConfiguration get_metric_config() metric_emission: MetricConfig metricEmission: MetricConfig
Health getHealthConfig()HealthConfiguration get_health_config() health: HealthConfig health: HealthConfig
Tags getTagConfig()TagConfiguration get_tag_config() tags: BTreeMap<String, Value> tags: Record<string, unknown>
ConfigManager config = gg.getConfigManager();
LoggingConfiguration logging = config.getLoggingConfig();
HeartbeatConfiguration heartbeat = config.getHeartbeatConfig();
MetricConfiguration metric = config.getMetricConfig();
HealthConfiguration health = config.getHealthConfig();
TagConfiguration tags = config.getTagConfig();
int interval = heartbeat.getIntervalSecs();
String env = tags.getKeyValue("environment");

Substitute the built-in placeholders {ThingName}, {ComponentName} (the short name — the segment after the last .), {ComponentFullName}, and any {<tagKey>} from the tags section into config strings such as log paths and MQTT topics. Substituted values are sanitized (each of /, \, +, #, and control characters becomes _, then any remaining .. traversal becomes _); the template literal itself is left intact, so legitimate separators in the template survive.

The entry point diverges: Java/Python expose resolveTemplate / resolve_template as instance methods on the manager; Rust/TypeScript expose a free function resolve that takes a Config.

ConfigManager config = gg.getConfigManager();
// tags.environment from config is substituted into {environment}
String path = config.resolveTemplate(
"/var/log/{ComponentName}-{ThingName}-{environment}.log");

The resolved Thing name and component name are available everywhere; Java/Python additionally expose the resolved platform on the manager.

Value Java Python Rust TypeScript
Thing name getThingName() get_thing_name() cfg.thing_name (field) cfg.thingName (field)
Component name (short) getComponentName() get_component_name() — see note — see note
Component full name getComponentFullName() get_component_full_name() cfg.component_name (field) cfg.componentName (field)
Platform getPlatform()Platform get_platform() not on Config — see note not on Config — see note

Register a listener to react to hot reloads. Three things diverge across languages: the method name/signature, whether the callback receives the new config, and where you register the listener.

Aspect Java Python Rust TypeScript
Method onConfigurationChanged() on_configuration_change(configuration) on_configuration_change(config) onConfigurationChange(config)
Receives new config? no — read back from manager yes — dict yes — Arc<Config> yes — Config
Async? no no yes (async) may return Promise<boolean> | boolean
Register on ConfigManager ConfigManager runtime gg runtime gg
Remove with removeConfigChangeListener(l) remove_config_change_listener(l) remove_config_change_listener(&l) removeConfigChangeListener(l)

The return value is informational only — it is logged but does not change reload behavior in any language.

public interface ConfigurationChangeListener {
// Takes NO argument — read back from the ConfigManager inside the callback.
boolean onConfigurationChanged();
}
ConfigManager configManager = gg.getConfigManager();
configManager.addConfigChangeListener(() -> {
// The callback takes no config argument — re-read from the manager.
JsonObject global = configManager.getGlobalConfig();
return true; // logged, but does not affect reload
});

Component authors normally receive a ready config object from the GGCommons builder/runtime and do not construct it directly. The underlying factory/builder is listed here for completeness.

Language Entry point
Java ConfigManagerFactory.create(componentName, cmdLine[, messagingClient]) — validates before the first apply
Python ConfigManagerBuilder.build(args, component_name) — returns the matching *ConfigManager subclass
Rust config::source::build(spec, messaging, thing, component) builds the source; Config::from_value(component_name, thing_name, raw) builds a snapshot
TypeScript buildConfigSource(spec, opts) builds the source; Config.fromValue(componentName, thingName, raw) builds a snapshot