Home/Field Guide/OSGi & Java
CONCEPT 04
OSGi bundles and Declarative Services
Understand package wiring, service registration, component activation, and Gogo triage.
Two lifecycles
An OSGi bundle is a JAR with manifest metadata. The framework resolves a bundle by wiring its required packages and capabilities to providers. A Declarative Services component is a managed class declared with metadata, commonly generated by bnd from annotations. DS activates components when their required references and configuration are satisfied. A bundle can be active while a component in it is unsatisfied.
An exported Java package makes types visible to consumers. Registering a service makes an implementation discoverable by interface and optional properties. Publish a small API package, keep implementation packages private, and let DS handle implementation binding. Avoid creating the service with new in a consumer because that bypasses its managed lifecycle.
A provider and consumer
// In an exported API package, as a separate source file
public interface RequestPolicy {
boolean canSubmit(String summary);
}
// In the implementation bundle
@Component(service = RequestPolicy.class)
public class DefaultRequestPolicy implements RequestPolicy {
@Override
public boolean canSubmit(String summary) {
return summary != null && !summary.isBlank();
}
}
// In a Declarative Services consumer
@Reference
private RequestPolicy requestPolicy;
Use org.osgi.service.component.annotations.Component and Reference. Separate public types into their own Java source files. Business input validation belongs alongside resource permission checks in the calling operation.
Triage in order
| Symptom | Look at | Common cause |
|---|---|---|
| Bundle never appears | Deployment log and lb |
Wrong artifact or deployment location |
| Bundle stays installed | diag <bundleId>, headers <bundleId> |
Missing export or incompatible version range |
| Bundle active, feature absent | scr:list, scr:info <componentName> |
Unsatisfied reference, config, or activation failure |
| Component active, wrong behavior | Service properties, request context, and logs | Filter mismatch, competing implementations, or wrong scope |
Operate safely
Check package imports before increasing their range. Never embed a second copy of a shared API just to make resolution succeed. Keep activation lightweight, release resources on deactivation, and treat dynamic references and optional dependencies explicitly. Test against the target runtime and run Gogo only through an authorized administration path.
Configuration is part of activation
A configuration PID identifies a set of OSGi settings. A component that requires a configuration can remain unsatisfied until the matching PID is available. Declare defaults and types with the supported metatype model. Decide whether the value is system-wide or needs Liferay’s scope-aware configuration facilities. Verify the actual runtime configuration and its source when a build works in one environment and fails in another.
