Skip to content
AI & Agents
Skill

/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.

From plugin
adobe-skills
162160 skills6 agents4 MCP
Install
$ npx -y skills add adobe/skills --skill event-migration --agent claude-code

How 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.md
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-

Read more
Ships withadobe-skills

Repository of Adobe skills for AI coding agents.

Get the whole plugin

Other skills on adobe-skills.