implement an "event-listener" that listens for page deletions in the source language-master folder, finds live copies, and deletes them automatically.
Create a Sling event listener that listens to JCR NODE_REMOVED events under /content/language-master.
package com.example.aem.listeners;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.Session;
import org.apache.sling.api.resource.PersistenceException;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.jcr.RepositoryException;
import javax.jcr.Node;
import com.day.cq.wcm.msm.api.LiveRelationshipManager;
import com.day.cq.wcm.msm.api.LiveRelationship;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Component(
immediate = true,
service = EventListener.class,
property = {
"event.topics=org/apache/jackrabbit/jcr/observation/namespace/REMOVED",
"event.types=NODE_REMOVED"
}
)
public class PageDeleteListener implements EventListener {
private static final Logger LOG = LoggerFactory.getLogger(PageDeleteListener.class);
@3214626
private ResourceResolverFactory resolverFactory;
@3214626
private LiveRelationshipManager liveRelationshipManager;
private static final String LANGUAGE_MASTER_PATH = "/content/language-master";
@9944223
public void onEvent(EventIterator events) {
while (events.hasNext()) {
Event event = events.nextEvent();
try {
String path = event.getPath();
// Check if deleted node is under language-master
if (path != null && path.startsWith(LANGUAGE_MASTER_PATH)) {
LOG.info("Detected deletion of source page: {}", path);
// Obtain a ResourceResolver with write permission
Map<String, Object> params = new HashMap<>();
params.put(ResourceResolverFactory.SUBSERVICE, "datawrite"); // make sure this service user exists with required perms
try (ResourceResolver resolver = resolverFactory.getServiceResourceResolver(params)) {
Resource deletedPageResource = resolver.getResource(path);
// Since node is deleted, this resource might be null
// Instead, get the parent path to find live copies
String sourcePagePath = path;
// Get live relationships for the source path
Collection<LiveRelationship> liveRelationships = liveRelationshipManager.getLiveRelationships(sourcePagePath);
for (LiveRelationship liveRel : liveRelationships) {
Resource liveCopy = liveRel.getLiveCopy();
if (liveCopy != null) {
LOG.info("Deleting live copy page at: {}", liveCopy.getPath());
deletePage(resolver, liveCopy);
}
}
resolver.commit();
} catch (Exception e) {
LOG.error("Failed to delete live copies for source page: {}", path, e);
}
}
} catch (RepositoryException e) {
LOG.error("Error processing deletion event", e);
}
}
}
private void deletePage(ResourceResolver resolver, Resource pageResource) throws PersistenceException {
if (pageResource != null) {
resolver.delete(pageResource);
LOG.info("Deleted page {}", pageResource.getPath());
}
}
}
- Configure a service user (e.g., datawrite) with write permissions on your content paths (including language-master and live copies).
- Bind the service user in your OSGi config for ResourceResolverFactory under Apache Sling Service User Mapper Service.
- Make sure the service user has jcr:removeChildNodes and jcr:removeNode permissions on the live copy paths.
- Deploy your listener bundle.
- Test by deleting a page under /content/language-master and verify if the corresponding live copies get deleted.