All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.analytics.testandtarget.util.MboxHelper Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2011 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.day.cq.analytics.testandtarget.util;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

import org.apache.commons.lang.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.analytics.sitecatalyst.Framework;
import com.day.cq.analytics.testandtarget.MboxConstants;
import com.day.cq.commons.inherit.HierarchyNodeInheritanceValueMap;
import com.day.cq.commons.inherit.InheritanceValueMap;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.personalization.impl.util.PersonalizationConstants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.webservicesupport.Configuration;
import com.day.cq.wcm.webservicesupport.ConfigurationManager;

public class MboxHelper {

    private static final Logger log = LoggerFactory.getLogger(MboxHelper.class);
    
    //no instance
    private MboxHelper() {
        
    }
    
    /**
     * Returns a name for the {@link Resource}. As name the jcr:title with
     * removed whitespaces is used if available. If no jcr:title is specified,
     * a name is generated by {@link MboxHelper#getMboxId(Resource)}.
     * 
     * @param rsrc {@link Resource}
     * @return a name for the {@link Resource}
     */
    public static String getMboxName(Resource rsrc) {
        String mboxName = "";
        rsrc = getStartResource(rsrc);
        ValueMap resourceConfig = rsrc.adaptTo(ValueMap.class);
        if(resourceConfig != null) {
            mboxName = resourceConfig.get("jcr:title","");
            if ("".equals(mboxName)) {
                mboxName = getMboxId(rsrc);
            }
            mboxName = mboxName.replaceAll("\\s", "");
        }
        return mboxName;
    }

    /**
     * Generates the location name used by this location in Adobe Target.
     * The location name uses the following pattern:
     * {location-name-in-aem}-{the non-master ambit names joined by # and hashed using MD5}--{wcm mode}. If the {@link WCMMode} is {@link WCMMode#DISABLED} then it's omitted. If not, the "--author" suffix is used.
     *
     * @param currentResource the {@link Resource} representing the target component
     * @param wcmMode the {@link WCMMode}
     * @param ambitMappings Array of ambits
     * @return the location name generated using the pattern described above
     */
    public static String generateLocationName(Resource currentResource, WCMMode wcmMode, String... ambitMappings) {

        String mboxBaseName = getMboxName(currentResource);
        String mboxName;

        if (ambitMappings != null && ambitMappings.length > 0) {
            SortedSet mappings = new TreeSet();
            // check that we don't have the master ambit mapped to the parent page
            for (String mapping: ambitMappings) {
                if (!mapping.endsWith("master")) {
                    mappings.add(mapping);
                }
            }
            String hashedInfo = mappings.size() > 0 ?
                    "-" + hashData(StringUtils.join(mappings, "#")) :
                    "";
            mboxName = MboxHelper.qualifyMboxNameOrId(mboxBaseName + hashedInfo, wcmMode);
        } else {
            mboxName = MboxHelper.qualifyMboxNameOrId(mboxBaseName, wcmMode);
        }

        return mboxName;
    }

    /**
     * Generates an mbox ID. The ID is generated by replacing slashes and
     * removing jcr:content from the resource path of the start element.
     * If the corresponding start element can not be found the provided 
     * element is used.
     * 
     * @param rsrc Resource of start/end element
     * @return an MboxId for the {@link Resource}
     */
    public static String getMboxId(Resource rsrc) {
        String mboxId = "";
        rsrc = getStartResource(rsrc);
        if(rsrc != null) {
            ValueMap vm = rsrc.adaptTo(ValueMap.class);
            String loc = vm.get(MboxConstants.PROP_MBOX_LOCATION, rsrc.getPath());
            mboxId = getMboxId(loc);
        }
        return mboxId;
    }

    /**
     * Adds the WCM mode qualifier to the mbox name, if necessary
     * @param mboxNameOrId the mbox name
     * @param wcmMode the {@link WCMMode}
     * @return the mbox name containing the WCM mode, if necessary. It the WCM mode is {@link WCMMode#DISABLED} then the return value is the one passed in the mboxNameOrId parameter
     */
    public static String qualifyMboxNameOrId(String mboxNameOrId, WCMMode wcmMode) {

        if (wcmMode == WCMMode.DISABLED)
            return mboxNameOrId;

        // the double dash is guaranteed to not come from a valid JCR path since we
        // translate slashes to dashes and a double slash is not a valid JCR path
        return mboxNameOrId + "--author";
    }

    /**
     * Adds the necessary qualifiers (WCM Mode and the name of the ambit) to the mbox name
     * @param mboxNameOrId the actual mbox name
     * @param wcmMode the {@link WCMMode}
     * @param ambitName the name of the ambit, if this mbox belongs to a site using MSM
     * @return the location name containing the ambit name and the wcm mode, if necessary. If the WCM mode is {@link WCMMode#DISABLED} and the ambit name is "master" then the return value is the one passed on the mboxNameOrId parameter
     */
    public static String qualifyMboxNameOrId(String mboxNameOrId, WCMMode wcmMode, String ambitName) {
        if (StringUtils.isEmpty(ambitName) || PersonalizationConstants.AMBIT_DEFAULT_NAME.equals(ambitName)) {
            return qualifyMboxNameOrId(mboxNameOrId, wcmMode);
        }

        return qualifyMboxNameOrId(StringUtils.join(new String[] { mboxNameOrId, ambitName }, "-"), wcmMode);
    }


    /**
     * Generates an mbox ID from an mbox location. 
* Slashes are replaced with dashes. If this location is a repository path then jcr:content is stripped from it. * * @param location the mbox location * @return the mbox id * * @see #getMboxId(Resource) */ public static String getMboxId(String location) { if (location.startsWith("/")) { // strip the leading / from paths location = location.substring(1); } return location.replaceAll("/", "-").replaceAll("-jcr:content", ""); } /** * Search the start element for the current element type. * @param resource {@link Resource} * @return start element for the current element type */ public static Resource searchStartElement(final Resource resource) { if ( ResourceUtil.getName(resource).equals(JcrConstants.JCR_CONTENT) ) { return null; } if ( resource.getPath().lastIndexOf("/") == 0 ) { return null; } if ( ResourceUtil.isA(resource, MboxConstants.RT_MBOX_BEGIN) ) { return resource; } // first, we have to collect all predecessors final Resource parent = ResourceUtil.getParent(resource); final List predecessor = new ArrayList(); final Iterator i = ResourceUtil.listChildren(parent); while ( i.hasNext() ) { final Resource current = i.next(); if ( current.getPath().equals(resource.getPath()) ) { break; } predecessor.add(current); } // reverse the order, to get the immediate predecessors first Collections.reverse(predecessor); // iterate, as soon as we find a form begin, we're done // as soon as we find a form end, the form begin is missing for this form final Iterator rsrcIter = predecessor.iterator(); while ( rsrcIter.hasNext() ) { final Resource current = rsrcIter.next(); if ( ResourceUtil.isA(current, MboxConstants.RT_MBOX_BEGIN) ) { return current; } if ( ResourceUtil.isA(current, MboxConstants.RT_MBOX_END) ) { return null; } } return searchStartElement(parent); } /** * Checks {@link Resource} for end element and returns start element if * possible. If the {@link Resource} is a start element it is returned * directly. * * @param rsrc {@link Resource} */ private static Resource getStartResource(Resource rsrc) { if(ResourceUtil.isA(rsrc, MboxConstants.RT_MBOX_END)) { Resource startElement = searchStartElement(rsrc); if(startElement !=null) { return startElement; } } return rsrc; } /** * Returns the repository path to a custom mbox.js file for the current specified resource and currentPage * * @param resource {@link Resource} * @param currentPage current {@link Page} * @param cfgMgr {@link ConfigurationManager} * @return the path to the custom mbox.js file or null if the default one should be used * @throws RepositoryException {@link RepositoryException} */ public static String getCustomMboxJsPath(Resource resource, Page currentPage, ConfigurationManager cfgMgr) throws RepositoryException { Configuration configuration = null; HierarchyNodeInheritanceValueMap mboxProperties = new HierarchyNodeInheritanceValueMap(resource); String[] services = mboxProperties.getInherited( "cq:cloudserviceconfigs", new String[] {}); if (services.length == 0) { mboxProperties = new HierarchyNodeInheritanceValueMap( currentPage.getContentResource()); services = mboxProperties.getInherited("cq:cloudserviceconfigs", new String[] {}); } if (cfgMgr != null) configuration = cfgMgr.getConfiguration("testandtarget", services); boolean isValidConfig = configuration != null && (configuration.getInherited("clientcode", null) != null); if (isValidConfig) { Node configNode = null; if (configuration != null) configNode = configuration.getResource().adaptTo(Node.class); if (configNode.hasNode("./jcr:content/public/mbox.js")) { final Node scriptNode = configNode.getNode("./jcr:content/public/mbox.js"); return scriptNode.getPath(); } } return null; } /** * Returns true if the mbox represented by the resource has accurateTargeting enabled. * * @param resource {@link Resource} * @return true if the mbox represented by the resource has accurateTargeting enabled. * @throws RepositoryException {@link RepositoryException} */ public static boolean isAccurateRendering(Resource resource) throws RepositoryException { return resource.adaptTo(ValueMap.class).get("accurateTargeting", false); } /** * Returns the names of the ClientContext parameters which should be sent as part of mbox calls * *

* This method merges the directly defined parameter names with the parameters names inherited from a Adobe Target * framework. *

* * @param resource the target resource * @param pageProperties {@link InheritanceValueMap} * @param configurationManager {@link ConfigurationManager} * @return a list of parameter names, never null * @throws RepositoryException {@link RepositoryException} */ public static List getClientContextParameterNames(Resource resource, InheritanceValueMap pageProperties, ConfigurationManager configurationManager) throws RepositoryException { return new ArrayList(getMappedClientContextParameterNames(resource, pageProperties, configurationManager).values()); } /** * Returns the names and mapped values of the ClientContext parameters which should be sent as part of mbox calls * *

* This method merges the directly defined parameter names with the parameters names inherited from a Adobe Target * framework. *

* *

* The mapped values are usually defined by the {@link Framework}. In case they are defined statically on the * component the property name is transformed by transforming all slashes ('/') to dots ('.'). *

* * @param resource the target resource * @param pageProperties {@link InheritanceValueMap} * @param configurationManager {@link ConfigurationManager} * @return parameter mappings never null * @throws RepositoryException {@link RepositoryException} */ public static Map getMappedClientContextParameterNames(Resource resource, InheritanceValueMap pageProperties, ConfigurationManager configurationManager) throws RepositoryException { Map mappedProperties = new LinkedHashMap(); List directMappings = Arrays.asList(resource.adaptTo(ValueMap.class).get("cq:mappings", new String[0])); for (String directMapping : directMappings) mappedProperties.put(directMapping, directMapping.replace('/', '.')); // same as cbmappings.jsp Framework framework = getFramework(pageProperties, configurationManager); if (framework == null) return mappedProperties; for (String scVar : framework.scVars()) mappedProperties.put(framework.getMapping(scVar), scVar); return mappedProperties; } /** * Returns the static parameters configured for this target component. These parameters are used when performing mbox calls. * @param resource the {@link Resource} representing the target component * @return a {@link Map} containing the mapped parameters */ public static Map getStaticParameters(Resource resource) { String[] staticParameters = resource.adaptTo(ValueMap.class).get("staticParams", new String[0]); Map toReturn = new HashMap(); try { for (String keyAndValue : staticParameters) { JSONArray array = new JSONArray(keyAndValue); toReturn.put(array.getString(0), array.getString(1)); } } catch (JSONException e) { log.error(e.getMessage(),e); } return toReturn; } private static Framework getFramework(InheritanceValueMap pageProperties, ConfigurationManager configurationManager) { // check for a framework defined on the page or above String[] services = pageProperties.getInherited(Constants.PN_CQ_CLOUD_SERVICE_CONFIGS, new String[] {}); log.debug("Found has {} service configs", services.length); if (services.length == 0) return null; Configuration configuration = configurationManager.getConfiguration("testandtarget", services); if (configuration == null) return null; log.debug("Resource configured to use configuration at {}", configuration.getPath()); return configuration.getContentResource().adaptTo(Framework.class); } private static String hashData(String data) { MessageDigest md = null; String mappings = ""; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { return data; } md.update(data.getBytes()); byte[] hashedBytes = md.digest(); // convert to hex StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashedBytes.length; i++) { sb.append(Integer.toString((hashedBytes[i] & 0xff) + 0x100, 16).substring(1)); } return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy