io.wcm.handler.url.suffix.SuffixParser.java Source code

Java tutorial

Introduction

Here is the source code for io.wcm.handler.url.suffix.SuffixParser.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.suffix;

import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.KEY_VALUE_DELIMITER;
import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeKey;
import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeResourcePathPart;
import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.decodeValue;
import static io.wcm.handler.url.suffix.impl.UrlSuffixUtil.splitSuffix;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.osgi.annotation.versioning.ProviderType;

import com.day.cq.commons.Filter;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;

/**
 * Parses suffixes from Sling URLs build with {@link SuffixBuilder}.
 */
@ProviderType
public final class SuffixParser {

    private final SlingHttpServletRequest request;

    /**
     * Create a {@link SuffixParser} with the default {@link SuffixStateKeepingStrategy} (which discards all existing
     * suffix state when constructing a new suffix)
     * @param request Sling request
     */
    public SuffixParser(SlingHttpServletRequest request) {
        this.request = request;
    }

    /**
     * Create a {@link SuffixParser} that keeps only the suffix parts matched by the given filter when constructing
     * a new suffix
     * @param request Sling request
     * @param suffixPartFilter the filter that is called for each suffix part
     */
    public SuffixParser(SlingHttpServletRequest request, Filter<String> suffixPartFilter) {
        this.request = request;
    }

    /**
     * Extract the value of a named suffix part from this request's suffix
     * @param key key of the suffix part
     * @param clazz Type expected for return value.
     *          Only String, Boolean, Integer, Long are supported.
     * @param <T> Parameter type.
     * @return the value of that named parameter (or the default value if not used)
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key, Class<T> clazz) {
        if (clazz == String.class) {
            return (T) getString(key, (String) null);
        }
        if (clazz == Boolean.class) {
            return (T) (Boolean) getBoolean(key, false);
        }
        if (clazz == Integer.class) {
            return (T) (Integer) getInt(key, 0);
        }
        if (clazz == Long.class) {
            return (T) (Long) getLong(key, 0L);
        }
        throw new IllegalArgumentException("Unsupported type: " + clazz.getName());
    }

    /**
     * Extract the value of a named suffix part from this request's suffix
     * @param key key of the suffix part
     * @param defaultValue the default value to return if suffix part not set.
     *          Only String, Boolean, Integer, Long are supported.
     * @param <T> Parameter type.
     * @return the value of that named parameter (or the default value if not used)
     */
    @SuppressWarnings("unchecked")
    public <T> T get(String key, T defaultValue) {
        if (defaultValue instanceof String || defaultValue == null) {
            return (T) getString(key, (String) defaultValue);
        }
        if (defaultValue instanceof Boolean) {
            return (T) (Boolean) getBoolean(key, (Boolean) defaultValue);
        }
        if (defaultValue instanceof Integer) {
            return (T) (Integer) getInt(key, (Integer) defaultValue);
        }
        if (defaultValue instanceof Long) {
            return (T) (Long) getLong(key, (Long) defaultValue);
        }
        throw new IllegalArgumentException("Unsupported type: " + defaultValue.getClass().getName());
    }

    private String getString(String key, String defaultValue) {
        String value = findSuffixPartByKey(key);
        if (value == null) {
            return defaultValue;
        }
        return value;
    }

    private boolean getBoolean(String key, boolean defaultValue) {
        String value = findSuffixPartByKey(key);
        if (value == null) {
            return defaultValue;
        }

        // value must match exactly "true" or "false"
        if ("true".equals(value)) {
            return true;
        }
        if ("false".equals(value)) {
            return false;
        }

        // invalid boolean value - return default
        return defaultValue;
    }

    private int getInt(String key, int defaultValue) {
        String value = findSuffixPartByKey(key);
        if (value == null) {
            return defaultValue;
        }
        return NumberUtils.toInt(value, defaultValue);
    }

    private long getLong(String key, long defaultValue) {
        String value = findSuffixPartByKey(key);
        if (value == null) {
            return defaultValue;
        }
        return NumberUtils.toLong(value, defaultValue);
    }

    /**
     * Extract the value of a named suffix part from this request's suffix
     * @param key key of the suffix part
     * @return the value of that named parameter (or null if not used)
     */
    private String findSuffixPartByKey(String key) {
        for (String part : splitSuffix(request.getRequestPathInfo().getSuffix())) {
            if (part.indexOf(KEY_VALUE_DELIMITER) >= 0) {
                String partKey = decodeKey(part);
                if (partKey.equals(key)) {
                    String value = decodeValue(part);
                    return value;
                }
            }
        }
        return null;
    }

    /**
     * Get a resource within the current page by interpreting the suffix as a JCR path relative to this page's jcr:content
     * node
     * @return the Resource or null if no such resource exists
     */
    public Resource getResource() {
        return getResource((Filter<Resource>) null, (Resource) null);
    }

    /**
     * Parse the suffix as resource paths and return the first resource that exists
     * @param baseResource the suffix path is relative to this resource path (null for current page's jcr:content node)
     * @return the resource or null if no such resource was selected by suffix
     */
    public Resource getResource(Resource baseResource) {
        return getResource((Filter<Resource>) null, baseResource);
    }

    /**
     * Parse the suffix as resource paths, return the first resource from the suffix (relativ to the current page's
     * content) that matches the given filter.
     * @param filter a filter that selects only the resource you're interested in.
     * @return the resource or null if no such resource was selected by suffix
     */
    public Resource getResource(Filter<Resource> filter) {
        return getResource(filter, (Resource) null);
    }

    /**
     * Get the first item returned by {@link #getResources(Filter, Resource)} or null if list is empty
     * @param filter the resource filter
     * @param baseResource the suffix path is relative to this resource path (null for current page's jcr:content node)
     * @return the first {@link Resource} or null
     */
    public Resource getResource(Filter<Resource> filter, Resource baseResource) {
        List<Resource> suffixResources = getResources(filter, baseResource);
        if (suffixResources.isEmpty()) {
            return null;
        } else {
            return suffixResources.get(0);
        }
    }

    /**
     * Get the resources within the current page selected in the suffix of the URL
     * @return a list containing the Resources
     */
    public List<Resource> getResources() {
        return getResources((Filter<Resource>) null, (Resource) null);
    }

    /**
     * Get the resources selected in the suffix of the URL
     * @param baseResource the suffix path is relative to this resource path (null for current page's jcr:content node)
     * @return a list containing the Resources
     */
    public List<Resource> getResources(Resource baseResource) {
        return getResources((Filter<Resource>) null, baseResource);
    }

    /**
     * Get the resources selected in the suffix of the URL
     * @param filter optional filter to select only specific resources
     * @return a list containing the Resources
     */
    public List<Resource> getResources(Filter<Resource> filter) {
        return getResources(filter, (Resource) null);
    }

    /**
     * Get the resources selected in the suffix of the URL
     * @param filter optional filter to select only specific resources
     * @param baseResource the suffix path is relative to this resource path (null for current page's jcr:content node)
     * @return a list containing the Resources
     */
    public List<Resource> getResources(Filter<Resource> filter, Resource baseResource) {

        // resolve base path or fallback to current page's content if not specified
        Resource baseResourceToUse = baseResource;
        if (baseResourceToUse == null) {
            PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
            Page currentPage = pageManager.getContainingPage(request.getResource());
            if (currentPage != null) {
                baseResourceToUse = currentPage.getContentResource();
            } else {
                baseResourceToUse = request.getResource();
            }
        }

        // split the suffix to extract the paths of the selected components
        String[] suffixParts = splitSuffix(request.getRequestPathInfo().getSuffix());

        // iterate over all parts and gather those resources
        List<Resource> selectedResources = new ArrayList<>();
        for (String path : suffixParts) {

            // if path contains the key/value-delimiter then don't try to resolve it as a content path
            if (StringUtils.contains(path, KEY_VALUE_DELIMITER)) {
                continue;
            }

            String decodedPath = decodeResourcePathPart(path);

            // lookup the resource specified by the path (which is relative to the current page's content resource)
            Resource resource = request.getResourceResolver().getResource(baseResourceToUse, decodedPath);
            if (resource == null) {
                // no resource found with given path, continue with next path in suffix
                continue;
            }

            // if a filter is given - check
            if (filter == null || filter.includes(resource)) {
                selectedResources.add(resource);
            }

        }

        return selectedResources;
    }

}