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

com.day.cq.wcm.tags.IncludeTag Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*
 * 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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy