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/09/19 15:39:18 UTC

svn commit: r1761468 [2/4] - in /sling/trunk/contrib/extensions/contextaware-config: api/ api/src/main/java/org/apache/sling/contextaware/config/ api/src/main/java/org/apache/sling/contextaware/config/resource/spi/ api/src/main/java/org/apache/sling/co...

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,80 @@
+/*
+ * 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.contextaware.config.management;
+
+import javax.annotation.CheckForNull;
+
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Provides detailed information about a given configuration value.
+ * @param <T> Property type
+ */
+@ProviderType
+public interface ValueInfo<T> {
+
+    /**
+     * Property metadata.
+     * @return Property metadata. Null if no metadata exists.
+     */
+    @CheckForNull PropertyMetadata<T> getPropertyMetadata();
+    
+    /**
+     * Get value stored for the current context path. No inherited value. No default value.
+     * @return Value
+     */
+    @CheckForNull T getValue();
+    
+    /**
+     * Get value storedf or the current context path, or inherited from upper levels, or the default value.
+     * @return Value
+     */
+    @CheckForNull T getEffectiveValue();
+    
+    /**
+     * Get the path of the configuration resource the value is stored in.
+     * @return Resource path or null if no resource associated. 
+     */
+    @CheckForNull String getConfigSourcePath();
+
+    /**
+     * @return true if no value is defined but a default value is returned.
+     */
+    boolean isDefault();
+    
+    /**
+     * @return true if the value is not defined for the current context path but inherited from upper levels.
+     */
+    // for future use
+    //boolean isInherited();
+    
+    /**
+     * @return true if the value is overridden by an configuration override provider.
+     */
+    // for future use
+    //boolean isOverridden();
+    
+    /**
+     * @return true if this value is locked on a higher level and is not allowed to be overridden.
+     */
+    // for future use
+    //boolean isLocked();
+    
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/ValueInfo.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,97 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.contextaware.config.management.ConfigurationData;
+import org.apache.sling.contextaware.config.management.ValueInfo;
+import org.apache.sling.contextaware.config.spi.metadata.ConfigurationMetadata;
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+
+final class ConfigurationDataImpl implements ConfigurationData {
+    
+    private final ValueMap properties;
+    private final String configSourcePath;
+    private final ConfigurationMetadata configMetadata;
+    
+    public ConfigurationDataImpl(Resource configResource, ConfigurationMetadata configMetadata) {
+        this(configResource.getValueMap(), configResource.getPath(), configMetadata);
+    }
+
+    public ConfigurationDataImpl(ConfigurationMetadata configMetadata) {
+        this(ValueMap.EMPTY, null, configMetadata);
+    }
+
+    private ConfigurationDataImpl(ValueMap propertes, String configSourcePath, ConfigurationMetadata configMetadata) {
+        this.properties = propertes;
+        this.configSourcePath = configSourcePath;
+        this.configMetadata = configMetadata;
+    }
+
+    @Override
+    public Set<String> getPropertyNames() {
+        Set<String> propertyNames = new HashSet<>();
+        if (configMetadata != null) {
+            propertyNames.addAll(configMetadata.getPropertyMetadata().keySet());
+        }
+        propertyNames.addAll(properties.keySet());
+        return propertyNames;
+    }
+
+    @Override
+    public ValueMap getValues() {
+        return properties;
+    }
+
+    @Override
+    public ValueMap getEffectiveValues() {
+        Map<String,Object> props = new HashMap<>();
+        if (configMetadata != null) {
+            for (PropertyMetadata<?> propertyMetadata : configMetadata.getPropertyMetadata().values()) {
+                if (propertyMetadata.getDefaultValue() != null) {
+                    props.put(propertyMetadata.getName(), propertyMetadata.getDefaultValue());
+                }
+            }
+        }
+        props.putAll(properties);
+        return new ValueMapDecorator(props);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public ValueInfo<?> getValueInfo(String propertyName) {
+        PropertyMetadata propertyMetadata = configMetadata != null ? configMetadata.getPropertyMetadata().get(propertyName) : null;
+        Object value;
+        if (propertyMetadata != null) {
+            value = properties.get(propertyName, propertyMetadata.getType());
+        }
+        else {
+            value = properties.get(propertyName);
+        }
+        return new ValueInfoImpl(value, configSourcePath, propertyMetadata);
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationDataImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,107 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import static org.apache.sling.contextaware.config.impl.ConfigurationNameConstants.CONFIGS_PARENT_NAME;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contextaware.config.impl.metadata.ConfigurationMetadataProviderMultiplexer;
+import org.apache.sling.contextaware.config.management.ConfigurationData;
+import org.apache.sling.contextaware.config.management.ConfigurationManager;
+import org.apache.sling.contextaware.config.resource.ConfigurationResourceResolver;
+import org.apache.sling.contextaware.config.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer;
+import org.apache.sling.contextaware.config.spi.ConfigurationPersistenceException;
+import org.apache.sling.contextaware.config.spi.metadata.ConfigurationMetadata;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Component(service = ConfigurationManager.class)
+public class ConfigurationManagerImpl implements ConfigurationManager {
+    
+    @Reference
+    private ConfigurationResourceResolver configurationResourceResolver;
+    @Reference
+    private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
+    @Reference
+    private ConfigurationMetadataProviderMultiplexer configurationMetadataProvider;
+    @Reference
+    private ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy;
+
+    @Override
+    public ConfigurationData get(Resource resource, String configName) {
+        ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+        Resource configResource = configurationResourceResolver.getResource(resource, CONFIGS_PARENT_NAME, configName);
+        if (configResource != null) {
+            return new ConfigurationDataImpl(configurationPersistenceStrategy.getResource(configResource), configMetadata);
+        }
+        if (configMetadata != null) {
+            // if no config resource found but config metadata exist return empty config data with default values
+            return new ConfigurationDataImpl(configMetadata);
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<ConfigurationData> getCollection(Resource resource, String configName) {
+        ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+        Collection<Resource> configResources = configurationResourceResolver.getResourceCollection(resource, CONFIGS_PARENT_NAME, configName);
+        List<ConfigurationData> configData = new ArrayList<>();
+        for (Resource configResource : configResources) {
+            configData.add(new ConfigurationDataImpl(configurationPersistenceStrategy.getResource(configResource), configMetadata));
+        }
+        return configData;
+    }
+
+    @Override
+    public void persist(Resource resource, String configName, Map<String,Object> values) {
+        String configResourcePath = configurationResourceResolvingStrategy.getResourcePath(resource, CONFIGS_PARENT_NAME, configName);
+        if (configResourcePath == null) {
+            throw new ConfigurationPersistenceException("Unable to persist configuration: Configuration resolving strategy returned no path.");
+        }
+        if (!configurationPersistenceStrategy.persist(resource.getResourceResolver(), configResourcePath, values)) {
+            throw new ConfigurationPersistenceException("Unable to persist configuration: No persistence strategy found.");
+        }
+    }
+
+    @Override
+    public void persistCollection(Resource resource, String configName, Collection<Map<String,Object>> values) {
+        String configResourceParentPath = configurationResourceResolvingStrategy.getResourceCollectionParentPath(resource, CONFIGS_PARENT_NAME, configName);
+        if (configResourceParentPath == null) {
+            throw new ConfigurationPersistenceException("Unable to persist configuration collection: Configuration resolving strategy returned no parent path.");
+        }
+        if (!configurationPersistenceStrategy.persistCollection(resource.getResourceResolver(), configResourceParentPath, values)) {
+            throw new ConfigurationPersistenceException("Unable to persist configuration: No persistence strategy found.");
+        }
+    }
+
+    @Override
+    public ConfigurationData newCollectionItem(String configName) {
+        ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
+        if (configMetadata != null) {
+            return new ConfigurationDataImpl(configMetadata);
+        }
+        return null;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationManagerImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,99 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.spi.ConfigurationPersistenceStrategy;
+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 ConfigurationPersistenceStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationPersistenceStrategyMultiplexer.class,
+reference={
+        @Reference(name="configurationResourcePersistenceStrategy", service=ConfigurationPersistenceStrategy.class,
+                bind="bindConfigurationResourcePersistenceStrategy", unbind="unbindConfigurationResourcePersistenceStrategy",
+                cardinality=ReferenceCardinality.MULTIPLE,
+                policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationPersistenceStrategyMultiplexer implements ConfigurationPersistenceStrategy {
+    
+    private RankedServices<ConfigurationPersistenceStrategy> items = new RankedServices<>(Order.DESCENDING);
+        
+    protected void bindConfigurationResourcePersistenceStrategy(ConfigurationPersistenceStrategy configurationResourcePersistenceStrategy, Map<String, Object> props) {
+        items.bind(configurationResourcePersistenceStrategy, props);
+    }
+    
+    protected void unbindConfigurationResourcePersistenceStrategy(ConfigurationPersistenceStrategy configurationResourcePersistenceStrategy, Map<String, Object> props) {
+        items.unbind(configurationResourcePersistenceStrategy, props);
+    }
+
+    /**
+     * Transform the configuration resource by the first implementation that has an answer.
+     */    
+    @Override
+    public Resource getResource(Resource resource) {
+        for (ConfigurationPersistenceStrategy item : items) {
+            Resource result = item.getResource(resource);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Persist configuration data with the first implementation that accepts it.
+     */
+    @Override
+    public boolean persist(ResourceResolver resourceResolver, String configResourcePath, Map<String,Object> properties) {
+        for (ConfigurationPersistenceStrategy item : items) {
+            if (item.persist(resourceResolver, configResourcePath, properties)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Persist configuration data with the first implementation that accepts it.
+     */
+    @Override
+    public boolean persistCollection(ResourceResolver resourceResolver, String configResourceCollectionParentPath,
+            Collection<Map<String,Object>> propertiesCollection) {
+        for (ConfigurationPersistenceStrategy item : items) {
+            if (item.persistCollection(resourceResolver, configResourceCollectionParentPath, propertiesCollection)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ConfigurationPersistenceStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,64 @@
+/*
+ * 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.contextaware.config.management.impl;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.sling.contextaware.config.management.ValueInfo;
+import org.apache.sling.contextaware.config.spi.metadata.PropertyMetadata;
+
+final class ValueInfoImpl<T> implements ValueInfo<T> {
+    
+    private final T value;
+    private final T defaultValue;
+    private final String configSourcePath;
+    private final PropertyMetadata<T> propertyMetadata;
+    
+    public ValueInfoImpl(T value, String configSourcePath, PropertyMetadata<T> propertyMetadata) {
+        this.value = value;
+        this.defaultValue = propertyMetadata != null ? propertyMetadata.getDefaultValue() : null;
+        this.configSourcePath = configSourcePath;
+        this.propertyMetadata = propertyMetadata;
+    }
+
+    @Override
+    public PropertyMetadata<T> getPropertyMetadata() {
+        return propertyMetadata;
+    }
+
+    @Override
+    public T getValue() {
+        return value;
+    }
+
+    @Override
+    public T getEffectiveValue() {
+        return ObjectUtils.defaultIfNull(value, defaultValue);
+    }
+
+    @Override
+    public String getConfigSourcePath() {
+        return configSourcePath;
+    }
+
+    @Override
+    public boolean isDefault() {
+        return value == null && defaultValue != null;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/impl/ValueInfoImpl.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+/**
+ * Management API of the Context-Aware configuration implementation.
+ * This API is only indented for advanced use cases like writing a configuration editor,
+ * not for "normal" applications just reading configuration.
+ */
+@org.osgi.annotation.versioning.Version("1.0.0")
+package org.apache.sling.contextaware.config.management;

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/management/package-info.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java?rev=1761468&r1=1761467&r2=1761468&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolverImpl.java Mon Sep 19 15:39:17 2016
@@ -20,255 +20,37 @@ package org.apache.sling.contextaware.co
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.contextaware.config.resource.ConfigurationResourceResolver;
-import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.metatype.annotations.AttributeDefinition;
-import org.osgi.service.metatype.annotations.Designate;
-import org.osgi.service.metatype.annotations.ObjectClassDefinition;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.osgi.service.component.annotations.Reference;
 
 @Component(service=ConfigurationResourceResolver.class, immediate=true)
-@Designate(ocd=ConfigurationResourceResolverImpl.Config.class)
 public class ConfigurationResourceResolverImpl implements ConfigurationResourceResolver {
 
-    @ObjectClassDefinition(name="Apache Sling Context Aware Configuration Resolver",
-                           description="Standardized access to configurations in the resource tree.")
-    public static @interface Config {
-
-        @AttributeDefinition(name="Allowed paths",
-                             description = "Whitelist of paths where configurations can reside in.")
-        String[] allowedPaths() default {"/conf", "/apps/conf", "/libs/conf"};
-
-        @AttributeDefinition(name="Fallback paths",
-                description = "Global fallback configurations, ordered from most specific (checked first) to least specific.")
-        String[] fallbackPaths() default {"/conf/global", "/apps/conf", "/libs/conf"};
-    }
-
-    private static final String PROPERTY_CONFIG = "sling:config-ref";
-
-    private final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    private volatile Config configuration;
-
-    Config getConfiguration() {
-        return this.configuration;
-    }
-
-    @Activate
-    private void activate(final Config config) {
-        this.configuration = config;
-    }
-
-    @Deactivate
-    private void deactivate() {
-        this.configuration = null;
-    }
-
-    List<String> getResolvePaths(final Resource contentResource) {
-        final List<String> refPaths = new ArrayList<>();
-
-        // add all config references found in resource hierarchy
-        final List<ConfigReference> refs = new ArrayList<>();
-        findConfigRefs(refs, contentResource);
-        for (ConfigReference ref : refs) {
-            refPaths.add(ref.getConfigReference());
-        }
-
-        // finally add the global fallbacks
-        if ( this.configuration.fallbackPaths() != null ) {
-            for(final String path : this.configuration.fallbackPaths()) {
-                logger.debug("[{}] fallback config => {}", refs.size(), path);
-                refPaths.add(path);
-            }
-        }
-
-        return refPaths;
-    }
-
-    /**
-     * Check the name.
-     * A name must not be null and relative.
-     * @param name The name
-     * @return {@code true} if it is valid
-     */
-    private boolean checkName(final String name) {
-        if (name == null || name.isEmpty() || name.startsWith("/") || name.contains("../") ) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Find next configuration refrence for given resource or one of it's parents.
-     * @param startResource Resource to start searching
-     * @return Config reference or null if none found
-     */
-    private ConfigReference findNextConfigRef(final Resource startResource) {
-        // start at resource, go up
-        Resource resource = startResource;
-        while (resource != null) {
-            String ref = getReference(resource);
-            if (ref != null) {
-                // if absolute path found we are (probably) done
-                if (ref.startsWith("/")) {
-                    // combine full path if relativeRef is present
-                    ref = ResourceUtil.normalize(ref);
-
-                    if (ref != null && !isAllowedConfigPath(ref)) {
-                        logger.warn("Ignoring reference to {} from {} - not in allowed paths.", ref, resource.getPath());
-                        ref = null;
-                    }
-
-                    if (ref != null && isFallbackConfigPath(ref)) {
-                        logger.warn("Ignoring reference to {} from {} - already a fallback path.", ref, resource.getPath());
-                        ref = null;
-                    }
-
-                    if (ref != null) {
-                        return new ConfigReference(resource, ref);
-                    }
-
-                } else {
-                    logger.error("Invalid relative reference found for {} : {}. This entry is ignored", resource.getPath(), ref);
-                }
-            }
-            // if getParent() returns null, stop
-            resource = resource.getParent();
-        }
-
-        // if hit root and nothing found, return null
-        return null;
-    }
-
-    /**
-     * Searches the resource hierarchy upwards for all config references and returns them.
-     * @param refs List to add found resources to
-     * @param startResource Resource to start searching
-     */
-    private void findConfigRefs(final List<ConfigReference> refs, final Resource startResource) {
-        ConfigReference ref = findNextConfigRef(startResource);
-        if (ref != null) {
-            refs.add(ref);
-            findConfigRefs(refs, ref.getContentResource().getParent());
-        }
-    }
-
-    private String getReference(final Resource resource) {
-        final String ref = resource.getValueMap().get(PROPERTY_CONFIG, String.class);
-        logger.trace("Reference '{}' found at {}", ref, resource.getPath());
-
-        return ref;
-    }
-
-    private boolean isAllowedConfigPath(String path) {
-        if (this.configuration.allowedPaths() == null) {
-            return false;
-        }
-        for (String pattern : this.configuration.allowedPaths()) {
-            if (logger.isTraceEnabled()) {
-                logger.trace("- checking if '{}' starts with {}", path, pattern);
-            }
-            if (path.equals(pattern) || path.startsWith(pattern + "/")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isFallbackConfigPath(final String ref) {
-        if ( this.configuration.fallbackPaths() != null ) {
-            for(final String name : this.configuration.fallbackPaths()) {
-                if ( name.equals(ref) ) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
+    @Reference
+    private ContextPathStrategyMultiplexer contextPathStrategy;
+    @Reference
+    private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
 
     @Override
-    public Resource getResource(final Resource contentResource, final String bucketName, final String configName) {
-        if (contentResource == null || !checkName(bucketName) || !checkName(configName)) {
-            return null;
-        }
-        String name = bucketName + "/" + configName;
-        logger.debug("Searching {} for resource {}", name, contentResource.getPath());
-
-        // strategy: find first item among all configured paths
-        int idx = 1;
-        for (final String path : getResolvePaths(contentResource)) {
-            final Resource item = contentResource.getResourceResolver().getResource(ResourceUtil.normalize(path + "/" + name));
-            if (item != null) {
-                logger.debug("Resolved config item at [{}]: {}", idx, item.getPath());
-
-                return item;
-            }
-            idx++;
-        }
-
-        logger.debug("Could not resolve any config item for '{}' (or no permissions to read it)", name);
-
-        // nothing found
-        return null;
+    public Resource getResource(Resource resource, String bucketName, String configName) {
+        return configurationResourceResolvingStrategy.getResource(resource, bucketName, configName);
     }
 
     @Override
-    public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
-        if (contentResource == null || !checkName(bucketName) || !checkName(configName)) {
-            return Collections.emptyList();
-        }
-        String name = bucketName + "/" + configName;
-        if (logger.isTraceEnabled()) {
-            logger.trace("- searching for list '{}'", name);
-        }
-
-        final Set<String> names = new HashSet<>();
-        final List<Resource> result = new ArrayList<>();
-        int idx = 1;
-        for (String path : this.getResolvePaths(contentResource)) {
-            Resource item = contentResource.getResourceResolver().getResource(ResourceUtil.normalize(path + "/" + name));
-            if (item != null) {
-                if (logger.isTraceEnabled()) {
-                    logger.trace("+ resolved config item at [{}]: {}", idx, item.getPath());
-                }
-
-                for (Resource child : item.getChildren()) {
-                    if ( !child.getName().contains(":") && !names.contains(child.getName()) ) {
-                        result.add(child);
-                        names.add(child.getName());
-                    }
-                }
-
-            } else {
-                if (logger.isTraceEnabled()) {
-                    logger.trace("- no item '{}' under config '{}'", name, path);
-                }
-            }
-            idx++;
-        }
-
-        if (logger.isTraceEnabled()) {
-            logger.trace("- final list has {} items", result.size());
-        }
-
-        return result;
+    public Collection<Resource> getResourceCollection(Resource resource, String bucketName, String configName) {
+        return configurationResourceResolvingStrategy.getResourceCollection(resource, bucketName, configName);
     }
 
     @Override
     public String getContextPath(Resource resource) {
-        ConfigReference ref = findNextConfigRef(resource);
-        if (ref != null) {
-            return ref.getContentResource().getPath();
+        Iterator<Resource> it = contextPathStrategy.findContextResources(resource);
+        if (it.hasNext()) {
+            return it.next().getPath();
         }
         else {
             return null;
@@ -278,28 +60,11 @@ public class ConfigurationResourceResolv
     @Override
     public Collection<String> getAllContextPaths(Resource resource) {
         final List<String> contextPaths = new ArrayList<>();
-        final List<ConfigReference> refs = new ArrayList<>();
-        findConfigRefs(refs, resource);
-        for (ConfigReference ref : refs) {
-            contextPaths.add(ref.getContentResource().getPath());
+        Iterator<Resource> contextResources = contextPathStrategy.findContextResources(resource);
+        while (contextResources.hasNext()) {
+            contextPaths.add(contextResources.next().getPath());
         }
         return contextPaths;
     }
 
-    private static class ConfigReference {
-        private final Resource contentResource;
-        private final String configReference;
-
-        public ConfigReference(Resource contentResource, String configReference) {
-            this.contentResource = contentResource;
-            this.configReference = configReference;
-        }
-        public Resource getContentResource() {
-            return contentResource;
-        }
-        public String getConfigReference() {
-            return configReference;
-        }
-    }
-
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,113 @@
+/*
+ * 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.contextaware.config.resource.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.resource.spi.ConfigurationResourceResolvingStrategy;
+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 ConfigurationResourceResolvingStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationResourceResolvingStrategyMultiplexer.class,
+reference={
+        @Reference(name="configurationResourceResolvingStrategy", service=ConfigurationResourceResolvingStrategy.class,
+                bind="bindConfigurationResourceResolvingStrategy", unbind="unbindConfigurationResourceResolvingStrategy",
+                cardinality=ReferenceCardinality.MULTIPLE,
+                policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationResourceResolvingStrategyMultiplexer implements ConfigurationResourceResolvingStrategy {
+    
+    private RankedServices<ConfigurationResourceResolvingStrategy> items = new RankedServices<>(Order.DESCENDING);
+        
+    protected void bindConfigurationResourceResolvingStrategy(ConfigurationResourceResolvingStrategy contextPathStrategy, Map<String, Object> props) {
+        items.bind(contextPathStrategy, props);
+    }
+    
+    protected void unbindConfigurationResourceResolvingStrategy(ConfigurationResourceResolvingStrategy contextPathStrategy, Map<String, Object> props) {
+        items.unbind(contextPathStrategy, props);
+    }
+
+    /**
+     * Gets the configuration resource from the first implementation that has an answer.
+     */
+    @Override
+    public Resource getResource(Resource resource, String bucketName, String configName) {
+        for (ConfigurationResourceResolvingStrategy item : items) {
+            Resource result = item.getResource(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Merge the configuration resources from all implementations into a combined list.
+     */
+    @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));
+        }
+        return result;
+    }
+
+    /**
+     * Gets the configuration resource path from the first implementation that has an answer.
+     */
+    @Override
+    public String getResourcePath(Resource resource, String bucketName, String configName) {
+        for (ConfigurationResourceResolvingStrategy item : items) {
+            String result = item.getResourcePath(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the configuration resource collection parent path from the first implementation that has an answer.
+     */
+    @Override
+    public String getResourceCollectionParentPath(Resource resource, String bucketName, String configName) {
+        for (ConfigurationResourceResolvingStrategy item : items) {
+            String result = item.getResourceCollectionParentPath(resource, bucketName, configName);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ConfigurationResourceResolvingStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,127 @@
+/*
+ * 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.contextaware.config.resource.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.collections.iterators.CollatingIterator;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.contextaware.config.resource.spi.ContextPathStrategy;
+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 ContextPathStrategy} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ContextPathStrategyMultiplexer.class,
+reference={
+        @Reference(name="contextPathStrategy", service=ContextPathStrategy.class,
+                bind="bindContextPathStrategy", unbind="unbindContextPathStrategy",
+                cardinality=ReferenceCardinality.MULTIPLE,
+                policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ContextPathStrategyMultiplexer implements ContextPathStrategy {
+    
+    private static Comparator<Resource> PATH_LENGTH_COMPARATOR = new Comparator<Resource>() {
+        @Override
+        public int compare(Resource o1, Resource o2) {
+            Integer length1 = o1.getPath().length();
+            Integer length2 = o2.getPath().length();
+            return length2.compareTo(length1);
+        }
+    };
+    
+    private RankedServices<ContextPathStrategy> items = new RankedServices<>(Order.DESCENDING);
+        
+    protected void bindContextPathStrategy(ContextPathStrategy contextPathStrategy, Map<String, Object> props) {
+        items.bind(contextPathStrategy, props);
+    }
+    
+    protected void unbindContextPathStrategy(ContextPathStrategy contextPathStrategy, Map<String, Object> props) {
+        items.unbind(contextPathStrategy, props);
+    }
+
+    /**
+     * Merges all results from the detected implementations into a single answer.
+     */
+    @Override
+    public Iterator<Resource> findContextResources(Resource resource) {
+        List<Iterator<Resource>> allResults = getAllResults(resource);
+        if (allResults.isEmpty()) {
+            return Collections.emptyIterator();
+        }
+        if (allResults.size() == 1) {
+            return allResults.get(0);
+        }
+        return mergeResults(allResults);
+    }
+    
+    /**
+     * Get all results from all registered context path strategies.
+     * @param resource Start resource
+     * @return List of all results
+     */
+    private List<Iterator<Resource>> getAllResults(Resource resource) {
+        List<Iterator<Resource>> results = new ArrayList<>();
+        for (ContextPathStrategy item : items) {
+            Iterator<Resource> result = item.findContextResources(resource);
+            if (result.hasNext()) {
+                results.add(result);
+            }
+        }
+        return results;
+    }
+    
+    /**
+     * Merges results from different context path strategy implementations.
+     * Eliminating of duplicates and sorting is done solely based on path length.
+     * The contract of the ContextPathStrategy defines that only parents or the resource itself
+     * is returned, so the assumption should be safe.
+     * @param allResults List of all results
+     * @return Merged result
+     */
+    @SuppressWarnings("unchecked")
+    private Iterator<Resource> mergeResults(List<Iterator<Resource>> allResults) {
+        return new FilterIterator(new CollatingIterator(PATH_LENGTH_COMPARATOR, allResults),
+                // eliminate duplicate resources reported by different implementations
+                new Predicate() {
+                    private Set<String> resourcePaths = new HashSet<>();
+                    @Override
+                    public boolean evaluate(Object object) {
+                        return resourcePaths.add(((Resource)object).getPath());
+                    }
+                });
+    }
+    
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/ContextPathStrategyMultiplexer.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,301 @@
+/*
+ * 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.contextaware.config.resource.impl.def;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+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.FilterIterator;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.commons.collections.iterators.TransformIterator;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.contextaware.config.resource.impl.ContextPathStrategyMultiplexer;
+import org.apache.sling.contextaware.config.resource.spi.ConfigurationResourceResolvingStrategy;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service=ConfigurationResourceResolvingStrategy.class)
+@Designate(ocd=DefaultConfigurationResourceResolvingStrategy.Config.class)
+public class DefaultConfigurationResourceResolvingStrategy implements ConfigurationResourceResolvingStrategy {
+
+    @ObjectClassDefinition(name="Apache Sling Context-Aware Default Configuration Resource Resolving Strategy",
+                           description="Standardized access to configurations in the resource tree.")
+    static @interface Config {
+
+        @AttributeDefinition(name="Enabled",
+                description = "Enable this configuration resourcer resolving strategy.")
+        boolean enabled() default true;
+        
+        @AttributeDefinition(name="Allowed paths",
+                             description = "Whitelist of paths where configurations can reside in.")
+        String[] allowedPaths() default {"/conf", "/apps/conf", "/libs/conf"};
+
+        @AttributeDefinition(name="Fallback paths",
+                description = "Global fallback configurations, ordered from most specific (checked first) to least specific.")
+        String[] fallbackPaths() default {"/conf/global", "/apps/conf", "/libs/conf"};
+    }
+
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    private volatile Config config;
+    
+    @Reference
+    private ContextPathStrategyMultiplexer contextPathStrategy;
+
+    Config getConfiguration() {
+        return this.config;
+    }
+
+    @Activate
+    private void activate(final Config config) {
+        this.config = config;
+    }
+
+    @Deactivate
+    private void deactivate() {
+        this.config = null;
+    }
+
+    @SuppressWarnings("unchecked")
+    Iterator<String> getResolvePaths(final Resource contentResource) {
+        return new IteratorChain(
+            // add all config references found in resource hierarchy
+            findConfigRefs(contentResource),
+            // finally add the global fallbacks
+            new ArrayIterator(this.config.fallbackPaths())
+        );
+    }
+
+    /**
+     * Check the name.
+     * A name must not be null and relative.
+     * @param name The name
+     * @return {@code true} if it is valid
+     */
+    private boolean checkName(final String name) {
+        if (name == null || name.isEmpty() || name.startsWith("/") || name.contains("../") ) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Searches the resource hierarchy upwards for all config references and returns them.
+     * @param refs List to add found resources to
+     * @param startResource Resource to start searching
+     */
+    @SuppressWarnings("unchecked")
+    private Iterator<String> findConfigRefs(final Resource startResource) {
+        Iterator<Resource> contextResources = contextPathStrategy.findContextResources(startResource);
+        // get config resource path for each context resource, filter out items where not reference could be resolved
+        return new FilterIterator(new TransformIterator(contextResources, new Transformer() {
+                @Override
+                public Object transform(Object input) {
+                    return getReference((Resource)input);
+                }
+            }), PredicateUtils.notNullPredicate());
+    }
+
+    private String getReference(final Resource resource) {
+        String ref = resource.getValueMap().get(DefaultContextPathStrategy.PROPERTY_CONFIG, String.class);
+
+        if (ref != null) {
+            // if absolute path found we are (probably) done
+            if (ref.startsWith("/")) {
+                // combine full path if relativeRef is present
+                ref = ResourceUtil.normalize(ref);
+
+                if (ref != null && !isAllowedConfigPath(ref)) {
+                    logger.warn("Ignoring reference to {} from {} - not in allowed paths.", ref, resource.getPath());
+                    ref = null;
+                }
+
+                if (ref != null && isFallbackConfigPath(ref)) {
+                    logger.warn("Ignoring reference to {} from {} - already a fallback path.", ref, resource.getPath());
+                    ref = null;
+                }
+
+            } else {
+                logger.error("Invalid relative reference found for {} : {}. This entry is ignored", resource.getPath(), ref);
+            }
+        }
+        
+        if (ref != null) {
+            logger.trace("Reference '{}' found at {}", ref, resource.getPath());
+        }
+
+        return ref;
+    }
+
+    private boolean isAllowedConfigPath(String path) {
+        for (String pattern : this.config.allowedPaths()) {
+            if (logger.isTraceEnabled()) {
+                logger.trace("- checking if '{}' starts with {}", path, pattern);
+            }
+            if (path.equals(pattern) || path.startsWith(pattern + "/")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isFallbackConfigPath(final String ref) {
+        for(final String name : this.config.fallbackPaths()) {
+            if ( name.equals(ref) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private boolean isEnabledAndParamsValid(final Resource contentResource, final String bucketName, final String configName) {
+        return config.enabled() && contentResource != null && checkName(bucketName) && checkName(configName);
+    }
+    
+    private String buildResourcePath(String path, String name) {
+        return ResourceUtil.normalize(path + "/" + name);
+    }
+
+    @Override
+    public Resource getResource(final Resource contentResource, final String bucketName, final String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+            return null;
+        }
+        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);
+        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 item;
+            }
+            idx++;
+        }
+
+        logger.debug("Could not resolve any config item for '{}' (or no permissions to read it)", name);
+
+        // nothing found
+        return null;
+    }
+
+    @Override
+    public Collection<Resource> getResourceCollection(final Resource contentResource, final String bucketName, final String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+            return Collections.emptyList();
+        }
+        String name = bucketName + "/" + configName;
+        if (logger.isTraceEnabled()) {
+            logger.trace("- searching for list '{}'", name);
+        }
+
+        final Set<String> names = new HashSet<>();
+        final List<Resource> result = new ArrayList<>();
+        int idx = 1;
+        Iterator<String> paths = getResolvePaths(contentResource);
+        while (paths.hasNext()) {
+            final String path = paths.next();
+            Resource item = contentResource.getResourceResolver().getResource(buildResourcePath(path, name));
+            if (item != null) {
+                if (logger.isTraceEnabled()) {
+                    logger.trace("+ resolved config item at [{}]: {}", idx, item.getPath());
+                }
+
+                for (Resource child : item.getChildren()) {
+                    if ( !child.getName().contains(":") && !names.contains(child.getName()) ) {
+                        result.add(child);
+                        names.add(child.getName());
+                    }
+                }
+
+            } else {
+                if (logger.isTraceEnabled()) {
+                    logger.trace("- no item '{}' under config '{}'", name, path);
+                }
+            }
+            idx++;
+        }
+
+        if (logger.isTraceEnabled()) {
+            logger.trace("- final list has {} items", result.size());
+        }
+
+        return result;
+    }
+    
+    @Override
+    public String getResourcePath(Resource contentResource, String bucketName, String configName) {
+        if (!isEnabledAndParamsValid(contentResource, bucketName, configName)) {
+            return null;
+        }
+        String name = bucketName + "/" + configName;
+
+        Iterator<String> configPaths = this.findConfigRefs(contentResource);
+        if (configPaths.hasNext()) {
+            String configPath = buildResourcePath(configPaths.next(), name);
+            logger.debug("Building configuration path {} for resource {}: {}", name, contentResource.getPath(), configPath);
+            return configPath;
+        }
+        else {
+            logger.debug("No configuration path {}  foundfor 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);
+        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;
+        }
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultConfigurationResourceResolvingStrategy.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java?rev=1761468&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java Mon Sep 19 15:39:17 2016
@@ -0,0 +1,132 @@
+/*
+ * 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.contextaware.config.resource.impl.def;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.contextaware.config.resource.spi.ContextPathStrategy;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(service = ContextPathStrategy.class)
+@Designate(ocd=DefaultContextPathStrategy.Config.class)
+public class DefaultContextPathStrategy implements ContextPathStrategy {
+
+    @ObjectClassDefinition(name="Apache Sling Context-Aware Default Context Path Strategy",
+            description="Detects context path by existence of " + PROPERTY_CONFIG + " properties.")
+    static @interface Config {
+        
+        @AttributeDefinition(name="Enabled",
+                      description = "Enable this context path strategy.")
+        boolean enabled() default true;
+        
+    }
+    
+    /**
+     * Property that points to the configuration to be used.
+     * Additionally each resource having this property marks the beginning of a new context sub-tree.
+     */
+    public static final String PROPERTY_CONFIG = "sling:config-ref";
+   
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+    
+    private volatile Config config;
+    
+    @Activate
+    private void activate(ComponentContext componentContext, Config config) {
+        this.config = config; 
+    }
+    
+    @Override
+    public Iterator<Resource> findContextResources(Resource resource) {
+        if (!config.enabled()) {
+            return Collections.emptyIterator();
+        }
+        return new ConfigResourceIterator(resource);
+    }
+    
+    /**
+     * Searches the resource hierarchy upwards for all context and returns the root resource for each of them.
+     */
+    private class ConfigResourceIterator implements Iterator<Resource> {
+
+        private Resource next;
+        
+        public ConfigResourceIterator(Resource startResource) {
+            next = findNextContextResource(startResource);
+        }
+        
+        @Override
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        @Override
+        public Resource next() {
+            if (next == null) {
+                throw new NoSuchElementException();
+            }
+            Resource result = next;
+            next = findNextContextResource(next.getParent());
+            return result;
+        }
+        
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Find next configuration context root for given resource.
+         * @param startResource Resource to start searching
+         * @return Next resource with sling:config-ref property or null if none found.
+         */
+        private Resource findNextContextResource(Resource startResource) {
+            // start at resource, go up
+            Resource resource = startResource;
+            
+            while (resource != null) {
+                if (hasConfigRef(resource)) {
+                    log.trace("Found context path '{}'.", resource.getPath());
+                    return resource;
+                }
+                // if getParent() returns null, stop
+                resource = resource.getParent();
+            }
+
+            // if hit root and nothing found, return null
+            return null;
+        }
+        
+        private boolean hasConfigRef(final Resource resource) {
+            return resource.getValueMap().get(PROPERTY_CONFIG, String.class) != null;
+        }
+
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/contextaware/config/resource/impl/def/DefaultContextPathStrategy.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon Sep 19 15:39:17 2016
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

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