> For AI agents: the complete documentation index is available at https://nhanbe.id.vn/llms.txt, the full documentation bundle is available at https://nhanbe.id.vn/llms-full.txt.

# OSGi Fundamentals

## OSGi Fundamentals in AEM

OSGi is the module system managing all Java code in AEM. Every Java piece — your code, AEM's code, third-party libraries — runs inside an **OSGi bundle**. Understanding OSGi is essential for writing services, managing configurations, and debugging.

***

### 1. What is OSGi?

OSGi (Open Services Gateway initiative) is a modular architecture specification for Java applications. In AEM, it is implemented by **Apache Felix**.

Core concepts:

| Concept           | Description                                                                                   |
| ----------------- | --------------------------------------------------------------------------------------------- |
| **Bundle**        | A JAR file with special metadata. It is the deployment unit                                   |
| **Service**       | A Java interface registered in the service registry. Other bundles can look up and consume it |
| **Component**     | A managed Java class that provides services and consumes other services                       |
| **Configuration** | Key-value set used to alter component behavior without redeploying                            |

```mermaid
graph TD
    A[OSGi Framework - Apache Felix] --> B[Bundle]
    A --> C[Service Registry]
    A --> D[Configuration Admin]
    B --> E[Component]
    E -->|registers| C
    E -->|consumes| C
    D -->|configures| E
```

***

### 2. Bundles

A bundle is a JAR file declaring OSGi metadata in `MANIFEST.MF`:

```
Bundle-SymbolicName: com.mysite.core
Bundle-Version: 1.0.0
Import-Package: org.apache.sling.api, javax.inject
Export-Package: com.mysite.core.models
```

In Maven projects, the `core/` module produces an OSGi bundle. The `maven-bundle-plugin` (or `bnd-maven-plugin`) automatically generates the manifest.

#### Bundle Lifecycle

Each bundle passes through these states:

| State         | Meaning                                                          |
| ------------- | ---------------------------------------------------------------- |
| **Installed** | Bundle loaded into container, but dependencies remain unresolved |
| **Resolved**  | All imports satisfied; ready to start                            |
| **Active**    | Running — services registered                                    |
| **Stopping**  | Shutting down                                                    |

```mermaid
stateDiagram-v2
    [*] --> Installed : deploy JAR
    Installed --> Resolved : all imports satisfied
    Resolved --> Active : bundle.start()
    Active --> Stopping : bundle.stop()
    Stopping --> Resolved : stop complete
    Resolved --> Installed : dependency removed
    Installed --> [*] : uninstall

    note right of Installed
        Missing dependency → bundle stuck here
        Check at /system/console/bundles
    end note
```

> **Note:** If a bundle gets stuck in the **Installed** state instead of **Active**, dependencies are unresolved. Web Console displays missing packages.

***

### 3. Services

Services are the primary communication method between Java components in OSGi. A service consists of:

1. A **Java interface** defining the contract
2. An **implementation class** registered in the service registry
3. **Consumers** looking up and using the service

```mermaid
graph LR
    subgraph Bundle A
        I[GreetingService interface]
        Impl[GreetingServiceImpl]
        Impl -->|implements| I
    end
    subgraph OSGi Runtime
        SR[(Service Registry)]
    end
    subgraph Bundle B
        C[SomeOtherServiceImpl]
    end
    Impl -->|register @Component| SR
    C -->|inject @Reference| SR
```

#### Declarative Services (DS)

Modern AEM uses **OSGi Declarative Services** with annotations:

**Interface Definition:**

```java
package com.mysite.core.services;

public interface GreetingService {
    String greet(String name);
}
```

**Implementation:**

```java
package com.mysite.core.services.impl;

import com.mysite.core.services.GreetingService;
import org.osgi.service.component.annotations.Component;

@Component(service = GreetingService.class)
public class GreetingServiceImpl implements GreetingService {

    @Override
    public String greet(String name) {
        return "Hello, " + name + "!";
    }
}
```

The `@Component` annotation informs OSGi:

- This class is a **managed component**
- It provides the `GreetingService` **service interface**
- OSGi manages its lifecycle and registers it in the service registry

#### Consuming Services

Services reference other services using `@Reference`:

```java
import com.mysite.core.services.GreetingService;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(service = SomeOtherService.class)
public class SomeOtherServiceImpl implements SomeOtherService {

    @Reference
    private GreetingService greetingService;

    public void doSomething() {
        String message = greetingService.greet("AEM");
    }
}
```

Inside Sling Models, use `@OSGiService`:

```java
@Model(
    adaptables = {SlingHttpServletRequest.class, Resource.class},
    adapters = {GreetingModel.class, ComponentExporter.class},
    resourceType = GreetingModel.RESOURCE_TYPE,
    defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class GreetingModel {

    @OSGiService
    private GreetingService greetingService;

    @PostConstruct
    public void init() {
        final String message = greetingService.greet("AEM");
    }
}
```

OSGi automatically **injects** the service. If the service is unavailable, the component will not activate — known as **dependency satisfaction**.

#### Service Ranking

When multiple implementations exist for an interface, OSGi uses **service ranking** to choose which is injected:

```java
@Component(
    service = GreetingService.class,
    property = {
        "service.ranking:Integer=100"
    }
)
public class CustomGreetingServiceImpl implements GreetingService {
    // Priority implementation over lower ranking ones
}
```

Higher ranking wins when picking a single service (default cardinality for `@Reference` is **mandatory/unary**). This is how default AEM services are overridden.

Control cardinality and target filtering on `@Reference`:

```java
// Optional: component activates even if no implementation exists
@Reference(cardinality = ReferenceCardinality.OPTIONAL)
private GreetingService greetingService;

// Multiple: inject all implementations (List)
@Reference(cardinality = ReferenceCardinality.MULTIPLE)
private List<GreetingService> greetingServices;

// Target filter: pick specific implementation by property
@Reference(target = "(service.pid=com.mysite.core.services.impl.CustomGreetingServiceImpl)")
private GreetingService greetingService;
```

***

### 4. OSGi Web Console

Web Console is a versatile debugging tool. Access at:

```
http://localhost:4502/system/console
```

Credentials: **admin / admin**

#### Important Console Pages

| Console               | URL                           | Displays                                           |
| --------------------- | ----------------------------- | -------------------------------------------------- |
| **Bundles**           | `/system/console/bundles`     | All installed bundles and status                   |
| **Components**        | `/system/console/components`  | All DS components (active, satisfied, unsatisfied) |
| **Services**          | `/system/console/services`    | All registered services                            |
| **Configuration**     | `/system/console/configMgr`   | All OSGi configurations                            |
| **Resource Resolver** | `/system/console/jcrresolver` | Test resource resolution                           |
| **Log Support**       | `/system/console/slinglog`    | Logging configuration                              |

```mermaid
graph TD
    WebConsole["/system/console"] --> Bundles["/bundles<br/>Bundle status"]
    WebConsole --> Components["/components<br/>DS Components"]
    WebConsole --> Services["/services<br/>Service Registry"]
    WebConsole --> ConfigMgr["/configMgr<br/>OSGi Configurations"]
    WebConsole --> JcrResolver["/jcrresolver<br/>Resource Resolution"]
    WebConsole --> SlingLog["/slinglog<br/>Log Configuration"]

    Bundles -->|bundle stuck Installed| Debug1[Check unresolved imports]
    Components -->|component unsatisfied| Debug2[Check missing references]
    ConfigMgr -->|incorrect config| Debug3[Check PID and run mode folder]
```

#### Debugging Unstarted Bundles

1. Go to **Bundles** (`/system/console/bundles`)
2. Find your bundle (search by `Bundle-SymbolicName`)
3. If bundle state is **Installed** (not Active), click it to inspect **unresolved imports**
4. Missing packages identify unresolved dependencies

**Common Causes:**

- Third-party library not embedded into bundle
- Package version conflict between custom code and AEM
- Missing AEM API dependency

#### Test Resource Resolution

The **Sling Resource Resolver** page tests URL resolution:

1. Access `/system/console/jcrresolver`
2. Enter URL (e.g. `/content/mysite/en/about.html`)
3. Click **Resolve** to view matched resource and rendering script

***

### 5. OSGi Configurations

Configurations modify service behavior without code edits. Stored in JCR and varied by **run mode** (author, publish, dev, stage, prod).

#### Declaring Configurations via Annotations

Use `@ObjectClassDefinition` and `@AttributeDefinition`:

```java
package com.mysite.core.services.impl;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "Greeting Service Configuration")
public @interface GreetingServiceConfig {

    @AttributeDefinition(
        name = "Default Greeting",
        description = "The greeting prefix to use"
    )
    String greeting_prefix() default "Hello";

    @AttributeDefinition(
        name = "Enabled",
        description = "Whether the service is active"
    )
    boolean enabled() default true;
}
```

#### Consuming Configurations in Services

```java
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.Designate;

@Component(service = GreetingService.class)
@Designate(ocd = GreetingServiceConfig.class)
public class GreetingServiceImpl implements GreetingService {

    private String prefix;
    private boolean enabled;

    @Activate
    protected void activate(GreetingServiceConfig config) {
        this.prefix = config.greeting_prefix();
        this.enabled = config.enabled();
    }

    @Override
    public String greet(String name) {
        if (!enabled) {
            return "";
        }
        return prefix + ", " + name + "!";
    }
}
```

The `@Activate` method executes when the component starts and receives active configurations.

#### Configuration Files in Repository

