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

com.atlassian.plugin.clientsideextensions.ExtensionPageServlet Maven / Gradle / Ivy

The newest version!
package com.atlassian.plugin.clientsideextensions;

import com.atlassian.annotations.VisibleForTesting;
import com.atlassian.sal.api.message.I18nResolver;
import com.atlassian.soy.renderer.SoyException;
import com.atlassian.soy.renderer.SoyTemplateRenderer;
import com.google.common.collect.ImmutableMap;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.isBlank;

/**
 * Servlet that bootstraps the Client-side Extension based on provided extension-point and extension-key
 */
public class ExtensionPageServlet extends HttpServlet {

    @VisibleForTesting
    static final String CONTENT_TYPE = "text/html;charset=UTF-8";

    // ----- ServletConfig keys

    public static final String EXTENSION_KEY_PARAM_NAME = "extension-key";

    public static final String EXTENSION_POINT_PARAM_NAME = "extension-point";

    public static final String PAGE_DATA_PROVIDER_KEY_PARAM_NAME = "page-data-provider-key";

    public static final String PAGE_DECORATOR_PARAM_NAME = "page-decorator";

    public static final String PAGE_TITLE_PARAM_NAME = "page-title";

    public static final String PAGE_TITLE_KEY_PARAM_NAME = "page-title-key";

    public static final String WEB_RESOURCE_KEYS_PARAM_NAME = "web-resources";

    public static final String  WEB_RESOURCE_KEYS_SEPARATOR = ",";

    // ----- ServletConfig defaults

    // https://developer.atlassian.com/server/framework/atlassian-sdk/using-standard-page-decorators
    @VisibleForTesting
    static final String DEFAULT_PAGE_DECORATOR = "atl.general";

    @VisibleForTesting
    static final String DEFAULT_PAGE_TITLE = "";

    // ----- Soy template coordinates

    @VisibleForTesting
    static final String RESOURCE_KEY = "com.atlassian.plugins.atlassian-clientside-extensions-page-bootstrapper:server-soy-templates";

    @VisibleForTesting
    static final String TEMPLATE_KEY = "CSE.Templates.page";

    // ----- Soy template model keys

    @VisibleForTesting
    static final String MODEL_KEY_EXTENSION_POINT = "extensionPoint";

    @VisibleForTesting
    static final String MODEL_KEY_EXTENSION_KEY = "extensionKey";

    @VisibleForTesting
    static final String MODEL_KEY_PAGE_DATA_PROVIDER_KEY = "pageDataProviderKey";

    @VisibleForTesting
    static final String MODEL_KEY_PAGE_DECORATOR = "pageDecorator";

    @VisibleForTesting
    static final String MODEL_KEY_PAGE_TITLE = "pageTitle";

    @VisibleForTesting
    static final String MODEL_KEY_PATH = "path";

    @VisibleForTesting
    static final String MODEL_KEY_WEB_RESOURCE_KEYS = "webResourceKeys";

    private final I18nResolver i18nResolver;
    private final SoyTemplateRenderer soyTemplateRenderer;

    private String extensionPoint;
    private String extensionKey;
    private String pageDecorator;
    private String pageTitle;
    private String pageDataProviderKey;
    private String pageTitleKey;

    /**
     * Comma separated list of web-resource keys
     */
    private String webResourceKeys;

    public ExtensionPageServlet(final I18nResolver i18nResolver, final SoyTemplateRenderer soyTemplateRenderer) {
        this.i18nResolver = requireNonNull(i18nResolver);
        this.soyTemplateRenderer = requireNonNull(soyTemplateRenderer);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        extensionPoint = getRequiredInitParam(EXTENSION_POINT_PARAM_NAME, config);
        extensionKey = getRequiredInitParam(EXTENSION_KEY_PARAM_NAME, config);
        webResourceKeys = getRequiredInitParam(WEB_RESOURCE_KEYS_PARAM_NAME, config);
        pageDataProviderKey = getOptionalInitParam(PAGE_DATA_PROVIDER_KEY_PARAM_NAME, config, null);
        pageDecorator = getOptionalInitParam(PAGE_DECORATOR_PARAM_NAME, config, DEFAULT_PAGE_DECORATOR);
        pageTitle = getOptionalInitParam(PAGE_TITLE_PARAM_NAME, config, DEFAULT_PAGE_TITLE);
        pageTitleKey = getOptionalInitParam(PAGE_TITLE_KEY_PARAM_NAME, config, null);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        final ImmutableMap.Builder params = ImmutableMap.builder();

        final String path = req.getPathInfo();
        if (path != null) {
            params.put(MODEL_KEY_PATH, path);
        }

        params
            .put(MODEL_KEY_PAGE_TITLE, getPageTitle())
            .put(MODEL_KEY_PAGE_DECORATOR, pageDecorator)
            .put(MODEL_KEY_EXTENSION_POINT, extensionPoint)
            .put(MODEL_KEY_EXTENSION_KEY, extensionKey)
            .put(MODEL_KEY_WEB_RESOURCE_KEYS, getWebResourceKeys());

        if (pageDataProviderKey != null) {
            params.put(MODEL_KEY_PAGE_DATA_PROVIDER_KEY, pageDataProviderKey);
        }

        render(resp, params.build());
    }

    private String getPageTitle() {
        //noinspection ConstantConditions
        return Optional.ofNullable(pageTitleKey)
            .map(i18nResolver::getText)
            .filter(Objects::nonNull)
            .filter(text -> !text.equals(pageTitleKey)) // i.e. a translation was found
            .orElse(pageTitle);
    }

    private List getWebResourceKeys() {
        return Arrays.stream(webResourceKeys.split(WEB_RESOURCE_KEYS_SEPARATOR))
            .map(String::trim)
            .collect(toList());
    }

    private void render(ServletResponse resp, Map data) throws IOException, ServletException {
        resp.setContentType(CONTENT_TYPE);

        try {
            soyTemplateRenderer.render(resp.getWriter(), RESOURCE_KEY, TEMPLATE_KEY, data);
        } catch (SoyException e) {
            Throwable cause = e.getCause();
            if (cause instanceof IOException) {
                throw (IOException) cause;
            }
            throw new ServletException(e);
        }
    }

    private static String getRequiredInitParam(final String key, final ServletConfig config) throws UnavailableException {
        final String paramValue = config.getInitParameter(key);
        if (isBlank(paramValue)) {
            throw new UnavailableException("The required '" + key + "' init-param is missing or undefined");
        }
        return paramValue;
    }

    private static String getOptionalInitParam(final String key, final ServletConfig config, final String defaultValue) {
        return defaultIfEmpty(config.getInitParameter(key), defaultValue);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy