io.wcm.handler.url.impl.UrlHandlerImpl.java Source code

Java tutorial

Introduction

Here is the source code for io.wcm.handler.url.impl.UrlHandlerImpl.java

Source

/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2014 wcm.io
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package io.wcm.handler.url.impl;

import io.wcm.handler.url.UrlBuilder;
import io.wcm.handler.url.UrlHandler;
import io.wcm.handler.url.UrlMode;
import io.wcm.handler.url.spi.UrlHandlerConfig;
import io.wcm.sling.commons.request.RequestParam;
import io.wcm.sling.models.annotations.AemObject;

import java.util.Set;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.adapter.Adaptable;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.apache.sling.models.annotations.injectorspecific.SlingObject;
import org.apache.sling.settings.SlingSettingsService;

import com.day.cq.wcm.api.Page;

/**
 * Default implementation of a {@link UrlHandler}
 */
@Model(adaptables = { SlingHttpServletRequest.class, Resource.class }, adapters = UrlHandler.class)
public final class UrlHandlerImpl implements UrlHandler {

    @Self
    private Adaptable self;
    @Self
    private UrlHandlerConfig urlHandlerConfig;
    @SlingObject
    private ResourceResolver resolver;
    @OSGiService
    private SlingSettingsService slingSettings;

    // optional injections (only available if called inside a request)
    @SlingObject(optional = true)
    private SlingHttpServletRequest request;
    @AemObject(optional = true)
    private Page currentPage;

    @Override
    public UrlBuilder get(String path) {
        return new UrlBuilderImpl(path, this);
    }

    @Override
    public UrlBuilder get(Resource resource) {
        return new UrlBuilderImpl(resource, this);
    }

    @Override
    public UrlBuilder get(Page page) {
        return new UrlBuilderImpl(page, this);
    }

    @Override
    public String rewritePathToContext(final String path) {
        if (currentPage != null) {
            return rewritePathToContext(path, currentPage.getPath());
        } else {
            return path;
        }
    }

    @Override
    public String rewritePathToContext(final String path, final String contextPath) {
        if (StringUtils.isEmpty(path) || StringUtils.isEmpty(contextPath)) {
            return path;
        }

        // split up paths
        String[] contextPathParts = StringUtils.split(contextPath, "/");
        String[] pathParts = StringUtils.split(path, "/");

        // check if both paths are valid - return unchanged path if not
        int siteRootLevelContextPath = urlHandlerConfig.getSiteRootLevel(contextPath);
        int siteRootLevelPath = urlHandlerConfig.getSiteRootLevel(path);
        if ((contextPathParts.length <= siteRootLevelContextPath) || (pathParts.length <= siteRootLevelPath)
                || !StringUtils.equals(contextPathParts[0], "content")
                || !StringUtils.equals(pathParts[0], "content")) {
            return path;
        }

        // rewrite path to current context
        StringBuilder rewrittenPath = new StringBuilder();
        for (int i = 0; i <= siteRootLevelContextPath; i++) {
            rewrittenPath.append('/').append(contextPathParts[i]);
        }
        for (int i = siteRootLevelPath + 1; i < pathParts.length; i++) {
            rewrittenPath.append('/').append(pathParts[i]);
        }
        return rewrittenPath.toString();
    }

    String externalizeLinkUrl(final String url, final Page targetPage, final UrlMode urlMode) {

        // check for empty url
        if (StringUtils.isEmpty(url)) {
            return null;
        }

        // do not externalize urls again that are already externalized
        if (Externalizer.isExternalized(url)) {
            return url;
        }

        // apply sling mapping, namespace mangling and add webapp context path if required
        String externalizedUrl = Externalizer.externalizeUrl(url, resolver, request);

        // add link URL prefix (scheme/hostname or integrator placeholder) if required
        String linkUrlPrefix = getLinkUrlPrefix(urlMode, targetPage);
        externalizedUrl = StringUtils.defaultString(linkUrlPrefix) + externalizedUrl; //NOPMD

        return externalizedUrl;
    }

    private String getLinkUrlPrefix(UrlMode urlMode, Page targetPage) {
        UrlMode mode = ObjectUtils.defaultIfNull(urlMode, urlHandlerConfig.getDefaultUrlMode());
        return mode.getLinkUrlPrefix(self, slingSettings.getRunModes(), currentPage, targetPage);
    }

