You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2016/11/17 17:50:36 UTC

svn commit: r1770249 [1/2] - in /sling/trunk/contrib/extensions/contextaware-config: impl/ impl/src/main/java/org/apache/sling/caconfig/impl/ impl/src/main/java/org/apache/sling/caconfig/impl/def/ impl/src/main/java/org/apache/sling/caconfig/resource/i...

Author: sseifert
Date: Thu Nov 17 17:50:36 2016
New Revision: 1770249

URL: http://svn.apache.org/viewvc?rev=1770249&view=rev
Log:
SLING-6293 refactor property inheritance out of DefaultConfigurationResourceResolvingStrategy and create separate SPI and impl for it
*this breaks backward compatibility of package org.apache.sling.caconfig.resource.spi -> major version increase*

Added:
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationInheritanceStrategy.java   (with props)
Removed:
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceWrapper.java
Modified:
    sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResolverImpl.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceNameConstants.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverAnnotationClassTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationTestUtils.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/ConfigurationResolverPropertyInheritanceTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexerTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyHierarchyTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyTest.java
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/resource/spi/ConfigurationResourceResolvingStrategy.java
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/resource/spi/package-info.java
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/package-info.java

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml Thu Nov 17 17:50:36 2016
@@ -85,7 +85,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.caconfig.spi</artifactId>
-            <version>1.1.0</version>
+            <version>1.1.1-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationBuilderImpl.java Thu Nov 17 17:50:36 2016
@@ -23,7 +23,10 @@ import static org.apache.sling.caconfig.
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.commons.collections.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceUtil;
@@ -33,26 +36,30 @@ import org.apache.sling.caconfig.Configu
 import org.apache.sling.caconfig.ConfigurationResolver;
 import org.apache.sling.caconfig.impl.ConfigurationProxy.ChildResolver;
 import org.apache.sling.caconfig.impl.metadata.AnnotationClassParser;
