MsmLocationNameProvider.java 7.6 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.analytics.testandtarget.TargetLocationNameProvider
 *  com.day.cq.wcm.api.Page
 *  com.day.cq.wcm.api.WCMMode
 *  org.apache.commons.lang.StringUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.AbstractResourceVisitor
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ValueMap
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.msmtarget.impl;

import com.day.cq.analytics.testandtarget.TargetLocationNameProvider;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.WCMMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.AbstractResourceVisitor;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
@Component
@Properties(value={@Property(name="service.ranking", intValue={7000})})
public class MsmLocationNameProvider
implements TargetLocationNameProvider {
    private static final Logger LOG = LoggerFactory.getLogger(MsmLocationNameProvider.class);

    public Set<String> getOfferLocationNames(Page offerPage, WCMMode wcmMode) {
        LOG.debug("Using custom location name provider");
        HashSet<String> locations = new HashSet<String>();
        Page ambitPage = this.getOfferAmbit(offerPage);
        String locationBaseName = this.getLocationBaseName(offerPage);
        if (!ambitPage.getName().equals("master")) {
            ResourceResolver resourceResolver = ambitPage.getContentResource().getResourceResolver();
            Set<SortedSet<String>> ambitMappings = this.getAmbitMappingsForLocation(resourceResolver, ambitPage.getPath(), locationBaseName);
            if (ambitMappings.isEmpty()) {
                LOG.warn("No ambit mappings have been found for ambit {}.", (Object)ambitPage.getPath());
            } else {
                LOG.debug("Found {} ambit mappings for ambit {}. Computing hashes...", (Object)ambitMappings.size(), (Object)ambitPage.getPath());
                for (SortedSet<String> ambitMapping : ambitMappings) {
                    String hashKey = this.hashAmbitMappings(ambitMapping);
                    String locationName = StringUtils.isNotEmpty((String)hashKey) ? locationBaseName + "-" + hashKey : locationBaseName;
                    locations.add(this.qualifyLocationName(locationName, wcmMode));
                    LOG.warn("Generated location name {}", (Object)locationName);
                }
            }
        } else {
            LOG.debug("Offer page is in master ambit, falling back to the default naming scheme...");
            locations.add(this.qualifyLocationName(locationBaseName, wcmMode));
        }
        return locations;
    }

    private Page getOfferAmbit(Page page) {
        if (page == null) {
            return null;
        }
        if (page.getContentResource().isResourceType("cq/personalization/components/ambitpage")) {
            return page;
        }
        return this.getOfferAmbit(page.getParent());
    }

    private Set<SortedSet<String>> getAmbitMappingsForLocation(ResourceResolver resolver, String ambitPath, String locationName) {
        LOG.debug("Searching for ambit mappings involving ambit {} (location: {})", (Object)ambitPath, (Object)locationName);
        HashSet<SortedSet<String>> ambitMappings = new HashSet<SortedSet<String>>();
        String query = "SELECT * FROM [nt:unstructured] as N where ISDESCENDANTNODE(N,'/content') AND N.[cq:target-ambits] = '" + ambitPath + "'";
        Iterator resources = resolver.findResources(query, "JCR-SQL2");
        while (resources.hasNext()) {
            Resource res = (Resource)resources.next();
            if (this.isLocationUnderResource(res, locationName)) {
                ambitMappings.add(this.getAmbitMappings(res));
            }
            LOG.debug("Location {} is not under resource at path {}. Skipping ambit mapping.", (Object)res.getPath());
        }
        return ambitMappings;
    }

    private SortedSet<String> getAmbitMappings(Resource res) {
        LOG.debug("Reading ambit mappings for resource at {}", (Object)res.getPath());
        TreeSet<String> ambitMappings = new TreeSet<String>();
        ValueMap props = (ValueMap)res.adaptTo(ValueMap.class);
        String[] mappings = (String[])props.get("cq:target-ambits", String[].class);
        ambitMappings.addAll(Arrays.asList(mappings));
        LOG.debug("Found ambit mappings {}", (Object)ambitMappings.toString());
        return ambitMappings;
    }

    private boolean isLocationUnderResource(Resource res, String locationName) {
        LocationNameChecker visitor = new LocationNameChecker(locationName);
        visitor.accept(res);
        return visitor.isFound();
    }

    private String hashAmbitMappings(Set<String> ambitMappings) {
        MessageDigest md = null;
        String mappings = "";
        try {
            md = MessageDigest.getInstance("MD5");
            mappings = StringUtils.join(ambitMappings, (String)"#");
            LOG.warn("Found mapping {}", (Object)mappings);
        }
        catch (NoSuchAlgorithmException e) {
            return mappings;
        }
        md.update(mappings.getBytes());
        byte[] hashedBytes = md.digest();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hashedBytes.length; ++i) {
            sb.append(Integer.toString((hashedBytes[i] & 255) + 256, 16).substring(1));
        }
        return sb.toString();
    }

    private String getLocationBaseName(Page offerPage) {
        String location = (String)offerPage.getProperties().get("location", (Object)"");
        if ("".equals(location)) {
            return null;
        }
        if (location.startsWith("/")) {
            location = location.substring(1);
        }
        location.replaceAll("/", "-").replaceAll("-jcr:content", "");
        return location;
    }

    private String qualifyLocationName(String locationName, WCMMode wcmMode) {
        return wcmMode == WCMMode.DISABLED ? locationName : locationName + "--author";
    }

    private class LocationNameChecker
    extends AbstractResourceVisitor {
        private boolean found;
        private boolean keepSearching;
        private String locationName;

        LocationNameChecker(String name) {
            this.found = false;
            this.keepSearching = true;
            this.locationName = name;
        }

        protected boolean isFound() {
            return this.found;
        }

        protected void visit(Resource res) {
            if (!this.keepSearching) {
                return;
            }
            if (res.isResourceType("cq/personalization/components/target")) {
                ValueMap props = (ValueMap)res.adaptTo(ValueMap.class);
                this.found = this.locationName.equals(props.get("location", (Object)""));
                this.keepSearching = !this.found;
            }
        }
    }

}