April 1, 2020
Estimated Post Reading Time ~

How to perform Tree Activation in CQ AEM

Use Case: You want to tree activate a page as part of your code or scheduler

Example: Replication Helper Class

package com.wemblog;

import java.util.Iterator;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.dam.api.Asset;
import com.day.cq.replication.Agent;
import com.day.cq.replication.AgentManager;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationException;
import com.day.cq.replication.ReplicationQueue;
import com.day.cq.replication.ReplicationStatus;
import com.day.cq.replication.Replicator;
import com.day.cq.wcm.api.Page;

/**
* Helper Method to do tree activation
*
* @author Yogesh Upadhyay
* @since 1.0.12
*
*/
public class ReplicationHelper {

private Logger logger = LoggerFactory.getLogger(ReplicationHelper.class);

private final Replicator replicator;

private final ResourceResolver resolver;

private final Session session;

private boolean onlyModified=false;

private boolean reactivate=false;

private boolean ignoreDeactivated=false;

private boolean dryRun;

private long lastUpdate;

private long tCount = 0;
private long aCount = 0;

private AgentManager agentManager;

private ReplicationActionType replicationActionType = ReplicationActionType.ACTIVATE;

/**
* Default Constructor
*
* @param replicator
* @param resolver
* @param agentManager
*/

public ReplicationHelper(final Replicator replicator, final ResourceResolver resolver,
final AgentManager agentManager) {
this.replicator = replicator;
this.resolver = resolver;
this.session = resolver.adaptTo(Session.class);
this.agentManager = agentManager;
}

public void setOnlyModified(final boolean onlyModified) {
this.onlyModified = onlyModified;
}

public void setReactivate(final boolean reactivate) {
this.reactivate = reactivate;
}

public void setIgnoreDeactivated(final boolean ignoreDeactivated) {
this.ignoreDeactivated = ignoreDeactivated;
}

public void setReplicationActionType(final ReplicationActionType actionType){
this.replicationActionType = actionType;
}

/**
* Process Replication based on path
*
* @param path
*/
public void process(String path) {
if (path == null || path.length() == 0) {
return;
}
// snip off all trailing slashes
while (path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
}
// reject root and 1 level paths
if (path.lastIndexOf('/') <= 0) {
if (path.length() == 0) {
path = "/";
}
return;

}
Resource res = resolver.getResource(path);
if (res == null) {
return;
}
long startTime = System.currentTimeMillis();
try {
process(res);
long endTime = System.currentTimeMillis();
logger.debug("Time taken to do tree activation ", endTime - startTime);

} catch (Exception e) {
logger.error("Error during tree activation of " + path, e);
}

}

/**
* Get all throttled Agents
*
* @return
*/
private Agent getThrottleAgent() {
// get the first enabled agents
AgentManager agentMgr = this.agentManager;
for (Agent agent : agentMgr.getAgents().values()) {
if (agent.isEnabled()) {
return agent;
}
}
return null;
}

/**
* Process replication Job based on resource
*
* @param res
* @return
* @throws RepositoryException
* @throws ReplicationException
*/
private boolean process(Resource res) throws RepositoryException,
ReplicationException {

// we can only tree-activate hierarchy nodes
Node node = res.adaptTo(Node.class);
if (!node.isNodeType("nt:hierarchyNode")) {
return false;
}
Page page = res.adaptTo(Page.class);
Asset asset = res.adaptTo(Asset.class);
long lastModified;
if (page != null) {
lastModified = page.getLastModified() == null ? -1 : page
.getLastModified().getTimeInMillis();
} else if (asset != null) {
lastModified = asset.getLastModified() == 0 ? -1 : asset
.getLastModified();
} else {
ResourceMetadata data = res.getResourceMetadata();
lastModified = data.getModificationTime();
}

ReplicationStatus rs = res.adaptTo(ReplicationStatus.class);
long lastPublished = 0;
boolean isDeactivated = false;
boolean isActivated = false;
if (rs != null && rs.getLastPublished() != null) {
lastPublished = rs.getLastPublished().getTimeInMillis();
isDeactivated = rs.isDeactivated();
isActivated = rs.isActivated();
}
boolean isModified = lastModified > lastPublished;
boolean doActivate = false;

if (!isModified && onlyModified) {
doActivate = false;
}else {
try {
replicator.checkPermission(this.session,
this.replicationActionType, res.getPath());
doActivate = true;
} catch (ReplicationException e) {
logger.error(e.getMessage());
}
}

tCount++;

Agent agent = getThrottleAgent();
ReplicationQueue queue = agent == null ? null : agent.getQueue();
int num = queue == null ? 0 : queue.entries().size();
int test = 0;

//Check for queue full or not
while (num > 3) {
try {
logger.error("Queue is Full waiting for queue to be empty");
Thread.sleep(500);
} catch (InterruptedException e) {
// ignore
}
num = queue.entries().size();
test++;
}

if (doActivate) {
if (!dryRun) {
try {
logger.debug("Replicating file "+res.getPath());
replicator.replicate(session, this.replicationActionType,
res.getPath());
} catch (ReplicationException e) {
logger.error("Error during tree activation of " + res.getPath(), e);
}
}
aCount++;
}

long now = System.currentTimeMillis();
if (now - lastUpdate > 1000L) {
lastUpdate = now;

}
Iterator<Resource> iter = resolver.listChildren(res);
while (iter.hasNext()) {
process(iter.next());
}
return true;
}

}


Tree Activation Service
package com.wemblog.utility;

import java.util.List;

import org.apache.sling.api.resource.ResourceResolver;

import com.day.cq.replication.Agent;
import com.day.cq.replication.ReplicationActionType;
/**
* Replication Utility Method for some common replication task
* All task are performed using ADMIN user, use
* @author Yogesh Upadhyay
* @since 1.0.12
*
*/
public interface ReplicationUtilService {
/**
* Tree replicate based on given path.
* It is recommended to use more refined path rather than activating parent with a lot of nodes
* Note that all resources under this tree will get activated. Use other settings to make sure that only modified is activated.
* @param parent_path
* @param {@link ResourceResolver}
*/
public void treeReplicate(String parent_path,ResourceResolver resolver);
/**
* Tree replication with {@link ReplicationActionType}
* This will activate or deactivate entire tree
* @param parent_path
* @param {@link ReplicationActionType}
* @param {@link ResourceResolver}
*/
public void treeReplicate(String parent_path, ReplicationActionType actionType, ResourceResolver resolver);
/**
* Tree activation for only modified content
* @param parent_path
* @param onlyModified
* @param {@link ResourceResolver}
*/
public void treeReplicate(String parent_path,boolean onlyModified, ResourceResolver resolver);
/**
* Tree activation for modified and ignore deactivate setting.
* @param parent_path
* @param onlyModified
* @param ignoreDeactivated
* @param {@link ResourceResolver}
*/
public void treeReplicate(String parent_path,boolean onlyModified, boolean ignoreDeactivated, ResourceResolver resolver);
/**
* Method to get all Active Agents
* This include both replication and dispatcher agent
* @return {@link List<Agent>}
*/
public List<Agent> getAllActiveAgents();
/**
* Method to get all active publish agents
* @return
*/
public List<Agent> getAllPublishAgent();
/**
* Method to get all active dispatcher agents
* @return
*/
public List<Agent> getAllDispatcherAgent();
/**
* Simple method to activate a content path
* @param resource_path
* @param {@link ResourceResolver}
*/
public void activate(String resource_path, ResourceResolver resolver);
/**
* Method to deactive a path
* @param resource_path
* @param {@link ResourceResolver}
*/
public void deactivate(String resource_path, ResourceResolver resolver);
}

Tree Activation Impl
package com.wemblog.utility.impl;

import java.util.ArrayList;
import java.util.List;

import javax.jcr.Session;

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.NonExistingResource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.replication.Agent;
import com.day.cq.replication.AgentManager;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.Replicator;
import com.wemblog.ReplicationHelper;
import com.wemblog.ReplicationUtilService;

/**
*
* @author Yogesh Upadhyay
* @since 1.0.12
*
*/

@Service
@Component
public class ReplicationUtilServiceImpl implements ReplicationUtilService {

private Logger logger = LoggerFactory.getLogger(ReplicationUtilServiceImpl.class);

@Reference
private Replicator replicator;

@Reference
private ResourceResolverFactory resourceResolverFactory;

@Reference
private AgentManager agentManager;

private ResourceResolver resourceResolver = null;

private Session session;

/**
* Tree Replicate based on path
*/
@Override
public void treeReplicate(final String parent_path, final ResourceResolver resolver) {
treeReplicate(parent_path, ReplicationActionType.ACTIVATE, resolver);
}

@Override
public void treeReplicate(final String parent_path,
final ReplicationActionType actionType,final ResourceResolver resolver) {
try {
if (null == resolver) {
logger.error("Resolver is null can not tree activate " + parent_path);
return;
}
if (resolver.resolve(parent_path) instanceof NonExistingResource) {
logger.error("Parent path does not exist can not activate "
+ parent_path);
return;
}
this.resourceResolver = resolver;
ReplicationHelper replicationHelper = new ReplicationHelper(replicator,
resourceResolver, agentManager);
replicationHelper.setReplicationActionType(actionType);
replicationHelper.process(parent_path);
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
// we do not close resource resolver here because it's passed as reference
}

}

@Override
public void treeReplicate(final String parent_path, final boolean onlyModified,
final ResourceResolver resolver) {
treeReplicate(parent_path, onlyModified, false, resolver);

}

@Override
public void treeReplicate(final String parent_path, final boolean onlyModified,
final boolean ignoreDeactivated, final ResourceResolver resolver) {
try {
if (null == resolver) {
logger.error("Resolver is null can not tree activate " + parent_path);
return;
}
if (resolver.resolve(parent_path) instanceof NonExistingResource) {
logger.error("Parent path does not exist can not activate "
+ parent_path);
return;
}
resourceResolver = resolver;

ReplicationHelper replicationHelper = new ReplicationHelper(replicator,
resourceResolver, agentManager);
replicationHelper.setOnlyModified(onlyModified);
replicationHelper.setIgnoreDeactivated(ignoreDeactivated);
replicationHelper.process(parent_path);
} catch (Exception e) {
logger.error(e.getMessage());
} finally {
// we do not close resource resolver here because it's passed as reference
}

}

@Override
public List<Agent> getAllActiveAgents() {
List<Agent> all_active_agent = new ArrayList<Agent>();
for (Agent agent : agentManager.getAgents().values()) {
if (agent.isEnabled()) {
all_active_agent.add(agent);
}
}
return all_active_agent;
}

@Override
public List<Agent> getAllPublishAgent() {
List<Agent> all_active_agent = new ArrayList<Agent>();
for (Agent agent : agentManager.getAgents().values()) {
if (agent.isEnabled() && !agent.isCacheInvalidator()) {
all_active_agent.add(agent);
}
}
return all_active_agent;
}

@Override
public List<Agent> getAllDispatcherAgent() {
List<Agent> all_active_agent = new ArrayList<Agent>();
for (Agent agent : agentManager.getAgents().values()) {
if (agent.isEnabled() && agent.isCacheInvalidator()) {
all_active_agent.add(agent);
}
}
return all_active_agent;
}

@Override
public void activate(final String resource_path, final ResourceResolver resolver) {
try {
resourceResolver = resolver;
if (resolver == null) {
logger.error("Resolver is null can not activate " + resource_path);
return;
}
this.session = resourceResolver.adaptTo(Session.class);
if (!(resourceResolver.resolve(resource_path) instanceof NonExistingResource)) {
replicator.replicate(this.session, ReplicationActionType.ACTIVATE,
resource_path);
} else {
logger.error("Resource you are trying to replicate does not exist "
+ resource_path);
}

} catch (Exception e) {
logger.error(e.getMessage());
} finally {
// we do not close resource resolver here because it's passed as reference
}

}

@Override
public void deactivate(final String resource_path, final ResourceResolver resolver) {
try {
if (resolver == null) {
logger.error("Resolver is null can not activate " + resource_path);
return;
}
this.resourceResolver = resolver;
this.session = resourceResolver.adaptTo(Session.class);
if (!(resourceResolver.resolve(resource_path) instanceof NonExistingResource)) {
replicator.replicate(this.session, ReplicationActionType.DEACTIVATE,
resource_path);
} else {
logger.error("Resource you are trying to replicate does not exist "
+ resource_path);
}

} catch (Exception e) {
logger.error(e.getMessage());
} finally {
// we do not close resource resolver here because it's passed as reference
}

}

}


Note: In the above example replication action is performed using admin user. You could also create a replication user and use that user to replicate instead.


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.