April 10, 2020
Estimated Post Reading Time ~

Replication API in action

Replication is an important concept in AEM as it enables an enterprise to author the content in the Author AEM instance and after it is final replicate to the Publish instance which is visible to the end-users of the website.

AEM provides a rich Replication API which replicates the content from AEM Author to the AEM Publish instance. Though AEM provides out of the box Replication agents which are super easy to configure and provides much abstraction for the replication process, sometimes we are required to achieve this functionality programmatically such as when asset metadata is changed, or a page is versioned any many other cases.

In this post, we will see how can we replicate content programmatically. For this, we will be creating a Sling Servlet (how? see here) and passing the content path which we want to replicate as a query parameter. So without wasting much time, let's get our hands dirty with some code.

Replication by code

For using the Replication API, we will be using an API com.day.cq.replication.Replicator to replicate the content. 
  • Create a class named ReplicationServlet and paste the following code in it.
package org.redquark.demo.core.servlets;

import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import javax.jcr.Node;
import javax.jcr.Session;
import javax.servlet.Servlet;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.commons.util.AssetReferenceSearch;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationException;
import com.day.cq.replication.Replicator;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;

/**
 * @author Anirudh Sharma
 *
 */
@Component(service = Servlet.class, property = {
 Constants.SERVICE_DESCRIPTION + "= Servlet to replicate the passed contents",
 "sling.servlet.methods=" + HttpConstants.METHOD_GET,
 "sling.servlet.paths=" + "/bin/demo/replication"
})
public class ReplicationServlet extends SlingSafeMethodsServlet {

 /**
  * Generated serialVersionUID
  */
 private static final long serialVersionUID = 1860103923125331408 L;

 /**
  * Logger
  */
 private static final Logger log = LoggerFactory.getLogger(ReplicationServlet.class);

 @Reference
 private Replicator replicator;

 @Override
 protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {

  log.info("----------< Processing starts >----------");

  try {

   String path = request.getParameter("contentPath");

   ResourceResolver resolver = request.getResourceResolver();

   Session session = resolver.adaptTo(Session.class);

   replicateContent(session, path);

   activatePageAssets(resolver, path);

   log.info("----------< Processing ends >----------");

   response.getWriter().println("Replicated content");

  } catch (Exception e) {

   log.error(e.getMessage(), e);
  }
 }

 private void activatePageAssets(ResourceResolver resolver, String path) {

  Set < String > pageAssetPaths = getPageAssetsPaths(resolver, path);

  if (pageAssetPaths == null) {

   return;
  }

  Session session = resolver.adaptTo(Session.class);

  for (String assetPath: pageAssetPaths) {
   replicateContent(session, assetPath);
  }
 }

 private Set < String > getPageAssetsPaths(ResourceResolver resolver, String pagePath) {

  PageManager pageManager = resolver.adaptTo(PageManager.class);

  Page page = pageManager.getPage(pagePath);

  if (page == null) {
   return new LinkedHashSet < > ();
  }

  Resource resource = page.getContentResource();
  AssetReferenceSearch assetReferenceSearch = new AssetReferenceSearch(resource.adaptTo(Node.class),
   DamConstants.MOUNTPOINT_ASSETS, resolver);
  Map < String, Asset > assetMap = assetReferenceSearch.search();

  return assetMap.keySet();
 }

 private void replicateContent(Session session, String path) {

  try {
   replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
   log.info("Replicated: {}", path);
  } catch (ReplicationException e) {
   log.error(e.getMessage(), e);
   e.printStackTrace();
  }
 }

}
  • First, we are getting the path of the path to be replicated as a request parameter.
  • All we need to do is to define a field of the type com.day.cq.replication.Replicator, let OSGi injects the reference to the Replicator service.
  • The code is pretty simple as we are calling the replicate(Session session, ReplicationActionType type, String path) to replicate the content to the publish instance.
  • But wait a minute? What about the assets that are referenced on the page? How do we replicate them? We have an awesome class com.day.cq.dam.commons.util.AssetReferenceSearch will get the reference of the Assets and replicate them as well. Pretty cool stuff, eh?.
  • We pass page paths and assets paths and they are replicated one by one.
  • After deploying the code, go to the browser and hit http://<host>:<port>/bin/demo/replication?contentPath=/content/we-retail/language-masters/en/user and see the content on the publish.
  • The logs will look like this - 
2018-10-19 22:34:10 - INFO - publish : Creating content for path /content/we-retail/language-masters/en/user
2018-10-19 22:34:11 - INFO - publish : Creating content for path /content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/northern-lights.jpg
2018-10-19 22:34:11 - INFO - publish : Sending POST request to http://localhost:4503/bin/receive?sling:authRequestLogin=1
2018-10-19 22:34:11 - INFO - publish : sent. Response: 200 OK
2018-10-19 22:34:11 - INFO - publish : ------------------------------------------------
2018-10-19 22:34:11 - INFO - publish : Sending message to localhost:4503
2018-10-19 22:34:11 - INFO - publish : >> POST /bin/receive HTTP/1.0
2018-10-19 22:34:11 - INFO - publish : >> Action: Activate
2018-10-19 22:34:11 - INFO - publish : >> Path: /content/we-retail/language-masters/en/user
2018-10-19 22:34:11 - INFO - publish : >> Handle: /content/we-retail/language-masters/en/user
2018-10-19 22:34:11 - INFO - publish : >> Referer: about:blank
2018-10-19 22:34:11 - INFO - publish : >> ...spooling 2606 bytes...
2018-10-19 22:34:11 - INFO - publish : --
2018-10-19 22:34:11 - INFO - publish : << HTTP/1.1 200 OK
2018-10-19 22:34:11 - INFO - publish : << Date: Fri, 19 Oct 2018 17:04:11 GMT
2018-10-19 22:34:11 - INFO - publish : << X-Content-Type-Options: nosniff
2018-10-19 22:34:11 - INFO - publish : << Content-Type: text/plain;charset=utf-8
2018-10-19 22:34:11 - INFO - publish : << Content-Length: 30
2018-10-19 22:34:11 - INFO - publish : << 
2018-10-19 22:34:11 - INFO - publish : << ReplicationAction ACTIVATE ok.
2018-10-19 22:34:11 - INFO - publish : Message sent.
2018-10-19 22:34:11 - INFO - publish : ------------------------------------------------
2018-10-19 22:34:11 - INFO - publish : Replication (ACTIVATE) of /content/we-retail/language-masters/en/user successful.
2018-10-19 22:34:11 - INFO - publish : Sending POST request to http://localhost:4503/bin/receive?sling:authRequestLogin=1
2018-10-19 22:34:11 - INFO - publish : sent. Response: 200 OK
2018-10-19 22:34:11 - INFO - publish : ------------------------------------------------
2018-10-19 22:34:11 - INFO - publish : Sending message to localhost:4503
2018-10-19 22:34:11 - INFO - publish : >> POST /bin/receive HTTP/1.0
2018-10-19 22:34:11 - INFO - publish : >> Action: Activate
2018-10-19 22:34:11 - INFO - publish : >> Path: /content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/northern-lights.jpg
2018-10-19 22:34:11 - INFO - publish : >> Handle: /content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/northern-lights.jpg
2018-10-19 22:34:11 - INFO - publish : >> Referer: about:blank
2018-10-19 22:34:11 - INFO - publish : >> ...spooling 568041 bytes...
2018-10-19 22:34:11 - INFO - publish : --
2018-10-19 22:34:11 - INFO - publish : << HTTP/1.1 200 OK
2018-10-19 22:34:11 - INFO - publish : << Date: Fri, 19 Oct 2018 17:04:11 GMT
2018-10-19 22:34:11 - INFO - publish : << X-Content-Type-Options: nosniff
2018-10-19 22:34:11 - INFO - publish : << Content-Type: text/plain;charset=utf-8
2018-10-19 22:34:11 - INFO - publish : << Content-Length: 30
2018-10-19 22:34:11 - INFO - publish : << 
2018-10-19 22:34:11 - INFO - publish : << ReplicationAction ACTIVATE ok.
2018-10-19 22:34:11 - INFO - publish : Message sent.
2018-10-19 22:34:11 - INFO - publish : ------------------------------------------------
2018-10-19 22:34:11 - INFO - publish : Replication (ACTIVATE) of /content/dam/we-retail/en/experiences/arctic-surfing-in-lofoten/northern-lights.jpg successful.



By aem4beginner

No comments:

Post a Comment

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