com.day.cq.wcm.tags.IncludeTag Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.wcm.tags;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.IOException;
import org.apache.commons.lang.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.request.RequestProgressTracker;
import org.apache.sling.api.request.RequestUtil;
import org.apache.sling.api.resource.NonExistingResource;
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.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.api.servlets.ServletResolver;
import org.apache.sling.scripting.jsp.util.JspSlingHttpServletResponseWrapper;
import org.apache.sling.scripting.jsp.util.TagUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* IncludeTag
implements the <cq:include/> tag.
*/
public class IncludeTag extends TagSupport {
static final long serialVersionUID = -5953960896840203934L;
/**
* default logger
*/
private static final Logger log = LoggerFactory.getLogger(IncludeTag.class);
/**
* resource type
*/
private String resourceType;
/**
* path
*/
private String path;
/**
* jsp script
*/
private String script;
/**
* flush
*/
private boolean flush;
/**
* defaultResourceType
*
*/
private String defaultResourceType;
/**
* ignores the component hierarchy and only respect scripts paths
*/
private boolean ignoreComponentHierarchy;
/**
* {@inheritDoc}
*
* @return EVAL_PAGE
* @throws JspException if an error occurs
*/
public int doEndTag() throws JspException {
if (script != null) {
return includeScript();
}
if (resourceType != null && defaultResourceType != null) {
throw new JspException("Only one of resourceType or defaultResourceType attributes must be specified.");
}
if (path != null && (resourceType != null || defaultResourceType != null)) {
return includeResource();
}
// neither a script nor a resource
throw new JspException("Either path/resourceType/defaultResourceType or script must be defined.");
}
/**
* Includes the given script.
* @return EVAL_PAGE
* @throws JspException if an error occurs
*/
private int includeScript() throws JspException {
final SlingBindings bindings = (SlingBindings) pageContext.getRequest().getAttribute(
SlingBindings.class.getName());
final SlingScriptHelper scriptHelper = bindings.getSling();
final ServletResolver servletResolver = scriptHelper.getService(ServletResolver.class);
RequestProgressTracker tracker = TagUtil.getRequest(pageContext).getRequestProgressTracker();
String servletName = null;
final Servlet servlet;
if ( !ignoreComponentHierarchy ) {
final Resource resource = bindings.getResource();
servlet = servletResolver.resolveServlet(resource, this.script);
if (servlet != null) {
servletName = RequestUtil.getServletName(servlet);
tracker.log("Including script {0} for path={1}, type={2}: {3}", script, resource.getPath(), resource.getResourceType(), servletName);
}
} else {
final ResourceResolver rr = bindings.getRequest().getResourceResolver();
final String scriptPath;
if (!script.startsWith("/")) {
// resolve relative script
String parentPath = ResourceUtil.getParent(scriptHelper.getScript().getScriptResource().getPath());
// check if parent resides on search path
for (String sp: rr.getSearchPath()) {
if (parentPath.startsWith(sp)) {
parentPath = parentPath.substring(sp.length());
break;
}
}
scriptPath = parentPath + "/" + script;
} else {
scriptPath = this.script;
}
servlet = servletResolver.resolveServlet(rr, scriptPath);
if (servlet != null) {
servletName = RequestUtil.getServletName(servlet);
tracker.log("Including script {0} (ignoring component hierarchy): {1}", script, servletName);
}
}
if (servlet == null) {
throw new JspException("Could not find script " + script);
}
try {
if (flush && !(pageContext.getOut() instanceof BodyContent)) {
// might throw an IOException of course
pageContext.getOut().flush();
}
// wrap the response to get the correct output order
SlingHttpServletResponse response = new JspSlingHttpServletResponseWrapper(
pageContext);
tracker.startTimer(servletName);
servlet.service(pageContext.getRequest(), response);
tracker.logTimer(servletName);
return EVAL_PAGE;
} catch (Exception e) {
log.error("Error while executing script " + script, e);
throw new JspException("Error while executing script " + script, e);
}
}
/**
* Includes the rendering of a resource or path set by the respective
* tag attribute.
* This method is essentially the same as the doEndTag implementation of
* (a previous version of) the Sling taglib include tag.
*
* @return
* @throws JspException
*/
private int includeResource() throws JspException {
RequestDispatcherOptions opts = new RequestDispatcherOptions();
SlingHttpServletRequest request = TagUtil.getRequest(pageContext);
Resource resource = request.getResource();
if (!path.startsWith("/")) {
path = resource.getPath() + "/" + path;
}
path = ResourceUtil.normalize(path);
// take the type from one of the attributes that we have set
// to use it later
String type = defaultResourceType != null ? defaultResourceType: resourceType;
// normalize the resource type
if (type.startsWith("./") || type.startsWith("../")) {
// use relative resource type
type = ResourceUtil.normalize(resource.getResourceType() + "/" + type);
}
// check whether the path (would) resolve, else SyntheticRes.
resource = request.getResourceResolver().resolve(path);
if (resource instanceof NonExistingResource) {
// create the resource with the type that we declared
// (either defaultResourceType or resourceType)
resource = new SyntheticResource(
request.getResourceResolver(), path, type);
} else {
// the resource may be in the repository
// but without a resource type
// (this can happen with nested cq:includes)
ValueMap resourceProps = resource.adaptTo(ValueMap.class);
String actualResourceType = resourceProps != null ?
resourceProps.get("sling:resourceType",""):
"";
if (resourceType != null || StringUtils.isEmpty(actualResourceType)) {
// if we have the resourceType attribute than we force that resource type
// otherwise we don't do anything
opts.setForceResourceType(type);
}
}
try {
// optionally flush
if (flush && !(pageContext.getOut() instanceof BodyContent)) {
// might throw an IOException of course
pageContext.getOut().flush();
}
// create a dispatcher for the resource or path
RequestDispatcher dispatcher = request.getRequestDispatcher(resource, opts);
if (dispatcher != null) {
SlingHttpServletResponse response = new JspSlingHttpServletResponseWrapper(
pageContext);
dispatcher.include(request, response);
} else {
TagUtil.log(log, pageContext, "No content to include...", null);
}
} catch (IOException ioe) {
throw new JspException("Error including " + path, ioe);
} catch (ServletException ce) {
throw new JspException("Error including " + path,
TagUtil.getRootCause(ce));
}
return EVAL_PAGE;
}
/**
* {@inheritDoc}
*/
public void setPageContext(PageContext pageContext) {
super.setPageContext(pageContext);
resourceType = null;
path = null;
script = null;
flush = false;
}
/**
* Sets the defaultResourceType attribute
* @param type attribute value
*/
public void setDefaultResourceType(String type) {
this.defaultResourceType = StringUtils.isNotEmpty(type) ? type : null;
}
/**
* Sets the resource type attribute
* @param resourceType attribute value
*/
public void setResourceType(String resourceType) {
this.resourceType = StringUtils.isNotEmpty(resourceType) ? resourceType : null;
}
/**
* Sets the path attribute
* @param path attribute value
*/
public void setPath(String path) {
this.path = path;
}
/**
* Sets the script attribute
* @param script attribute value
*/
public void setScript(String script) {
this.script = script;
}
/**
* Sets the flush attribute
* @param flush attribute value
*/
public void setFlush(boolean flush) {
this.flush = flush;
}
/**
* Set the ignore component hierarchy attribute
* @param ignoreComponentHierarchy attribute value
*/
public void setIgnoreComponentHierarchy(boolean ignoreComponentHierarchy) {
this.ignoreComponentHierarchy = ignoreComponentHierarchy;
}
}