aa-conversion-funnel-a…
Analyzes a multi-step conversion funnel to find where visitors drop off and which steps have…
AEM Cloud Service expert skill for Sling ResourceChangeListener. Covers the lightweight listener + JobConsumer pattern, migration from javax.jcr.observation.EventListener and resource-topic OSGi EventHandler, ResourceChangeListener vs ExternalResourceChangeListener decision,
$ npx -y skills add adobe/skills --skill resource-change-listener --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/resource-change-listenerContext preview
The summary Claude sees to decide when to auto-load this skill.
AEM Cloud Service expert skill for Sling ResourceChangeListener. Covers the lightweight listener + JobConsumer pattern, migration from javax.jcr.observation.EventListener and resource-topic OSGi EventHandler, ResourceChangeListener vs ExternalResourceChangeListener decision,
name: resource-change-listener description: AEM Cloud Service expert skill for Sling ResourceChangeListener. Covers the lightweight listener + JobConsumer pattern, migration from javax.jcr.observation.EventListener and resource-topic OSGi EventHandler, ResourceChangeListener vs ExternalResourceChangeListener decision, OSGi filter configuration, review checklist, troubleshooting (silent failures, hot-path blocking, missing service-user mapping), and common pitfalls. license: Apache-2.0
`org.apache.sling.api.resource.observation.ResourceChangeListener` is the preferred API on AEM CS for reacting to repository content changes. The listener runs on a shared Sling thread and should return as quickly as possible.
For any blocking, repository-intensive, network, workflow, replication, indexing, asset-processing, or otherwise non-trivial work, enqueue a Sling Job and perform the processing in a `JobConsumer`.
Very small in-memory operations (metrics, counters, simple event translation, lightweight filtering, or enqueueing a job) may remain inside `onChange()` provided they do not perform repository access, network I/O, workflow operations, or expensive computation.
Two interface variants:
| Interface | Receives | Use when | |-----------|----------|----------| | `ResourceChangeListener` | Local changes only (same JVM) | Post-processing what *this* pod just wrote | | `ExternalResourceChangeListener` (extends RCL) | Local **and** external (other cluster nodes) | Cluster-wide reactions: cache invalidation, replication follow-ups |
Three CS-specific constraints every listener must satisfy:
| Constraint | Why | |-----------|-----| | No `ResourceResolver` / `Session` / JCR ops inside `onChange()` | Blocks the shared listener thread; delays every other registered listener | | `getServiceResourceResolver(SUBSERVICE)` in the consumer | `getAdministrativeResourceResolver` is removed from the CS SDK | | Filter via `PATHS` / `CHANGES` OSGi properties — not in code | Sling delivers only matching events; in-code filtering wastes the listener thread |
> **`PATHS` are chosen by the implementer from the business scope.** Do not ask the customer for raw `PATHS` syntax (`/content/dam`, `glob:/**/jcr:content/*`, etc.) unless the business scope itself is unclear. Derive the path from what the listener is supposed to react to.
---
**Already implements `ResourceChangeListener`** and `onChange()` only enqueues jobs → Already compliant — verify against the [Review Checklist](#review-checklist) only.
**Already implements `ResourceChangeListener`** and `onChange()` contains business logic (resolver, JCR ops, heavy processing) → Apply **R1–R5** (skip R0).
**Implements `javax.jcr.observation.EventListener`** or **`EventHandler`** subscribed to `org/apache/sling/api/resource/Resource/*` → Apply **R0 then R1–R5**.
**Implements `EventHandler`** subscribed to replication / workflow / custom topics → Use the `event-migration` skill instead — not this one.
**One pattern per session.** If the bundle has multiple legacy listeners, 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.
---
Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook:
bash ../scripts/analyze.sh <workspace-root> --pattern resource-change-listener
**Match criteria (what the detector flags):** a class that **`implements org.apache.sling.api.resource.observation.ResourceChangeListener`** or **`ExternalResourceChangeListener`** (import-aware) — the modern API, flagged for review against the lightweight + JobConsumer contract.
Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause; reached-via-base-class is not resolved. Legacy `javax.jcr.observation.EventListener` is detected by the `event-migration` pattern (matching the BPA subtype taxonomy); when its logic is plain content observation, that guide routes it back here. A class implementing both `ResourceChangeListener` and an event interface is flagged by both patterns (rare).
**guided** — `apply (guided)`. The analyzer locates each `ResourceChangeListener`; remediation is judgment-based and applied via R0–R5 (per the Classification above) in an apply session.
| Site shape | Disposition | |---|---| | `implements ResourceChangeListener`, `onChange()` does repository/JCR/heavy work | apply (guided) → R1–R5 | | Legacy `javax.jcr.observation.EventListener` / resource-topic `EventHandler` routed here *(arrives via `event-migration` redirect or migration handoff — this pattern's own detector flags only the modern API)* | apply (guided) → R0 then R1–R5 | | `implements ResourceChangeListener`, `onChange()` only enqueues a Sling Job | skipped: `already-compliant` | | Test code (`src/test/`) | skipped: `test-scope` |
---
package com.example.listeners;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
@Component(immediate = true)
@Service
public class ACLPolicyListener implements EventListener {
@Reference
private ResourceResolverFactory resolverFactory;
@Override
public void onEvent(EventIterator events) {
try {Repo: adobe/skills
Analyzes a multi-step conversion funnel to find where visitors drop off and which steps have…
Generates a concise, executive-ready performance summary covering key metrics, trends, and…
Produces a compact KPI digest showing how key metrics changed over a period and what's…
Compares the performance of two or more audience segments across key metrics side by side.…
Identifies which items (pages, campaigns, products, channels, regions) had the biggest…
Comprehensive dimension analysis and reporting for CJA. Use this skill whenever the user…