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/18 23:42:02 UTC

svn commit: r1770448 [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/management...

Author: sseifert
Date: Fri Nov 18 23:42:02 2016
New Revision: 1770448

URL: http://svn.apache.org/viewvc?rev=1770448&view=rev
Log:
SLING-6060 Context-Aware Config: Configuration property override providers

Added:
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManagerTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/DummyConfigurationOverrideProvider.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProviderTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/OverrideItemTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/OverrideStringParserTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProviderTest.java   (with props)
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationOverrideProvider.java   (with props)
Removed:
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/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/impl/def/DefaultConfigurationInheritanceStrategy.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ValueInfo.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ValueInfoImpl.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverValueMapTest.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/management/impl/ConfigurationDataImplTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java
    sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ValueInfoImplTest.java
    sling/trunk/contrib/extensions/contextaware-config/spi/pom.xml
    sling/trunk/contrib/extensions/contextaware-config/spi/src/main/java/org/apache/sling/caconfig/spi/ConfigurationMetadataProvider.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=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/pom.xml Fri Nov 18 23:42:02 2016
@@ -74,19 +74,19 @@
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.osgi</artifactId>
             <version>2.4.0</version>
-            <scope>provided</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.caconfig.api</artifactId>
             <version>1.0.0</version>
-            <scope>provided</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.caconfig.spi</artifactId>
             <version>1.1.1-SNAPSHOT</version>
-            <scope>provided</scope>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>com.google.code.findbugs</groupId>
@@ -110,6 +110,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.10</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <version>3.3.2</version>

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=1770448&r1=1770447&r2=1770448&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 Fri Nov 18 23:42:02 2016
@@ -36,6 +36,7 @@ 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.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.resource.spi.ConfigurationResourceResolvingStrategy;
 import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
 import org.apache.sling.caconfig.spi.ConfigurationPersistenceStrategy;
@@ -47,6 +48,7 @@ class ConfigurationBuilderImpl implement
     private final ConfigurationResourceResolvingStrategy configurationResourceResolvingStrategy;
     private final ConfigurationPersistenceStrategy configurationPersistenceStrategy;
     private final ConfigurationInheritanceStrategy configurationInheritanceStrategy;
+    private final ConfigurationOverrideManager configurationOverrideManager;
 
     private String configName;
 
@@ -54,12 +56,14 @@ class ConfigurationBuilderImpl implement
             final ConfigurationResolver configurationResolver,
             final ConfigurationResourceResolvingStrategy configurationResourceResolvingStrategy,
             final ConfigurationPersistenceStrategy configurationPersistenceStrategy,
-            final ConfigurationInheritanceStrategy configurationInheritanceStrategy) {
+            final ConfigurationInheritanceStrategy configurationInheritanceStrategy,
+            final ConfigurationOverrideManager configurationOverrideManager) {
         this.contentResource = resource;
         this.configurationResolver = configurationResolver;
         this.configurationResourceResolvingStrategy = configurationResourceResolvingStrategy;
         this.configurationPersistenceStrategy = configurationPersistenceStrategy;
         this.configurationInheritanceStrategy = configurationInheritanceStrategy;
+        this.configurationOverrideManager = configurationOverrideManager;
     }
 
     @Override
@@ -159,6 +163,8 @@ class ConfigurationBuilderImpl implement
                     });
             // apply resource inheritance
             configResource = configurationInheritanceStrategy.getResource(transformedResources);
+            // apply overrides
+            configResource = configurationOverrideManager.overrideProperties(contentResource.getPath(), name, configResource);
             // build name
             if (configResource != null && appendResourceName) {
                 conversionName = conversionName + "/" + configResource.getName();

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=1770448&r1=1770447&r2=1770448&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 Fri Nov 18 23:42:02 2016
@@ -22,6 +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.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
@@ -31,17 +32,18 @@ public class ConfigurationResolverImpl i
 
     @Reference
     private ConfigurationResourceResolvingStrategyMultiplexer configurationResourceResolvingStrategy;
-
     @Reference
     private ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy;
-    
     @Reference
     private ConfigurationInheritanceStrategyMultiplexer configurationInheritanceStrategy;
+    @Reference
+    private ConfigurationOverrideManager configurationOverrideManager;
     
     @Override
     public ConfigurationBuilder get(Resource resource) {
         return new ConfigurationBuilderImpl(resource, this,
-                configurationResourceResolvingStrategy, configurationPersistenceStrategy, configurationInheritanceStrategy);
+                configurationResourceResolvingStrategy, configurationPersistenceStrategy,
+                configurationInheritanceStrategy, configurationOverrideManager);
     }
 
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,61 @@
+/*
+ * 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 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.
+ */
+public final class ConfigurationResourceWrapper extends ResourceWrapper {
+    
+    private final ValueMap props;
+
+    public ConfigurationResourceWrapper(Resource resource, ValueMap props) {
+        super(unwrap(resource));
+        this.props = props;
+    }
+    
+    private static Resource unwrap(Resource resource) {
+        if (resource instanceof ConfigurationResourceWrapper) {
+            return ((ConfigurationResourceWrapper)resource).getResource();
+        }
+        else {
+            return resource;
+        }
+    }
+
+    @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/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/ConfigurationResourceWrapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: 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=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/impl/def/DefaultConfigurationInheritanceStrategy.java Fri Nov 18 23:42:02 2016
@@ -26,6 +26,7 @@ import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.caconfig.impl.ConfigurationResourceWrapper;
 import org.apache.sling.caconfig.spi.ConfigurationInheritanceStrategy;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.metatype.annotations.AttributeDefinition;

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ValueInfo.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ValueInfo.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ValueInfo.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/ValueInfo.java Fri Nov 18 23:42:02 2016
@@ -74,13 +74,6 @@ public interface ValueInfo<T> {
     /**
      * @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();
+    boolean isOverridden();
     
 }

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImpl.java Fri Nov 18 23:42:02 2016
@@ -32,6 +32,7 @@ import org.apache.sling.api.resource.Val
 import org.apache.sling.api.wrappers.ValueMapDecorator;
 import org.apache.sling.caconfig.management.ConfigurationData;
 import org.apache.sling.caconfig.management.ValueInfo;
+import org.apache.sling.caconfig.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
 import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
 
@@ -41,20 +42,29 @@ final class ConfigurationDataImpl implem
     private final Resource resolvedConfigurationResource;
     private final Resource writebackConfigurationResource;
     private final List<Resource> configurationResourceInheritanceChain;
+    private final Resource contextResource;
+    private final String configName;
+    private final ConfigurationOverrideManager configurationOverrideManager;
     
     @SuppressWarnings("unchecked")
     public ConfigurationDataImpl(ConfigurationMetadata configMetadata,
             Resource resolvedConfigurationResource, Resource writebackConfigurationResource,
-            Iterator<Resource> configurationResourceInheritanceChain) {
+            Iterator<Resource> configurationResourceInheritanceChain,
+            Resource contextResource, String configName, ConfigurationOverrideManager configurationOverrideManager) {
         this.configMetadata = configMetadata;
         this.resolvedConfigurationResource = resolvedConfigurationResource;
         this.writebackConfigurationResource = writebackConfigurationResource;
         this.configurationResourceInheritanceChain = configurationResourceInheritanceChain != null
                 ? IteratorUtils.toList(configurationResourceInheritanceChain) : null;
+        this.contextResource = contextResource;
+        this.configName = configName;
+        this.configurationOverrideManager = configurationOverrideManager;
     }
 
-    public ConfigurationDataImpl(ConfigurationMetadata configMetadata) {
-        this(configMetadata, null, null, null);
+    public ConfigurationDataImpl(ConfigurationMetadata configMetadata,
+            Resource contextResource, String configName, ConfigurationOverrideManager configurationOverrideManager) {
+        this(configMetadata, null, null, null,
+                contextResource, configName, configurationOverrideManager);
     }
 
     @Override
@@ -117,7 +127,10 @@ final class ConfigurationDataImpl implem
                 propertyMetadata,
                 resolvedConfigurationResource,
                 writebackConfigurationResource,
-                configurationResourceInheritanceChain);
+                configurationResourceInheritanceChain,
+                contextResource,
+                configName,
+                configurationOverrideManager);
     }
 
 }

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImpl.java Fri Nov 18 23:42:02 2016
@@ -35,6 +35,7 @@ import org.apache.sling.caconfig.impl.Co
 import org.apache.sling.caconfig.impl.metadata.ConfigurationMetadataProviderMultiplexer;
 import org.apache.sling.caconfig.management.ConfigurationData;
 import org.apache.sling.caconfig.management.ConfigurationManager;
+import org.apache.sling.caconfig.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.resource.impl.ConfigurationResourceResolvingStrategyMultiplexer;
 import org.apache.sling.caconfig.spi.ConfigurationPersistenceException;
 import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
@@ -52,6 +53,8 @@ public class ConfigurationManagerImpl im
     private ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy;
     @Reference
     private ConfigurationInheritanceStrategyMultiplexer configurationInheritanceStrategy;
+    @Reference
+    private ConfigurationOverrideManager configurationOverrideManager;
 
     @SuppressWarnings("unchecked")
     @Override
@@ -60,7 +63,7 @@ public class ConfigurationManagerImpl im
         Iterator<Resource> configResourceInheritanceChain = configurationResourceResolvingStrategy
                 .getResourceInheritanceChain(resource, CONFIGS_PARENT_NAME, configName);
         ResettableIterator resettableConfigResourceInheritanceChain = new ListIteratorWrapper(configResourceInheritanceChain);
-        Resource configResource = applyPersistenceAndInheritance(resettableConfigResourceInheritanceChain);
+        Resource configResource = applyPersistenceAndInheritance(resource.getPath(), configName, resettableConfigResourceInheritanceChain);
         if (configResource != null) {
             // get writeback resource for "reverse inheritance detection"
             Resource writebackConfigResource = null;
@@ -73,11 +76,13 @@ public class ConfigurationManagerImpl im
             }
             resettableConfigResourceInheritanceChain.reset();
             return new ConfigurationDataImpl(configMetadata, configResource, writebackConfigResource,
-                    applyPersistence(resettableConfigResourceInheritanceChain));
+                    applyPersistence(resettableConfigResourceInheritanceChain),
+                    resource, configName, configurationOverrideManager);
         }
         if (configMetadata != null) {
             // if no config resource found but config metadata exist return empty config data with default values
-            return new ConfigurationDataImpl(configMetadata);
+            return new ConfigurationDataImpl(configMetadata,
+                    resource, configName, configurationOverrideManager);
         }
         return null;
     }
@@ -93,7 +98,7 @@ public class ConfigurationManagerImpl im
                 .getResourceCollectionInheritanceChain(resource, CONFIGS_PARENT_NAME, configName);
         for (Iterator<Resource> configResourceInheritanceChain : configResourceInheritanceChains) {
             ResettableIterator resettableConfigResourceInheritanceChain = new ListIteratorWrapper(configResourceInheritanceChain);
-            Resource configResource = applyPersistenceAndInheritance(resettableConfigResourceInheritanceChain);
+            Resource configResource = applyPersistenceAndInheritance(resource.getPath(), configName, resettableConfigResourceInheritanceChain);
             if (configResource != null) {
                 // get writeback resource for "reverse inheritance detection"
                 Resource writebackConfigResource = null;
@@ -108,7 +113,8 @@ public class ConfigurationManagerImpl im
                 }
                 resettableConfigResourceInheritanceChain.reset();
                 configData.add(new ConfigurationDataImpl(configMetadata, configResource, writebackConfigResource,
-                        applyPersistence(resettableConfigResourceInheritanceChain)));
+                        applyPersistence(resettableConfigResourceInheritanceChain),
+                        resource, configName, configurationOverrideManager));
             }
         }
         return configData;
@@ -128,7 +134,7 @@ public class ConfigurationManagerImpl im
                 });
     }
 
-    private Resource applyPersistenceAndInheritance(Iterator<Resource> configResourceInheritanceChain) {
+    private Resource applyPersistenceAndInheritance(String contextPath, String configName, Iterator<Resource> configResourceInheritanceChain) {
         if (configResourceInheritanceChain == null) {
             return null;
         }
@@ -137,7 +143,10 @@ public class ConfigurationManagerImpl im
         Iterator<Resource> transformedConfigResources = applyPersistence(configResourceInheritanceChain);
         
         // apply resource inheritance
-        return configurationInheritanceStrategy.getResource(transformedConfigResources);
+        Resource configResource = configurationInheritanceStrategy.getResource(transformedConfigResources);
+        
+        // apply overrides
+        return configurationOverrideManager.overrideProperties(contextPath, configName, configResource);
     }
 
     @Override
@@ -166,7 +175,8 @@ public class ConfigurationManagerImpl im
     public ConfigurationData newCollectionItem(String configName) {
         ConfigurationMetadata configMetadata = configurationMetadataProvider.getConfigurationMetadata(configName);
         if (configMetadata != null) {
-            return new ConfigurationDataImpl(configMetadata);
+            return new ConfigurationDataImpl(configMetadata,
+                    null, configName, configurationOverrideManager);
         }
         return null;
     }

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ValueInfoImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ValueInfoImpl.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ValueInfoImpl.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/management/impl/ValueInfoImpl.java Fri Nov 18 23:42:02 2016
@@ -18,13 +18,16 @@
  */
 package org.apache.sling.caconfig.management.impl;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.caconfig.management.ValueInfo;
+import org.apache.sling.caconfig.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
 
 final class ValueInfoImpl<T> implements ValueInfo<T> {
@@ -36,10 +39,14 @@ final class ValueInfoImpl<T> implements
     private final Resource resolvedConfigurationResource;
     private final Resource writebackConfigurationResource;
     private final List<Resource> configurationResourceInheritanceChain;
+    private final Resource contextResource;
+    private final String configName;
+    private final ConfigurationOverrideManager configurationOverrideManager;
     
     public ValueInfoImpl(String name, T value, PropertyMetadata<T> propertyMetadata,
             Resource resolvedConfigurationResource, Resource writebackConfigurationResource,
-            List<Resource> configurationResourceInheritanceChain) {
+            List<Resource> configurationResourceInheritanceChain,
+            Resource contextResource, String configName, ConfigurationOverrideManager configurationOverrideManager) {
         this.name = name;
         this.value = value;
         this.defaultValue = propertyMetadata != null ? propertyMetadata.getDefaultValue() : null;
@@ -47,6 +54,9 @@ final class ValueInfoImpl<T> implements
         this.resolvedConfigurationResource = resolvedConfigurationResource;
         this.writebackConfigurationResource = writebackConfigurationResource;
         this.configurationResourceInheritanceChain = configurationResourceInheritanceChain;
+        this.contextResource = contextResource;
+        this.configName = configName;
+        this.configurationOverrideManager = configurationOverrideManager;
     }
     
     @Override
@@ -59,9 +69,18 @@ final class ValueInfoImpl<T> implements
         return propertyMetadata;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public T getValue() {
-        return value;
+        if (writebackConfigurationResource == null) {
+            return null;
+        }
+        else if (propertyMetadata != null) {
+            return writebackConfigurationResource.getValueMap().get(name, propertyMetadata.getType());
+        }
+        else {
+            return (T)writebackConfigurationResource.getValueMap().get(name);
+        }
     }
 
     @Override
@@ -128,4 +147,21 @@ final class ValueInfoImpl<T> implements
         }
         return getResourceFromInheritanceChain(inheritanceChain);
     }
+
+    @Override
+    public boolean isOverridden() {
+        if (contextResource == null) {
+            return false;
+        }
+        Map<String,Object> overrideProperties = configurationOverrideManager.overrideProperties(
+                    contextResource.getPath(), configName, Collections.<String,Object>emptyMap());
+        if (overrideProperties != null) {
+            return overrideProperties.containsKey(name)
+                    || (getValue() != null && value == null);
+        }
+        else {
+            return false;
+        }
+    }
+
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,128 @@
+/*
+ * 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.override.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.caconfig.impl.ConfigurationResourceWrapper;
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
+import org.apache.sling.commons.osgi.Order;
+import org.apache.sling.commons.osgi.RankedServices;
+import org.apache.sling.commons.osgi.RankedServices.ChangeListener;
+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 ConfigurationOverrideProvider} implementations in the container
+ * and consolidates their result based on service ranking.
+ */
+@Component(service = ConfigurationOverrideManager.class,
+reference={
+        @Reference(name="configurationOverrideProvider", service=ConfigurationOverrideProvider.class,
+                bind="bindConfigurationOverrideProvider", unbind="unbindConfigurationOverrideProvider",
+                cardinality=ReferenceCardinality.MULTIPLE,
+                policy=ReferencePolicy.DYNAMIC, policyOption=ReferencePolicyOption.GREEDY)
+})
+public class ConfigurationOverrideManager implements ChangeListener {
+
+    private RankedServices<ConfigurationOverrideProvider> items = new RankedServices<>(Order.DESCENDING, this);
+    private volatile Collection<OverrideItem> allOverrides = Collections.emptyList();
+    
+    protected void bindConfigurationOverrideProvider(ConfigurationOverrideProvider item, Map<String, Object> props) {
+        items.bind(item, props);
+    }
+    
+    protected void unbindConfigurationOverrideProvider(ConfigurationOverrideProvider item, Map<String, Object> props) {
+        items.unbind(item, props);
+    }
+
+    /**
+     * Override properties for given context path and configuration name.
+     * @param contextPath Path of context resource for which configuration was resolved
+     * @param configName Configuration name
+     * @param properties Resolved configuration properties
+     * @return Overwritten or replaced properties - or null if no override took place
+     */
+    public Map<String,Object> overrideProperties(String contextPath, String configName, Map<String,Object> properties) {
+        if (allOverrides.size() == 0) {
+            return null;
+        }
+        boolean anyMatch = false;
+        Map<String,Object> overrideProperties = new HashMap<>(properties);
+        
+        for (OverrideItem override : allOverrides) {
+            if (StringUtils.equals(configName, override.getConfigName()) && override.matchesPath(contextPath)) {
+                if (override.isAllProperties()) {
+                    overrideProperties.clear();
+                }
+                overrideProperties.putAll(override.getProperties());
+                anyMatch = true;
+            }
+        }
+        
+        if (anyMatch) {
+            return overrideProperties;
+        }
+        else {
+            return null;
+        }
+    }
+    
+    /**
+     * Override properties in given configuration resource (if any overrides are defined).
+     * @param contextPath Context path
+     * @param configName Configuration name
+     * @param configResource Resolved configuration resource
+     * @return Resource with overwritten configuration properties - or original configuration resource if no override took place
+     */
+    public Resource overrideProperties(String contextPath, String configName, Resource configResource) {
+        if (configResource == null) {
+            return null;
+        }
+        Map<String,Object> overrideProperties = overrideProperties(contextPath, configName, configResource.getValueMap());
+        if (overrideProperties == null) {
+            return configResource;
+        }
+        return new ConfigurationResourceWrapper(configResource, new ValueMapDecorator(overrideProperties));
+    }
+
+    /**
+     * If a provider is added or removed parse and collect all overrides again (to ensure correct overall order is preserved).
+     */
+    @Override
+    public void changed() {
+        List<OverrideItem> overrides = new ArrayList<>();
+        for (ConfigurationOverrideProvider item : items) {
+            overrides.addAll(OverrideStringParser.parse(item.getOverrideStrings()));
+        }
+        allOverrides = overrides;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManager.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/override/impl/ConfigurationOverrideManager.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,84 @@
+/*
+ * 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.override.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
+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;
+
+/**
+ * Provides parameter override map from OSGi factory configuration.
+ */
+@Component(service = ConfigurationOverrideProvider.class, immediate = true)
+@Designate(ocd = OsgiConfigurationOverrideProvider.Config.class, factory = true)
+public final class OsgiConfigurationOverrideProvider implements ConfigurationOverrideProvider {
+
+    @ObjectClassDefinition(name = "Apache Sling Context-Aware OSGi Configuration Override Provider",
+            description = "Allows to override configuration property values from OSGi configurations.")
+    public static @interface Config {
+
+        @AttributeDefinition(name = "Description",
+                description = "This description is used for display in the web console.")
+        String description();
+
+        @AttributeDefinition(name = "Overrides",
+                description = "Override strings - examples:<br>\n"
+                + "{configName}/{propertyName}={propertyJsonValue}<br>\n"
+                + "{configName}={propertyJsonObject}<br>\n"
+                + "[{contextPath}]{configName}/{propertyName}={propertyJsonValue}<br>\n"
+                + "[{contextPath}]{configName}={propertyJsonObject}")
+        String[] overrides();
+
+        @AttributeDefinition(name = "Enabled",
+                description = "Enable this override provider.")
+        boolean enabled() default false;
+
+        @AttributeDefinition(name = "Service Ranking",
+                description = "Priority of configuration override providers (higher = higher priority).")
+        int service_ranking() default 100;
+        
+        String webconsole_configurationFactory_nameHint() default "{description}, enabled={enabled}";
+
+    }
+
+    private Collection<String> overrideStrings;
+
+    @Activate
+    void activate(Config config) {
+        List<String> overrides = new ArrayList<>();
+        if (config.enabled()) {
+            overrides.addAll(Arrays.asList(config.overrides()));
+        }
+        this.overrideStrings = overrides;
+    }
+
+    @Override
+    public Collection<String> getOverrideStrings() {
+        return overrideStrings;
+    }
+    
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OsgiConfigurationOverrideProvider.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/override/impl/OsgiConfigurationOverrideProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,95 @@
+/*
+ * 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.override.impl;
+
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Holds override information provided by override providers.
+ */
+class OverrideItem {
+
+    private final String path;
+    private final Pattern pathPattern;
+    private final String configName;
+    private final Map<String,Object> properties;
+    private final boolean allProperties;
+    
+    public OverrideItem(String path, String configName,
+            Map<String, Object> properties, boolean allProperties) {
+        this.path = path;
+        this.pathPattern = toPathPattern(path);
+        this.configName = configName;
+        this.properties = properties;
+        this.allProperties = allProperties;
+    }
+    
+    private static Pattern toPathPattern(String path) {
+        if (StringUtils.isBlank(path)) {
+            return null;
+        }
+        return Pattern.compile("^" + Pattern.quote(StringUtils.trim(path)) + "(/.*)?$");
+    }
+
+    /**
+     * @return Path (incl. subtree) to match - or null for all paths
+     */
+    public String getPath() {
+        return path;
+    }
+    
+    /**
+     * @param path Path to check
+     * @return true if path matches
+     */
+    public boolean matchesPath(String path) {
+        if (pathPattern == null) {
+            return true;
+        }
+        else {
+            return pathPattern.matcher(path).matches();
+        }
+    }
+
+    /**
+     * @return Configuration name (may contain a relative hierarchy with "/")
+     */
+    public String getConfigName() {
+        return configName;
+    }
+
+    /**
+     * @return Properties map
+     */
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    /**
+     * @return If true, all properties for this config name should be replaced
+     *    with those from the map. Otherwise they are merged.
+     */
+    public boolean isAllProperties() {
+        return allProperties;
+    }
+    
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideItem.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/override/impl/OverrideItem.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,273 @@
+/*
+ * 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.override.impl;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Parses override configuration strings like these:
+ * <ul>
+ * <li><code>{configName}/{propertyName}={propertyJsonValue}</code></li>
+ * <li><code>{configName}={propertyJsonObject}</code></li>
+ * <li><code>[{contextPath}]{configName}/{propertyName}={propertyJsonValue}</code></li>
+ * <li><code>[{contextPath}]{configName}={propertyJsonObject}</code></li>
+ * </ul>
+ */
+class OverrideStringParser {
+    
+    private static final Logger log = LoggerFactory.getLogger(OverrideStringParser.class);
+    
+    private static final Pattern OVERRIDE_PATTERN = Pattern.compile("^(\\[([^\\[\\]=]+)\\])?([^\\[\\]=]+)=(.*)$");
+    
+    private OverrideStringParser() {
+        // static method sonly
+    }
+    
+    /**
+     * Parses a list of override strings from a override provider.
+     * @param overrideStrings Override strings
+     * @return Override objects
+     */
+    public static Collection<OverrideItem> parse(Collection<String> overrideStrings) {
+        List<OverrideItem> result = new ArrayList<>();
+        
+        for (String overrideString : overrideStrings) {
+            
+            // check if override generic pattern is matched
+            Matcher matcher = OVERRIDE_PATTERN.matcher(StringUtils.defaultString(overrideString));
+            if (!matcher.matches()) {
+                log.warn("Ignore config override string - invalid syntax: {}", overrideString);
+                continue;
+            }
+            
+            // get single parts
+            String path = StringUtils.trim(matcher.group(2));
+            String configName = StringUtils.trim(matcher.group(3));
+            String value = StringUtils.trim(StringUtils.defaultString(matcher.group(4)));
+            
+            OverrideItem item;
+            try {
+                // check if value is JSON = defines whole parameter map for a config name
+                JSONObject json = toJson(value);
+                if (json != null) {
+                    item = new OverrideItem(path, configName, toMap(json), true);
+                }
+                else {
+                    // otherwise it defines a key/value pair in a single line
+                    String propertyName = StringUtils.substringAfterLast(configName, "/");
+                    if (StringUtils.isEmpty(propertyName)) {
+                        log.warn("Ignore config override string - missing property name: {}", overrideString);
+                        continue;
+                    }
+                    configName = StringUtils.substringBeforeLast(configName, "/");
+                    Map<String,Object> props = new HashMap<>();
+                    props.put(propertyName, convertJsonValue(value));
+                    item = new OverrideItem(path, configName, props, false);
+                }
+            }
+            catch (JSONException ex) {
+                log.warn("Ignore config override string - invalid JSON syntax ({}): {}", ex.getMessage(), overrideString);
+                continue;
+            }
+            
+            // convert arrays
+            convertArrays(item.getProperties());
+            
+            // validate item
+            if (!isValid(item, overrideString)) {
+                continue;
+            }
+            
+            // if item does not contain a full property set try to merge with existing one
+            if (!item.isAllProperties()) {
+                boolean foundMatchingItem = false;
+                for (OverrideItem existingItem : result) {
+                    if (!existingItem.isAllProperties()
+                            && StringUtils.equals(item.getPath(), existingItem.getPath())
+                            && StringUtils.equals(item.getConfigName(), existingItem.getConfigName())) {
+                        existingItem.getProperties().putAll(item.getProperties());
+                        foundMatchingItem = true;
+                        break;
+                    }
+                }
+                if (foundMatchingItem) {
+                    continue;
+                }
+            }
+            
+            // add item to result
+            result.add(item);
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Try to convert value to JSON object
+     * @param value Value string
+     * @return JSON object or null if the string does not start with "{"
+     * @throws JSONException when JSON parsing failed
+     */
+    private static JSONObject toJson(String value) throws JSONException {
+        if (!StringUtils.startsWith(value, "{")) {
+            return null;
+        }
+        return new JSONObject(value);
+    }
+    
+    /**
+     * Convert JSON object to map.
+     * @param json JSON object
+     * @return Map (keys/values are not validated)
+     */
+    private static Map<String,Object> toMap(JSONObject json) {
+        Map<String,Object> props = new HashMap<>();
+        Iterator<String> keys = json.keys();
+        while (keys.hasNext()) {
+            String key = keys.next();
+            try {
+                props.put(key, json.get(key));
+            }
+            catch (JSONException e) {
+                // should never happen
+            }
+        }
+        return props;
+    }
+    
+    /**
+     * Convert single JSON-conformant value object
+     * @param jsonValue JSON value
+     * @return Object
+     * @throws JSONException If JSON-parsing of value failed
+     */
+    private static Object convertJsonValue(String jsonValue) throws JSONException {
+        String jsonString = "{\"value\":" + jsonValue + "}";
+        JSONObject json = toJson(jsonString);
+        return json.opt("value");
+    }
+    
+    /**
+     * Convert all JSON arrays in the properties map to Java Array counterparts. Invalid arrays are ignored.
+     * @param props Properties
+     */
+    private static void convertArrays(Map<String,Object> props) {
+        Map<String,Object> convertedProps = new HashMap<>();
+        for (Map.Entry<String, Object> entry : props.entrySet()) {
+            Object value = entry.getValue();
+            if (value.getClass().equals(JSONArray.class)) {
+                JSONArray array = (JSONArray)value;
+                if (array.length() == 0) {             
+                    convertedProps.put(entry.getKey(), new String[0]);
+                }
+                else {
+                    Object firstValue = array.opt(0);
+                    if (firstValue != null) {
+                        try {
+                            Class firstType = firstValue.getClass();
+                            Object convertedArray = Array.newInstance(firstType, array.length());
+                            for (int i=0; i<array.length(); i++) {
+                                Array.set(convertedArray, i, array.opt(i));
+                            }
+                            convertedProps.put(entry.getKey(), convertedArray);
+                        }
+                        catch (IllegalArgumentException ex) {
+                            // ignore arrays with mixed types - will fail later in validation
+                        }
+                    }
+                }
+            }
+        }
+        if (!convertedProps.isEmpty()) {
+            props.putAll(convertedProps);
+        }
+    }
+    
+    /**
+     * Validate override item and it's properties map.
+     * @param item Override item
+     * @param overrideString Override string
+     * @return true if item is valid
+     */
+    private static boolean isValid(OverrideItem item, String overrideString) {
+        if (item.getPath() != null && (!StringUtils.startsWith(item.getPath(), "/") || StringUtils.contains(item.getPath(), "."))) {
+            log.warn("Ignore config override string - invalid path: {}", overrideString);
+            return false;
+        }
+        if (StringUtils.startsWith(item.getConfigName(), "/") || StringUtils.contains(item.getConfigName(), ".")) {
+            log.warn("Ignore config override string - invalid configName: {}", overrideString);
+            return false;
+        }
+        for (Map.Entry<String, Object> entry : item.getProperties().entrySet()) {
+            String propertyName = entry.getKey();
+            if (StringUtils.isEmpty(propertyName) || StringUtils.contains(propertyName, "/")) {
+                log.warn("Ignore config override string - invalid property name ({}): {}", propertyName, overrideString);
+                return false;
+            }
+            Object value = entry.getValue();
+            if (value == null || !isSupportedType(value)) {
+                log.warn("Ignore config override string - invalid property value ({} - {}): {}", value, value.getClass().getName(), overrideString);
+                return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Validate if the given object is not null, and the type is supported for configuration values.
+     * @param value Value
+     * @return true if valid
+     */
+    private static boolean isSupportedType(Object value) {
+        if (value == null) {
+            return false;
+        }
+        Class clazz = value.getClass();
+        if (clazz.isArray()) {
+            clazz = clazz.getComponentType();
+        }
+        for (Class type : PropertyMetadata.SUPPORTED_TYPES) {
+            if (type.equals(clazz )) {
+                return true;
+            }
+            if (type.isPrimitive() && ClassUtils.primitiveToWrapper(type).equals(clazz)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/OverrideStringParser.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/override/impl/OverrideStringParser.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java Fri Nov 18 23:42:02 2016
@@ -0,0 +1,89 @@
+/*
+ * 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.override.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
+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;
+
+/**
+ * Provides parameter override map from system properties.
+ */
+@Component(service = ConfigurationOverrideProvider.class, immediate = true)
+@Designate(ocd = SystemPropertyConfigurationOverrideProvider.Config.class)
+public final class SystemPropertyConfigurationOverrideProvider implements ConfigurationOverrideProvider {
+
+    /**
+     * Prefix for override system property
+     */
+    public static final String SYSTEM_PROPERTY_PREFIX = "sling.config.override.";
+
+    @ObjectClassDefinition(name = "Apache Sling Context-Aware System Property Configuration Override Provider",
+            description = "Allows to override configuration property values from system environment properties.")
+    public static @interface Config {
+
+        @AttributeDefinition(name = "Enabled",
+                description = "Enable this override provider.")
+        boolean enabled() default false;
+
+        @AttributeDefinition(name = "Service Ranking",
+                description = "Priority of configuration override providers (higher = higher priority).")
+        int service_ranking() default 200;
+
+    }
+
+    private Collection<String> overrideStrings;
+
+    @Activate
+    void activate(Config config) {
+        List<String> overrides = new ArrayList<>();
+
+        if (config.enabled()) {
+            Properties properties = System.getProperties();
+            Enumeration<Object> keys = properties.keys();
+            while (keys.hasMoreElements()) {
+                Object keyObject = keys.nextElement();
+                if (keyObject instanceof String) {
+                    String key = (String) keyObject;
+                    if (StringUtils.startsWith(key, SYSTEM_PROPERTY_PREFIX)) {
+                        overrides.add(StringUtils.substringAfter(key, SYSTEM_PROPERTY_PREFIX) + "=" + System.getProperty(key));
+                    }
+                }
+            }
+        }
+
+        this.overrideStrings = overrides;
+    }
+
+    @Override
+    public Collection<String> getOverrideStrings() {
+        return overrideStrings;
+    }
+
+}

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

Propchange: sling/trunk/contrib/extensions/contextaware-config/impl/src/main/java/org/apache/sling/caconfig/override/impl/SystemPropertyConfigurationOverrideProvider.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Fri Nov 18 23:42:02 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/override/impl/SystemPropertyConfigurationOverrideProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverValueMapTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverValueMapTest.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverValueMapTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/impl/ConfigurationResolverValueMapTest.java Fri Nov 18 23:42:02 2016
@@ -30,6 +30,8 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.caconfig.ConfigurationResolveException;
 import org.apache.sling.caconfig.ConfigurationResolver;
+import org.apache.sling.caconfig.override.impl.DummyConfigurationOverrideProvider;
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
 import org.junit.Rule;
@@ -102,6 +104,42 @@ public class ConfigurationResolverValueM
     }
 
     @Test
+    public void testConfigWithOverride() {
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "[/content]sampleName={stringParam='override1',intParam=222}"));
+
+        context.build().resource("/conf/content/site1/sling:configs/sampleName", 
+                "stringParam", "configValue1",
+                "intParam", 111,
+                "boolParam", true);
+
+        ValueMap props = underTest.get(site1Page1).name("sampleName").asValueMap();
+
+        assertEquals("override1", props.get("stringParam", String.class));
+        assertEquals(222, (int)props.get("intParam", 0));
+        assertEquals(false, props.get("boolParam", false));
+    }
+
+    @Test
+    public void testConfigCollectionWithOverride() {
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "[/content]sampleList/stringParam='override1'"));
+
+        context.build().resource("/conf/content/site1/sling:configs/sampleList")
+            .siblingsMode()
+            .resource("1", "stringParam", "configValue1.1")
+            .resource("2", "stringParam", "configValue1.2")
+            .resource("3", "stringParam", "configValue1.3");
+
+        Collection<ValueMap> propsList = underTest.get(site1Page1).name("sampleList").asValueMapCollection();
+
+        Iterator<ValueMap> propsIterator = propsList.iterator();
+        assertEquals("override1", propsIterator.next().get("stringParam", String.class));
+        assertEquals("override1", propsIterator.next().get("stringParam", String.class));
+        assertEquals("override1", propsIterator.next().get("stringParam", String.class));
+    }
+
+    @Test
     public void testNonExistingContentResource() {
         ValueMap props = underTest.get(null).name("sampleName").asValueMap();
 

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=1770448&r1=1770447&r2=1770448&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 Fri Nov 18 23:42:02 2016
@@ -22,6 +22,7 @@ import org.apache.sling.caconfig.Configu
 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.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.resource.impl.ConfigurationResourceTestUtils;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 
@@ -41,6 +42,7 @@ public final class ConfigurationTestUtil
         context.registerInjectActivateService(new ConfigurationPersistenceStrategyMultiplexer());
         context.registerInjectActivateService(new DefaultConfigurationInheritanceStrategy());
         context.registerInjectActivateService(new ConfigurationInheritanceStrategyMultiplexer());
+        context.registerInjectActivateService(new ConfigurationOverrideManager());
         return context.registerInjectActivateService(new ConfigurationResolverImpl());
     }
     

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationDataImplTest.java Fri Nov 18 23:42:02 2016
@@ -26,20 +26,29 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.caconfig.management.ConfigurationData;
 import org.apache.sling.caconfig.management.ValueInfo;
+import org.apache.sling.caconfig.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
 import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
 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.runners.MockitoJUnitRunner;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
+@RunWith(MockitoJUnitRunner.class)
 public class ConfigurationDataImplTest {
     
     @Rule
     public SlingContext context = new SlingContext();
+    @Mock
+    private Resource contextResource;
+    @Mock
+    private ConfigurationOverrideManager configurationOverrideManager;
     
     private Resource configResource;
     private ConfigurationMetadata configMetadata;
@@ -58,7 +67,8 @@ public class ConfigurationDataImplTest {
 
     @Test
     public void testWithResourceMetadata() {
-        ConfigurationData underTest = new ConfigurationDataImpl(configMetadata, configResource, configResource, null);
+        ConfigurationData underTest = new ConfigurationDataImpl(configMetadata, configResource, configResource, null,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals(configResource.getPath(), underTest.getResourcePath());
         assertEquals(ImmutableSet.of("prop1", "prop2", "prop3", "prop4"), underTest.getPropertyNames());
@@ -93,7 +103,8 @@ public class ConfigurationDataImplTest {
 
     @Test
     public void testWithResourceOnly() {
-        ConfigurationData underTest = new ConfigurationDataImpl(null, configResource, configResource, null);
+        ConfigurationData underTest = new ConfigurationDataImpl(null, configResource, configResource, null,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals(ImmutableSet.of("prop1", "prop4"), underTest.getPropertyNames());
         
@@ -118,7 +129,8 @@ public class ConfigurationDataImplTest {
 
     @Test
     public void testMetadataOnly() {
-        ConfigurationData underTest = new ConfigurationDataImpl(configMetadata);
+        ConfigurationData underTest = new ConfigurationDataImpl(configMetadata,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals(ImmutableSet.of("prop1", "prop2", "prop3"), underTest.getPropertyNames());
         

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ConfigurationManagerImplTest.java Fri Nov 18 23:42:02 2016
@@ -38,7 +38,9 @@ import org.apache.sling.caconfig.impl.Co
 import org.apache.sling.caconfig.impl.metadata.ConfigurationMetadataProviderMultiplexer;
 import org.apache.sling.caconfig.management.ConfigurationData;
 import org.apache.sling.caconfig.management.ConfigurationManager;
+import org.apache.sling.caconfig.override.impl.DummyConfigurationOverrideProvider;
 import org.apache.sling.caconfig.spi.ConfigurationMetadataProvider;
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
 import org.apache.sling.caconfig.spi.metadata.ConfigurationMetadata;
 import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
@@ -197,6 +199,25 @@ public class ConfigurationManagerImplTes
     }
 
     @Test
+    public void testGet_WithOverride() {
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "[/content]" + CONFIG_NAME + "={prop1='override1'}"));
+        
+        ConfigurationData configData = underTest.get(contextResource, CONFIG_NAME);
+        assertNotNull(configData);
+
+        assertEquals(ImmutableSet.of("prop1", "prop2", "prop3"), configData.getPropertyNames());
+        assertEquals("value1", configData.getValues().get("prop1", String.class));
+        assertEquals("override1", configData.getEffectiveValues().get("prop1", String.class));
+        assertEquals((Integer)5, configData.getEffectiveValues().get("prop3", 0));
+
+        assertFalse(configData.getValueInfo("prop1").isInherited());
+        assertTrue(configData.getValueInfo("prop1").isOverridden());
+        assertFalse(configData.getValueInfo("prop3").isInherited());
+        assertFalse(configData.getValueInfo("prop3").isOverridden());
+    }
+
+    @Test
     public void testGet_NoConfigResource() {
         ConfigurationData configData = underTest.get(contextResourceNoConfig, CONFIG_NAME);
         assertNotNull(configData);
@@ -330,6 +351,37 @@ public class ConfigurationManagerImplTes
     }
 
     @Test
+    public void testGetCollection_WithOverride() {
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "[/content]" + CONFIG_COL_NAME + "/prop1='override1'"));
+        
+        List<ConfigurationData> configDatas = ImmutableList.copyOf(underTest.getCollection(contextResource, CONFIG_COL_NAME));
+        assertEquals(2, configDatas.size());
+
+        ConfigurationData configData1 = configDatas.get(0);
+        assertEquals(ImmutableSet.of("prop1", "prop2", "prop3"), configData1.getPropertyNames());
+        assertEquals("value1", configData1.getValues().get("prop1", String.class));
+        assertEquals("override1", configData1.getEffectiveValues().get("prop1", String.class));
+        assertEquals((Integer)5, configData1.getEffectiveValues().get("prop3", 0));
+
+        assertFalse(configData1.getValueInfo("prop1").isInherited());
+        assertTrue(configData1.getValueInfo("prop1").isOverridden());
+        assertFalse(configData1.getValueInfo("prop3").isInherited());
+        assertFalse(configData1.getValueInfo("prop3").isOverridden());
+        
+        ConfigurationData configData2 = configDatas.get(1);
+        assertEquals(ImmutableSet.of("prop1", "prop2", "prop3", "prop4"), configData2.getPropertyNames());
+        assertNull(configData2.getValues().get("prop1", String.class));
+        assertEquals("override1", configData2.getEffectiveValues().get("prop1", String.class));
+        assertEquals((Integer)5, configData2.getEffectiveValues().get("prop3", 0));
+
+        assertFalse(configData2.getValueInfo("prop1").isInherited());
+        assertTrue(configData2.getValueInfo("prop1").isOverridden());
+        assertFalse(configData2.getValueInfo("prop3").isInherited());
+        assertFalse(configData2.getValueInfo("prop3").isOverridden());
+    }
+
+    @Test
     public void testGetCollection_NoConfigResources() {
         List<ConfigurationData> configDatas = ImmutableList.copyOf(underTest.getCollection(contextResourceNoConfig, CONFIG_COL_NAME));
         assertEquals(0, configDatas.size());

Modified: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ValueInfoImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ValueInfoImplTest.java?rev=1770448&r1=1770447&r2=1770448&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ValueInfoImplTest.java (original)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/management/impl/ValueInfoImplTest.java Fri Nov 18 23:42:02 2016
@@ -24,14 +24,25 @@ import static org.junit.Assert.assertNul
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import org.apache.sling.api.resource.Resource;
 import org.apache.sling.caconfig.management.ValueInfo;
+import org.apache.sling.caconfig.override.impl.ConfigurationOverrideManager;
 import org.apache.sling.caconfig.spi.metadata.PropertyMetadata;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
 
+@RunWith(MockitoJUnitRunner.class)
 public class ValueInfoImplTest {
     
     private PropertyMetadata<String> propertyMetadata;
+    
+    @Mock
+    private Resource contextResource;
+    @Mock
+    private ConfigurationOverrideManager configurationOverrideManager;
 
     @Before
     public void setUp() {
@@ -40,20 +51,23 @@ public class ValueInfoImplTest {
     
     @Test
     public void testValueMetadata() {
-        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", "value", propertyMetadata, null, null, null);
+        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", "value", propertyMetadata, null, null, null,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals("name1", underTest.getName());
         assertSame(propertyMetadata, underTest.getPropertyMetadata());
-        assertEquals("value", underTest.getValue());
+        assertNull(underTest.getValue());
         assertEquals("value", underTest.getEffectiveValue());
         assertNull(underTest.getConfigSourcePath());
         assertFalse(underTest.isDefault());
         assertFalse(underTest.isInherited());
+        assertFalse(underTest.isOverridden());
     }
 
     @Test
     public void testNoValueMetadata() {
-        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", null, propertyMetadata, null, null, null);
+        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", null, propertyMetadata, null, null, null,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals("name1", underTest.getName());
         assertSame(propertyMetadata, underTest.getPropertyMetadata());
@@ -62,19 +76,22 @@ public class ValueInfoImplTest {
         assertNull(underTest.getConfigSourcePath());
         assertTrue(underTest.isDefault());
         assertFalse(underTest.isInherited());
+        assertFalse(underTest.isOverridden());
     }
 
     @Test
     public void testValueNoMetadata() {
-        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", "value", null, null, null, null);
+        ValueInfo<String> underTest = new ValueInfoImpl<>("name1", "value", null, null, null, null,
+                contextResource, "test", configurationOverrideManager);
         
         assertEquals("name1", underTest.getName());
         assertNull(underTest.getPropertyMetadata());
-        assertEquals("value", underTest.getValue());
+        assertNull(underTest.getValue());
         assertEquals("value", underTest.getEffectiveValue());
         assertNull(underTest.getConfigSourcePath());
         assertFalse(underTest.isDefault());
         assertFalse(underTest.isInherited());
+        assertFalse(underTest.isOverridden());
     }
 
 }

Added: sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManagerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManagerTest.java?rev=1770448&view=auto
==============================================================================
--- sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManagerTest.java (added)
+++ sling/trunk/contrib/extensions/contextaware-config/impl/src/test/java/org/apache/sling/caconfig/override/impl/ConfigurationOverrideManagerTest.java Fri Nov 18 23:42:02 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.caconfig.override.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Map;
+
+import org.apache.sling.caconfig.spi.ConfigurationOverrideProvider;
+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.collect.ImmutableMap;
+
+public class ConfigurationOverrideManagerTest {
+    
+    @Rule
+    public SlingContext context = new SlingContext();
+    
+    private ConfigurationOverrideManager underTest;
+    
+    @Before
+    public void setUp() {
+        underTest = context.registerInjectActivateService(new ConfigurationOverrideManager());
+    }
+
+    @Test
+    public void testWithNoProviders() {
+        assertOverride("/a/b", "test",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                null);
+    }
+
+    @Test
+    public void testWithMultipleProviders() {
+
+        // 1st provider
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "test/globalParam1='globalValue1'",
+                "[/a/b]test/param1='value1'"), Constants.SERVICE_RANKING, 200);
+
+        // 2nd provider (may overwrite 1st one)
+        context.registerService(ConfigurationOverrideProvider.class, new DummyConfigurationOverrideProvider(
+                "test/globalParam1='globalValue1a'",
+                "[/a/b/c]test={'param1'='value2'}"), Constants.SERVICE_RANKING, 100);
+
+        assertOverride("/a", "test",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                ImmutableMap.<String,Object>of("param1", "initialValue", "globalParam1", "globalValue1a"));
+
+        assertOverride("/a/b", "test",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                ImmutableMap.<String,Object>of("param1", "value1", "globalParam1", "globalValue1a"));
+
+        assertOverride("/a/b/c", "test",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                ImmutableMap.<String,Object>of("param1", "value2"));
+
+        assertOverride("/a/b/c/d", "test",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                ImmutableMap.<String,Object>of("param1", "value2"));
+
+        assertOverride("/a/b", "test2",
+                ImmutableMap.<String,Object>of("param1", "initialValue"),
+                null);
+    }
+    
+    private void assertOverride(String path, String configName, Map<String,Object> input, Map<String,Object> output) {
+        if (output == null) {
+            assertNull(underTest.overrideProperties(path, configName, input));
+        }
+        else {
+            assertEquals(output, underTest.overrideProperties(path, configName, input));
+        }
+    }
+
+}