/event-migration
AEM Cloud Service expert skill for OSGi Event Admin handlers (non-resource events). Covers migration of javax.jcr.observation.EventListener (residual non-resource cases) and OSGi EventHandler with inline business logic to the lightweight EventHandler + JobConsumer split.
$ npx -y skills add adobe/skills --skill event-migration --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/event-migration
Context preview
The summary Claude sees to decide when to auto-load this skill.
AEM Cloud Service expert skill for OSGi Event Admin handlers (non-resource events). Covers migration of javax.jcr.observation.EventListener (residual non-resource cases) and OSGi EventHandler with inline business logic to the lightweight EventHandler + JobConsumer split.
SKILL.md
event-migration.SKILL.mdname: event-migration
description: AEM Cloud Service expert skill for OSGi Event Admin handlers (non-resource events). Covers migration of javax.jcr.observation.EventListener (residual non-resource cases) and OSGi EventHandler with inline business logic to the lightweight EventHandler + JobConsumer split. Includes routing rules (resource events go to resource-change-listener, external notification goes to AEM Eventing), TopologyEventListener for leader-only execution, replication and workflow event patterns, service-user setup, review checklist, troubleshooting, and common pitfalls.
license: Apache-2.0
Event Migration — AEM as a Cloud Service
Overview
`org.osgi.service.event.EventHandler` is the API for reacting to **non-resource** OSGi Event Admin events on AEM CS — replication events (`com.day.cq.replication.ReplicationEvent.EVENT_TOPIC`), workflow events (`com/adobe/granite/workflow/*`), and custom inter-bundle event topics. The handler runs on a shared OSGi event thread and **must** stay lightweight — all business logic must be offloaded to a Sling Job via `JobManager.addJob()`.
**Three CS-specific constraints every event handler must satisfy:**
| Constraint | Why | |-----------|-----| | No `ResourceResolver` / `Session` / JCR ops inside `handleEvent()` | Blocks the shared OSGi event-admin thread; can delay every other registered handler | | `getServiceResourceResolver(SUBSERVICE)` in the consumer | `getAdministrativeResourceResolver` is removed from the CS SDK | | Leader-only handlers must implement `TopologyEventListener` and check `isLeader` | A simple run-mode check fires on every author cluster pod — `TopologyEventListener` is the supported way to elect a single leader |
> **`handleEvent()` runs synchronously on a shared OSGi thread.** Doing repository, network, or workflow work inline blocks event delivery for every other handler subscribed to anything. Always offload to a `JobConsumer`.
---
Routing — is this the right skill?
**Use this skill when** the source listens to a **non-resource** OSGi Event Admin topic:
| Source topic | Description | |--------------|-------------| | `com.day.cq.replication.ReplicationEvent.EVENT_TOPIC` | Replication actions (activate, deactivate, etc.) | | `com/adobe/granite/workflow/*` | Workflow lifecycle events | | Custom OSGi topics posted by another bundle | Inter-bundle event signaling | | Other non-resource OSGi events | Any OSGi event that is not a resource-change topic |
**Route elsewhere when:**
| Source observes… | Use instead | |------------------|-------------| | Repository content (page, asset, property added/changed/removed) | **`resource-change-listener` skill** — `ResourceChangeListener` is the supported API on CS | | External system notification (Adobe I/O Events, App Builder, webhooks, downstream services) | **AEM Eventing** — cloud-native, runs outside AEM, distinct from OSGi Event Admin | | Anything subscribed to `org/apache/sling/api/resource/Resource/*` | **`resource-change-listener` skill** — those OSGi resource topics are a deprecated internal Sling dispatcher detail |
**Do not** subscribe a new `EventHandler` to `org/apache/sling/api/resource/Resource/ADDED|CHANGED|REMOVED`. Those topics are an internal Sling dispatcher detail, deprecated as an application-facing API. Use `ResourceChangeListener` for resource observation.
Where to find topic constants
Always subscribe via a documented topic constant — never invent or copy-paste a topic string. The canonical constants live in the producing bundle's API:
| Producing API | Constant | |---------------|----------| | Replication | `com.day.cq.replication.ReplicationEvent.EVENT_TOPIC` | | Workflow | `com.adobe.granite.workflow.event.WorkflowEvent.EVENT_TOPIC` — combine with `WorkflowEvent.EVENT_TYPE` property to discriminate the sub-event | | Sling Jobs (lifecycle) | `org.apache.sling.event.jobs.NotificationConstants.*` | | Custom bundle topics | Check the producing bundle's source or documentation for its declared `static final String` topic constant |
A typo'd topic string compiles fine and silently subscribes to a topic that nothing posts to — the handler is `ACTIVE` but never fires. Reference the constant in code instead of duplicating the literal string.
---
Classification — choose before making any changes
**Implements `EventHandler` for a non-resource topic** and `handleEvent()` only enqueues jobs → Already compliant — verify against the [Review Checklist](#review-checklist) only.
**Implements `EventHandler` for a non-resource topic** and `handleEvent()` contains business logic (resolver, JCR ops, heavy processing) → Apply **E1–E5**.
**Implements `javax.jcr.observation.EventListener`** for a concern that **cannot** be expressed as a `ResourceChangeListener` (rare — most legacy JCR listeners should route to the `resource-change-listener` skill) → Apply **E0** (convert to `EventHandler` for the appropriate non-resource topic) then **E1–E5**. If unsure whether RCL covers it, prefer RCL and ask before falling through to this skill.
**One pattern per session.** If the bundle has multiple legacy handlers, migrate one class at a time.
**Before starting:** Read [`../references/aem-cloud-service-pattern-prerequisites.md`](../references/aem-cloud-service-pattern-prerequisites.md) and apply SCR→DS, service-user, and SLF4J fixes if present in the same changeset.
---
Discovery
Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook:
bash ../scripts/analyze.sh <workspace-root> --pattern event-migration
**Match criteria (what the detector flags):** a class that **`implements org.osgi.service.event.EventHandler`** or **`javax.jcr.observation.EventListener`** (import-aware) — both map here per the BPA subtype taxonomy.
Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause; the subscribed topic (resource vs non-
Read more
name: event-migration description: AEM Cloud Service expert skill for OSGi Event Admin handlers (non-resource events). Covers migration of javax.jcr.observation.EventListener (residual non-resource cases) and OSGi EventHandler with inline business logic to the lightweight EventHandler + JobConsumer split. Includes routing rules (resource events go to resource-change-listener, external notification goes to AEM Eventing), TopologyEventListener for leader-only execution, replication and workflow event patterns, service-user setup, review checklist, troubleshooting, and common pitfalls. license: Apache-2.0
Event Migration — AEM as a Cloud Service
Overview
`org.osgi.service.event.EventHandler` is the API for reacting to **non-resource** OSGi Event Admin events on AEM CS — replication events (`com.day.cq.replication.ReplicationEvent.EVENT_TOPIC`), workflow events (`com/adobe/granite/workflow/*`), and custom inter-bundle event topics. The handler runs on a shared OSGi event thread and **must** stay lightweight — all business logic must be offloaded to a Sling Job via `JobManager.addJob()`.
**Three CS-specific constraints every event handler must satisfy:**
| Constraint | Why | |-----------|-----| | No `ResourceResolver` / `Session` / JCR ops inside `handleEvent()` | Blocks the shared OSGi event-admin thread; can delay every other registered handler | | `getServiceResourceResolver(SUBSERVICE)` in the consumer | `getAdministrativeResourceResolver` is removed from the CS SDK | | Leader-only handlers must implement `TopologyEventListener` and check `isLeader` | A simple run-mode check fires on every author cluster pod — `TopologyEventListener` is the supported way to elect a single leader |
> **`handleEvent()` runs synchronously on a shared OSGi thread.** Doing repository, network, or workflow work inline blocks event delivery for every other handler subscribed to anything. Always offload to a `JobConsumer`.
---
Routing — is this the right skill?
**Use this skill when** the source listens to a **non-resource** OSGi Event Admin topic:
| Source topic | Description | |--------------|-------------| | `com.day.cq.replication.ReplicationEvent.EVENT_TOPIC` | Replication actions (activate, deactivate, etc.) | | `com/adobe/granite/workflow/*` | Workflow lifecycle events | | Custom OSGi topics posted by another bundle | Inter-bundle event signaling | | Other non-resource OSGi events | Any OSGi event that is not a resource-change topic |
**Route elsewhere when:**
| Source observes… | Use instead | |------------------|-------------| | Repository content (page, asset, property added/changed/removed) | **`resource-change-listener` skill** — `ResourceChangeListener` is the supported API on CS | | External system notification (Adobe I/O Events, App Builder, webhooks, downstream services) | **AEM Eventing** — cloud-native, runs outside AEM, distinct from OSGi Event Admin | | Anything subscribed to `org/apache/sling/api/resource/Resource/*` | **`resource-change-listener` skill** — those OSGi resource topics are a deprecated internal Sling dispatcher detail |
**Do not** subscribe a new `EventHandler` to `org/apache/sling/api/resource/Resource/ADDED|CHANGED|REMOVED`. Those topics are an internal Sling dispatcher detail, deprecated as an application-facing API. Use `ResourceChangeListener` for resource observation.
Where to find topic constants
Always subscribe via a documented topic constant — never invent or copy-paste a topic string. The canonical constants live in the producing bundle's API:
| Producing API | Constant | |---------------|----------| | Replication | `com.day.cq.replication.ReplicationEvent.EVENT_TOPIC` | | Workflow | `com.adobe.granite.workflow.event.WorkflowEvent.EVENT_TOPIC` — combine with `WorkflowEvent.EVENT_TYPE` property to discriminate the sub-event | | Sling Jobs (lifecycle) | `org.apache.sling.event.jobs.NotificationConstants.*` | | Custom bundle topics | Check the producing bundle's source or documentation for its declared `static final String` topic constant |
A typo'd topic string compiles fine and silently subscribes to a topic that nothing posts to — the handler is `ACTIVE` but never fires. Reference the constant in code instead of duplicating the literal string.
---
Classification — choose before making any changes
**Implements `EventHandler` for a non-resource topic** and `handleEvent()` only enqueues jobs → Already compliant — verify against the [Review Checklist](#review-checklist) only.
**Implements `EventHandler` for a non-resource topic** and `handleEvent()` contains business logic (resolver, JCR ops, heavy processing) → Apply **E1–E5**.
**Implements `javax.jcr.observation.EventListener`** for a concern that **cannot** be expressed as a `ResourceChangeListener` (rare — most legacy JCR listeners should route to the `resource-change-listener` skill) → Apply **E0** (convert to `EventHandler` for the appropriate non-resource topic) then **E1–E5**. If unsure whether RCL covers it, prefer RCL and ask before falling through to this skill.
**One pattern per session.** If the bundle has multiple legacy handlers, migrate one class at a time.
**Before starting:** Read [`../references/aem-cloud-service-pattern-prerequisites.md`](../references/aem-cloud-service-pattern-prerequisites.md) and apply SCR→DS, service-user, and SLF4J fixes if present in the same changeset.
---
Discovery
Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook:
bash ../scripts/analyze.sh <workspace-root> --pattern event-migration
**Match criteria (what the detector flags):** a class that **`implements org.osgi.service.event.EventHandler`** or **`javax.jcr.observation.EventListener`** (import-aware) — both map here per the BPA subtype taxonomy.
Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause; the subscribed topic (resource vs non-
Repo: adobe/skills
Other skills on adobe-skills.
- /aa-conversion-funnel-analysis
Analyzes a multi-step conversion funnel to find where visitors drop off and which steps have the worst leakage. Use this skill when someone describes a journey and asks about conversion rates, drop-off, fallout, or step completion. Trigger for "analyze our checkout funnel,"
Open skill - /aa-executive-briefing
Generates a concise, executive-ready performance summary covering key metrics, trends, and what's driving movement. Use this skill when someone needs to produce a briefing, executive summary, performance narrative, or stakeholder readout — for example, "write an exec summary of
Open skill - /aa-kpi-pulse
Produces a compact KPI digest showing how key metrics changed over a period and what's driving the movement. Use this skill when someone asks for a performance summary, a weekly recap, a morning briefing, a KPI update, or any variation of "how did we do this week/month." Also
Open skill - /aa-segment-performance-comparator
Compares the performance of two or more audience segments across key metrics side by side. Use this skill when someone wants to compare audiences or visitor groups — for example, "how do mobile visitors compare to desktop on conversion," "compare new vs. returning visitors,"
Open skill - /aa-top-movers-watchlist
Identifies which items (pages, campaigns, products, channels, regions) had the biggest increases or decreases for a key metric between two time periods. Use this skill when someone asks "what's up and what's down," "which campaigns moved the most," "top gainers and losers,"
Open skill - /cja-dimension-analysis
Comprehensive dimension analysis and reporting for CJA. Use this skill whenever the user wants to analyze one or more dimensions — including cardinality, distribution/skew, trends, anomalies, data quality errors, comparisons, and forecasting. Also trigger when someone asks "what
Open skill

