CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

adobe/aem-6-5-lts

All AEM 6.5 LTS skills: Workflow model design, development, triggering, launchers, debugging, and triaging; Dispatcher config authoring, advisory, incident response, performance tuning, and security hardening; Replication agent configuration, content activation, API usage, and troubleshooting for AEM 6.5 LTS and AMS environments; Jackrabbit Oak query/index tuning (property, Lucene index definitions); and extracting/inventorying JCR queries (XPath, SQL2, QueryBuilder) across a codebase.

Quality

79%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

api-reference.mdskills/aem-replication/references/replication-foundation/

Replication API Quick Reference

Quick reference for AEM 6.5 LTS Replication API methods and interfaces.

Core Interfaces

Replicator

Package: com.day.cq.replication.Replicator

Purpose: Core interface for replication operations

MethodParametersReturnsUse Case
replicate()Session, Type, StringvoidSimple activation/deactivation
replicate()Session, Type, String, OptionsvoidActivation with custom options
replicate()Session, Type, String[], OptionsvoidBulk activation of multiple paths
checkPermission()Session, Type, StringvoidVerify user can replicate (throws if denied)
getReplicationStatus()Session, StringReplicationStatusQuery replication state of resource
getActivatedPaths()Session, StringIteratorList all activated paths under root

ReplicationOptions

Package: com.day.cq.replication.ReplicationOptions

Purpose: Configure replication behavior

MethodParameterDefaultUse Case
setSynchronous()booleanfalseWait for replication to complete
setSuppressVersions()booleanfalseDon't create version on activation
setSuppressStatusUpdate()booleanfalseDon't update replication metadata
setFilter()AgentFilternullTarget specific agents only
setRevision()StringnullReplicate specific version

ReplicationStatus

Package: com.day.cq.replication.ReplicationStatus

Purpose: Query replication state

MethodReturnsDescription
isActivated()booleanTrue if replicated to at least one agent
isDeactivated()booleanTrue if deactivated
getLastPublished()CalendarLast activation timestamp
getLastPublishedBy()StringUser who last activated
getLastReplicationAction()StringLast action (ACTIVATE, DEACTIVATE, etc.)
getLastReplicatedRevision()StringVersion ID last replicated

AgentManager

Package: com.day.cq.replication.AgentManager

Purpose: Inspect and manage agents

MethodParametersReturnsUse Case
getAgents()-Map<String, Agent>Get all agents
getAgents()AgentFilterMap<String, Agent>Get filtered agents
getAgent()String agentIdAgentGet specific agent

ReplicationQueue

Package: com.day.cq.replication.ReplicationQueue

Purpose: Inspect queue state (read-only via JMX)

MethodReturnsDescription
getEntries()CollectionAll queued items
getSize()intQueue depth
getState()StateIDLE, RUNNING, BLOCKED, PAUSED

ReplicationListener

Package: com.day.cq.replication.ReplicationListener

Purpose: Monitor replication events

MethodParametersUse Case
onStart()Agent, ReplicationActionReplication initiated
onEnd()Agent, ReplicationAction, ReplicationResultReplication completed
onError()Agent, ReplicationAction, ExceptionReplication failed

ReplicationActionType Enum

Package: com.day.cq.replication.ReplicationActionType

ConstantPurpose
ACTIVATEPublish content to target instances
DEACTIVATERemove content from target instances
DELETEDelete content on target (use with caution)
TESTTest agent connectivity without replicating
INTERNAL_POLLInternal use (reverse replication)

Exception Handling

ReplicationException

Package: com.day.cq.replication.ReplicationException

Common Causes:

  • Network connectivity failure
  • Authentication error
  • Target instance unavailable
  • Invalid resource path
  • Insufficient permissions

Handling Pattern:

try {
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
} catch (ReplicationException e) {
    LOG.error("Replication failed for path: {}", path, e);
    // Handle error (retry, alert, log)
}

Common Patterns

Simple Activation

@Reference
private Replicator replicator;

public void activate(ResourceResolver resolver, String path) 
    throws ReplicationException {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
}

Synchronous Activation

public void activateSync(ResourceResolver resolver, String path) 
    throws ReplicationException {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    
    ReplicationOptions opts = new ReplicationOptions();
    opts.setSynchronous(true);
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, opts);
}

Bulk Activation

public void activateBulk(ResourceResolver resolver, List<String> paths) 
    throws ReplicationException {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    
    ReplicationOptions opts = new ReplicationOptions();
    opts.setSynchronous(false); // Async for performance
    
    String[] pathArray = paths.toArray(new String[0]);
    replicator.replicate(session, ReplicationActionType.ACTIVATE, pathArray, opts);
}

Agent Filtering

public void activateToSpecificAgent(ResourceResolver resolver, String path, 
                                     String targetAgentId) 
    throws ReplicationException {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    
    ReplicationOptions opts = new ReplicationOptions();
    opts.setFilter(agent -> agent.getId().equals(targetAgentId));
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, opts);
}

Check Replication Status

public boolean isActivated(ResourceResolver resolver, String path) {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        return false;
    }
    
    ReplicationStatus status = replicator.getReplicationStatus(session, path);
    return status != null && status.isActivated();
}

Permission Check

public boolean canActivate(ResourceResolver resolver, String path) {
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        return false;
    }
    
    try {
        replicator.checkPermission(session, ReplicationActionType.ACTIVATE, path);
        return true;
    } catch (ReplicationException e) {
        return false; // User lacks permission
    }
}

Service User Pattern

@Reference
private ResourceResolverFactory resolverFactory;

@Reference
private Replicator replicator;

public void activateWithServiceUser(String path) throws ReplicationException {
    Map<String, Object> authInfo = new HashMap<>();
    authInfo.put(ResourceResolverFactory.SUBSERVICE, "replication-service");
    
    try (ResourceResolver resolver = resolverFactory.getServiceResourceResolver(authInfo)) {
        Session session = resolver.adaptTo(Session.class);
        if (session == null) {
            throw new IllegalStateException("Unable to adapt to Session");
        }
        replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
    } catch (LoginException e) {
        LOG.error("Service user login failed", e);
        throw new ReplicationException("Authentication failed", e);
    }
}

Error Recovery Patterns

Retry with Exponential Backoff

Retry transient failures with increasing delays to avoid overwhelming the target system.

public void activateWithRetry(ResourceResolver resolver, String path, int maxRetries) 
    throws ReplicationException {
    
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    
    int attempt = 0;
    long delayMs = 1000; // Start with 1 second
    
    while (attempt < maxRetries) {
        try {
            replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
            LOG.info("Replication succeeded on attempt {}", attempt + 1);
            return; // Success
            
        } catch (ReplicationException e) {
            attempt++;
            
            if (attempt >= maxRetries) {
                LOG.error("Replication failed after {} attempts", maxRetries, e);
                throw e; // Give up after max retries
            }
            
            // Exponential backoff: 1s, 2s, 4s, 8s, etc.
            LOG.warn("Replication attempt {} failed, retrying in {}ms", attempt, delayMs, e);
            
            try {
                Thread.sleep(delayMs);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new ReplicationException("Retry interrupted", ie);
            }
            
            delayMs *= 2; // Double the delay for next attempt
        }
    }
}

Fallback to Asynchronous on Timeout

If synchronous replication times out, fall back to asynchronous mode.

public void activateWithFallback(ResourceResolver resolver, String path) 
    throws ReplicationException {
    
    Session session = resolver.adaptTo(Session.class);
    if (session == null) {
        throw new IllegalStateException("Unable to adapt to Session");
    }
    
    // Try synchronous first
    ReplicationOptions syncOpts = new ReplicationOptions();
    syncOpts.setSynchronous(true);
    
    try {
        replicator.replicate(session, ReplicationActionType.ACTIVATE, path, syncOpts);
        LOG.info("Synchronous replication completed");
        
    } catch (ReplicationException e) {
        // Check if it's a timeout or transient error
        if (isTransientError(e)) {
            LOG.warn("Synchronous replication failed, falling back to async", e);
            
            // Fallback to asynchronous
            ReplicationOptions asyncOpts = new ReplicationOptions();
            asyncOpts.setSynchronous(false);
            
            replicator.replicate(session, ReplicationActionType.ACTIVATE, path, asyncOpts);
            LOG.info("Asynchronous replication queued as fallback");
        } else {
            // Permanent error, don't retry
            throw e;
        }
    }
}

private boolean isTransientError(ReplicationException e) {
    String message = e.getMessage();
    return message != null && (
        message.contains("timeout") ||
        message.contains("Connection refused") ||
        message.contains("SocketTimeoutException")
    );
}

Circuit Breaker Pattern

Prevent cascading failures by stopping replication attempts when the target system is down.

public class ReplicationCircuitBreaker {
    
    private static final int FAILURE_THRESHOLD = 5;
    private static final long TIMEOUT_MS = 60000; // 1 minute
    
    private int failureCount = 0;
    private long lastFailureTime = 0;
    private boolean circuitOpen = false;
    
    @Reference
    private Replicator replicator;
    
    public void activateWithCircuitBreaker(ResourceResolver resolver, String path) 
        throws ReplicationException {
        
        // Check if circuit is open
        if (circuitOpen) {
            if (System.currentTimeMillis() - lastFailureTime < TIMEOUT_MS) {
                throw new ReplicationException("Circuit breaker open - replication disabled temporarily");
            } else {
                // Timeout expired, try to close circuit
                circuitOpen = false;
                failureCount = 0;
                LOG.info("Circuit breaker reset, attempting replication");
            }
        }
        
        Session session = resolver.adaptTo(Session.class);
        if (session == null) {
            throw new IllegalStateException("Unable to adapt to Session");
        }
        
        try {
            replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
            
            // Success - reset failure count
            failureCount = 0;
            LOG.info("Replication successful");
            
        } catch (ReplicationException e) {
            failureCount++;
            lastFailureTime = System.currentTimeMillis();
            
            if (failureCount >= FAILURE_THRESHOLD) {
                circuitOpen = true;
                LOG.error("Circuit breaker opened after {} failures", failureCount);
            }
            
            throw e;
        }
    }
}

Official Documentation

skills

aem-replication

README.md

SKILL.md

README.md

tile.json