Configurations are stored as `.cfg.json` files inside module `ui.config`:

```
ui.config/src/main/content/jcr_root/apps/mysite/osgiconfig/
├── config/                          # All environments
│   └── com.mysite.core.services.impl.GreetingServiceImpl.cfg.json
├── config.author/                   # Author only
├── config.publish/                  # Publish only
├── config.dev/                      # Dev environment
├── config.stage/                    # Stage environment
└── config.prod/                     # Production
```

File content:

```json
{
  "greeting.prefix": "Welcome",
  "enabled": true
}
```

> **Naming Convention:** Annotation method `greeting_prefix()` maps to config key `greeting.prefix`. OSGi converts underscores (`_`) in method names to dots (`.`) in configuration keys.

| Method Name         | Config Property Key |
| ------------------- | ------------------- |
| `greeting_prefix()` | `greeting.prefix`   |
| `my__property()`    | `my_property`       |
| `trailing_()`       | `trailing`          |

#### Run Modes

Run modes determine active configurations:

| Run Mode  | Active Context          |
| --------- | ----------------------- |
| `author`  | Author instance         |
| `publish` | Publish instance        |
| `dev`     | Development environment |
| `stage`   | Stage environment       |
| `prod`    | Production environment  |

```mermaid
graph TD
    Base["config/<br/>(applies to all environments)"]
    Base --> Author["config.author/<br/>Author instance only"]
    Base --> Publish["config.publish/<br/>Publish instance only"]
    Base --> Dev["config.dev/<br/>Dev environment"]
    Base --> Stage["config.stage/<br/>Stage environment"]
    Base --> Prod["config.prod/<br/>Production environment"]
```

Configurations are **cumulative** — `config/` applies universally, while specific folders add/override properties when matching run modes are active.

> **Tip:** Keep defaults in `config/`, adding specific environment overrides in respective folders.

#### Editing Configurations via Web Console

During development, edit configurations directly:

1. Go to `/system/console/configMgr`
2. Search for your service name
3. Edit values and click **Save**

> **Important:** Console edits are transient — lost upon instance restart. For durable configurations, use `.cfg.json` files in `ui.config`.

***

### 6. Component Lifecycle Annotations

In addition to `@Activate`, OSGi supports other lifecycle annotations:

```java
@Component(service = MyService.class)
public class MyServiceImpl implements MyService {

    @Activate
    protected void activate(MyConfig config) {
        // Called when component starts
        // Initialize resources, read config
    }

    @Modified
    protected void modified(MyConfig config) {
        // Called when configuration updates at runtime
        // Update internal state without restarting
    }

    @Deactivate
    protected void deactivate() {
        // Called when component stops
        // Release resources
    }
}
```

| Annotation    | Invocation Trigger                                 |
| ------------- | -------------------------------------------------- |
| `@Activate`   | Component starts (all dependencies satisfied)      |
| `@Modified`   | Configuration changes while component is active    |
| `@Deactivate` | Component stops (bundle stops, or dependency lost) |

```mermaid
sequenceDiagram
    participant OSGi as OSGi Runtime
    participant Comp as MyServiceImpl
    participant Config as Configuration Admin

    OSGi->>Comp: new MyServiceImpl()
    OSGi->>Comp: inject @Reference dependencies
    Config->>Comp: @Activate(config)
    Note over Comp: Component ACTIVE - services registered

    Config->>Comp: @Modified(newConfig)
    Note over Comp: Update state without restart

    OSGi->>Comp: @Deactivate()
    Note over Comp: Release resources
    OSGi->>Comp: Cleanup instance
```

***

### 7. Sling Models and OSGi

Sling Models are **not** standard Declarative Services components (`@Component`). Instead, Sling Model metadata is discovered by the Sling Models framework running inside OSGi:

```java
@Model(adaptables = Resource.class, adapters = MyModel.class)
public class MyModelImpl implements MyModel {
    // ...
}
```

```mermaid
graph LR
    subgraph "Core Bundle"
        SM["MyModelImpl<br/>@Model"]
        DS["GreetingServiceImpl<br/>@Component"]
    end
    subgraph "OSGi Runtime"
        SR["(Service Registry)"]
        SMF["Sling Models Framework"]
    end
    DS -->|registers| SR
    SMF -->|discovers model| SM
    SM -->|@OSGiService injects from| SR
    SMF -->|runs as OSGi service in| SR
```

The `core/` bundle still requires proper metadata and dependencies because model discovery and adaptation execute within the OSGi runtime.

***

### 8. Troubleshooting Guide

