com.adobe.cq.sightly.WCMScriptHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
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);
}
}
}