ElasticPath (EP) is a robust technology for e-commerce solutions. EP partners with Adobe to provide integrated services for e-commerce solutions inside AEM. Out of the box (OOTB), users can import products from EP into AEM. This can be done manually or dynamically. To manually pull the products from EP to AEM, go to: http://localhost:4502/etc/importers/elasticpath.html.

This article will illustrate on how to update and/or create category(ies) and product(s) when the products get imported from EP.

 

Event Handler. We need an event handler. Below is a sample event handler:

package com.myproject.eventhandlers;

import java.util.HashSet;
import java.util.Set;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.settings.SlingSettingsService;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.myproject.utils.EpCategoryToCQPage;
import com.myproject.utils.EpProductToCQPage;
import javax.jcr.Node;
import org.apache.sling.api.resource.ResourceResolverFactory;

@Component(immediate = true)
@Service(value = EventHandler.class)
@Property(name = EventConstants.EVENT_TOPIC, value = "org/apache/sling/api/resource/Resource/ADDED")
public class EpProductImport implements EventHandler {

    private static final Logger LOG = LoggerFactory.getLogger(EpProductImport.class);

    @Reference
    private ResourceResolverFactory resolverFactory;
    @Reference
    private SlingSettingsService slingSettingsService;

    private ResourceResolver rr;
    private static final String EP_COMMERCE_PROD_ROOT = "/etc/commerce/products/geometrixx/hvacequipment";
    private static final String EVENT_TOPIC = "org/apache/sling/api/resource/Resource/ADDED";
    private static final String THE_PROP_NAME = "path";
    private static final String COMMERCE_RES_TYPE = "commerce/components/product";
    private boolean isAuthor;
    
    @Override
    public void handleEvent(Event event) {
        if (isAuthor && event.getTopic().equals(EVENT_TOPIC)) {
            Set<String> paths = new HashSet<>();
            for (String propertyName : event.getPropertyNames()) {
                if (propertyName.equals(THE_PROP_NAME)) {
                    String path = event.getProperty(propertyName).toString();
                    if (path.startsWith(EP_COMMERCE_PROD_ROOT)) {
                        paths.add(event.getProperty(propertyName).toString());
                    }
                }
            }
            
            if (this.rr != null) {
                if (paths.size() > 0) {
                    this.addCQPageOnProductAdded(paths);
                }
            }
            else {
                LOG.error("this.rr (ResourceResolver) is null: " + (this.rr == null));
            }
        }
    }

    @Activate
    protected void activate(ComponentContext context) {
        try {
            this.rr = resolverFactory.getAdministrativeResourceResolver(null);
            Set<String> runModes = slingSettingsService.getRunModes();
            isAuthor = runModes.contains("author");
        }
        catch(Exception e) {
            LOG.error(e.getMessage(), e);
        }
    }
    
    private void addCQPageOnProductAdded(Set<String> paths) {
        try {
            EpCategoryToCQPage epCategoryToCQPage = new EpCategoryToCQPage(this.rr);
            EpProductToCQPage epProductToCQPage = new EpProductToCQPage(this.rr);
            for (String path : paths) {
                Resource r = this.rr.getResource(path);
                Node n = r.adaptTo(Node.class);
                if (n.hasProperty("jcr:primaryType")
                        && n.getProperty("jcr:primaryType").getString()
                        .toLowerCase().equals("sling:folder")) {
                    epCategoryToCQPage.create(path);
                } else if (n.hasProperty("sling:resourceType")
                        && n.getProperty("sling:resourceType").getString()
                        .toLowerCase().equals(COMMERCE_RES_TYPE)) {
                    epProductToCQPage.create(path);
                }
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }
    }
}

You need utility classes to handle the creation on Category(ies) and Product(s) pages. Below are example codes for the 2 utility classes:

EP Category to CQ Page 

package com.myproject.utils;

import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.WCMException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EpCategoryToCQPage {
    
    private static final Logger LOG = LoggerFactory.getLogger(EpCategoryToCQPage.class);
    private static final String CQPAGE_ROOT = "/content/myproject",
            COMMERCE_PROD_ROOT = "/etc/commerce/products",
            CATALOG_NAME = "geometrixx",
            TMPL = "/apps/myproject/templates/category",
            RES_TYPE = "myproject/components/page/categorypage";
    private final ResourceResolver resourceResolver;
    private final Session session;
    private Resource cqParentPageRes, cqPageRootRes;
    private Node epProdNode, cqPageNode;
    private String epProdPath, cqPagePath, cqParentPagePath, cqPageNodeName;
    
    public EpCategoryToCQPage(ResourceResolver rr) {
        this.resourceResolver = rr;
        this.session = this.resourceResolver.adaptTo(Session.class);
    }
    
    public void create(String path) {
        this.epProdPath = path;
        this.formatPath();
        this.epProdNode = this.resourceResolver.getResource(this.epProdPath).adaptTo(Node.class);
        this.cqPageRootRes = this.resourceResolver.getResource(CQPAGE_ROOT);
        
        // check if session is not null and root page exist
        if (this.session != null && this.cqPageRootRes != null) {
            // check if parent page exist
            this.cqParentPageRes = this.resourceResolver.getResource(this.cqParentPagePath);
            if (this.cqParentPageRes != null) {
                Resource r = this.resourceResolver.getResource(this.cqPagePath);
                // check if the page exist
                if (r != null && r.getChild(JcrConstants.JCR_CONTENT) != null) {
                    this.cqPageNode = r.adaptTo(Node.class);
                    this.overrideProperties();
                }
                else {
                    this.create();
                }
            }
            else {
                LOG.error(this.cqParentPagePath + " doesn't exist.");
            }
        }
        else {
            LOG.error("Session is null");
        }
    }
    
    private void formatPath() {
        this.cqPagePath = this.epProdPath.replace(
                COMMERCE_PROD_ROOT + "/" + CATALOG_NAME,
                CQPAGE_ROOT);
        String[] arr = this.cqPagePath.split("/");
        this.cqPageNodeName = arr[arr.length - 1];
        this.cqParentPagePath = this.cqPagePath.replace("/" + this.cqPageNodeName, "");
    }

    private void overrideProperties() {
        // have your detailed codes to update 
        // existing category's CQ page, if exists
    }

    private void create() {
        // have your detailed codes to create new category's CQ page
    }
}

EP Product to CQ Page

package com.myproject.utils;

import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.WCMException;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EpProductToCQPage {
    
    private static final Logger LOG = LoggerFactory.getLogger(EpProductToCQPage.class);
    private static final String CQPAGE_ROOT = "/content/myproject",
            COMMERCE_PROD_ROOT = "/etc/commerce/products",
            CATALOG_NAME = "geometrixx",
            TMPL = "/apps/myproject/templates/productdetails",
            RES_TYPE = "myproject/components/page/productdetailspage";
    private final ResourceResolver resourceResolver;
    private final Session session;
    private Resource cqParentPageRes, cqPageRootRes;
    private Node epProdNode, cqPageNode;
    private String epProdPath, cqPagePath, cqParentPagePath, cqPageNodeName;
    
    public EpProductToCQPage(ResourceResolver rr) {
        this.resourceResolver = rr;
        this.session = this.resourceResolver.adaptTo(Session.class);
    }
    
    public void create(String path) {
        this.epProdPath = path;
        this.formatPath();
        this.epProdNode = this.resourceResolver.getResource(this.epProdPath).adaptTo(Node.class);
        this.cqPageRootRes = this.resourceResolver.getResource(CQPAGE_ROOT);
        
        // check if session is not null and root page exist
        if (this.session != null && this.cqPageRootRes != null) {
            // check if parent page exist
            this.cqParentPageRes = this.resourceResolver.getResource(this.cqParentPagePath);
            if (this.cqParentPageRes != null) {
                Resource r = this.resourceResolver.getResource(this.cqPagePath);
                // check if the page exist
                if (r != null && r.getChild(JcrConstants.JCR_CONTENT) != null) {
                    this.cqPageNode = r.adaptTo(Node.class);
                    this.overrideProperties();
                }
                else {
                    this.create();
                }
            }
            else {
                LOG.error(this.cqParentPagePath + " doesn't exist.");
            }
        }
        else {
            LOG.error("Session is null");
        }
    }
    
    private void formatPath() {
        this.cqPagePath = this.epProdPath.replace(
                COMMERCE_PROD_ROOT + "/" + CATALOG_NAME,
                CQPAGE_ROOT);
        String[] arr = this.cqPagePath.split("/");
        this.cqPageNodeName = arr[arr.length - 1];
        this.cqParentPagePath = this.cqPagePath.replace("/" + this.cqPageNodeName, "");
    }
    
    private void overrideProperties() {
        // have your detailed codes to update 
        // existing product's CQ page, if exists
    }
    
    private void create() {
        // have your detailed codes to create new product's CQ page
    }
}

All comments/questions are welcome!