org.apache.sling.resourcemerger.impl.MergedResourceProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.sling.resourcemerger.impl.MergedResourceProvider.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */
package org.apache.sling.resourcemerger.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;

/**
 * The <code>MergedResourceProvider</code> is the resource provider providing
 * access to {@link MergedResource} objects.
 */
public class MergedResourceProvider implements ResourceProvider {

    private final String mergeRootPath;

    public MergedResourceProvider(String mergeRootPath) {
        this.mergeRootPath = mergeRootPath;
    }

    /**
     * {@inheritDoc}
     */
    public Resource getResource(ResourceResolver resolver, HttpServletRequest request, String path) {
        return getResource(resolver, path);
    }

    /**
     * {@inheritDoc}
     */
    public Resource getResource(ResourceResolver resolver, String path) {
        List<String> mappedResources = new ArrayList<String>();

        if (resolver.getSearchPath() != null) {
            String relativePath = getRelativePath(path);

            // Loop over provided base paths
            for (String basePath : resolver.getSearchPath()) {
                // Try to get the corresponding physical resource for this base path
                Resource baseRes = resolver.getResource(ResourceUtil.normalize(basePath + "/" + relativePath));
                if (baseRes != null) {
                    // Physical resource exists, add it to the list of mapped resources
                    mappedResources.add(0, baseRes.getPath());
                }
            }

            if (!mappedResources.isEmpty()) {
                // Create a new merged resource based on the list of mapped physical resources
                return new MergedResource(resolver, mergeRootPath, relativePath, mappedResources);
            }
        }

        // Either base paths were not defined, or the resource does not exist in any of them
        return null;
    }

    /**
     * {@inheritDoc}
     */
    public Iterator<Resource> listChildren(Resource resource) {
        if (resource instanceof MergedResource) {
            MergedResource mergedResource = (MergedResource) resource;
            ResourceResolver resolver = mergedResource.getResourceResolver();
            List<Resource> children = new ArrayList<Resource>();

            for (String mappedResourcePath : mergedResource.getMappedResources()) {
                Resource mappedResource = resolver.getResource(mappedResourcePath);

                // Check if the resource exists
                if (mappedResource == null) {
                    continue;
                }

                // Check if some previously defined children have to be ignored
                ValueMap mappedResourceProps = mappedResource.adaptTo(ValueMap.class);
                List<String> childrenToHide = Arrays
                        .asList(mappedResourceProps.get(MergedResourceConstants.PN_HIDE_CHILDREN, new String[0]));
                if (childrenToHide.isEmpty()) {
                    String childToHide = mappedResourceProps.get(MergedResourceConstants.PN_HIDE_CHILDREN,
                            String.class);
                    if (childToHide != null) {
                        childrenToHide.add(childToHide);
                    }
                }
                if (childrenToHide.contains("*")) {
                    // Clear current children list
                    children.clear();
                } else {
                    // Go through current children in order to hide them individually
                    Iterator<Resource> it = children.iterator();
                    while (it.hasNext()) {
                        if (childrenToHide.contains(it.next().getName())) {
                            it.remove();
                        }
                    }
                }

                // Browse children of current physical resource
                for (Resource child : mappedResource.getChildren()) {
                    String childRelativePath = ResourceUtil
                            .normalize(mergedResource.getRelativePath() + "/" + child.getName());

                    if (child.adaptTo(ValueMap.class).get(MergedResourceConstants.PN_HIDE_RESOURCE,
                            Boolean.FALSE)) {
                        // Child resource has to be hidden
                        children.remove(new MergedResource(resolver, mergeRootPath, childRelativePath));

                    } else {
                        // Check if the child resource already exists in the children list
                        MergedResource mergedResChild = new MergedResource(resolver, mergeRootPath,
                                childRelativePath);
                        int mergedResChildIndex = -1;
                        if (children.contains(mergedResChild)) {
                            // Get current index of the merged resource's child
                            mergedResChildIndex = children.indexOf(mergedResChild);
                            mergedResChild = (MergedResource) children.get(mergedResChildIndex);
                        }
                        // Add a new mapped resource to the merged resource
                        mergedResChild.addMappedResource(child.getPath());
                        boolean mergedResChildExists = mergedResChildIndex > -1;

                        // Check if children need reordering
                        int orderBeforeIndex = -1;
                        String orderBefore = ResourceUtil.getValueMap(child)
                                .get(MergedResourceConstants.PN_ORDER_BEFORE, String.class);
                        if (orderBefore != null && !orderBefore.equals(mergedResChild.getName())) {
                            // Get a dummy merged resource just to know the index of that merged resource
                            MergedResource orderBeforeRes = new MergedResource(resolver, mergeRootPath,
                                    mergedResource.getRelativePath() + "/" + orderBefore);
                            if (children.contains(orderBeforeRes)) {
                                orderBeforeIndex = children.indexOf(orderBeforeRes);
                            }
                        }

                        if (orderBeforeIndex > -1) {
                            // Add merged resource's child at the right position
                            children.add(orderBeforeIndex, mergedResChild);
                            if (mergedResChildExists) {
                                children.remove(mergedResChildIndex > orderBeforeIndex ? ++mergedResChildIndex
                                        : mergedResChildIndex);
                            }
                        } else if (!mergedResChildExists) {
                            // Only add the merged resource's child if it did not exist yet
                            children.add(mergedResChild);
                        }
                    }
                }
            }

            return children.iterator();
        }

        // Return null for resources that aren't a MergedResource
        return null;
    }

    /**
     * Gets the relative path out of merge root path
     *
     * @param path Absolute path
     * @return Relative path
     */
    private String getRelativePath(String path) {
        return StringUtils.removeStart(path, mergeRootPath);
    }

}