SegmentServiceImpl.java 15.2 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.jcr.JcrUtil
 *  com.day.cq.wcm.api.Page
 *  com.day.cq.wcm.api.PageManager
 *  com.day.cq.wcm.api.WCMException
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Value
 *  javax.jcr.ValueFactory
 *  javax.jcr.Workspace
 *  javax.jcr.query.Query
 *  javax.jcr.query.QueryManager
 *  javax.jcr.query.QueryResult
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.jackrabbit.util.Text
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.aam.client;

import com.adobe.cq.aam.client.AudienceManagerItemImpl;
import com.adobe.cq.aam.client.spi.AudienceManagerConfiguration;
import com.adobe.cq.aam.client.spi.AudienceManagerFolder;
import com.adobe.cq.aam.client.spi.AudienceManagerFolders;
import com.adobe.cq.aam.client.spi.AudienceManagerItem;
import com.adobe.cq.aam.client.spi.InvalidItemPage;
import com.adobe.cq.aam.client.spi.SegmentService;
import com.adobe.cq.aam.client.spi.SyncResult;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.WCMException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(immediate=1, description="Adobe CQ Audience Manager Segment Service Implementation")
@Service(value={SegmentService.class})
public class SegmentServiceImpl
implements SegmentService {
    private static final Logger LOGGER = LoggerFactory.getLogger(SegmentServiceImpl.class);
    public static final String AAMSEGMENTPAGE_RESOURCE_TYPE = "cq/personalization/audiencemanager/components/segmentation/aamsegmentpage";
    public static final String AAMMAPPINGTRAIT_RESOURCE_TYPE = "cq/personalization/audiencemanager/components/segmentation/aammappingtrait";
    private static final String TRAITS_ANDPAR_AAMMAPPING_PATH = "/traits/andpar/aammapping";
    private static final String CQ_PERSONALIZATION_COMPONENTS_TRAITS_LOGIC_AND = "cq/personalization/components/traits/logic/and";
    private static final String FOUNDATION_COMPONENTS_PARSYS = "foundation/components/parsys";

    @Override
    public Iterable<AudienceManagerItem> getSegments(final AudienceManagerConfiguration config, final Iterable<String> segmentIds, final String segmentPropertyName) {
        return new Iterable<AudienceManagerItem>(){

            @Override
            public Iterator<AudienceManagerItem> iterator() {
                final HashMap cache = new HashMap();
                final Iterator ids = segmentIds.iterator();
                return new Iterator<AudienceManagerItem>(){

                    @Override
                    public boolean hasNext() {
                        return ids.hasNext();
                    }

                    @Override
                    public AudienceManagerItem next() {
                        return SegmentServiceImpl.this.getSegment(config, (String)ids.next(), segmentPropertyName, cache);
                    }

                    @Override
                    public void remove() {
                    }
                };
            }

        };
    }

    private AudienceManagerItem getSegment(AudienceManagerConfiguration config, String id, String segmentPropertyName, Map<String, AudienceManagerHolder> cache) {
        try {
            Node configNode = config.getNode();
            Session session = configNode.getSession();
            ResourceResolver resolverResolver = config.getResource().getResourceResolver();
            PageManager pageManager = (PageManager)resolverResolver.adaptTo(PageManager.class);
            AudienceManagerItem item = this.findAudienceManagerItem(this.getOrCreateBasePage(config, pageManager, session), id, segmentPropertyName, cache);
            if (item == null && cache != null) {
                LOGGER.debug("Segment Not found {} ", (Object)id);
                cache.put(id, new AudienceManagerHolder(null));
            } else {
                LOGGER.debug("Segment found {} ", (Object)id);
            }
            return item;
        }
        catch (RepositoryException e) {
            LOGGER.error(e.getMessage(), (Throwable)e);
        }
        catch (WCMException e) {
            LOGGER.error(e.getMessage(), (Throwable)e);
        }
        return null;
    }

    private AudienceManagerItem findAudienceManagerItem(Page page, String id, String segmentPropertyName, Map<String, AudienceManagerHolder> cache) {
        if (cache != null && cache.containsKey(id)) {
            return cache.get(id).getItem();
        }
        try {
            AudienceManagerItemImpl item = new AudienceManagerItemImpl(page);
            if (cache != null && item.getProperty(segmentPropertyName) != null) {
                cache.put(item.getProperty(segmentPropertyName), new AudienceManagerHolder(item));
            }
            if (id.equals(item.getProperty(segmentPropertyName))) {
                return item;
            }
        }
        catch (InvalidItemPage e) {
            LOGGER.trace("Attempting to load a non item page into a page {} ", (Object)e.getMessage());
        }
        Iterator subPages = page.listChildren();
        while (subPages.hasNext()) {
            AudienceManagerItem item = this.findAudienceManagerItem((Page)subPages.next(), id, segmentPropertyName, cache);
            if (item == null) continue;
            return item;
        }
        return null;
    }

    @Override
    public SyncResult syncSegments(AudienceManagerConfiguration config, AudienceManagerFolders folders, Iterable<AudienceManagerItem> segments) throws WCMException, RepositoryException {
        Calendar lastSync;
        Node configNode = config.getNode();
        ResourceResolver resolverResolver = config.getResource().getResourceResolver();
        Session session = configNode.getSession();
        PageManager pageManager = (PageManager)resolverResolver.adaptTo(PageManager.class);
        Page segmentsBasePage = this.getOrCreateBasePage(config, pageManager, session);
        Node segmentBaseContentNode = (Node)segmentsBasePage.getContentResource().adaptTo(Node.class);
        Calendar startThisSync = lastSync = Calendar.getInstance();
        if (segmentBaseContentNode.hasProperty("lastSync")) {
            lastSync = segmentBaseContentNode.getProperty("lastSync").getDate();
        }
        SyncResult result = this.createSubFolders(folders, segments, pageManager, config, lastSync, session);
        segmentBaseContentNode.setProperty("lastSync", Calendar.getInstance());
        QueryManager qm = session.getWorkspace().getQueryManager();
        ValueFactory vf = session.getValueFactory();
        Query q = qm.createQuery("SELECT * FROM [cq:PageContent] AS s   WHERE ISDESCENDANTNODE([" + segmentsBasePage.getPath() + "]) and " + "  CONTAINS(s.*, 'cq:lastModified') and " + "  s.[cq:lastModified] < $syncdate", "JCR-SQL2");
        q.bindValue("syncdate", vf.createValue(lastSync));
        QueryResult qr = q.execute();
        NodeIterator ni = qr.getNodes();
        while (ni.hasNext()) {
            ni.nextNode().getParent().remove();
        }
        Calendar touch = Calendar.getInstance();
        q = qm.createQuery("SELECT * FROM [cq:PageContent] AS s   WHERE ISDESCENDANTNODE([" + segmentsBasePage.getPath() + "]) and " + "  CONTAINS(s.*, 'cq:lastModified') and " + "  s.[cq:lastModified] > $syncdate and " + "  s.[cq:lastModified] < $thissync ", "JCR-SQL2");
        q.bindValue("syncdate", vf.createValue(lastSync));
        q.bindValue("thissync", vf.createValue(startThisSync));
        qr = q.execute();
        ni = qr.getNodes();
        while (ni.hasNext()) {
            ni.nextNode().setProperty("cq:lastModified", touch);
        }
        return result;
    }

    private SyncResult createSubFolders(AudienceManagerFolders folders, Iterable<AudienceManagerItem> items, PageManager pageManager, AudienceManagerConfiguration config, Calendar lastSync, Session session) throws WCMException, RepositoryException {
        AudienceManagerItem item;
        SyncResult syncResult = new SyncResult();
        for (AudienceManagerFolder folder : folders) {
            syncResult.incFolders();
            Page folderPage = pageManager.getPage(folder.getAbsolutePath(config));
            if (folderPage == null) {
                LOGGER.debug("Creating folder {} ", (Object)folder.getAbsolutePath(config));
                String folderParent = folder.getParent().getAbsolutePath(config);
                LOGGER.debug("FolderParent folder {} parent {} ", (Object)folderParent, (Object)folder.getParent());
                if (!session.itemExists(folderParent)) {
                    LOGGER.debug("Creating path {} ", (Object)folderParent);
                    JcrUtil.createPath((String)folderParent, (String)"sling:Folder", (Session)session);
                    session.save();
                }
                folderPage = pageManager.create(folderParent, folder.getName(), folder.getTemplate(), folder.getTitle());
                ((Node)folderPage.getContentResource().adaptTo(Node.class)).setProperty("sling:resourceType", "cq/personalization/audiencemanager/components/segmentation/aamsegmentpage");
                this.setFolderProperties(folder, folderPage);
                syncResult.add(folder);
                continue;
            }
            if (folderPage.getLastModified().before(lastSync)) {
                this.setFolderProperties(folder, folderPage);
                continue;
            }
            this.updateFolderProperties(folder, folderPage);
        }
        Iterator i$ = items.iterator();
        while (i$.hasNext() && (item = (AudienceManagerItem)i$.next()) != null) {
            Page itemPage = pageManager.getPage(item.getAbsolutePath(config));
            if (itemPage == null) {
                LOGGER.debug("Creating item page {} ", (Object)item.getAbsolutePath(config));
                String itemParent = item.getParent().getAbsolutePath(config);
                if (!session.nodeExists(itemParent)) {
                    LOGGER.warn("Parent folder {} does not exist, it should have been created, item {} skipped", (Object)itemParent, (Object)item.getName());
                    continue;
                }
                itemPage = pageManager.create(item.getParent().getAbsolutePath(config), item.getName(), item.getTemplate(), item.getTitle());
                ((Node)itemPage.getContentResource().adaptTo(Node.class)).setProperty("sling:resourceType", "cq/personalization/audiencemanager/components/segmentation/aamsegmentpage");
                this.setItemProperties(item, itemPage);
                syncResult.incSegments();
                syncResult.add(item);
                continue;
            }
            syncResult.incSegments();
            if (itemPage.getLastModified().before(lastSync)) {
                this.setItemProperties(item, itemPage);
                continue;
            }
            this.updateItemProperties(item, itemPage);
        }
        return syncResult;
    }

    private void updateItemProperties(AudienceManagerItem ams, Page itemPage) throws RepositoryException {
        this.setItemProperties(ams, itemPage);
    }

    private void updateFolderProperties(AudienceManagerFolder ams, Page folderPage) throws RepositoryException {
        this.setFolderProperties(ams, folderPage);
    }

    private void setItemProperties(AudienceManagerItem item, Page itemPage) throws RepositoryException {
        Node contentNode = (Node)itemPage.getContentResource().adaptTo(Node.class);
        for (Map.Entry<String, Object> e : item.getEntrySet()) {
            JcrUtil.setProperty((Node)contentNode, (String)e.getKey(), (Object)e.getValue());
        }
        Session session = contentNode.getSession();
        Node mappingNode = null;
        if (Text.isDescendant((String)"/etc/segmentation/aam", (String)contentNode.getPath())) {
            String relativePath = StringUtils.removeStart((String)(contentNode.getPath() + "/traits/andpar/aammapping"), (String)"/etc/segmentation/aam/");
            Node absoluteBase = session.getNode("/etc/segmentation/aam");
            mappingNode = JcrUtil.createPath((Node)absoluteBase, (String)relativePath, (boolean)false, (String)"nt:unstructured", (String)"nt:unstructured", (Session)session, (boolean)false);
            mappingNode.setProperty("sling:resourceType", "cq/personalization/audiencemanager/components/segmentation/aammappingtrait");
            mappingNode.getParent().setProperty("sling:resourceType", "foundation/components/parsys");
            mappingNode.getParent().getParent().setProperty("sling:resourceType", "cq/personalization/components/traits/logic/and");
            mappingNode.setProperty("aam_sid", String.valueOf(item.getItemId()));
        } else {
            LOGGER.error("Unexpected path {} to store segments - service expects path underneath {}", (Object)contentNode.getPath(), (Object)"/etc/segmentation/aam");
        }
    }

    private void setFolderProperties(AudienceManagerFolder ams, Page segmentPage) throws RepositoryException {
        Node contentNode = (Node)segmentPage.getContentResource().adaptTo(Node.class);
        for (Map.Entry<String, Object> e : ams.getEntrySet()) {
            JcrUtil.setProperty((Node)contentNode, (String)e.getKey(), (Object)e.getValue());
        }
    }

    private Page getOrCreateBasePage(AudienceManagerConfiguration config, PageManager pageManager, Session session) throws RepositoryException, WCMException {
        Page segmentsBasePage = pageManager.getPage(config.getTarget());
        if (segmentsBasePage == null) {
            if (!session.itemExists(config.getTargetParent())) {
                JcrUtil.createPath((String)config.getTargetParent(), (String)"sling:OrderedFolder", (Session)session);
                session.save();
            }
            segmentsBasePage = pageManager.create(config.getTargetParent(), config.getName(), config.getSegmentationTemplate(), config.getTitle());
            ((Node)segmentsBasePage.getContentResource().adaptTo(Node.class)).setProperty("sling:resourceType", "cq/personalization/audiencemanager/components/segmentation/aamsegmentpage");
        }
        return segmentsBasePage;
    }

    public class AudienceManagerHolder {
        private AudienceManagerItem item;

        public AudienceManagerHolder(AudienceManagerItem amitem) {
            this.item = amitem;
        }

        public AudienceManagerItem getItem() {
            return this.item;
        }
    }

}