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

com.adobe.cq.social.srp.internal.SocialProviderUtils Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2014 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 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.adobe.cq.social.srp.internal;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Various utilities useful to provider impls.
 */
public final class SocialProviderUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(SocialProviderUtils.class);

    /* dot (.) sling selector resources that we don't need AS to resolve since they won't exist */
    private static final String IGNORE_DOT_SUFFIX =
        "html|json|form|feed|deletecomment|editcomment|createcomment|composer|social|socialuserstatetoggle";
    /* known resource suffix that won't resolve */
    private static final String IGNORE_SLASH_SUFFIX = "editcomment|editforum";
    private static final String PAGING_PATTERN = "(\\.social(\\.[0-9]+){1,2})" // .social.number.number
            + "|" // OR
            + "(\\.social.\\$\\{startIndex}.*)"; // .social.${startIndex}

    // SLING dot selectors
    // ?i - ignore case in match
    // \\. - follow by a dot '.'
    private static final String DOT_PATTERN = "(\\.(?i)(" + IGNORE_DOT_SUFFIX + "))";
    // known path suffix such as /editforum
    private static final String SLASH_PATTERN = "(\\/(?i)(" + IGNORE_SLASH_SUFFIX + "))";
    // [^\\s] - must start with one or more characters except white space
    // list of SLING selectors OR known suffix to ignore
    // $ - end of the string
    private static final String SUFFIX_PATTERN = "([^\\s]+(" + DOT_PATTERN + "|" + SLASH_PATTERN + "|"
            + PAGING_PATTERN + ")$)";
    private static final Pattern PATTERN = Pattern.compile(SUFFIX_PATTERN);

    private SocialProviderUtils() {
    }

    /**
     * Figure out if the path is one that we will never store in the cloud.
     * @param path the path to check
     * @return true iff the path will never be stored in the cloud.
     */
    public static boolean isExtraneousSlingPath(final String path) {
        return isExtraneousSlingPath(null, null, path);
    }

    /**
     * Figure out if the path is one that we will never store in the cloud. Special case for paths ending with
     * ".social.json" since those are POST requests which go directly to Sling and Sling does a resolve on the
     * resource path.
     * @param resolver resolver to use for pre-fetch resources
     * @param srp SocialResourceProvider to batch reading
     * @param path the path to check
     * @return true iff the path will never be stored in the cloud.
     */
    public static boolean isExtraneousSlingPath(final ResourceResolver resolver, final CachingResourceProvider srp,
        final String path) {
        // There are paths that sling asks us to resolve that will never resolve. Don't
        // take the hit of asking Adobe Cloud Storage.

        // Anything where jcr:content has been replaced with _jcr_content isn't going to be found.
        if (path.contains("/_jcr_content/")) {
            return true;
        }

        // Any directory requests isn't going to be found.
        if (path.endsWith("/")) {
            return true;
        }

        if (resolver != null && srp != null && StringUtils.endsWithIgnoreCase(path, ".social.json")) {
            batchResolve(resolver, srp, StringUtils.removeEndIgnoreCase(path, ".social.json"));
            return true;
        }

        // skip selectors and known suffix.
        final Matcher matcher = PATTERN.matcher(path);
        if (matcher.matches()) {
            LOGGER.debug("Ignoring extraneous path: {}", path);
            return true;
        }

        return false;
    }

    /**
     * Convenient method to "convert" a resolve() to a batch read. Not as efficient as a real resolve() since it will
     * read all the "nodes" in the path up to the ASI Root.
     * @param resolver resolver for the batch read
     * @param srp SocialResourceProvider for getResources()
     * @param path The full path will ".social.json" already stripped from the end
     */
    private static void batchResolve(final ResourceResolver resolver, final CachingResourceProvider srp,
        final String path) {
        final List resourcePaths = new ArrayList();

        // the component doing the post, voting, following, etc.
        final String component = StringUtils.substringAfterLast(path, "/");
        final String prefix = StringUtils.substringBeforeLast(path, "/");

        final StringBuilder sb = new StringBuilder(srp.getASIPath());

        final StringTokenizer tokener =
            new StringTokenizer(StringUtils.removeStartIgnoreCase(prefix, srp.getASIPath()), "/");
        while (tokener.hasMoreTokens()) {
            sb.append('/');
            sb.append(tokener.nextToken());
            resourcePaths.add(sb.toString());
        }

        // add the voting node and voting/userid node if it's a voting operation
        if ("voting".equalsIgnoreCase(component)) {
            sb.append("/voting");
            resourcePaths.add(sb.toString());
            sb.append("/");
            sb.append(resolver.getUserID());
            resourcePaths.add(sb.toString());
        }

        // add socialgraph path if it's a follow operation
        if ("socialgraph".equalsIgnoreCase(component)) {
            sb.append("/socialgraph");
            resourcePaths.add(sb.toString());
        } else {
            // we may as well grab what we're originally be asked for (minus selectors) while we are here. it's the
            // next thing we're asked for
            final String resourceName = StringUtils.substringBefore(component, ".");
            sb.append("/");
            sb.append(resourceName);
            resourcePaths.add(sb.toString());
        }

        if (!resourcePaths.isEmpty()) {
            srp.getResources(resolver, resourcePaths);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy