ConfImpl.java 13.6 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.text.GlobPattern
 *  org.apache.commons.lang.ArrayUtils
 *  org.apache.commons.lang.StringUtils
 *  org.apache.jackrabbit.util.Text
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.api.wrappers.ValueMapDecorator
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.confmgr.impl;

import com.adobe.granite.confmgr.Conf;
import com.adobe.granite.confmgr.impl.SymlinkResource;
import com.day.text.GlobPattern;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.util.Text;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
public class ConfImpl
implements Conf {
    private static final Logger log = LoggerFactory.getLogger(ConfImpl.class);
    private List<String> confPaths;
    private final Resource originalResource;
    private final ResourceResolver configResolver;
    private final String[] allowedPaths;
    private final String[] fallbackPaths;

    public ConfImpl(Resource originalResource, ResourceResolver configResolver, String[] allowedPaths, String[] fallbackPaths) {
        if (log.isTraceEnabled()) {
            log.trace("conf requested for {}", (Object)(originalResource != null ? originalResource.getPath() : "null"));
        }
        this.originalResource = originalResource;
        this.configResolver = configResolver != null ? configResolver : (originalResource != null ? originalResource.getResourceResolver() : null);
        this.allowedPaths = allowedPaths;
        this.fallbackPaths = fallbackPaths;
    }

    @Override
    public ValueMap getItem(String itemName) {
        Resource res = this.getItemResource(itemName);
        Resource valueMapRes = this.handleJcrContent(res);
        if (res == null) {
            return ValueMap.EMPTY;
        }
        if (log.isTraceEnabled() && "jcr:content".equals(valueMapRes.getName())) {
            log.trace("- using jcr:content child for ValueMap: {}", (Object)valueMapRes.getPath());
        }
        return new ResourceNamedValueMap(valueMapRes.getValueMap(), res);
    }

    @Override
    public Resource getItemResource(String itemName) {
        if (this.originalResource == null) {
            return null;
        }
        if (log.isTraceEnabled()) {
            log.trace("- searching for item '{}'", (Object)itemName);
        }
        int idx = 1;
        for (String path : this.getPaths()) {
            Resource item = this.configResolver.getResource(path + "/" + "settings" + "/" + itemName);
            if (item != null) {
                if (log.isTraceEnabled()) {
                    log.trace("+ resolved config item at [{}]: {}", (Object)idx, (Object)item.getPath());
                }
                return this.handleSymlink(item);
            }
            if (log.isTraceEnabled()) {
                log.trace("- no item '{}' under config '{}'", (Object)itemName, (Object)path);
            }
            ++idx;
        }
        if (log.isTraceEnabled()) {
            log.trace("- could not resolve any config item for '{}' (or no permissions to read it)", (Object)itemName);
        }
        return null;
    }

    @Override
    public List<ValueMap> getList(String parentItemName) {
        List<Resource> resources = this.getListResources(parentItemName);
        ArrayList<ValueMap> maps = new ArrayList<ValueMap>(resources.size());
        for (Resource res : resources) {
            Resource valueMapRes = this.handleJcrContent(res);
            if (log.isTraceEnabled() && "jcr:content".equals(valueMapRes.getName())) {
                log.trace("- using jcr:content child for ValueMap: {}", (Object)valueMapRes.getPath());
            }
            maps.add((ValueMap)new ResourceNamedValueMap(valueMapRes.getValueMap(), res));
        }
        return maps;
    }

    @Override
    public List<Resource> getListResources(String parentItemName) {
        if (log.isTraceEnabled()) {
            log.trace("- searching for list '{}'", (Object)parentItemName);
        }
        ArrayList<Resource> result = new ArrayList<Resource>();
        if (this.configResolver == null) {
            return result;
        }
        HashSet<String> blocked = new HashSet<String>();
        int idx = 1;
        boolean mergeLists = false;
        for (String path : this.getPaths()) {
            Resource item = this.configResolver.getResource(path + "/" + "settings" + "/" + parentItemName);
            if (item != null) {
                if (log.isTraceEnabled()) {
                    log.trace("+ resolved config item at [{}]: {}", (Object)idx, (Object)item.getPath());
                }
                if (!mergeLists) {
                    Resource content = this.handleJcrContent(item);
                    mergeLists = (Boolean)content.getValueMap().get("mergeList", (Object)false);
                    if (log.isTraceEnabled()) {
                        if (mergeLists) {
                            log.trace("- merging lists because of {}/{} = true", (Object)content.getPath(), (Object)"mergeList");
                        } else {
                            log.trace("- fixed list");
                        }
                    }
                }
                item = this.handleSymlink(item);
                if (!mergeLists) {
                    ArrayList<Resource> list = new ArrayList<Resource>();
                    for (Resource kid : item.getChildren()) {
                        if ("jcr:content".equals(kid.getName())) continue;
                        list.add(kid);
                    }
                    if (log.isTraceEnabled()) {
                        log.trace("- final list has {} items", (Object)list.size());
                    }
                    return list;
                }
                for (Resource kid : item.getChildren()) {
                    String name = kid.getName();
                    if ("jcr:content".equals(name)) continue;
                    if (!blocked.contains(name) && kid.getChild("jcr:content") != null) {
                        if (log.isTraceEnabled()) {
                            log.trace("- adding    {}", (Object)name);
                        }
                        result.add(kid);
                    } else if (log.isTraceEnabled()) {
                        log.trace("- skipping  {}", (Object)name);
                    }
                    blocked.add(name);
                }
            } else if (log.isTraceEnabled()) {
                log.trace("- no item '{}' under config '{}'", (Object)parentItemName, (Object)path);
            }
            ++idx;
        }
        if (log.isTraceEnabled()) {
            log.trace("- final merged list has {} items", (Object)result.size());
        }
        return result;
    }

    private Resource handleSymlink(Resource item) {
        if (item == null) {
            return null;
        }
        Resource source = this.handleJcrContent(item);
        String link = (String)source.getValueMap().get("sling:target", String.class);
        if (link != null) {
            if (log.isTraceEnabled()) {
                log.trace("+ symlink from {} to {}", new Object[]{item.getPath(), link});
            }
            Resource target = this.configResolver.getResource(source, link);
            return new SymlinkResource(source, target);
        }
        return item;
    }

    private Resource handleJcrContent(Resource resource) {
        Resource jcrContent;
        if (resource != null && (jcrContent = resource.getChild("jcr:content")) != null) {
            resource = jcrContent;
        }
        return resource;
    }

    public List<String> getPaths() {
        if (this.confPaths == null) {
            ArrayList<String> refs = new ArrayList<String>();
            if (this.originalResource != null) {
                String ref = this.findConfigurationRef(this.originalResource);
                if (ref == null) {
                    if (log.isTraceEnabled()) {
                        log.trace("- no config reference found in cq:conf properties");
                    }
                    ref = this.originalResource.getPath();
                }
                if (ref != null) {
                    do {
                        if (!this.isAllowedConfigPath(ref) || this.isFallbackConfigPath(ref)) continue;
                        if (log.isTraceEnabled()) {
                            if (refs.size() == 0) {
                                log.trace("- [{}] specific config => {}", (Object)refs.size(), (Object)ref);
                            } else {
                                log.trace("- [{}] parent config   => {}", (Object)refs.size(), (Object)ref);
                            }
                        }
                        refs.add(ref);
                    } while (!"/".equals(ref = Text.getRelativeParent((String)ref, (int)1)) && StringUtils.isNotEmpty((String)ref));
                }
            }
            for (String fallbackPath : this.fallbackPaths) {
                if (log.isTraceEnabled()) {
                    log.trace("- [{}] fallback config => {}", (Object)refs.size(), (Object)fallbackPath);
                }
                refs.add(fallbackPath);
            }
            this.confPaths = Collections.unmodifiableList(refs);
        }
        return this.confPaths;
    }

    private String findConfigurationRef(Resource startResource) {
        String relativeRef = null;
        Resource relativeRefResource = null;
        for (Resource resource = startResource; resource != null; resource = resource.getParent()) {
            String ref = this.getReference(resource);
            if (ref == null) continue;
            if (ref.startsWith("/")) {
                if ("settings".equals(Text.getName((String)(ref = this.makeAbsoluteAndNormalize(ref, relativeRef))))) {
                    log.warn("Ignoring reference to '{}' from {} - do not point to special 'settings' child or use it as configuration name.", (Object)ref, (Object)resource.getPath());
                    ref = null;
                }
                if (ref != null && !this.isAllowedConfigPath(ref)) {
                    log.warn("Ignoring reference to {} from {} - not in allowed paths.", (Object)ref, (Object)resource.getPath());
                    ref = null;
                }
                if (ref != null && this.isFallbackConfigPath(ref)) {
                    log.warn("Ignoring reference to {} from {} - already a fallback path.", (Object)ref, (Object)resource.getPath());
                    ref = null;
                }
                if (ref == null) continue;
                return ref;
            }
            if (relativeRef != null) continue;
            relativeRef = ref;
            relativeRefResource = resource;
        }
        if (relativeRef != null) {
            log.warn("Ignoring relative path '{}' from {} since there is no absolute path in the preceding cq:conf properties.", (Object)relativeRef, (Object)relativeRefResource.getPath());
        }
        return null;
    }

    private String getReference(Resource resource) {
        String ref = null;
        Resource jcrContent = resource.getChild("jcr:content");
        if (jcrContent != null) {
            ref = (String)jcrContent.getValueMap().get("cq:conf", String.class);
            if (log.isTraceEnabled() && ref != null) {
                log.trace("- reference '{}' found at {}", (Object)ref, (Object)jcrContent);
            }
        }
        if (ref == null) {
            ref = (String)resource.getValueMap().get("cq:conf", String.class);
            if (log.isTraceEnabled() && ref != null) {
                log.trace("- reference '{}' found at {}", (Object)ref, (Object)resource);
            }
        }
        return ref;
    }

    private String makeAbsoluteAndNormalize(String base, String relative) {
        if (base == null) {
            return null;
        }
        String result = relative == null ? base : (base.endsWith("/") ? base + relative : base + "/" + relative);
        return ResourceUtil.normalize((String)result);
    }

    private boolean isAllowedConfigPath(String path) {
        if (this.allowedPaths == null) {
            return false;
        }
        for (String pattern : this.allowedPaths) {
            if (log.isTraceEnabled()) {
                log.trace("- checking if '{}' starts with {}", (Object)path, (Object)pattern);
            }
            if (!GlobPattern.matches((String)pattern, (String)path)) continue;
            return true;
        }
        return false;
    }

    private boolean isFallbackConfigPath(String ref) {
        return ArrayUtils.contains((Object[])this.fallbackPaths, (Object)ref);
    }

    private static class ResourceNamedValueMap
    extends ValueMapDecorator {
        private final Resource resource;

        public ResourceNamedValueMap(ValueMap valueMap, Resource resource) {
            super((Map)valueMap);
            this.resource = resource;
        }

        public Object get(Object key) {
            if ("jcr:name".equals(key)) {
                return this.resource.getName();
            }
            return super.get(key);
        }
    }

}