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

com.adobe.cq.sightly.WCMScriptHelper Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2013 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.sightly;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.SyntheticResource;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.api.servlets.ServletResolver;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.apache.sling.scripting.sightly.SightlyException;
import org.osgi.annotation.versioning.ProviderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.sightly.internal.PrintWriterResponseWrapper;
import com.day.cq.wcm.api.WCMMode;
import com.day.cq.wcm.api.components.IncludeOptions;

/**
 * The {@code WCMScriptHelper} class provides helper methods to support CQ Sightly extensions. This is to be used only with the CQ specific
 * Sightly plugins.
 *
 * This class is not meant to be extended.
 **/
@ProviderType
public class WCMScriptHelper {

    private final Logger log = LoggerFactory.getLogger(WCMScriptHelper.class);

    private SlingScriptHelper slingHelper;

    private SlingHttpServletRequest request;

    private SlingHttpServletResponse response;

    private SightlyWCMMode mode;

    public WCMScriptHelper(SlingScriptHelper sling) {
        slingHelper = sling;
        request = sling.getRequest();
        response = sling.getResponse();
        mode = new SightlyWCMMode(request);
    }

    /**
     * Include the resource and redirect the output into a custom print writer.
     *
     * @param out                the custom writer
     * @param script             the path of the resource to include
     * @param dispatcherOptions  {@code key=value} comma separated pairs as String
     * @param resourceType       Sling resource type to be used while including the resource
     * @param wcmResourceOptions the WCM specific options for including the resource
     */
    public void includeResource(PrintWriter out, String script, String dispatcherOptions, String resourceType,
                                WCMResourceOptions wcmResourceOptions) {
        SlingHttpServletResponse customResponse = new PrintWriterResponseWrapper(out, response);
        includeResource(customResponse, script, dispatcherOptions, resourceType, wcmResourceOptions);
    }

    /**
     * Include a resource and redirect the output into a custom response.
     *
     * @param customResponse     the custom response
     * @param script             the path of the resource to include
     * @param dispatcherOptions  {@code key=value} comma separated pairs as String
     * @param resourceType       Sling resource type to be used while including the resource
     * @param wcmResourceOptions the WCM specific options for including the resource
     */
    public void includeResource(SlingHttpServletResponse customResponse, String script, String dispatcherOptions, String resourceType,
                                WCMResourceOptions wcmResourceOptions) {
        includeResource(customResponse, script, dispatcherOptions, resourceType, wcmResourceOptions, Collections.EMPTY_MAP);

    }

    /**
     * Include a {@link SyntheticResource} and redirect the output into a custom response.
     *
     * @param response           the custom response
     * @param script             the path of the resource to include
     * @param dispatcherOptions  {@code key=value} comma separated pairs as String
     * @param resourceType       Sling resource type to be used while including the resource
     * @param wcmResourceOptions the WCM specific options for including the resource
     * @param resourceProperties the properties of the {@link SyntheticResource} that will be included
     */
    public void includeResource(SlingHttpServletResponse response, String script, String dispatcherOptions, String resourceType,
                                WCMResourceOptions wcmResourceOptions, Map resourceProperties) {
        if (StringUtils.isEmpty(script)) {
            log.error("Script path cannot be empty.");
        } else {
            script = normalizePath(script);
            ResourceResolver resourceResolver = request.getResourceResolver();
            Resource includedResource;
            if (resourceProperties != null && resourceProperties.size() > 0) {
                 includedResource = new SyntheticResourceWithProperties(resourceResolver, script, resourceType,
                    resourceProperties);
            } else {
                includedResource = resourceResolver.resolve(script);
                if (ResourceUtil.isNonExistingResource(includedResource) && resourceType != null) {
                    includedResource = new SyntheticResource(resourceResolver, script, resourceType);
                }
            }
            includeResource(response, includedResource, dispatcherOptions, resourceType, wcmResourceOptions);
        }
    }

    /**
     * Include a {@link Resource} and redirect the output into a custom response
     *
     * @param response           the custom response
     * @param resource           the {@link Resource} to include
     * @param dispatcherOptions  {@code key=value} comma separated pairs as String
     * @param resourceType       Sling resource type to be used while including the resource
     * @param wcmResourceOptions the WCM specific options for including the resource
     */
    public void includeResource(SlingHttpServletResponse response, Resource resource, String dispatcherOptions, String resourceType,
                                WCMResourceOptions wcmResourceOptions) {
        if (resource == null) {
            log.error("Included resource cannot be null.");
        } else {
            WCMMode currentMode = (WCMMode) request.getAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME);
            try {
                WCMMode mode = wcmResourceOptions.getWCMMode();
                if (mode != null) {
                    request.setAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME, mode);
                }
                IncludeOptions includeOptions = IncludeOptions.getOptions(request, true);
                String decorationTagName = wcmResourceOptions.getDecorationTagName();
                if (StringUtils.isNotEmpty(decorationTagName)) {
                    includeOptions.setDecorationTagName(decorationTagName);
                } else if(!wcmResourceOptions.getDecoration()) {
                    includeOptions.setDecorationTagName(StringUtils.EMPTY);
                }
                String cssClassName = wcmResourceOptions.getCssClassName();
                if (StringUtils.isNotEmpty(cssClassName)) {
                    includeOptions.getCssClassNames().addAll(expandClassName(cssClassName));
                }
                RequestDispatcherOptions requestDispatcherOptions = new RequestDispatcherOptions(dispatcherOptions);
                if (StringUtils.isNotEmpty(resourceType)) {
                    requestDispatcherOptions.setForceResourceType(resourceType);
                }
                RequestDispatcher dispatcher = request.getRequestDispatcher(resource, requestDispatcherOptions);
                if (resource.getClass() == SyntheticResource.class) {
                    // remove resource type overwrite as synthetic resource
                    // is correctly typed as requested
                    requestDispatcherOptions.remove(RequestDispatcherOptions.OPT_FORCE_RESOURCE_TYPE);
                }
                dispatcher.include(request, response);
            } catch (Exception e) {
                if (e instanceof SightlyException) {
                    throw (SightlyException) e;
                } else {
                    throw new SightlyException(e);
                }
            } finally {
                // reset mode
                if (currentMode == null) {
                    request.removeAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME);
                } else {
                    request.setAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME, currentMode);
                }
            }
        }
    }

    /**
     * Calls the given script.
     *
     * @param script    script path to be called
     * @param wcmMode   WCM mode to be used, its an optional parameter. If the current request contains mode attribute,
     *                  it will be reset after the script call.
     *
     * */
    public void includeScript(String script, String wcmMode, PrintWriter out) {
        if (StringUtils.isEmpty(script)) {
            log.error("Script path cannot be empty.");
        } else {
            WCMMode currentMode = (WCMMode) request.getAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME);
            if (StringUtils.isNotEmpty(wcmMode)) {
                WCMMode mode = WCMMode.valueOf(wcmMode.toUpperCase());
                if (mode != null) {
                    request.setAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME, mode);
                }
            }
            ServletResolver servletResolver = slingHelper.getService(ServletResolver.class);
            if (servletResolver != null) {
                Servlet servlet = servletResolver.resolveServlet(request.getResource(), script);
                if (servlet != null) {
                    try {
                        PrintWriterResponseWrapper resWrapper = new PrintWriterResponseWrapper(out, response);
                        servlet.service(request, resWrapper);
                    } catch (Exception e) {
                        if (e instanceof SightlyException) {
                            throw (SightlyException) e;
                        } else {
                            throw new SightlyException(e);
                        }
                    }
                } else {
                    log.error("Failed to locate script {}.", script);
                }
            } else {
                String msg = String.format("Sling ServletResolver service is unavailable, failed to include %s.", script);
                throw new SightlyException(msg);
            }
            if (currentMode == null) {
                request.removeAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME);
            } else {
                request.setAttribute(WCMMode.REQUEST_ATTRIBUTE_NAME, currentMode);
            }
        }
    }

    public SightlyWCMMode getMode() {
        return mode;
    }

    //------------------------- private ---------------------------
    private String normalizePath(String path) {
        if (!path.startsWith("/")) {
            path = request.getResource().getPath() + "/" + path;
        }
        return ResourceUtil.normalize(path);
    }

    private List expandClassName(String classesString) {
        String[] classesArray = classesString.split("\\s");
        List classes = new ArrayList();
        for (String c : classesArray) {
            c = c.trim();
            if (StringUtils.isNotEmpty(c)) {
                classes.add(c);
            }
        }
        return classes;
    }

    /**
     * The {@code SyntheticResourceWithProperties} allows creating virtual resources that can be used for rendering content not obeying
     * an AEM component's expected content structure.
     */
    private static class SyntheticResourceWithProperties extends SyntheticResource {

        private Map properties;

        SyntheticResourceWithProperties(ResourceResolver resourceResolver, String path, String resourceType, Map properties) {
            super(resourceResolver, path, resourceType);
            this.properties = properties;
        }

        @Override
        public  AdapterType adaptTo(Class type) {
            if (type == ValueMap.class) {
                return (AdapterType) new ValueMapDecorator(properties);
            }
            return super.adaptTo(type);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy