If you are ever faced with the requirement of replicating AEM content between systems where the content hierarchy on one of the systems does not exactly match the other system, this post is for you.
Let’s take this example:
Your AEM author instance has pages under “/content/site/page/”
and you have a sling mapping that transforms incoming URLs:
“/content/site/page/subpage/<pageName>” to “/content/site/page/<pageName>”
For example, your sling mapping transforms the URL: “/content/site/page/subpage/mypage” to “/content/site/page/mypage”
in this case the dispatcher will create cache in this directory: “/content/site/page/subpage/mypage”. Now you try to publish “/content/site/page/mypage” but the dispatcher cache is not flushed, why? because the replication path is actally “/content/site/page/mypage” (not the same as the cached path). The replication agent only knows your author/publisher hiarchy.
To solve this issue, we need to transform the replication path, we can achieve this by implementing the ReplicationPathTransformer
ReplicationPathTransformer was inroduced in AEM 6.2
public interface ReplicationPathTransformer
Transforms the replication path for the replication request. It provides a hook, while building and importing replication content package, that can map a given replication path (i.e. /content/dam/skiing/images/Banner.JPG) to new target replication path (i.e. /content/dam/campaigns/skiing/images/Banner.JPG) This can be used when you need to replicate between system where path hierarchies on one system do not exactly match to path hierarchies on other system. Please note that it only allows for one-to-one mapping between source and target for a replication request. Implementations can choose using #accepts(javax.jcr.Session, ReplicationAction, Agent), whether to map/transform given replication path in the context of the current replication request.
Here is an example ReplicationPathTransformer implementation you can use to start your implementation:
package org.kp.fdl.facility.replication; import com.day.cq.replication.Agent; import com.day.cq.replication.ReplicationAction; import com.day.cq.replication.ReplicationLog; import com.day.cq.replication.ReplicationPathTransformer; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.jcr.Session; import java.lang.reflect.Array; import java.util.Arrays; import java.util.List; @Component(metatype=false, immediate=true) @Service({ReplicationPathTransformer.class}) public class ExampleReplicationPathTransformer implements ReplicationPathTransformer { @Override public String transform(Session session, String replicationPath, ReplicationAction replicationAction, Agent agent) { /* * transform the replicationPath */ // for the sake of simplicity, and as this is an example return the replicationPath as is. return replicationPath } @Override public boolean accepts(Session session, ReplicationAction replicationAction, Agent agent) { /* Check if the agent is a dispatcher agent * if it is the agent you are targeting, return true */ // transform all urls return true; } }
Awesome!! great post!!