| Symptom                            | First Check                                         | Common Fix                                               |
| ---------------------------------- | --------------------------------------------------- | -------------------------------------------------------- |
| Bundle stuck in `Installed`        | `/system/console/bundles` — inspect imports/exports | Add/fix dependencies or package versions                 |
| Component unsatisfied              | `/system/console/components` — inspect references   | Register missing service or relax reference cardinality  |
| Config not applying                | `/system/console/configMgr` — verify PID and values | Fix PID/filename, verify run mode folder                 |
| Unexpected service implementation  | `/system/console/services` — inspect ranking        | Adjust `service.ranking` and target filters              |
| Works on local SDK, fails on cloud | Cloud logs + committed config files                 | Commit console edits as `.cfg.json` files in `ui.config` |

```mermaid
flowchart TD
    Start([Troubleshoot OSGi Issue]) --> Q1{Bundle State?}

    Q1 -->|Installed| A1["/system/console/bundles<br/>Inspect unresolved imports"]
    Q1 -->|Resolved but Component unsatisfied| A2["/system/console/components<br/>Inspect missing references"]
    Q1 -->|Active but incorrect behavior| A3["/system/console/configMgr<br/>Inspect configuration"]

    A1 --> F1{Missing package found?}
    F1 -->|Yes| Fix1["Add dependency to pom.xml<br/>or embed library in bundle"]
    F1 -->|No| Fix1b["Check version conflicts<br/>in Import-Package"]

    A2 --> F2{Service reference missing?}
    F2 -->|Yes| Fix2["Register missing service<br/>or change cardinality to OPTIONAL"]
    F2 -->|No| Fix2b["Check service.ranking<br/>and target filter"]

    A3 --> F3{PID correct?}
    F3 -->|No| Fix3["Fix .cfg.json filename<br/>to match class FQN"]
    F3 -->|Yes| Fix3b["Check run mode folder<br/>and property values"]

    Fix1 --> End([Resolved ✅])
    Fix1b --> End
    Fix2 --> End
    Fix2b --> End
    Fix3 --> End
    Fix3b --> End
```

***

### 9. Common OSGi Patterns in AEM

#### Pattern 1: Service Interface + Implementation

Separate interfaces from implementations:

```
com.mysite.core.services/
├── GreetingService.java          # Interface (exported)
└── impl/
    └── GreetingServiceImpl.java  # Implementation (not exported)
```

The interface resides in an **exported** package. The implementation lives in an unexported `impl` sub-package, ensuring encapsulation.

```mermaid
graph LR
    subgraph "Package: com.mysite.core.services (EXPORTED)"
        I[GreetingService.java<br/>interface]
    end
    subgraph "Package: com.mysite.core.services.impl (NOT EXPORTED)"
        Impl[GreetingServiceImpl.java<br/>class]
    end
    subgraph "Consumer Bundle B"
        C[SomeOtherServiceImpl]
    end
    Impl -->|implements| I
    C -->|@Reference — sees interface only| I
```

#### Pattern 2: Scheduler Service

Execute code on schedule:

```java
@Component(
    service = Runnable.class,
    property = {
        "scheduler.expression=0 0 2 * * ?",  // Every day at 2:00 AM
        "scheduler.concurrent=false"
    }
)
public class DailyCleanupJob implements Runnable {

    @Override
    public void run() {
        // Cleanup logic
    }
}
```

#### Pattern 3: Event Handler

React to OSGi events:

```java
@Component(
    service = EventHandler.class,
    property = {
        "event.topics=org/apache/sling/api/resource/Resource/CHANGED"
    }
)
public class ResourceChangeHandler implements EventHandler {

    @Override
    public void handleEvent(Event event) {
        String path = (String) event.getProperty("path");
        if (path != null) {
            // Handle resource change at path
        }
    }
}
```

> **AEM 6.5 vs AEMaaCS Note:** Classic replication events (`com/day/cq/replication/job/publish`) apply to AEM 6.5. In AEM as a Cloud Service, content distribution replaces classic replication. For resource tracking, prefer `ResourceChangeListener` or OSGi events with resource topics.

***

### Summary

```text
OSGi in AEM
├── Bundle
│   ├── JAR file with special MANIFEST.MF
│   ├── Lifecycle: Installed → Resolved → Active
│   └── Debug at /system/console/bundles
├── Service
│   ├── Java interface + implementation
│   ├── Register via @Component
│   ├── Inject via @Reference / @OSGiService
│   └── Ranking for overrides
├── Configuration
│   ├── @ObjectClassDefinition / @AttributeDefinition
│   ├── .cfg.json files in ui.config
│   └── Run modes: author, publish, dev, stage, prod (cumulative)
├── Lifecycle Annotations
│   ├── @Activate — component starts
│   ├── @Modified — config changes at runtime
│   └── @Deactivate — component stops
├── Web Console
│   ├── /system/console/bundles
│   ├── /system/console/components
│   └── /system/console/configMgr
└── Patterns
    ├── Service interface + impl separation
    ├── Scheduler — Runnable + cron expression
    └── Event Handler — react to OSGi events
```
