Day 30 of 40
OSGi Configuration
Run-mode configs, OCD, and handling secrets
By the end of today you should be able to
- Define typed OSGi configuration with an Object Class Definition
- Ship configuration as files in ui.config using run-mode folders
- Explain configuration precedence when several run modes match
- Handle secrets correctly on AEM as a Cloud Service
Typed configuration with OCD
An Object Class Definition is an annotation interface describing your component's configuration. It gives you type safety, defaults and labels for the web console in one place:
@ObjectClassDefinition(
name = "WKND Adventure Service",
description = "Settings for the adventure lookup service")
public @interface AdventureServiceConfig {
@AttributeDefinition(name = "API endpoint",
description = "Base URL of the adventures API")
String apiEndpoint() default "https://api.example.com";
@AttributeDefinition(name = "Timeout (ms)")
int timeout() default 5000;
@AttributeDefinition(name = "Enabled")
boolean enabled() default true;
}
Then designate it on the component and receive it in @Activate:
@Component(service = AdventureService.class)
@Designate(ocd = AdventureServiceConfig.class)
public class AdventureServiceImpl implements AdventureService {
private String endpoint;
@Activate
@Modified
protected void activate(AdventureServiceConfig config) {
this.endpoint = config.apiEndpoint();
}
}
Without it, changing configuration in the web console deactivates and reactivates the whole component. With @Modified on the same method, the component is updated in place — which matters when activation is expensive or the component holds state.
Shipping configuration as files
Editing configuration in the web console is fine locally but never a deployment mechanism — Cloud
Service instances are replaced, and console edits do not survive. Configuration ships as JSON files in
ui.config:
ui.config/src/main/content/jcr_root/apps/wknd/osgiconfig/
config/
com.adobe.aem.guides.wknd.core.AdventureServiceImpl.cfg.json
config.author/
config.publish/
config.author.dev/
config.publish.prod/
The filename is the component's PID — usually the fully qualified class name. The content is plain JSON:
{
"apiEndpoint": "https://api-dev.example.com",
"timeout": 10000,
"enabled": true
}
For a factory configuration, append an identifier after a dash: com.example.MyFactory-instance1.cfg.json.
Precedence
When several folders could apply, the most specific run-mode match wins — the one
matching the greatest number of active run modes. With author and dev active:
config.author.dev— 2 matches, winsconfig.author— 1 matchconfig.dev— 1 matchconfig— the fallback
Two folders matching equally many run modes is ambiguous and to be avoided — put the shared value in
config and override only where it genuinely differs.
Secrets
An API key must never be committed. On Cloud Service the mechanism is
Cloud Manager environment variables of type secret, referenced from
configuration with the $[secret:...] placeholder:
{
"apiEndpoint": "$[env:ADVENTURE_API_URL;default=https://api.example.com]",
"apiKey": "$[secret:ADVENTURE_API_KEY]"
}
$[env:NAME]— a plain environment variable, with an optional;default=.$[secret:NAME]— a secret variable. Write-only in Cloud Manager: settable, never readable back.
Variables are set per environment through the Cloud Manager UI or API, so dev, stage and prod each carry their own values while the configuration file in Git stays identical and safe to read.
If a value would be damaging in a public repository, it is a secret variable. Never a config file, never a Java constant, never a comment "to be replaced before go-live".
Checking what actually applied
/system/console/configMgr shows the effective configuration for every component. When
behaviour differs between environments, this is where you confirm which run-mode folder won and what
values landed — far quicker than reasoning about precedence from the file tree.
OCD for typed configuration, @Modified to avoid needless restarts, run-mode folders for per-environment values, and $[secret:...] for anything sensitive.
Watch
Adobe's own videos for this topic. They load only when you press play.
Read on Experience League
The primary sources these notes are drawn from.
Your notes
Saved automatically to this browser.
Check yourself
10 questions on today's material. 80% to pass.