-import org.apache.sling.caconfig.resource.ConfigurationResourceResolver;
+import org.apache.sling.caconfig.resource.spi.ConfigurationResourceResolvingStrategy;
+import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
 import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy;
 
 class ConfigurationBuilderImpl implements ConfigurationBuilder {
 
     private final Resource contentResource;
     private final ConfigurationResolver configurationResolver;
-    private final ConfigurationResourceResolver configurationResourceResolver;
+    private final ConfigurationResourceResolvingStrategy configurationResourceResolvingStrategy;
     private final ConfigurationPersistenceStrategy configurationPersistenceStrategy;
+    private final ConfigurationInheritanceStrategy configurationInheritanceStrategy;
 
     private String configName;
 
     public ConfigurationBuilderImpl(final Resource resource,
             final ConfigurationResolver configurationResolver,
-            final ConfigurationResourceResolver configurationResourceResolver,
-            final ConfigurationPersistenceStrategy configurationPersistenceStrategy) {
+            final ConfigurationResourceResolvingStrategy configurationResourceResolvingStrategy,
+            final ConfigurationPersistenceStrategy configurationPersistenceStrategy,
+            final ConfigurationInheritanceStrategy configurationInheritanceStrategy) {
         this.contentResource = resource;
         this.configurationResolver = configurationResolver;
-        this.configurationResourceResolver = configurationResourceResolver;
+        this.configurationResourceResolvingStrategy = configurationResourceResolvingStrategy;
         this.configurationPersistenceStrategy = configurationPersistenceStrategy;
+        this.configurationInheritanceStrategy = configurationInheritanceStrategy;
     }
 
     @Override
@@ -102,12 +109,13 @@ class ConfigurationBuilderImpl implement
      * @return Converted singleton configuration
      */
     private <T> T getConfigResource(String name, Class<T> clazz, Converter<T> converter) {
-        Resource configResource = null;
+        Iterator<Resource> resourceInheritanceChain = null;
         if (this.contentResource != null) {
             validateConfigurationName(name);
-            configResource = this.configurationResourceResolver.getResource(this.contentResource, CONFIGS_PARENT_NAME, name);
+            resourceInheritanceChain = this.configurationResourceResolvingStrategy
+                    .getResourceInheritanceChain(this.contentResource, CONFIGS_PARENT_NAME, name);
         }
-        return convert(configResource, clazz, converter, name);
+        return convert(resourceInheritanceChain, clazz, converter, name, false);
     }
 
     /**
@@ -121,8 +129,9 @@ class ConfigurationBuilderImpl implement
         if (this.contentResource != null) {
            validateConfigurationName(name);
            final Collection<T> result = new ArrayList<>();
-           for (final Resource rsrc : this.configurationResourceResolver.getResourceCollection(this.contentResource, CONFIGS_PARENT_NAME, name)) {
-               final T obj = convert(rsrc, clazz, converter, name + "/" + rsrc.getName());
+           for (final Iterator<Resource> resourceInheritanceChain : this.configurationResourceResolvingStrategy
+                   .getResourceCollectionInheritanceChain(this.contentResource, CONFIGS_PARENT_NAME, name)) {
+               final T obj = convert(resourceInheritanceChain, clazz, converter, name, true);
                if (obj != null) {
                    result.add(obj);
                }
@@ -134,12 +143,28 @@ class ConfigurationBuilderImpl implement
         }
     }
     
-    private <T> T convert(Resource resource, Class<T> clazz, Converter<T> converter, String name) {
+    @SuppressWarnings("unchecked")
+    private <T> T convert(Iterator<Resource> resourceInhertianceChain, Class<T> clazz, Converter<T> converter,
+            String name, boolean appendResourceName) {
         Resource configResource = null;
-        if (resource != null) {
-            configResource = configurationPersistenceStrategy.getResource(resource);
+        String conversionName = name;
+        if (resourceInhertianceChain != null) {
+            // apply persistence transformation
+            Iterator<Resource> transformedResources = IteratorUtils.transformedIterator(resourceInhertianceChain,
+                    new Transformer() {
+                        @Override
+                        public Object transform(Object input) {
+                            return configurationPersistenceStrategy.getResource((Resource)input);
+                        }
+                    });
+            // apply resource inheritance
+            configResource = configurationInheritanceStrategy.getResource(transformedResources);
+            // build name
+            if (configResource != null && appendResourceName) {
+                conversionName = conversionName + "/" + configResource.getName();
+            }
         }
-        return converter.convert(configResource, clazz, name);
+        return converter.convert(configResource, clazz, conversionName);
     }
 
     // --- Annotation class support ---

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,88 @@
+/*
+ * 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.caconfig.impl;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.ResettableListIterator;
+import org.apache.commons.collections.iterators.ListIteratorWrapper;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+
+/**
+ * Detects all {@link ConfigurationInheritanceStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationInheritanceStrategyMultiplexer.class,
+reference={
+        @Reference(name="configurationInheritanceStrategy", service=ConfigurationInheritanceStrategy.class,
+                bind="bindConfigurationInheritanceStrategy", unbind="unbindConfigurationInheritanceStrategy",
+                cardinality=ReferenceCardinality.MULTIPLE,
+                policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationInheritanceStrategyMultiplexer implements ConfigurationInheritanceStrategy {
+
+    private RankedServices<ConfigurationInheritanceStrategy> items = new RankedServices<>(Order.DESCENDING);
+    
+    protected void bindConfigurationInheritanceStrategy(ConfigurationInheritanceStrategy item, Map<String, Object> props) {
+        items.bind(item, props);
+    }
+    
+    protected void unbindConfigurationInheritanceStrategy(ConfigurationInheritanceStrategy item, Map<String, Object> props) {
+        items.unbind(item, props);
+    }
+
+    /**
+     * Get result from first strategy implementation that has an answer.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Resource getResource(Iterator<Resource> configResources) {
+        List<ConfigurationInheritanceStrategy> itemList = items.getList();
+        if (itemList.isEmpty()) {
+            return null;
+        }
+        else if (itemList.size() == 1) {
+            return itemList.get(0).getResource(configResources);
+        }
+        else {
+            ResettableListIterator resettableConfigResources = new ListIteratorWrapper(configResources);
+            for (ConfigurationInheritanceStrategy item : items) {
+                Resource result = item.getResource(resettableConfigResources);
+                if (result != null) {
+                    return result;
+                }
+                else {
+                    resettableConfigResources.reset();
+                }
+            }
+            return null;
+        }
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResolverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResolverImpl.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResolverImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResolverImpl.java Thu Nov 17 17:50:36 2016
@@ -22,7 +22,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.caconfig.ConfigurationBuilder;
 import org.apache.sling.caconfig.ConfigurationResolver;
 import org.apache.sling.caconfig.management.impl.ConfigurationPersistenceStrategyMultiplexer;
-import org.apache.sling.caconfig.resource.ConfigurationResourceResolver;
+import org.apache.sling.caconfig.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 
@@ -30,15 +30,18 @@ import org.osgi.service.component.annota
 public class ConfigurationResolverImpl implements ConfigurationResolver {
 
     @Reference
-    private ConfigurationResourceResolver configurationResourceResolver;
+    private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
 
     @Reference
-    private ConfigurationPersistenceStrategyMultiplexer configurationResourcePersistenceStrategy;
+    private ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy;
+    
+    @Reference
+    private ConfigurationInheritanceStrategyMultiplexer configurationInheritanceStrategy;
     
     @Override
     public ConfigurationBuilder get(Resource resource) {
         return new ConfigurationBuilderImpl(resource, this,
-                configurationResourceResolver, configurationResourcePersistenceStrategy);
+                configurationResourceResolvingStrategy, configurationPersistenceStrategy, configurationInheritanceStrategy);
     }
 
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,33 @@
+/*
+ * 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.caconfig.impl.def;
+
+public final class ConfigurationDefNameConstants {
+
+    private ConfigurationDefNameConstants() {
+        // constants only
+    }
+
+    /**
+     * Boolean property that controls whether the properties (key/value pairs) of configuration resources
+     * should be inherited from the configuration hierarchy and merged.
+     */
+    public static final String PROPERTY_CONFIG_PROPERTY_INHERIT = "sling:configPropertyInherit";
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationDefNameConstants.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,52 @@
+/*
+ * 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.caconfig.impl.def;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceWrapper;
+import org.apache.sling.api.resource.ValueMap;
+
+/**
+ * Wrapper that returns an enhanced value map for the resource
+ * providing a merged map with all inherited property values.
+ */
+class ConfigurationResourceWrapper extends ResourceWrapper {
+    
+    private final ValueMap props;
+
+    public ConfigurationResourceWrapper(Resource resource, ValueMap props) {
+        super(resource);
+        this.props = props;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        if (type == ValueMap.class) {
+            return (AdapterType)props;
+        }
+        return super.adaptTo(type);
+    }
+
+    @Override
+    public ValueMap getValueMap() {
+        return props;
+    }
+    
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,87 @@
+/*
+ * 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.caconfig.impl.def;
+
+import static org.apache.sling.caconfig.impl.def.ConfigurationDefNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@Component(service=ConfigurationInheritanceStrategy.class)
+@Designate(ocd=DefaultConfigurationInheritanceStrategy.Config.class)
+public class DefaultConfigurationInheritanceStrategy implements ConfigurationInheritanceStrategy {
+
+    @ObjectClassDefinition(name="Apache Sling Context-Aware Default Configuration Inheritance Strategy",
+            description="Standardized resource inheritance for configurations.")
+    public static @interface Config {
+    
+        @AttributeDefinition(name="Enabled",
+                description = "Enable this configuration inheritance strategy.")
+        boolean enabled() default true;
+        
+        @AttributeDefinition(name="Config property inheritance property names",
+                description = "Additional property names to " + PROPERTY_CONFIG_PROPERTY_INHERIT + " to handle property inheritance. The names are used in the order defined, "
+                     + "always starting with " + PROPERTY_CONFIG_PROPERTY_INHERIT + ". Once a property with a value is found, that value is used and the following property names are skipped.")
+        String[] configPropertyInheritancePropertyNames();
+    
+    }
+
+    @Override
+    public Resource getResource(Iterator<Resource> configResources) {
+        if (!configResources.hasNext()) {
+            return null;
+        }
+        Resource primary = configResources.next();
+        if (!isPropertyInheritance(primary) || !configResources.hasNext()) {
+            return primary;
+        }
+        Map<String,Object> mergedProps = getInheritedProperties(primary.getValueMap(), configResources);
+        return new ConfigurationResourceWrapper(primary, new ValueMapDecorator(mergedProps));
+    }
+    
+    private boolean isPropertyInheritance(Resource resource) {
+        return resource.getValueMap().get(PROPERTY_CONFIG_PROPERTY_INHERIT, false);
+    }
+    
+    private Map<String,Object> getInheritedProperties(Map<String,Object> parentProps, Iterator<Resource> inheritanceChain) {
+        if (!inheritanceChain.hasNext()) {
+            return parentProps;
+        }
+        Resource next = inheritanceChain.next();
+        Map<String,Object> merged = new HashMap<>(next.getValueMap());
+        merged.putAll(parentProps);
+        if (isPropertyInheritance(next)) {
+            return getInheritedProperties(merged, inheritanceChain);
+        }
+        else {
+            return merged;
+        }
+    }
+
+}
+ 
\ No newline at end of file

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java Thu Nov 17 17:50:36 2016
@@ -18,9 +18,8 @@
  */
 package org.apache.sling.caconfig.resource.impl;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.List;
+import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
@@ -71,15 +70,46 @@ public class ConfigurationResourceResolv
     }
 
     /**
-     * Merge the configuration resources from all implementations into a combined list.
+     * Gets the configuration resource collection from the first implementation that has an answer.
      */
     @Override
     public Collection<Resource> getResourceCollection(Resource resource, String bucketName, String configName) {
-        List<Resource> result = new ArrayList<>();
         for (ConfigurationResourceResolvingStrategy item : items) {
-            result.addAll(item.getResourceCollection(resource, bucketName, configName));
+            Collection<Resource> result = item.getResourceCollection(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the configuration resource inheritance chain from the first implementation that has an answer.
+     */
+    @Override
+    public Iterator<Resource> getResourceInheritanceChain(Resource resource, String bucketName, String configName) {
+        for (ConfigurationResourceResolvingStrategy item : items) {
+            Iterator<Resource> result = item.getResourceInheritanceChain(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
         }
-        return result;
+        return null;
+    }
+
+    /**
+     * Gets the configuration resource collection inheritance chains from the first implementation that has an answer.
+     */
+    @Override
+    public Collection<Iterator<Resource>> getResourceCollectionInheritanceChain(Resource resource, String bucketName,
+            String configName) {
+        for (ConfigurationResourceResolvingStrategy item : items) {
+            Collection<Iterator<Resource>> result = item.getResourceCollectionInheritanceChain(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
     }
 
     /**

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceNameConstants.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceNameConstants.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceNameConstants.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/ConfigurationResourceNameConstants.java Thu Nov 17 17:50:36 2016
@@ -36,10 +36,4 @@ public final class ConfigurationResource
      */
     public static final String PROPERTY_CONFIG_COLLECTION_INHERIT = "sling:configCollectionInherit";
 
-    /**
-     * Boolean property that controls whether the properties (key/value pairs) of configuration resources
-     * should be inherited from the configuration hierarchy and merged.
-     */
-    public static final String PROPERTY_CONFIG_PROPERTY_INHERIT = "sling:configPropertyInherit";
-
 }

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java Thu Nov 17 17:50:36 2016
@@ -19,12 +19,9 @@
 package org.apache.sling.caconfig.resource.impl.def;
 
 import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_COLLECTION_INHERIT;
-import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -33,14 +30,17 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.commons.collections.PredicateUtils;
+import org.apache.commons.collections.Transformer;
 import org.apache.commons.collections.iterators.ArrayIterator;
 import org.apache.commons.collections.iterators.IteratorChain;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 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.apache.sling.caconfig.resource.impl.ContextPathStrategyMultiplexer;
 import org.apache.sling.caconfig.resource.impl.util.PathEliminateDuplicatesIterator;
 import org.apache.sling.caconfig.resource.impl.util.PathParentExpandIterator;
@@ -70,7 +70,7 @@ public class DefaultConfigurationResourc
     public static @interface Config {
 
         @AttributeDefinition(name="Enabled",
-                description = "Enable this configuration resourcer resolving strategy.")
+                description = "Enable this configuration resource resolving strategy.")
         boolean enabled() default true;
 
         @AttributeDefinition(name="Configurations path",
@@ -86,10 +86,6 @@ public class DefaultConfigurationResourc
                             + "always starting with " + PROPERTY_CONFIG_COLLECTION_INHERIT + ". Once a property with a value is found, that value is used and the following property names are skipped.")
         String[] configCollectionInheritancePropertyNames();
 
-        @AttributeDefinition(name="Config property inheritance property names",
-                description = "Additional property names to " + PROPERTY_CONFIG_PROPERTY_INHERIT + " to handle property inheritance. The names are used in the order defined, "
-                            + "always starting with " + PROPERTY_CONFIG_PROPERTY_INHERIT + ". Once a property with a value is found, that value is used and the following property names are skipped.")
-        String[] configPropertyInheritancePropertyNames();
     }
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
@@ -276,56 +272,40 @@ public class DefaultConfigurationResourc
 
     @Override
     public Resource getResource(final Resource contentResource, final String bucketName, final String configName) {
-        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
-            return null;
+        Iterator<Resource> resources = getResourceInheritanceChain(contentResource, bucketName, configName);
+        if (resources != null && resources.hasNext()) {
+            return resources.next();
         }
-        String name = bucketName + "/" + configName;
-        logger.debug("Searching {} for resource {}", name, contentResource.getPath());
-
-        // strategy: find first item among all configured paths
-        int idx = 1;
-        Iterator<String> paths = getResolvePaths(contentResource, bucketName);
-        Resource configResource = null;
-        Map<String,Object> configValueMap = null;
-        boolean propertyInheritance = false;
-        while (paths.hasNext()) {
-            final String path = paths.next();
-            final Resource item = contentResource.getResourceResolver().getResource(buildResourcePath(path, name));
-            if (item != null) {
-                logger.debug("Resolved config item at [{}]: {}", idx, item.getPath());
+        return null;
+    }
 
-                if (propertyInheritance) {
-                    // merge property map with values from inheritance parent
-                    Map<String,Object> mergedValueMap = new HashMap<>(item.getValueMap());
-                    mergedValueMap.putAll(configValueMap);
-                    configValueMap = mergedValueMap;
-                }
-                else {
-                    configResource = item;
-                    configValueMap = item.getValueMap();
-                }
+    @SuppressWarnings("unchecked")
+    private Iterator<Resource> getResourceInheritanceChainInternal(final String bucketName, final String configName,
+            final Iterator<String> paths, final ResourceResolver resourceResolver) {
+        final String name = bucketName + "/" + configName;
 
-                // check property inheritance mode on current level - should we check on next-highest level as well?
-                propertyInheritance = getBooleanValue(item.getValueMap(), PROPERTY_CONFIG_PROPERTY_INHERIT, config.configPropertyInheritancePropertyNames());
-                if (!propertyInheritance) {
-                    break;
-                }
+        // find all matching items among all configured paths
+        Iterator<Resource> matchingResources = IteratorUtils.transformedIterator(paths, new Transformer() {
+            @Override
+            public Object transform(Object input) {
+                String path = (String)input;
+                return resourceResolver.getResource(buildResourcePath(path, name));
             }
-            idx++;
-        }
+        });
+        return IteratorUtils.filteredIterator(matchingResources, PredicateUtils.notNullPredicate());
+    }
 
-        if (configResource == null) {
-            logger.debug("Could not resolve any config item for '{}' (or no permissions to read it)", name);
+    @Override
+    public Iterator<Resource> getResourceInheritanceChain(Resource contentResource, String bucketName, String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
             return null;
         }
+        final ResourceResolver resourceResolver = contentResource.getResourceResolver();
+        final String name = bucketName + "/" + configName;
+        logger.debug("Searching {} for resource {}", name, contentResource.getPath());
 
-        if (configValueMap instanceof ValueMap) {
-            // valuemap was not merged - return original resource with original valuemap
-            return configResource;
-        }
-        else {
-            return new ConfigurationResourceWrapper(configResource, new ValueMapDecorator(configValueMap));
-        }
+        Iterator<String> paths = getResolvePaths(contentResource, bucketName);
+        return getResourceInheritanceChainInternal(bucketName, configName, paths, resourceResolver);
     }
 
     private boolean include(final List<CollectionInheritanceDecider> deciders,
@@ -349,31 +329,22 @@ public class DefaultConfigurationResourc
         return result;
     }
 
-    @Override
-    public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
-        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
-            return Collections.emptyList();
-        }
+    private Collection<Resource> getResourceCollectionInternal(final String bucketName, final String configName,
+            Iterator<String> paths, ResourceResolver resourceResolver) {
         String name = bucketName + "/" + configName;
         if (logger.isTraceEnabled()) {
             logger.trace("- searching for list '{}'", name);
         }
 
         final Map<String,Resource> result = new LinkedHashMap<>();
-        final Map<String,Map<String,Object>> configValueMaps = new HashMap<>();
-
         final List<CollectionInheritanceDecider> deciders = this.collectionInheritanceDeciders;
         final Set<String> blockedItems = new HashSet<>();
 
         int idx = 1;
-        Iterator<String> paths = getResolvePaths(contentResource, bucketName);
-        boolean inheritCollection = false;
-        boolean inheritProperties = false;
         boolean inherit = false;
-        boolean propertyInheritanceApplied = false;
         while (paths.hasNext()) {
             final String path = paths.next();
-            Resource item = contentResource.getResourceResolver().getResource(buildResourcePath(path, name));
+            Resource item = resourceResolver.getResource(buildResourcePath(path, name));
             if (item != null) {
 
                 if (logger.isTraceEnabled()) {
@@ -381,26 +352,16 @@ public class DefaultConfigurationResourc
                 }
 
                 for (Resource child : item.getChildren()) {
-                    if (isValidResourceCollectionItem(child) && include(deciders, bucketName, child, blockedItems)) {
-                        if ((!inherit || inheritCollection) && !result.containsKey(child.getName())) {
-                            result.put(child.getName(), child);
-                            configValueMaps.put(child.getName(), child.getValueMap());
-                        }
-                        else if (inheritProperties && configValueMaps.containsKey(child.getName())) {
-                            // merge property map with values from inheritance parent
-                            Map<String,Object> mergedValueMap = new HashMap<>(child.getValueMap());
-                            mergedValueMap.putAll(configValueMaps.get(child.getName()));
-                            configValueMaps.put(child.getName(), mergedValueMap);
-                            propertyInheritanceApplied = true;
-                        }
-                    }
+                    if (isValidResourceCollectionItem(child)
+                            && !result.containsKey(child.getName())
+                            && include(deciders, bucketName, child, blockedItems)) {
+                        result.put(child.getName(), child);
+                   }
                 }
 
-                // check collection and property inheritance mode on current level - should we check on next-highest level as well?
+                // check collection inheritance mode on current level - should we check on next-highest level as well?
                 final ValueMap valueMap = item.getValueMap();
-                inheritCollection = getBooleanValue(valueMap, PROPERTY_CONFIG_COLLECTION_INHERIT, config.configCollectionInheritancePropertyNames());
-                inheritProperties = getBooleanValue(valueMap, PROPERTY_CONFIG_PROPERTY_INHERIT, config.configPropertyInheritancePropertyNames());
-                inherit = inheritCollection || inheritProperties;
+                inherit = getBooleanValue(valueMap, PROPERTY_CONFIG_COLLECTION_INHERIT, config.configCollectionInheritancePropertyNames());
                 if (!inherit) {
                     break;
                 }
@@ -417,23 +378,41 @@ public class DefaultConfigurationResourc
             logger.trace("- final list has {} items", result.size());
         }
 
-        // replace config resources with wrappers with merged properties if property inheritance was applied
-        if (propertyInheritanceApplied) {
-            List<Resource> transformedResult = new ArrayList<>();
-            for (Map.Entry<String, Resource> entry : result.entrySet()) {
-                Map<String,Object> configValueMap = configValueMaps.get(entry.getKey());
-                if (configValueMap instanceof ValueMap) {
-                    transformedResult.add(entry.getValue());
-                }
-                else {
-                    transformedResult.add(new ConfigurationResourceWrapper(entry.getValue(), new ValueMapDecorator(configValueMap)));
-                }
-            }
-            return transformedResult;
+        return result.values();
+    }
+
+    @Override
+    public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+            return null;
         }
-        else {
-            return result.values();
+        Iterator<String> paths = getResolvePaths(contentResource, bucketName);
+        return getResourceCollectionInternal(bucketName, configName, paths, contentResource.getResourceResolver());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Collection<Iterator<Resource>> getResourceCollectionInheritanceChain(final Resource contentResource,
+            final String bucketName, final String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+            return null;
         }
+        final ResourceResolver resourceResolver = contentResource.getResourceResolver();
+        final List<String> paths = IteratorUtils.toList(getResolvePaths(contentResource, bucketName));
+        
+        // get resource collection with respect to collection inheritance
+        Collection<Resource> resourceCollection = getResourceCollectionInternal(bucketName, configName, paths.iterator(), resourceResolver);
+        
+        // get inheritance chain for each item found
+        // yes, this resolves the closest item twice, but is the easiest solution to combine both logic aspects
+        Iterator<Iterator<Resource>> result = IteratorUtils.transformedIterator(resourceCollection.iterator(), new Transformer() {
+            @Override
+            public Object transform(Object input) {
+                Resource item = (Resource)input;
+                return getResourceInheritanceChainInternal(bucketName, configName + "/" + item.getName(), paths.iterator(), resourceResolver);
+            }
+        });
+        return IteratorUtils.toList(result);
     }
 
     private boolean isValidResourceCollectionItem(Resource resource) {
@@ -468,28 +447,14 @@ public class DefaultConfigurationResourc
             return configPath;
         }
         else {
-            logger.debug("No configuration path {}  foundfor resource {}.", name, contentResource.getPath());
+            logger.debug("No configuration path {} found for resource {}.", name, contentResource.getPath());
             return null;
         }
     }
 
     @Override
     public String getResourceCollectionParentPath(Resource contentResource, String bucketName, String configName) {
-        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
-            return null;
-        }
-        String name = bucketName + "/" + configName;
-
-        Iterator<String> configPaths = this.findConfigRefs(contentResource, bucketName);
-        if (configPaths.hasNext()) {
-            String configPath = buildResourcePath(configPaths.next(), name);
-            logger.debug("Building configuration collection parent path {} for resource {}: {}", name, contentResource.getPath(), configPath);
-            return configPath;
-        }
-        else {
-            logger.debug("No configuration collection parent path {}  foundfor resource {}.", name, contentResource.getPath());
-            return null;
-        }
+        return getResourcePath(contentResource, bucketName, configName);
     }
 
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,125 @@
+/*
+ * 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.caconfig.impl;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.Iterator;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+
+import com.google.common.collect.ImmutableList;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ConfigurationInheritanceStrategyMultiplexerTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext();
+
+    @Mock
+    private Resource resource1;
+    @Mock
+    private Resource resource2;
+    
+    private Iterator<Resource> resources;
+    private ConfigurationInheritanceStrategy underTest;
+    
+    @Before
+    public void setUp() {
+        resources = ImmutableList.of(resource1, resource2).iterator();
+        underTest = context.registerInjectActivateService(new ConfigurationInheritanceStrategyMultiplexer());
+    }
+
+    @Test
+    public void testWithNoStrategies() {
+        assertNull(underTest.getResource(resources));
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testWithOneStrategy() {
+        ConfigurationInheritanceStrategy strategy = mock(ConfigurationInheritanceStrategy.class);
+        
+        when(strategy.getResource((Iterator<Resource>)any())).thenAnswer(new Answer<Resource>() {
+            @Override
+            public Resource answer(InvocationOnMock invocation) throws Throwable {
+                Iterator<Resource> items = invocation.getArgument(0);
+                return items.next();
+            }
+        });
+        
+        context.registerService(ConfigurationInheritanceStrategy.class, strategy);
+        
+        assertSame(resource1, underTest.getResource(resources));
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testWithMultipleStrategies() {
+        ConfigurationInheritanceStrategy strategy1 = mock(ConfigurationInheritanceStrategy.class);
+        ConfigurationInheritanceStrategy strategy2 = mock(ConfigurationInheritanceStrategy.class);
+        ConfigurationInheritanceStrategy strategy3 = mock(ConfigurationInheritanceStrategy.class);
+        
+        when(strategy1.getResource((Iterator<Resource>)any())).thenAnswer(new Answer<Resource>() {
+            @Override
+            public Resource answer(InvocationOnMock invocation) throws Throwable {
+                Iterator<Resource> items = invocation.getArgument(0);
+                while (items.hasNext()) {
+                    items.next();
+                }
+                return null;
+            }
+        });
+        when(strategy2.getResource((Iterator<Resource>)any())).thenAnswer(new Answer<Resource>() {
+            @Override
+            public Resource answer(InvocationOnMock invocation) throws Throwable {
+                Iterator<Resource> items = invocation.getArgument(0);
+                return items.next();
+            }
+        });
+        
+        context.registerService(ConfigurationInheritanceStrategy.class, strategy1);
+        context.registerService(ConfigurationInheritanceStrategy.class, strategy2);
+        context.registerService(ConfigurationInheritanceStrategy.class, strategy3);
+        
+        assertSame(resource1, underTest.getResource(resources));
+        
+        verify(strategy1, times(1)).getResource((Iterator<Resource>)any());
+        verify(strategy2, times(1)).getResource((Iterator<Resource>)any());
+        verifyNoMoreInteractions(strategy3);
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationInheritanceStrategyMultiplexerTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverAnnotationClassTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverAnnotationClassTest.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverAnnotationClassTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverAnnotationClassTest.java Thu Nov 17 17:50:36 2016
@@ -18,8 +18,8 @@
  */
 package org.apache.sling.caconfig.impl;
 
+import static org.apache.sling.caconfig.impl.def.ConfigurationDefNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
 import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_COLLECTION_INHERIT;
-import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
 import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_REF;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -161,12 +161,11 @@ public class ConfigurationResolverAnnota
                 .siblingsMode()
                 .resource("1", "stringParam", "configValue1.1", "intParam", "111")
                 .resource("2", "stringParam", "configValue1.2", "intParam", "222")
-            .resource("/conf/content/site1/sling:configs/org.apache.sling.caconfig.example.ListConfig",
-                    PROPERTY_CONFIG_PROPERTY_INHERIT, true,
+            .resource("/conf/content/site1/sling:configs/org.apache.sling.caconfig.example.ListConfig",                    
                     PROPERTY_CONFIG_COLLECTION_INHERIT, true)
                 .siblingsMode()
-                .resource("2", "stringParam", "configValue2.2")
-                .resource("3", "stringParam", "configValue2.3", "intParam", "333");
+                .resource("2", "stringParam", "configValue2.2", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
+                .resource("3", "stringParam", "configValue2.3", "intParam", "333", PROPERTY_CONFIG_PROPERTY_INHERIT, true);
 
         List<ListConfig> cfgList = ImmutableList.copyOf(underTest.get(site1Page1).asCollection(ListConfig.class));
 

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationTestUtils.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationTestUtils.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationTestUtils.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationTestUtils.java Thu Nov 17 17:50:36 2016
@@ -19,6 +19,7 @@
 package org.apache.sling.caconfig.impl;
 
 import org.apache.sling.caconfig.ConfigurationResolver;
+import org.apache.sling.caconfig.impl.def.DefaultConfigurationInheritanceStrategy;
 import org.apache.sling.caconfig.impl.def.DefaultConfigurationPersistenceStrategy;
 import org.apache.sling.caconfig.management.impl.ConfigurationPersistenceStrategyMultiplexer;
 import org.apache.sling.caconfig.resource.impl.ConfigurationResourceTestUtils;
@@ -38,6 +39,8 @@ public final class ConfigurationTestUtil
         ConfigurationResourceTestUtils.registerConfigurationResourceResolver(context);
         context.registerInjectActivateService(new DefaultConfigurationPersistenceStrategy());
         context.registerInjectActivateService(new ConfigurationPersistenceStrategyMultiplexer());
+        context.registerInjectActivateService(new DefaultConfigurationInheritanceStrategy());
+        context.registerInjectActivateService(new ConfigurationInheritanceStrategyMultiplexer());
         return context.registerInjectActivateService(new ConfigurationResolverImpl());
     }
     

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/ConfigurationResolverPropertyInheritanceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/ConfigurationResolverPropertyInheritanceTest.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/ConfigurationResolverPropertyInheritanceTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/ConfigurationResolverPropertyInheritanceTest.java Thu Nov 17 17:50:36 2016
@@ -18,7 +18,7 @@
  */
 package org.apache.sling.caconfig.impl.def;
 
-import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
+import static org.apache.sling.caconfig.impl.def.ConfigurationDefNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
 import static org.apache.sling.caconfig.resource.impl.def.ConfigurationResourceNameConstants.PROPERTY_CONFIG_REF;
 import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.hasEntry;
@@ -158,8 +158,8 @@ public class ConfigurationResolverProper
         context.build()
             .resource("/conf/global/sling:configs/test")
                 .resource("item1", "param1", "value1", "param2", "value2")
-            .resource("/conf/brand1/tenant1/region1/site1/sling:configs/test", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
-                .resource("item1", "param1", "value1a")
+            .resource("/conf/brand1/tenant1/region1/site1/sling:configs/test")
+                .resource("item1", "param1", "value1a", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
             .resource("/conf/brand1/tenant1/region1/site2/sling:configs/test")
                 .resource("item1", "param1", "value1b");
         
@@ -176,12 +176,12 @@ public class ConfigurationResolverProper
         context.build()
             .resource("/conf/global/sling:configs/test")
                 .resource("item1", "param1", "value1", "param4", "value4")
-            .resource("/conf/brand1/tenant1/sling:configs/test", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
-                .resource("item1", "param1", "value1a", "param3", "value3")
-            .resource("/conf/brand1/tenant1/region1/sling:configs/test", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
-                .resource("item1", "param1", "value1b", "param2", "value2")
-            .resource("/conf/brand1/tenant1/region1/site1/sling:configs/test", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
-                .resource("item1", "param1", "value1c")
+            .resource("/conf/brand1/tenant1/sling:configs/test")
+                .resource("item1", "param1", "value1a", "param3", "value3", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
+            .resource("/conf/brand1/tenant1/region1/sling:configs/test")
+                .resource("item1", "param1", "value1b", "param2", "value2", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
+            .resource("/conf/brand1/tenant1/region1/site1/sling:configs/test")
+                .resource("item1", "param1", "value1c", PROPERTY_CONFIG_PROPERTY_INHERIT, true)
             .resource("/conf/brand1/tenant1/region1/site2/sling:configs/test")
                 .resource("item1", "param1", "value1d");
         

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java?rev=1770249&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java Thu Nov 17 17:50:36 2016
@@ -0,0 +1,100 @@
+/*
+ * 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.caconfig.impl.def;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Iterator;
+import static org.apache.sling.caconfig.impl.def.ConfigurationDefNameConstants.PROPERTY_CONFIG_PROPERTY_INHERIT;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class DefaultConfigurationInheritanceStrategyTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext();
+    
+    private ConfigurationInheritanceStrategy underTest;
+    
+    @Before
+    public void setUp() {
+        underTest = context.registerInjectActivateService(new DefaultConfigurationInheritanceStrategy());
+    }
+
+    @Test
+    public void testWithoutPropertyMerging() {
+        Iterator<Resource> resources = ImmutableList.of(
+                context.create().resource("/conf/resource1", "prop1", "value1a", "prop2", "value2a"),
+                context.create().resource("/conf/resource2", "prop2", "value2b", "prop3", "value3b"),
+                context.create().resource("/conf/resource3", "prop4", "value4b")
+                ).iterator();
+        
+        Resource inherited = underTest.getResource(resources);
+        ValueMap props = inherited.getValueMap();
+        
+        assertEquals("value1a", props.get("prop1", String.class));
+        assertEquals("value2a", props.get("prop2", String.class));
+        assertNull(props.get("prop3", String.class));
+        assertNull(props.get("prop4", String.class));        
+    }
+
+    @Test
+    public void testWithPropertyMerging() {
+        Iterator<Resource> resources = ImmutableList.of(
+                context.create().resource("/conf/resource1", "prop1", "value1a", "prop2", "value2a", PROPERTY_CONFIG_PROPERTY_INHERIT, true),
+                context.create().resource("/conf/resource2", "prop2", "value2b", "prop3", "value3b", PROPERTY_CONFIG_PROPERTY_INHERIT, true),
+                context.create().resource("/conf/resource3", "prop4", "value4b")
+                ).iterator();
+        
+        Resource inherited = underTest.getResource(resources);
+        ValueMap props = inherited.getValueMap();
+        
+        assertEquals("value1a", props.get("prop1", String.class));
+        assertEquals("value2a", props.get("prop2", String.class));
+        assertEquals("value3b", props.get("prop3", String.class));
+        assertEquals("value4b", props.get("prop4", String.class));        
+    }
+
+    @Test
+    public void testWithPartialPropertyMerging() {
+        Iterator<Resource> resources = ImmutableList.of(
+                context.create().resource("/conf/resource1", "prop1", "value1a", "prop2", "value2a", PROPERTY_CONFIG_PROPERTY_INHERIT, true),
+                context.create().resource("/conf/resource2", "prop2", "value2b", "prop3", "value3b"),
+                context.create().resource("/conf/resource3", "prop4", "value4b")
+                ).iterator();
+        
+        Resource inherited = underTest.getResource(resources);
+        ValueMap props = inherited.getValueMap();
+        
+        assertEquals("value1a", props.get("prop1", String.class));
+        assertEquals("value2a", props.get("prop2", String.class));
+        assertEquals("value3b", props.get("prop3", String.class));
+        assertNull(props.get("prop4", String.class));        
+    }
+
+}

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Thu Nov 17 17:50:36 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategyTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexerTest.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexerTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/ConfigurationResourceResolvingStrategyMultiplexerTest.java Thu Nov 17 17:50:36 2016
@@ -23,22 +23,26 @@ import static org.apache.sling.caconfig.
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
 
 import java.util.Collection;
+import java.util.Iterator;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.caconfig.resource.impl.def.DefaultConfigurationResourceResolvingStrategy;
 import org.apache.sling.caconfig.resource.impl.def.DefaultContextPathStrategy;
 import org.apache.sling.caconfig.resource.spi.ConfigurationResourceResolvingStrategy;
 import org.apache.sling.hamcrest.ResourceCollectionMatchers;
+import org.apache.sling.hamcrest.ResourceMatchers;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.osgi.framework.Constants;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterators;
 
 public class ConfigurationResourceResolvingStrategyMultiplexerTest {
 
@@ -82,9 +86,10 @@ public class ConfigurationResourceResolv
     @Test
     public void testWithNoStrategies() {
         assertNull(underTest.getResource(site1Page1, BUCKET, "test"));
-        
-        Collection<Resource> col1 = underTest.getResourceCollection(site1Page1, BUCKET, "feature");
-        assertTrue(col1.isEmpty());
+        assertNull(underTest.getResourceCollection(site1Page1, BUCKET, "feature"));
+
+        assertNull(underTest.getResourceInheritanceChain(site1Page1, BUCKET, "test"));
+        assertNull(underTest.getResourceCollectionInheritanceChain(site1Page1, BUCKET, "feature"));
 
         assertNull(underTest.getResourcePath(site1Page1, BUCKET, "test"));
         assertNull(underTest.getResourceCollectionParentPath(site1Page1, BUCKET, "feature"));
@@ -94,13 +99,18 @@ public class ConfigurationResourceResolv
     public void testWithDefaultStrategy() {
         context.registerInjectActivateService(new DefaultConfigurationResourceResolvingStrategy());
 
-        assertEquals("/conf/site1/sling:test/test", underTest.getResource(site1Page1, BUCKET, "test").getPath());
-
+        assertThat(underTest.getResource(site1Page1, BUCKET, "test"), ResourceMatchers.path("/conf/site1/sling:test/test"));
         assertThat(underTest.getResourceCollection(site1Page1, BUCKET, "feature"), ResourceCollectionMatchers.paths( 
                 "/conf/site1/sling:test/feature/c",
                 "/apps/conf/sling:test/feature/a", 
                 "/libs/conf/sling:test/feature/b"));
 
+        assertThat(first(underTest.getResourceInheritanceChain(site1Page1, BUCKET, "test")), ResourceMatchers.path("/conf/site1/sling:test/test"));
+        assertThat(first(underTest.getResourceCollectionInheritanceChain(site1Page1, BUCKET, "feature")), ResourceCollectionMatchers.paths( 
+                "/conf/site1/sling:test/feature/c",
+                "/apps/conf/sling:test/feature/a", 
+                "/libs/conf/sling:test/feature/b"));
+
         assertEquals("/conf/site1/sling:test/test", underTest.getResourcePath(site1Page1, BUCKET, "test"));
         assertEquals("/conf/site1/sling:test/feature", underTest.getResourceCollectionParentPath(site1Page1, BUCKET, "feature"));
     }
@@ -119,6 +129,20 @@ public class ConfigurationResourceResolv
                 return ImmutableList.copyOf(context.resourceResolver().getResource("/conf/site1/sling:test/feature").listChildren());
             }
             @Override
+            public Iterator<Resource> getResourceInheritanceChain(Resource resource, String bucketName, String configName) {
+                return Iterators.singletonIterator(getResource(resource, bucketName, configName));
+            }
+            @Override
+            public Collection<Iterator<Resource>> getResourceCollectionInheritanceChain(Resource resource,
+                    String bucketName, String configName) {
+                return Collections2.transform(getResourceCollection(resource, bucketName, configName), new Function<Resource, Iterator<Resource>>() {
+                    @Override
+                    public Iterator<Resource> apply(Resource input) {
+                        return Iterators.singletonIterator(input);
+                    }
+                });
+            }
+            @Override
             public String getResourcePath(Resource resource, String bucketName, String configName) {
                 return "/conf/site1/sling:test/test";
             }
@@ -139,6 +163,20 @@ public class ConfigurationResourceResolv
                 return ImmutableList.copyOf(context.resourceResolver().getResource("/libs/conf/sling:test/feature").listChildren());
             }
             @Override
+            public Iterator<Resource> getResourceInheritanceChain(Resource resource, String bucketName, String configName) {
+                return Iterators.singletonIterator(getResource(resource, bucketName, configName));
+            }
+            @Override
+            public Collection<Iterator<Resource>> getResourceCollectionInheritanceChain(Resource resource,
+                    String bucketName, String configName) {
+                return Collections2.transform(getResourceCollection(resource, bucketName, configName), new Function<Resource, Iterator<Resource>>() {
+                    @Override
+                    public Iterator<Resource> apply(Resource input) {
+                        return Iterators.singletonIterator(input);
+                    }
+                });
+            }
+            @Override
             public String getResourcePath(Resource resource, String bucketName, String configName) {
                 return null;
             }
@@ -148,14 +186,35 @@ public class ConfigurationResourceResolv
             }
         }, Constants.SERVICE_RANKING, 1000);
         
-        assertEquals("/conf/site1/sling:test/test", underTest.getResource(site1Page1, BUCKET, "test").getPath());
-
+        assertThat(underTest.getResource(site1Page1, BUCKET, "test"), ResourceMatchers.path("/conf/site1/sling:test/test"));
         assertThat(underTest.getResourceCollection(site1Page1, BUCKET, "feature"), ResourceCollectionMatchers.paths( 
-                "/conf/site1/sling:test/feature/c",
-                "/libs/conf/sling:test/feature/b"));
+                "/conf/site1/sling:test/feature/c"));
+        
+        assertThat(first(underTest.getResourceInheritanceChain(site1Page1, BUCKET, "test")), ResourceMatchers.path("/conf/site1/sling:test/test"));
+        assertThat(first(underTest.getResourceCollectionInheritanceChain(site1Page1, BUCKET, "feature")), ResourceCollectionMatchers.paths( 
+                "/conf/site1/sling:test/feature/c"));
         
         assertEquals("/conf/site1/sling:test/test", underTest.getResourcePath(site1Page1, BUCKET, "test"));
         assertEquals("/conf/site1/sling:test/feature", underTest.getResourceCollectionParentPath(site1Page1, BUCKET, "feature"));
     }
 
+    private Resource first(Iterator<Resource> resources) {
+        if (resources.hasNext()) {
+            return resources.next();
+        }
+        else {
+            return null;
+        }
+    }
+    
+    private Collection<Resource> first(Collection<Iterator<Resource>> resources) {
+        return Collections2.transform(underTest.getResourceCollectionInheritanceChain(site1Page1, BUCKET, "feature"),
+                new Function<Iterator<Resource>, Resource>() {
+                @Override
+                public Resource apply(Iterator<Resource> input) {
+                    return input.next();
+                }
+            });
+    }
+    
 }

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyHierarchyTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyHierarchyTest.java?rev=1770249&r1=1770248&r2=1770249&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyHierarchyTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/resource/impl/def/DefaultConfigurationResourceResolvingStrategyHierarchyTest.java Thu Nov 17 17:50:36 2016
@@ -24,15 +24,21 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 
+import java.util.Iterator;
+import java.util.List;
+
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.caconfig.resource.impl.ContextPathStrategyMultiplexer;
 import org.apache.sling.caconfig.resource.spi.ConfigurationResourceResolvingStrategy;
 import org.apache.sling.hamcrest.ResourceCollectionMatchers;
+import org.apache.sling.hamcrest.ResourceIteratorMatchers;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Tests with content and configurations that form a deeper nested hierarchy.
  */
@@ -62,12 +68,10 @@ public class DefaultConfigurationResourc
             .resource("/content/tenant1/region1/site2", PROPERTY_CONFIG_REF, "/conf/brand1/tenant1/region1/site2");
         site1Page1 = context.create().resource("/content/tenant1/region1/site1/page1");
         site2Page1 = context.create().resource("/content/tenant1/region1/site2/page1");
-
     }
 
     @Test
     public void testGetResource() {
-        // build config resources
         context.build()
             .resource("/conf/brand1/tenant1/region1/site1/sling:test/cfgSite1")
             .resource("/conf/brand1/tenant1/region1/sling:test/cfgRegion1")
@@ -101,8 +105,30 @@ public class DefaultConfigurationResourc
     }
 
     @Test
+    public void testGetResourceInheritanceChain() {
+        context.build()
+            .resource("/conf/brand1/tenant1/region1/site1/sling:test/test")
+            .resource("/conf/brand1/tenant1/sling:test/test")
+            .resource("/conf/global/sling:test/test")
+            .resource("/apps/conf/sling:test/test")
+            .resource("/libs/conf/sling:test/test");
+        
+        assertThat(underTest.getResourceInheritanceChain(site1Page1, BUCKET, "test"), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/region1/site1/sling:test/test",
+                "/conf/brand1/tenant1/sling:test/test",
+                "/conf/global/sling:test/test",
+                "/apps/conf/sling:test/test",
+                "/libs/conf/sling:test/test"));
+
+        assertThat(underTest.getResourceInheritanceChain(site2Page1, BUCKET, "test"), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/sling:test/test",
+                "/conf/global/sling:test/test",
+                "/apps/conf/sling:test/test",
+                "/libs/conf/sling:test/test"));
+    }
+
+    @Test
     public void testGetResourceCollectionWithInheritance() {
-        // build config resources
         context.build()
             .resource("/conf/brand1/tenant1/region1/site1/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true).resource("site1")
             .resource("/conf/brand1/tenant1/region1/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true).resource("region1")
@@ -134,8 +160,46 @@ public class DefaultConfigurationResourc
     }
 
     @Test
-    public void testGetResourceCollectionContentConfigRefInheritanceAndConfigResourceInheritance() {
+    public void testGetResourceCollectionInheritanceChain() {
+        context.build()
+            .resource("/conf/brand1/tenant1/region1/site1/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true)
+                .siblingsMode()
+                .resource("item1")
+                .resource("item2")
+            .resource("/conf/brand1/tenant1/region1/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true)
+                .siblingsMode()
+                .resource("item1")
+                .resource("item3")
+            .resource("/conf/brand1/tenant1/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true)
+                .siblingsMode()
+                .resource("item4")
+            .resource("/conf/global/sling:test/cfgCol", PROPERTY_CONFIG_COLLECTION_INHERIT, true)
+                .siblingsMode()
+                .resource("item1")
+            .resource("/libs/conf/sling:test/cfgCol")
+                .siblingsMode()
+                .resource("item2")
+                .resource("item3");
+        
+        List<Iterator<Resource>> resources = ImmutableList.copyOf(underTest.getResourceCollectionInheritanceChain(site1Page1, BUCKET, "cfgCol"));
+        assertEquals(4, resources.size());
         
+        assertThat(resources.get(0), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/region1/site1/sling:test/cfgCol/item1",
+                "/conf/brand1/tenant1/region1/sling:test/cfgCol/item1",
+                "/conf/global/sling:test/cfgCol/item1"));
+        assertThat(resources.get(1), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/region1/site1/sling:test/cfgCol/item2",
+                "/libs/conf/sling:test/cfgCol/item2"));
+        assertThat(resources.get(2), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/region1/sling:test/cfgCol/item3",
+                "/libs/conf/sling:test/cfgCol/item3"));
+        assertThat(resources.get(3), ResourceIteratorMatchers.paths(
+                "/conf/brand1/tenant1/sling:test/cfgCol/item4"));
+    }
+
+    @Test
+    public void testGetResourceCollectionContentConfigRefInheritanceAndConfigResourceInheritance() {
         context.build()
             .resource("/content/level1", PROPERTY_CONFIG_REF, "/conf/a1/a2")
             .resource("/content/level1/level2", PROPERTY_CONFIG_REF, "/conf/b1/b2")