    String externalizeResourceUrl(final String url, final Resource targetResource, final UrlMode urlMode) {

        // check for empty path
        if (StringUtils.isEmpty(url)) {
            return null;
        }

        // do not externalize urls again that are already externalized
        if (Externalizer.isExternalized(url)) {
            return url;
        }

        // try to resolve the target resource from url/path if it was not given initially (only below /content)
        Resource resource = targetResource;
        if (resource == null && StringUtils.startsWith(url, "/content/")) {
            resource = resolver.resolve(url); // accept NonExistingResource as well
        }

        // apply sling mapping when externalizing URLs
        String externalizedUrl = Externalizer.externalizeUrl(url, resolver, request);

        // add resource URL prefix (scheme/hostname or integrator placeholder) if required
        String resourceUrlPrefix = getResourceUrlPrefix(urlMode, resource);
        externalizedUrl = StringUtils.defaultString(resourceUrlPrefix) + externalizedUrl; //NOPMD

        return externalizedUrl;
    }

    private String getResourceUrlPrefix(UrlMode urlMode, Resource targetResource) {
        UrlMode mode = ObjectUtils.defaultIfNull(urlMode, urlHandlerConfig.getDefaultUrlMode());
        return mode.getResourceUrlPrefix(self, slingSettings.getRunModes(), currentPage, targetResource);
    }

    String buildUrl(String path, String selector, String extension, String suffix) { //NOPMD
        if (StringUtils.isBlank(path)) {
            return null;
        }

        // Extension url part
        StringBuilder extensionPart = new StringBuilder();
        if (StringUtils.isNotBlank(extension)) {
            extensionPart.append('.').append(extension);
        }

        // Selector url part
        StringBuilder selectorPart = new StringBuilder();
        if (StringUtils.isNotBlank(selector)) {
            // prepend delimiter to selector if required
            if (!StringUtils.startsWith(selector, ".")) {
                selectorPart.append('.');
            }
            selectorPart.append(selector);
        }

        // Suffix part
        StringBuilder suffixPart = new StringBuilder();
        if (StringUtils.isNotBlank(suffix)) {
            // prepend delimiter to suffix if required and add extension
            if (!StringUtils.startsWith(suffix, "/")) {
                suffixPart = suffixPart.append("/");
            }
            suffixPart.append(suffix);

            // if suffix does not contain a file extension add main file extension
            if (!StringUtils.contains(suffix, ".")) {
                suffixPart.append(extensionPart);
            }

            // add a ".suffix" selector to avoid overlapping of filenames between suffixed and non-suffixed versions of the same page in the dispatcher cache
            selectorPart.append('.').append(UrlHandler.SELECTOR_SUFFIX);
        }

        // build externalized url
        return path + selectorPart.toString() + extensionPart.toString() + suffixPart.toString();
    }

    String appendQueryString(String url, String queryString, Set<String> inheritableParameterNames) {
        if (StringUtils.isEmpty(url)) {
            return url;
        }

        // split url from existing query parameters
        StringBuilder urlBuilder = new StringBuilder();
        StringBuilder queryParams = new StringBuilder();
        int separatorPos = url.indexOf('?');
        if (separatorPos >= 0) {
            queryParams.append(url.substring(separatorPos + 1));
            urlBuilder.append(url.substring(0, separatorPos));
        } else {
            urlBuilder.append(url);
        }

        // append new query parameters
        if (StringUtils.isNotBlank(queryString)) {
            if (queryParams.length() > 0) {
                queryParams.append('&');
            }
            queryParams.append(queryString);
        }

        // inherit query parameters from current request (only if the parameter is not already included in the params list)
        if (inheritableParameterNames != null && request != null) {
            for (String parameterName : inheritableParameterNames) {
                if (queryParams.indexOf(parameterName + "=") == -1) {
                    String[] values = RequestParam.getMultiple(request, parameterName);
                    if (values != null) {
                        for (String value : values) {
                            if (StringUtils.isNotEmpty(value)) {
                                if (queryParams.length() > 0) {
                                    queryParams.append('&');
                                }
                                queryParams.append(parameterName);
                                queryParams.append('=');
                                queryParams.append(value);
                            }
                        }
                    }
                }
            }
        }

        // build complete url
        if (queryParams.length() > 0) {
            urlBuilder.append('?');
            urlBuilder.append(queryParams);
        }
        return urlBuilder.toString();
    }

    String setFragment(String url, String fragment) {
        if (StringUtils.isEmpty(url)) {
            return url;
        }

        // strip off anchor if already present
        StringBuilder urlBuilder;
        int index = url.indexOf('#');
        if (index >= 0) {
            urlBuilder = new StringBuilder(url.substring(0, index));
        } else {
            urlBuilder = new StringBuilder(url);
        }

        // prepend "#" for anchor if not present
        if (StringUtils.isNotBlank(fragment)) {
            if (!StringUtils.startsWith(fragment, "#")) {
                urlBuilder.append('#');
            }
            urlBuilder.append(fragment);
        }

        return urlBuilder.toString();
    }

}