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

com.adobe.granite.ui.components.htl.ComponentHelper Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2016 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.granite.ui.components.htl;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.script.Bindings;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.apache.sling.api.wrappers.SlingHttpServletResponseWrapper;
import org.apache.sling.scripting.sightly.pojo.Use;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.granite.ui.components.AttrBuilder;
import com.adobe.granite.ui.components.Options;
import com.adobe.granite.ui.components.impl.BaseComponentHelper;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.i18n.I18n;

/**
 * A convenient base Use class for development of Granite UI components that are
 * implemented using HTL.
 */
public abstract class ComponentHelper implements Use {
    private static final Logger LOG = LoggerFactory.getLogger(ComponentHelper.class);

    private BaseComponentHelper base;
    private StringWriter writer;
    private SlingBindings slingBindings = new SlingBindings();
    private Resource resource;
    private ResourceResolver resourceResolver;
    private AttrBuilder attrs;

    /**
     * Initialize bindings and calls #activate()
     *
     * @param scriptBindings
     *            Bindings to be used, there is no guarantee of having any
     *            particular bindings available.
     */
    @Override
    public final void init(Bindings scriptBindings) {
        slingBindings.putAll(scriptBindings);
        writer = new StringWriter();

        SlingScriptHelper sling = slingBindings.getSling();

        if (sling == null) {
            throw new RuntimeException("SlingScriptHelper is not available");
        }

        SlingHttpServletRequest request = slingBindings.getRequest();

        if (request == null) {
            throw new RuntimeException("SlingHttpServletRequest is not available");
        }

        base = new BaseComponentHelper(sling, request,
                new PrintWriterResponseWrapper(new PrintWriter(writer), slingBindings.getResponse()));
        try {
            activate();
        } catch (Exception e) {
            LOG.error("Failed to activate Use class", e);
        }
    }

    /**
     * Dependency Injection setter for inject the SlingBindings A subclass has the
     * possibility to override the used SlingBindings
     *
     * @param slingBindings
     *            SlingBindings to be used.
     */
    protected final void setSlingBindings(@Nonnull SlingBindings slingBindings) {
        this.slingBindings = slingBindings;
    }

    /**
     * Dependency Injection setter for inject the BaseComponentHelper A subclass has
     * the possibility to override the used BaseComponentHelper
     *
     * @param baseHelper
     *            BaseComponentHelper to be used.
     */
    protected final void setBaseComponentHelper(@Nonnull BaseComponentHelper baseHelper) {
        this.base = baseHelper;
    }

    private class PrintWriterResponseWrapper extends SlingHttpServletResponseWrapper {

        private final PrintWriter writer;

        /**
         * Create a wrapper for the supplied wrappedRequest
         *
         * @param writer
         *            - the base writer
         * @param wrappedResponse
         *            - the wrapped response
         */
        public PrintWriterResponseWrapper(@Nonnull PrintWriter writer, SlingHttpServletResponse wrappedResponse) {
            super(wrappedResponse);
            this.writer = writer;
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return writer;
        }
    }

    /**
     * Implement this method to perform post initialization tasks. This is called
     * from the {@link ComponentHelper#init(Bindings)}.
     *
     * @throws Exception
     *             in case of any error during activation
     */
    protected abstract void activate() throws Exception;

    /**
     * Get an object associated with the given name.
     *
     * @param name
     *            Object property name
     * @param type
     *            Expected object type
     * @param 
     *            The type of the object
     *
     * @return Object or {@code null} if Object cannot be found or typed.
     */
    @CheckForNull
    protected final  T get(String name, Class type) {
        Object obj = slingBindings.get(name);
        try {
            return type.cast(obj);
        } catch (ClassCastException e) {
            LOG.error("Failed to cast value", e);
        }
        return null;
    }

    /**
     * Gets the current {@link SlingHttpServletRequest}.
     *
     * @return The current {@link SlingHttpServletRequest}
     */
    @Nonnull
    protected final SlingHttpServletRequest getRequest() {
        return base.getRequest();
    }

    /**
     * Gets the current {@link Resource}
     *
     * @return The current {@link Resource}
     */
    @SuppressWarnings("null")
    @Nonnull
    protected final Resource getResource() {
        if (resource == null) {
            resource = slingBindings.getResource();
        }
        return resource;
    }

    /**
     * Gets the current request's {@link ResourceResolver}.
     *
     * @return The current request's {@link ResourceResolver}
     */
    @SuppressWarnings("null")
    @Nonnull
    protected final ResourceResolver getResourceResolver() {
        if (resourceResolver == null) {
            resourceResolver = getRequest().getResourceResolver();
        }
        return resourceResolver;
    }

    /**
     * Gets the options passed by the calling component.
     *
     * @return The {@link Options} passed by the calling component
     */
    @Nonnull
    protected final Options getOptions() {
        return base.getOptions();
    }

    /**
     * Gets an {@link I18n} helper for the current request.
     *
     * @return The {@link I18n} helper for the current request
     */
    @Nonnull
    protected final I18n getI18n() {
        return base.getI18n();
    }

    /**
     * Gets a {@link XSSAPI} helper.
     *
     * @return The {@link XSSAPI} helper
     */
    @Nonnull
    protected final XSSAPI getXss() {
        return base.getXss();
    }

    /**
     * Gets the attributes passed by the calling component
     *
     * @return The {@link AttrBuilder} with inherited attributes
     */
    @SuppressWarnings("null")
    @Nonnull
    protected final AttrBuilder getInheritedAttrs() {
        if (attrs == null) {
            attrs = base.consumeTag().getAttrs();
        }
        if (attrs == null) {
            attrs = new AttrBuilder(getRequest(), base.getXss());
        }
        return attrs;
    }

    /**
     * Includes the given resource with the given resourceType and passes the given
     * options to its renderer. This method performs similarly to <sling:include
     * resource="" replaceSelectors="" resourceType="" />.
     *
     * @param resource
     *            the resource to include
     * @param resourceType
     *            the resource type
     * @param selectors
     *            the selectors to be included as part of the request.
     * @param options
     *            the options
     * @return Output from included resource
     * @throws ServletException
     *             in case there's a servlet error
     * @throws IOException
     *             in case there's an i/o error
     */
    @SuppressWarnings("null")
    @Nonnull
    protected String include(@Nonnull Resource resource, @CheckForNull String resourceType,
            @CheckForNull String selectors, @Nonnull Options options) throws ServletException, IOException {
        base.include(resource, resourceType, selectors, options);
        return writer.toString();
    }

    /**
     * Calls the given script and passes the given options to its renderer. This
     * method performs similarly to <sling:call script="" />.
     *
     * @param script
     *            the script to be called
     * @param options
     *            the options
     * @return Output from included script
     * @throws ServletException
     *             in case there's a servlet error
     * @throws IOException
     *             in case there's an i/o error
     */
    @SuppressWarnings("null")
    @Nonnull
    protected String call(@Nonnull String script, @Nonnull Options options) throws ServletException, IOException {
        base.call(script, options);
        return writer.toString();
    }

    /**
     * Populates the common attributes to the given {@link AttrBuilder}.
     *
     * @param attrs
     *            the attribute builder
     */
    protected void populateCommonAttrs(@Nonnull AttrBuilder attrs) {
        base.populateCommonAttrs(attrs);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy