You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@archiva.apache.org by ma...@apache.org on 2019/02/12 23:20:50 UTC

[archiva-redback-core] branch master updated: Moving configuration projects into redback and update commons config version

This is an automated email from the ASF dual-hosted git repository.

martin_s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/archiva-redback-core.git


The following commit(s) were added to refs/heads/master by this push:
     new a528d21  Moving configuration projects into redback and update commons config version
a528d21 is described below

commit a528d214318ad43eb9a699004ffa3cdd75a32b50
Author: Martin Stockhammer <ma...@apache.org>
AuthorDate: Wed Feb 13 00:20:46 2019 +0100

    Moving configuration projects into redback and update commons config version
---
 pom.xml                                            |  17 +
 redback-common/pom.xml                             |   1 +
 .../{ => redback-common-configuration}/pom.xml     |  38 +-
 .../redback-common-configuration-acc2/pom.xml      | 107 ++++
 .../config/acc2/CommonsConfigurationRegistry.java  | 610 +++++++++++++++++++++
 .../src/main/resources/META-INF/spring-context.xml |  29 +
 .../common/config/acc2/AbstractRegistryTest.java   | 189 +++++++
 .../acc2/CommonsConfigurationRegistryTest.java     | 422 ++++++++++++++
 .../redback/common/config/acc2/Component.java      |  60 ++
 .../common/config/acc2/DefaultComponent.java       | 128 +++++
 .../archiva/redback/common/config/acc2/Nested.java |  33 ++
 .../src/test/resources/META-INF/spring-context.xml |  26 +
 .../src/test/resources/spring-context.xml          | 101 ++++
 .../src/test/resources/test-save.xml               |  23 +
 .../src/test/resources/test.properties             |  25 +
 .../src/test/resources/test.xml                    |  42 ++
 .../redback-common-configuration-api}/pom.xml      |  28 +-
 .../redback/common/config/api/ConfigRegistry.java  | 264 +++++++++
 .../common/config/api/RegistryException.java       |  38 ++
 .../common/config/api/RegistryListener.java        |  45 ++
 20 files changed, 2197 insertions(+), 29 deletions(-)

diff --git a/pom.xml b/pom.xml
index 61ab7fd..68ec204 100644
--- a/pom.xml
+++ b/pom.xml
@@ -308,6 +308,11 @@
         <version>${project.version}</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.archiva.redback</groupId>
+        <artifactId>redback-common-configuration-api</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>servlet-api</artifactId>
         <version>2.5</version>
@@ -648,6 +653,18 @@
         <artifactId>jaxb-api</artifactId>
         <version>2.3.0</version>
       </dependency>
+
+      <dependency>
+        <groupId>commons-beanutils</groupId>
+        <artifactId>commons-beanutils</artifactId>
+        <version>${commons-beanutils.version}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/redback-common/pom.xml b/redback-common/pom.xml
index 11391a9..7bc4277 100644
--- a/redback-common/pom.xml
+++ b/redback-common/pom.xml
@@ -35,5 +35,6 @@
     <module>redback-common-ldap</module>
     <module>redback-common-test-resources</module>
     <module>redback-common-jpa</module>
+    <module>redback-common-configuration</module>
   </modules>
 </project>
\ No newline at end of file
diff --git a/redback-common/pom.xml b/redback-common/redback-common-configuration/pom.xml
similarity index 63%
copy from redback-common/pom.xml
copy to redback-common/redback-common-configuration/pom.xml
index 11391a9..f1e8cf3 100644
--- a/redback-common/pom.xml
+++ b/redback-common/redback-common-configuration/pom.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one
   ~ or more contributor license agreements.  See the NOTICE file
@@ -17,23 +18,34 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
+    <artifactId>redback-common</artifactId>
     <groupId>org.apache.archiva.redback</groupId>
-    <artifactId>redback</artifactId>
     <version>3.0.0-SNAPSHOT</version>
   </parent>
-  <artifactId>redback-common</artifactId>
-  <name>Redback :: Commons</name>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>redback-common-configuration</artifactId>
   <packaging>pom</packaging>
-  <properties>
-    <site.staging.base>${project.parent.basedir}</site.staging.base>
-  </properties>
   <modules>
-    <module>redback-common-ldap</module>
-    <module>redback-common-test-resources</module>
-    <module>redback-common-jpa</module>
+    <module>redback-common-configuration-api</module>
+    <module>redback-common-configuration-acc2</module>
   </modules>
-</project>
\ No newline at end of file
+
+    <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <skipTests>true</skipTests>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/pom.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/pom.xml
new file mode 100644
index 0000000..0783bc9
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ 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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>redback-common-configuration</artifactId>
+    <groupId>org.apache.archiva.redback</groupId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>redback-common-configuration-acc2</artifactId>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.archiva.redback</groupId>
+      <artifactId>redback-common-configuration-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-configuration2</artifactId>
+      <version>2.4</version>
+      <exclusions>
+        <exclusion>
+          <groupId>commons-beanutils</groupId>
+          <artifactId>commons-beanutils-core</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>commons-beanutils</groupId>
+      <artifactId>commons-beanutils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>compile</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.annotation</groupId>
+      <artifactId>jsr250-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.inject</groupId>
+      <artifactId>javax.inject</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context-support</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-beans</artifactId>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistry.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistry.java
new file mode 100644
index 0000000..8fe30d9
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistry.java
@@ -0,0 +1,610 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.redback.common.config.api.ConfigRegistry;
+import org.apache.archiva.redback.common.config.api.RegistryException;
+import org.apache.archiva.redback.common.config.api.RegistryListener;
+import org.apache.commons.configuration2.CombinedConfiguration;
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.FileBasedConfiguration;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.commons.configuration2.SystemConfiguration;
+import org.apache.commons.configuration2.XMLConfiguration;
+import org.apache.commons.configuration2.builder.BasicConfigurationBuilder;
+import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.combined.CombinedConfigurationBuilder;
+import org.apache.commons.configuration2.builder.fluent.Parameters;
+import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
+import org.apache.commons.configuration2.interpol.DefaultLookups;
+import org.apache.commons.configuration2.interpol.InterpolatorSpecification;
+import org.apache.commons.configuration2.io.ClasspathLocationStrategy;
+import org.apache.commons.configuration2.io.FileHandler;
+import org.apache.commons.configuration2.io.FileSystem;
+import org.apache.commons.configuration2.io.FileSystemLocationStrategy;
+import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
+import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;
+import org.apache.commons.configuration2.tree.NodeCombiner;
+import org.apache.commons.configuration2.tree.UnionCombiner;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Pattern;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+
+/**
+ * Implementation of the registry component using
+ * <a href="http://commons.apache.org/commons/configuration">Commons Configuration</a>. The use of Commons Configuration
+ * enables a variety of sources to be used, including XML files, properties, JNDI, JDBC, etc.
+ * <p/>
+ * The component can be configured using the {@link #properties} configuration item, the content of which should take
+ * the format of an input to the Commons Configuration
+ * <a href="http://commons.apache.org/commons/configuration/howto_configurationbuilder.html">configuration
+ * builder</a>.
+ */
+@Service( "acc2-configuration" )
+public class CommonsConfigurationRegistry
+    implements ConfigRegistry
+{
+    /**
+     * The combined configuration instance that houses the registry.
+     */
+    private Configuration configuration;
+
+    private Logger logger = LoggerFactory.getLogger( getClass() );
+
+    private String propertyDelimiter = ".";
+
+    /**
+     * The configuration properties for the registry. This should take the format of an input to the Commons
+     * Configuration
+     * <a href="http://commons.apache.org/configuration/howto_configurationbuilder.html">configuration
+     * builder</a>.
+     */
+    private String properties;
+
+
+    public CommonsConfigurationRegistry()
+    {
+        // default constructor
+        logger.debug( "empty constructor" );
+    }
+
+    public CommonsConfigurationRegistry( Configuration configuration )
+    {
+        if ( configuration == null )
+        {
+            throw new NullPointerException( "configuration can not be null" );
+        }
+
+        this.configuration = configuration;
+    }
+
+    public String dump()
+    {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append( "Configuration Dump." );
+        for ( Iterator i = configuration.getKeys(); i.hasNext(); )
+        {
+            String key = (String) i.next();
+            Object value = configuration.getProperty( key );
+            buffer.append( "\n\"" ).append( key ).append( "\" = \"" ).append( value ).append( "\"" );
+        }
+        return buffer.toString();
+    }
+
+    public boolean isEmpty()
+    {
+        return configuration.isEmpty();
+    }
+
+    public ConfigRegistry getSubset( String key )
+    {
+        return new CommonsConfigurationRegistry( configuration.subset( key ) );
+    }
+
+    public List<String> getList( String key )
+    {
+        return configuration.getList(String.class,  key );
+    }
+
+    public List<ConfigRegistry> getSubsetList( String key )
+    {
+        List<ConfigRegistry> subsets = new ArrayList<>();
+
+        boolean done = false;
+        do
+        {
+            ConfigRegistry registry = getSubset( key + "(" + subsets.size() + ")" );
+            if ( !registry.isEmpty() )
+            {
+                subsets.add( registry );
+            }
+            else
+            {
+                done = true;
+            }
+        }
+        while ( !done );
+
+        return subsets;
+    }
+
+    @Override
+    public ConfigRegistry getSource( String name )
+    {
+        return null;
+    }
+
+    public Map<String,String> getProperties( String key )
+    {
+        Configuration configuration = this.configuration.subset( key );
+
+        Map<String,String> properties = new TreeMap<>();
+        Iterator<String> cfgIter = configuration.getKeys( );
+        String property;
+        while ( cfgIter.hasNext() )
+        {
+            property = cfgIter.next();
+            List<String> l = configuration.getList( String.class, property );
+            String value = String.join(",", l);
+            properties.put( property, value );
+        }
+        return properties;
+    }
+
+    public void save()
+        throws RegistryException
+    {
+        if ( configuration instanceof FileBasedConfiguration  )
+        {
+            FileBasedConfiguration fileConfiguration = (FileBasedConfiguration) configuration;
+            try
+            {
+                new FileHandler( fileConfiguration ).save();
+            }
+            catch ( ConfigurationException e )
+            {
+                throw new RegistryException( e.getMessage(), e );
+            }
+        }
+        else
+        {
+            throw new RegistryException( "Can only save file-based configurations" );
+        }
+    }
+
+    @Override
+    public void registerChangeListener( RegistryListener listener, Pattern... filter )
+    {
+
+    }
+
+    @Override
+    public boolean unregisterChangeListener( RegistryListener listener )
+    {
+        return false;
+    }
+
+
+    public Collection<String> getKeys()
+    {
+        Set<String> keys = new HashSet<String>();
+
+        for ( Iterator<String> i = configuration.getKeys(); i.hasNext(); )
+        {
+            String key = i.next();
+
+            int index = key.indexOf( '.' );
+            if ( index < 0 )
+            {
+                keys.add( key );
+            }
+            else
+            {
+                keys.add( key.substring( 0, index ) );
+            }
+        }
+
+        return keys;
+    }
+
+    public Collection getFullKeys()
+    {
+        Set<String> keys = new HashSet<String>();
+
+        for ( Iterator<String> i = configuration.getKeys(); i.hasNext(); )
+        {
+            keys.add( i.next() );
+        }
+
+        return keys;
+    }
+
+    public void remove( String key )
+    {
+        configuration.clearProperty( key );
+    }
+
+    public void removeSubset( String key )
+    {
+        // create temporary list since removing a key will modify the iterator from configuration
+        List keys = new ArrayList();
+        for ( Iterator i = configuration.getKeys( key ); i.hasNext(); )
+        {
+            keys.add( i.next() );
+        }
+
+        for ( Iterator i = keys.iterator(); i.hasNext(); )
+        {
+            configuration.clearProperty( (String) i.next() );
+        }
+    }
+
+    public String getString( String key )
+    {
+        return configuration.getString( key );
+    }
+
+    public String getString( String key, String defaultValue )
+    {
+        return configuration.getString( key, defaultValue );
+    }
+
+    public void setString( String key, String value )
+    {
+        configuration.setProperty( key, value );
+    }
+
+    public int getInt( String key )
+    {
+        return configuration.getInt( key );
+    }
+
+    public int getInt( String key, int defaultValue )
+    {
+        return configuration.getInt( key, defaultValue );
+    }
+
+    public void setInt( String key, int value )
+    {
+        configuration.setProperty( key, Integer.valueOf( value ) );
+    }
+
+    public boolean getBoolean( String key )
+    {
+        return configuration.getBoolean( key );
+    }
+
+    public boolean getBoolean( String key, boolean defaultValue )
+    {
+        return configuration.getBoolean( key, defaultValue );
+    }
+
+    public void setBoolean( String key, boolean value )
+    {
+        configuration.setProperty( key, Boolean.valueOf( value ) );
+    }
+
+    public void addConfigurationFromResource( String name, String resource )
+        throws RegistryException
+    {
+        addConfigurationFromResource( name, resource, null );
+    }
+
+    public void addConfigurationFromResource( String name, String resource, String prefix )
+        throws RegistryException
+    {
+        if (configuration instanceof CombinedConfiguration)
+        {
+            String atPrefix = StringUtils.isEmpty( prefix ) ? null : prefix;
+            CombinedConfiguration configuration = (CombinedConfiguration) this.configuration;
+            if ( resource.endsWith( ".properties" ) )
+            {
+                try
+                {
+                    logger.debug( "Loading properties configuration from classloader resource: {}", resource );
+                    FileBasedConfigurationBuilder<PropertiesConfiguration> builder = new FileBasedConfigurationBuilder<>( PropertiesConfiguration.class )
+                        .configure( new Parameters().properties()
+                            .setLocationStrategy( new ClasspathLocationStrategy() )
+                            .setFileName( resource ) );
+                    configuration.addConfiguration( builder.getConfiguration() , name, atPrefix );
+                }
+                catch ( ConfigurationException e )
+                {
+                    throw new RegistryException(
+                        "Unable to add configuration from resource '" + resource + "': " + e.getMessage( ), e );
+                }
+            }
+            else if ( resource.endsWith( ".xml" ) )
+            {
+                try
+                {
+                    logger.debug( "Loading XML configuration from classloader resource: {}", resource );
+                    FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class )
+                        .configure( new Parameters().xml()
+                            .setLocationStrategy( new ClasspathLocationStrategy() )
+                            .setFileName( resource ) );
+                    configuration.addConfiguration( builder.getConfiguration(), name, atPrefix );
+                }
+                catch ( ConfigurationException e )
+                {
+                    throw new RegistryException(
+                        "Unable to add configuration from resource '" + resource + "': " + e.getMessage( ), e );
+                }
+            }
+            else
+            {
+                throw new RegistryException(
+                    "Unable to add configuration from resource '" + resource + "': unrecognised type" );
+            }
+        } else {
+            throw new RegistryException( "The underlying configuration object is not a combined configuration " );
+        }
+    }
+
+    @Override
+    public void addConfigurationFromFile( String name, Path file ) throws RegistryException
+    {
+        addConfigurationFromFile( name, file, "" );
+    }
+
+    public void addConfigurationFromFile( String name, Path file, String prefix )
+        throws RegistryException
+    {
+        if (this.configuration instanceof CombinedConfiguration)
+        {
+            String atPrefix = StringUtils.isEmpty( prefix ) ? null : prefix;
+            CombinedConfiguration configuration = (CombinedConfiguration) this.configuration;
+            String fileName = file.getFileName().toString();
+            if ( fileName.endsWith( ".properties" ) )
+            {
+                try
+                {
+                    logger.debug( "Loading properties configuration from file: {}", file );
+                    FileBasedConfigurationBuilder<PropertiesConfiguration> builder = new FileBasedConfigurationBuilder<>( PropertiesConfiguration.class )
+                        .configure( new Parameters().properties()
+                            .setLocationStrategy( new FileSystemLocationStrategy() )
+                            .setFile( file.toFile() ) );
+                    configuration.addConfiguration( builder.getConfiguration() , name, atPrefix );
+                }
+                catch ( ConfigurationException e )
+                {
+                    throw new RegistryException(
+                        "Unable to add configuration from file '" + file.getFileName( ) + "': " + e.getMessage( ), e );
+                }
+            }
+            else if ( fileName.endsWith( ".xml" ) )
+            {
+                try
+                {
+                    logger.debug( "Loading XML configuration from file: {}", file );
+                    FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class )
+                        .configure( new Parameters().xml()
+                            .setLocationStrategy( new ClasspathLocationStrategy() )
+                            .setFile( file.toFile()) );
+                    configuration.addConfiguration( builder.getConfiguration(), name, atPrefix );
+                }
+                catch ( ConfigurationException e )
+                {
+                    throw new RegistryException(
+                        "Unable to add configuration from file '" + file.getFileName( ) + "': " + e.getMessage( ), e );
+                }
+            }
+            else
+            {
+                throw new RegistryException(
+                    "Unable to add configuration from file '" + file.getFileName( ) + "': unrecognised type" );
+            }
+        } else {
+            throw new RegistryException( "The underlying configuration is not a combined configuration object." );
+        }
+    }
+
+    class StringFileSystem extends FileSystem {
+
+        String content;
+        String encoding = "UTF-8";
+
+        StringFileSystem(String content) {
+            this.content = content;
+        }
+
+        @Override
+        public InputStream getInputStream( URL url ) throws ConfigurationException
+        {
+            try
+            {
+                return new ByteArrayInputStream( content.getBytes(encoding) );
+            }
+            catch ( UnsupportedEncodingException e )
+            {
+                logger.error("Bad encoding for FileSystem");
+                throw new ConfigurationException( "Bad encoding specified" );
+            }
+        }
+
+        @Override
+        public OutputStream getOutputStream( URL url ) throws ConfigurationException
+        {
+            return new ByteArrayOutputStream( 0 );
+        }
+
+        @Override
+        public OutputStream getOutputStream( File file ) throws ConfigurationException
+        {
+            return new ByteArrayOutputStream( 0 );
+        }
+
+        @Override
+        public String getPath( File file, URL url, String basePath, String fileName )
+        {
+            return basePath+"/"+fileName;
+        }
+
+        @Override
+        public String getBasePath( String path )
+        {
+            return path;
+        }
+
+        @Override
+        public String getFileName( String path )
+        {
+            return path;
+        }
+
+        @Override
+        public URL locateFromURL( String basePath, String fileName )
+        {
+            try
+            {
+                return new URL("file://"+getPath(null, null, basePath, fileName));
+            }
+            catch ( MalformedURLException e )
+            {
+                // ignore
+                return null;
+            }
+        }
+
+        @Override
+        public URL getURL( String basePath, String fileName ) throws MalformedURLException
+        {
+            try
+            {
+                return new URL("file://"+getPath(null, null, basePath, fileName));
+            }
+            catch ( MalformedURLException e )
+            {
+                // ignore
+                return null;
+            }
+        }
+
+    }
+
+    @PostConstruct
+    public void initialize()
+        throws RegistryException
+    {
+        try
+        {
+            CombinedConfiguration configuration;
+            if ( StringUtils.isNotBlank( properties ) )
+            {
+                System.out.println("Configuration");
+                System.out.println(properties);
+                    Parameters params = new Parameters();
+                    DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS )
+                        .setPropertyDelimiter( propertyDelimiter )
+                        .setIndexStart( "(" )
+                        .setIndexEnd( ")" )
+                        .setEscapedDelimiter( "\\"+propertyDelimiter )
+                        . create( );
+                    DefaultExpressionEngine expressionEngine = new DefaultExpressionEngine( symbols );
+                    ConfigurationInterpolator interpolator = ConfigurationInterpolator.fromSpecification( new InterpolatorSpecification.Builder().withDefaultLookup( DefaultLookups.SYSTEM_PROPERTIES.getLookup() ).create() );
+                    System.out.println(interpolator.getDefaultLookups().stream( ).map(p -> p.toString()).collect( Collectors.joining( ",")));
+                    String interpolatedProps = interpolator.interpolate( properties ).toString();
+                    logger.debug( "Loading configuration into commons-configuration, xml {}", interpolatedProps );
+                    FileSystem fs = new StringFileSystem( interpolatedProps );
+                    FileBasedConfigurationBuilder<XMLConfiguration> cfgBuilder =
+                        new FileBasedConfigurationBuilder<>(
+                            XMLConfiguration.class)
+                            .configure(params.xml()
+                                .setInterpolator( interpolator )
+                                .setFileSystem( fs )
+                                .setFileName( "config.xml")
+                                .setListDelimiterHandler(
+                                    new DefaultListDelimiterHandler(','))
+                                .setExpressionEngine( expressionEngine )
+                                .setThrowExceptionOnMissing(false));
+
+                    CombinedConfigurationBuilder builder = new CombinedConfigurationBuilder().
+                        configure(params.combined().setDefinitionBuilder( cfgBuilder ));
+
+                    configuration = builder.getConfiguration();
+
+                    // interpolation as plexus did it before
+
+                    //configuration.set
+            }
+            else
+            {
+                logger.debug( "Creating a default configuration - no configuration was provided" );
+                NodeCombiner combiner = new UnionCombiner();
+                configuration = new CombinedConfiguration(combiner);
+            }
+
+            configuration.addConfiguration( new SystemConfiguration(), "SystemProperties" );
+
+            this.configuration = configuration;
+        }
+        catch ( ConfigurationException e )
+        {
+            throw new RuntimeException( e.getMessage(), e );
+        }
+    }
+
+    public void setProperties( String properties )
+    {
+        this.properties = properties;
+    }
+
+    public ConfigRegistry getSection( String name )
+    {
+        CombinedConfiguration combinedConfiguration = (CombinedConfiguration) configuration;
+        Configuration configuration = combinedConfiguration.getConfiguration( name );
+        return configuration == null ? null : new CommonsConfigurationRegistry( configuration );
+    }
+
+    public String getPropertyDelimiter()
+    {
+        return propertyDelimiter;
+    }
+
+    public void setPropertyDelimiter( String propertyDelimiter )
+    {
+        this.propertyDelimiter = propertyDelimiter;
+    }
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/resources/META-INF/spring-context.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/resources/META-INF/spring-context.xml
new file mode 100755
index 0000000..4a924fb
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/resources/META-INF/spring-context.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+
+  <context:component-scan base-package="org.apache.archiva.redback.common.config.acc2" />
+
+</beans>
\ No newline at end of file
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/AbstractRegistryTest.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/AbstractRegistryTest.java
new file mode 100644
index 0000000..fa6d637
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/AbstractRegistryTest.java
@@ -0,0 +1,189 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+
+import junit.framework.TestCase;
+import org.apache.archiva.redback.common.config.api.ConfigRegistry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import javax.inject.Inject;
+import java.util.NoSuchElementException;
+
+/**
+ * @author Olivier Lamy
+ *
+ * @since 8 feb. 07
+ */
+@RunWith( value = SpringJUnit4ClassRunner.class )
+@ContextConfiguration( locations = { "classpath*:/META-INF/spring-context.xml", "classpath*:/spring-context.xml" } )
+public abstract class AbstractRegistryTest
+    extends TestCase
+{
+
+    @Inject
+    protected ApplicationContext applicationContext;
+
+    public abstract String getRoleHint();
+
+    public ConfigRegistry getRegistry()
+        throws Exception
+    {
+        return getRegistry( getRoleHint() );
+    }
+
+    public ConfigRegistry getRegistry( String name )
+        throws Exception
+    {
+        ConfigRegistry registry = applicationContext.getBean( name, ConfigRegistry.class );
+        registry.initialize();
+        return registry;
+    }
+
+    @Test
+    public void testInt()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        assertEquals( "not 2 ", 2, registry.getInt( "two" ) );
+    }
+
+    @Test
+    public void testIntUnknown()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        try
+        {
+            registry.getInt( "unknown" );
+            assertTrue( "no NoSuchElementException", false );
+        }
+        catch ( NoSuchElementException e )
+        {
+            // cool it works
+        }
+    }
+
+    @Test
+    public void testString()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        assertEquals( "not foo ", "foo", registry.getString( "string" ) );
+    }
+
+    @Test
+    public void testStringUnknown()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        String value = registry.getString( "unknown" );
+        assertNull( "unknow not null", value );
+
+    }
+
+    @Test
+    public void testBoolean()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        assertEquals( "not true ", true, registry.getBoolean( "boolean" ) );
+    }
+
+    @Test
+    public void testBooleanUnknown()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        try
+        {
+            registry.getBoolean( "unknown" );
+            assertTrue( "no NoSuchElementException", false );
+        }
+        catch ( NoSuchElementException e )
+        {
+            // cool it works
+        }
+    }
+
+    @Test
+    public void testIsNotEmpty()
+        throws Exception
+    {
+        assertFalse( getRegistry().isEmpty() );
+    }
+
+    @Test
+    public void testGetSubRegistry()
+        throws Exception
+    {
+        assertNotNull( getRegistry().getSubset( "subOne" ) );
+    }
+
+    @Test
+    public void testgetSubsetValues()
+        throws Exception
+    {
+        ConfigRegistry sub = getRegistry().getSubset( "subOne" );
+        assertNotNull( sub );
+        assertEquals( "entryOne", sub.getString( "firstEntry" ) );
+        assertEquals( "entryTwo", sub.getString( "secondEntry" ) );
+    }
+
+    @Test
+    public void testgetSubsetEmpty()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        assertNotNull( registry.getSubset( "none" ) );
+        assertTrue( registry.getSubset( "none" ).isEmpty() );
+
+    }
+
+    @Test
+    public void testSetBoolean()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        registry.setBoolean( "keyTrue", true );
+        assertTrue( registry.getBoolean( "keyTrue" ) );
+    }
+
+    @Test
+    public void testSetInt()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        registry.setInt( "keyInt", 3 );
+        assertEquals( 3, registry.getInt( "keyInt" ) );
+    }
+
+    @Test
+    public void testSetString()
+        throws Exception
+    {
+        ConfigRegistry registry = getRegistry();
+        registry.setString( "what", "zorglub" );
+        assertEquals( "zorglub", registry.getString( "what" ) );
+    }
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistryTest.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistryTest.java
new file mode 100644
index 0000000..a1c4e59
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/CommonsConfigurationRegistryTest.java
@@ -0,0 +1,422 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+
+import org.apache.archiva.redback.common.config.api.ConfigRegistry;
+import org.apache.archiva.redback.common.config.api.RegistryException;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+/**
+ * Test the commons configuration registry.
+ */
+public class CommonsConfigurationRegistryTest
+    extends AbstractRegistryTest
+{
+    private ConfigRegistry registry;
+
+    private final Logger logger = LoggerFactory.getLogger( CommonsConfigurationRegistryTest.class );
+
+
+    private static final int INT_TEST_VALUE = 8080;
+
+    public String getRoleHint()
+    {
+        return "builder";
+    }
+
+    @Test
+    public void requirementTest() {
+        assertNotNull(System.getProperty("basedir"));
+        assertTrue( System.getProperty( "basedir" ).length()>0 );
+        assertNotNull(System.getProperty("user.dir"));
+        assertTrue( System.getProperty( "user.dir" ).length()>0 );
+
+    }
+
+    @Test
+    public void testDefaultConfiguration()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        assertEquals( "Check system property override", System.getProperty( "user.dir" ),
+                      registry.getString( "user.dir" ) );
+        assertEquals( "Check system property", System.getProperty( "user.home" ), registry.getString( "user.home" ) );
+        assertNull( "Check other properties are not loaded", registry.getString( "test.value" ) );
+    }
+
+    @Test
+    public void testBuilderConfiguration()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        assertEquals( "Check system property override", "new user dir", registry.getString( "user.dir" ) );
+        assertEquals( "Check system property default", System.getProperty( "user.home" ),
+                      registry.getString( "user.home" ) );
+        assertEquals( "Check other properties are loaded", "foo", registry.getString( "test.value" ) );
+        assertEquals( "Check other properties are loaded", 1, registry.getInt( "test.number" ) );
+        assertTrue( "Check other properties are loaded", registry.getBoolean( "test.boolean" ) );
+    }
+
+    @Test
+    public void testDump()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        String dump = registry.dump();
+        assertTrue( dump.startsWith( "Configuration Dump.\n\"" ) );
+    }
+
+    @Test
+    public void testDefaults()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        assertNull( "Check getString returns null", registry.getString( "foo" ) );
+        assertEquals( "Check getString returns default", "bar", registry.getString( "foo", "bar" ) );
+
+        try
+        {
+            registry.getInt( "foo" );
+            fail();
+        }
+        catch ( NoSuchElementException e )
+        {
+            // success
+        }
+
+        assertEquals( "Check getInt returns default", INT_TEST_VALUE, registry.getInt( "foo", INT_TEST_VALUE ) );
+
+        try
+        {
+            registry.getBoolean( "foo" );
+            fail();
+        }
+        catch ( NoSuchElementException e )
+        {
+            // success
+        }
+
+        assertTrue( "Check getBoolean returns default", registry.getBoolean( "foo", true ) );
+    }
+
+    @Test
+    public void testInterpolation()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        assertEquals( "Check system property interpolation", System.getProperty( "user.home" ) + "/.m2/repository",
+                      registry.getString( "repository" ) );
+
+        assertEquals( "Check configuration value interpolation", "foo/bar",
+                      registry.getString( "test.interpolation" ) );
+    }
+
+    @Test
+    public void testAddConfigurationXmlFile()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        registry.addConfigurationFromFile( "test.xml", Paths.get( "src/test/resources/test.xml" ) );
+        System.out.println(registry.dump());
+        assertEquals( "Check system property default", System.getProperty( "user.dir" ),
+                      registry.getString( "user.dir" ) );
+        assertEquals( "Check other properties are loaded", "foo", registry.getString( "test.value" ) );
+    }
+
+    @Test
+    public void testAddConfigurationPropertiesFile()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        registry.addConfigurationFromFile(
+            "test.properties", Paths.get("src/test/resources/test.properties" ) );
+
+        assertEquals( "Check system property default", System.getProperty( "user.dir" ),
+                      registry.getString( "user.dir" ) );
+        assertEquals( "Check other properties are loaded", "baz", registry.getString( "foo.bar" ) );
+        assertNull( "Check other properties are not loaded", registry.getString( "test.value" ) );
+    }
+
+    @Test
+    public void testAddConfigurationXmlResource()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        registry.addConfigurationFromResource( "test.xml-r", "test.xml" );
+
+        assertEquals( "Check system property default", System.getProperty( "user.dir" ),
+                      registry.getString( "user.dir" ) );
+        assertEquals( "Check other properties are loaded", "foo", registry.getString( "test.value" ) );
+    }
+
+    @Test
+    public void testAddConfigurationPropertiesResource()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        registry.addConfigurationFromResource( "test.properties-r", "test.properties" );
+
+        assertEquals( "Check system property default", System.getProperty( "user.dir" ),
+                      registry.getString( "user.dir" ) );
+        assertEquals( "Check other properties are loaded", "baz", registry.getString( "foo.bar" ) );
+        assertNull( "Check other properties are not loaded", registry.getString( "test.value" ) );
+    }
+
+    @Test
+    public void testAddConfigurationUnrecognisedType()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        try
+        {
+            registry.addConfigurationFromResource( "test.foo", "test.foo" );
+            fail();
+        }
+        catch ( RegistryException e )
+        {
+            // success
+        }
+
+        try
+        {
+            registry.addConfigurationFromFile( "test.foo-file",
+                Paths.get( "src/test/resources/test.foo" ) );
+            fail();
+        }
+        catch ( RegistryException e )
+        {
+            // success
+        }
+    }
+
+    @Test
+    public void testIsEmpty()
+        throws Exception
+    {
+        registry = getRegistry( "default" );
+
+        assertFalse( registry.isEmpty() );
+        assertTrue( registry.getSubset( "foo" ).isEmpty() );
+    }
+
+    @Test
+    public void testGetSubset()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        ConfigRegistry registry = this.registry.getSubset( "test" );
+        assertEquals( "Check other properties are loaded", "foo", registry.getString( "value" ) );
+        assertEquals( "Check other properties are loaded", 1, registry.getInt( "number" ) );
+        assertTrue( "Check other properties are loaded", registry.getBoolean( "boolean" ) );
+    }
+
+    @Test
+    public void testGetSubsetList()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        List list = registry.getSubsetList( "objects.object" );
+        assertEquals( 2, list.size() );
+        ConfigRegistry r = (ConfigRegistry) list.get( 0 );
+        assertTrue( "bar".equals( r.getString( "foo" ) ) || "baz".equals( r.getString( "foo" ) ) );
+        r = (ConfigRegistry) list.get( 1 );
+        assertTrue( "bar".equals( r.getString( "foo" ) ) || "baz".equals( r.getString( "foo" ) ) );
+    }
+
+    @Test
+    public void testGetProperties()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        Map<String,String> properties = registry.getProperties( "properties" );
+        assertEquals( 2, properties.size() );
+        assertEquals( "bar", properties.get( "foo" ) );
+        assertEquals( "baz", properties.get( "bar" ) );
+    }
+
+    @Test
+    public void testGetList()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        List list = registry.getList( "strings.string" );
+        assertEquals( 3, list.size() );
+        assertEquals( "s1", list.get( 0 ) );
+        assertEquals( "s2", list.get( 1 ) );
+        assertEquals( "s3", list.get( 2 ) );
+    }
+
+    @Test
+    public void testGetSection()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        ConfigRegistry registry = this.registry.getSource( "properties" );
+        assertNull( registry.getString( "test.value" ) );
+        assertEquals( "baz", registry.getString( "foo.bar" ) );
+    }
+
+    @Test
+    public void testRemoveKey()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        ConfigRegistry registry = this.registry.getSource( "properties" );
+        assertEquals( "baz", registry.getString( "foo.bar" ) );
+        registry.remove( "foo.bar" );
+        assertNull( registry.getString( "foo.bar" ) );
+    }
+
+    @Test
+    public void testRemoveSubset()
+        throws Exception
+    {
+        registry = getRegistry( "builder" );
+
+        registry.removeSubset( "strings" );
+        assertEquals( Collections.EMPTY_LIST, registry.getList( "strings.string" ) );
+
+        ConfigRegistry registry = this.registry.getSource( "properties" );
+        assertEquals( "baz", registry.getString( "foo.bar" ) );
+        registry.remove( "foo" );
+        assertEquals( "baz", registry.getString( "foo.bar" ) );
+        registry.removeSubset( "foo" );
+        assertNull( registry.getString( "foo.bar" ) );
+    }
+
+/* TODO: for 1.4
+    public void testGetForcedCreateByName()
+        throws Exception
+    {
+        registry = (Registry) lookup( Registry.class.getName(), "forceCreate" );
+
+        String testFile = getTestFile( "target/foo-forced" ).getAbsolutePath();
+        assertFalse( FileUtils.fileExists( testFile ) );
+
+        assertNotNull( registry.getSection( "foo" ) );
+    }
+*/
+
+    @Test
+    public void testGetDontForceCreateByName()
+        throws Exception
+    {
+        registry = getRegistry( "noForceCreate" );
+
+        assertNull( registry.getSource( "foo" ) );
+    }
+
+    @Test
+    public void testSaveSection()
+        throws Exception
+    {
+        Path src = Paths.get( "src/test/resources/test-save.xml" );
+        Path dest = Paths.get( "target/test-classes/test-save.xml" );
+        Files.copy( src, dest );
+
+        registry = getRegistry( "test-save" );
+
+        ConfigRegistry registry = this.registry.getSource( "org.codehaus.plexus.registry" );
+        assertEquals( "check list elements", Arrays.asList( new String[]{ "1", "2", "3" } ),
+                      registry.getList( "listElements.listElement" ) );
+
+        registry.remove( "listElements.listElement(1)" );
+        registry.save();
+
+        // @TODO: Migrate test implementation to commons config 2.4
+//        XMLConfiguration configuration = new XMLConfiguration( dest );
+//        assertEquals( Arrays.asList( new String[]{ "1", "3" } ), configuration.getList( "listElements.listElement" ) );
+//
+//        // file in ${basedir}/target/conf/shared.xml
+//        Registry section = this.registry.getSection( "org.apache.maven.shared.app.user" );
+//        section.setString( "foo", "zloug" );
+//        section.save();
+//
+//        configuration = new XMLConfiguration( new File( "target/conf/shared.xml" ) );
+//        assertNotNull( configuration.getString( "foo" ) );
+
+    }
+
+
+    // TODO: Migrate implementation to commons configuration 2.4
+//    @Test
+//    public void test_listener()
+//        throws Exception
+//    {
+//        registry = getRegistry( "default" );
+//
+//        int listenerSize = CommonsConfigurationRegistry.class.cast( registry ).getChangeListenersSize();
+//
+//        MockChangeListener mockChangeListener = new MockChangeListener();
+//
+//        registry.addChangeListener( mockChangeListener );
+//
+//        registry.addChangeListener( new MockChangeListener() );
+//
+//        assertEquals( listenerSize + 2, CommonsConfigurationRegistry.class.cast( registry ).getChangeListenersSize() );
+//
+//        registry.removeChangeListener( mockChangeListener );
+//
+//        assertEquals( listenerSize + 1, CommonsConfigurationRegistry.class.cast( registry ).getChangeListenersSize() );
+//    }
+//
+//    private static class MockChangeListener
+//        implements RegistryListener
+//    {
+//        @Override
+//        public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
+//        {
+//            // no op
+//        }
+//
+//        @Override
+//        public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
+//        {
+//            // no op
+//        }
+//    }
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Component.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Component.java
new file mode 100644
index 0000000..916d2e6
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Component.java
@@ -0,0 +1,60 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Test component.
+ */
+public interface Component
+{
+    String ROLE = Component.class.getName();
+
+    String getKey( );
+
+    Properties getProperties( );
+
+    String getConfigKey( );
+
+    Properties getConfigProperties( );
+
+    Map getMap( );
+
+    List getList( );
+
+    Map getConfigMap( );
+
+    List getConfigList( );
+
+    Properties getMergeProperties( );
+
+    int getNumber( );
+
+    int getConfigNumber( );
+
+    Nested getNested( );
+
+    Nested getConfigNested( );
+
+    List getMergeList( );
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/DefaultComponent.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/DefaultComponent.java
new file mode 100644
index 0000000..723e751
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/DefaultComponent.java
@@ -0,0 +1,128 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Test component.
+ */
+public class DefaultComponent
+    implements Component
+{
+    private String key;
+
+    private Properties properties;
+
+    private Map map;
+
+    private List list;
+
+    private String configKey;
+
+    private Properties configProperties;
+
+    private Map configMap;
+
+    private List configList;
+
+    private Properties mergeProperties;
+
+    private int number;
+
+    private int configNumber;
+
+    private Nested nested;
+
+    private Nested configNested;
+
+    private List mergeList;
+
+    public List getMergeList()
+    {
+        return mergeList;
+    }
+
+    public Nested getConfigNested()
+    {
+        return configNested;
+    }
+
+    public Nested getNested()
+    {
+        return nested;
+    }
+
+    public int getNumber()
+    {
+        return number;
+    }
+
+    public int getConfigNumber()
+    {
+        return configNumber;
+    }
+
+    public String getConfigKey()
+    {
+        return configKey;
+    }
+
+    public Properties getConfigProperties()
+    {
+        return configProperties;
+    }
+
+    public String getKey()
+    {
+        return key;
+    }
+
+    public Properties getProperties()
+    {
+        return properties;
+    }
+
+    public Map getMap()
+    {
+        return map;
+    }
+
+    public List getList()
+    {
+        return list;
+    }
+
+    public Map getConfigMap()
+    {
+        return configMap;
+    }
+
+    public List getConfigList()
+    {
+        return configList;
+    }
+
+    public Properties getMergeProperties()
+    {
+        return mergeProperties;
+    }
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Nested.java b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Nested.java
new file mode 100644
index 0000000..6e54dce
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/Nested.java
@@ -0,0 +1,33 @@
+package org.apache.archiva.redback.common.config.acc2;
+
+/*
+ * 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.
+ */
+
+/**
+ * Nested class for testing.
+ */
+public class Nested
+{
+    private String foo;
+
+    public String getFoo()
+    {
+        return foo;
+    }
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/META-INF/spring-context.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/META-INF/spring-context.xml
new file mode 100755
index 0000000..8476963
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/META-INF/spring-context.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
+
+</beans>
\ No newline at end of file
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/spring-context.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/spring-context.xml
new file mode 100755
index 0000000..895ea07
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/spring-context.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
+
+  <alias name="acc2-configuration" alias="default"/>
+
+  <bean name="builder" class="org.apache.archiva.redback.common.config.acc2.CommonsConfigurationRegistry">
+    <property name="properties">
+      <value>
+        <![CDATA[
+          <configuration>
+            <xml fileName="test.xml"/>
+            <properties fileName="test.properties" config-name="properties"/>
+
+          </configuration>
+        ]]>
+      </value>
+    </property>
+  </bean>
+
+  <bean name="test-save" class="org.apache.archiva.redback.common.config.acc2.CommonsConfigurationRegistry">
+    <property name="properties">
+      <value>
+        <![CDATA[
+        <configuration>
+          <system/>
+          <xml fileName="${basedir}/target/test-classes/test-save.xml"
+               config-name="org.codehaus.plexus.registry"
+               config-at="org.codehaus.plexus.registry"/>
+          <xml fileName="${basedir}/target/conf/continuum.xml" config-optional="true"
+               config-at="org.apache.maven.continuum" config-forceCreate="true"/>
+          <xml fileName="${basedir}/target/conf/shared.xml" config-optional="true"
+               config-name="org.apache.maven.shared.app.user" config-at="org.apache.maven.shared.app"
+               config-forceCreate="true"/>
+          <xml fileName="${basedir}/target/conf/shared.xml" config-optional="true"
+               config-name="org.apache.maven.shared.app.base" config-at="org.apache.maven.shared.app"/>
+          <xml fileName="${basedir}/target/conf/common.xml" config-optional="true"/>
+          <properties fileName="${basedir}/conf/security.properties" config-optional="true"
+                      config-at="org.codehaus.plexus.redback"/>
+          <xml fileName="${basedir}/target/conf/continuum.xml" config-optional="true"
+               config-at="org.apache.maven.continuum" config-name="org.apache.maven.continuum.user"
+               config-forceCreate="true"/>
+          <xml fileName="${basedir}/target/conf/shared.xml" config-optional="true"
+               config-at="org.apache.maven.shared.app" />
+          <xml fileName="${basedir}/target/conf/common.xml" config-optional="true"/>
+          <properties fileName="${basedir}/conf/security.properties" config-optional="true"
+                      config-at="org.codehaus.plexus.redback"/>
+
+        </configuration>
+        ]]>
+      </value>
+    </property>
+  </bean>
+
+  <bean name="forceCreate" class="org.apache.archiva.redback.common.config.acc2.CommonsConfigurationRegistry">
+    <property name="properties">
+      <value>
+        <![CDATA[
+        <configuration>
+          <xml fileName="${basedir}/target/foo-forced" config-name="foo" config-forceCreate="true" config-optional="true"/>
+        </configuration>
+        ]]>
+      </value>
+    </property>
+  </bean>
+
+  <bean name="noForceCreate" class="org.apache.archiva.redback.common.config.acc2.CommonsConfigurationRegistry">
+    <property name="properties">
+      <value>
+        <![CDATA[
+        <configuration>
+          <xml fileName="${basedir}/target/foo" config-name="foo" config-optional="true"/>
+        </configuration>
+        ]]>
+      </value>
+    </property>
+  </bean>
+
+</beans>
\ No newline at end of file
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test-save.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test-save.xml
new file mode 100644
index 0000000..76667ad
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test-save.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright 2007 The Codehaus Foundation.
+  ~
+  ~ Licensed 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.
+  -->
+
+<registry>
+  <listElements>
+    <listElement>1</listElement>
+    <listElement>2</listElement>
+    <listElement>3</listElement>
+  </listElements>
+</registry>
\ No newline at end of file
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.properties b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.properties
new file mode 100644
index 0000000..332952e
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.properties
@@ -0,0 +1,25 @@
+#
+# Copyright 2007 The Codehaus Foundation.
+#
+# Licensed 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.
+#
+
+user.dir=new user dir
+foo.bar=baz
+
+# test from plexus-registry tests
+subOne.firstEntry=entryOne
+subOne.secondEntry=entryTwo
+two=2
+string=foo
+boolean=true
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.xml b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.xml
new file mode 100644
index 0000000..921aed7
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/test.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright 2007 The Codehaus Foundation.
+  ~
+  ~ Licensed 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.
+  -->
+
+<configuration>
+  <test>
+    <value>foo</value>
+    <number>1</number>
+    <boolean>true</boolean>
+    <interpolation>${test.value}/bar</interpolation>
+  </test>
+  <repository>${user.home}/.m2/repository</repository>
+  <objects>
+    <object>
+      <foo>bar</foo>
+    </object>
+    <object>
+      <foo>baz</foo>
+    </object>
+  </objects>
+  <properties>
+    <foo>bar</foo>
+    <bar>baz</bar>
+  </properties>
+  <strings>
+    <string>s1</string>
+    <string>s2</string>
+    <string>s3</string>
+  </strings>
+</configuration>
diff --git a/redback-common/pom.xml b/redback-common/redback-common-configuration/redback-common-configuration-api/pom.xml
similarity index 65%
copy from redback-common/pom.xml
copy to redback-common/redback-common-configuration/redback-common-configuration-api/pom.xml
index 11391a9..28f88cc 100644
--- a/redback-common/pom.xml
+++ b/redback-common/redback-common-configuration/redback-common-configuration-api/pom.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one
   ~ or more contributor license agreements.  See the NOTICE file
@@ -17,23 +18,18 @@
   ~ specific language governing permissions and limitations
   ~ under the License.
   -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <parent>
+    <artifactId>redback-common-configuration</artifactId>
     <groupId>org.apache.archiva.redback</groupId>
-    <artifactId>redback</artifactId>
     <version>3.0.0-SNAPSHOT</version>
   </parent>
-  <artifactId>redback-common</artifactId>
-  <name>Redback :: Commons</name>
-  <packaging>pom</packaging>
-  <properties>
-    <site.staging.base>${project.parent.basedir}</site.staging.base>
-  </properties>
-  <modules>
-    <module>redback-common-ldap</module>
-    <module>redback-common-test-resources</module>
-    <module>redback-common-jpa</module>
-  </modules>
-</project>
\ No newline at end of file
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>redback-common-configuration-api</artifactId>
+
+
+</project>
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/ConfigRegistry.java b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/ConfigRegistry.java
new file mode 100644
index 0000000..cba0548
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/ConfigRegistry.java
@@ -0,0 +1,264 @@
+package org.apache.archiva.redback.common.config.api;
+
+/*
+ * 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.
+ */
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * The configuration registry is a single source of external configuration.
+ *
+ * It can be used by components to source configuration, knowing that it can be used from within applications
+ * without the information being hard coded into the component.
+ *
+ */
+public interface ConfigRegistry
+{
+
+    /**
+     * Dump the entire registry to a string, for debugging purposes.
+     *
+     * @return the registry contents
+     */
+    String dump( );
+
+    /**
+     * Get a string value from the registry. If not found, <code>null</code> is returned.
+     *
+     * @param key the key in the registry
+     * @return the value
+     */
+    String getString( String key );
+
+    /**
+     * Get a string value from the registry. If not found, the default value is used.
+     *
+     * @param key          the key in the registry
+     * @param defaultValue the default value
+     * @return the value
+     */
+    String getString( String key, String defaultValue );
+
+    /**
+     * Set a string value in the registry.
+     *
+     * @param key   the key in the registry
+     * @param value the value to set
+     */
+    void setString( String key, String value );
+
+    /**
+     * Get an integer value from the registry. If not found, an exception is thrown.
+     *
+     * @param key the key in the registry
+     * @return the value
+     * @throws java.util.NoSuchElementException
+     *          if the key is not found
+     */
+    int getInt( String key );
+
+    /**
+     * Get an integer value from the registry. If not found, the default value is used.
+     *
+     * @param key          the key in the registry
+     * @param defaultValue the default value
+     * @return the value
+     */
+    int getInt( String key, int defaultValue );
+
+    /**
+     * Set an integer value in the registry.
+     *
+     * @param key   the key in the registry
+     * @param value the value to set
+     */
+    void setInt( String key, int value );
+
+    /**
+     * Get a boolean value from the registry. If not found, an exception is thrown.
+     *
+     * @param key the key in the registry
+     * @return the value
+     * @throws java.util.NoSuchElementException
+     *          if the key is not found
+     */
+    boolean getBoolean( String key );
+
+    /**
+     * Get a boolean value from the registry. If not found, the default value is used.
+     *
+     * @param key          the key in the registry
+     * @param defaultValue the default value
+     * @return the value
+     */
+    boolean getBoolean( String key, boolean defaultValue );
+
+    /**
+     * Set a boolean value in the registry.
+     *
+     * @param key   the key in the registry
+     * @param value the value to set
+     */
+    void setBoolean( String key, boolean value );
+
+    /**
+     * Load configuration from the given classloader resource.
+     *
+     * @param resource the location to load the configuration from
+     * @throws RegistryException if a problem occurred reading the resource to add to the registry
+     */
+    void addConfigurationFromResource( String name, String resource )
+        throws RegistryException;
+
+    /**
+     * Load configuration from the given classloader resource.
+     *
+     * @param resource the location to load the configuration from
+     * @param prefix   the location to add the configuration at in the registry
+     * @throws RegistryException if a problem occurred reading the resource to add to the registry
+     */
+    void addConfigurationFromResource( String name, String resource, String prefix )
+        throws RegistryException;
+
+    /**
+     * Load configuration from the given file.
+     *
+     * @param file the location to load the configuration from
+     * @throws RegistryException if a problem occurred reading the resource to add to the registry
+     */
+    void addConfigurationFromFile( String name, Path file )
+        throws RegistryException;
+
+    /**
+     * Load configuration from the given file.
+     *
+     * @param file   the location to load the configuration from
+     * @param prefix the location to add the configuration at in the registry
+     * @throws RegistryException if a problem occurred reading the resource to add to the registry
+     */
+    void addConfigurationFromFile( String name, Path file, String prefix )
+        throws RegistryException;
+
+    /**
+     * Determine if the registry contains any elements.
+     *
+     * @return whether the registry contains any elements
+     */
+    boolean isEmpty( );
+
+    /**
+     * Get a list of strings at the given key in the registry.
+     *
+     * @param key the key to lookup
+     * @return the list of strings
+     */
+    List<String> getList( String key );
+
+    /**
+     * Get the properties at the given key in the registry.
+     *
+     * @param key the key to lookup
+     * @return the properties
+     */
+    Map<String, String> getProperties( String key );
+
+    /**
+     * Get a subset of the registry, for all keys descended from the given key.
+     *
+     * @param key the key to take the subset from
+     * @return the registry subset
+     */
+    ConfigRegistry getSubset( String key );
+
+    /**
+     * Get a list of subsets of the registry, for all keys descended from the given key.
+     *
+     * @param key the key to take the subsets from
+     * @return the registry subsets
+     */
+    List<ConfigRegistry> getSubsetList( String key );
+
+    /**
+     * Get a configuration source part of the registry, identified by the given name. If it doesn't exist, <code>null</code> will be
+     * returned.
+     *
+     * Configurations can be combined from different sources. This gives the configuration of a specific source.
+     *
+     * @param name The source name of the configuration source.
+     * @return the The config registry object that represents this source part.
+     */
+    ConfigRegistry getSource( String name );
+
+    /**
+     * Save any changes to the registry since it was loaded.
+     *
+     * @throws RegistryException             if there was a problem saving the registry
+     * @throws UnsupportedOperationException if the registry is not writable
+     */
+    void save( )
+        throws RegistryException, UnsupportedOperationException;
+
+    /**
+     * Register a change listener for configuration keys that match the given patterns.
+     *
+     * @param listener the listener
+     */
+    void registerChangeListener( RegistryListener listener, Pattern... filter );
+
+    /**
+     * Unregister the change listener for all events.
+     *
+     * @param listener
+     * @return <code>true</code> if has been removed
+     */
+    boolean unregisterChangeListener( RegistryListener listener );
+
+    /**
+     * Get all the keys in this registry. Keys are only retrieved at a depth of 1.
+     *
+     * @return the set of keys
+     */
+    Collection<String> getKeys( );
+
+    /**
+     * Get all the keys in this registry.
+     * @return the set of keys
+     */
+    Collection<String> getFullKeys( );
+
+    /**
+     * Remove a keyed element from the registry.
+     *
+     * @param key the key to remove
+     */
+    void remove( String key );
+
+    /**
+     * Remove a keyed subset of the registry.
+     *
+     * @param key the subset to remove
+     */
+    void removeSubset( String key );
+
+    void initialize( ) throws RegistryException;
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryException.java b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryException.java
new file mode 100644
index 0000000..dc74788
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryException.java
@@ -0,0 +1,38 @@
+package org.apache.archiva.redback.common.config.api;
+
+/*
+ * 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.
+ */
+
+/**
+ * Exception occurring in the registry component.
+ */
+public class RegistryException
+    extends Exception
+{
+    public RegistryException( String message )
+    {
+        super( message );
+    }
+
+    public RegistryException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}
diff --git a/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryListener.java b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryListener.java
new file mode 100644
index 0000000..a76d6df
--- /dev/null
+++ b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/RegistryListener.java
@@ -0,0 +1,45 @@
+package org.apache.archiva.redback.common.config.api;
+
+/*
+ * 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.
+ */
+
+/**
+ * Receives notifications of configuration changes in thre registry.
+ */
+public interface RegistryListener
+{
+    /**
+     * Notify the object that there is about to be a configuration change.
+     *
+     * @param registry      the registry that was changed
+     * @param propertyName  the property being changed
+     * @param propertyValue the value the property is about to be changed to
+     */
+    void beforeConfigurationChange( ConfigRegistry registry, String propertyName, Object propertyValue );
+
+    /**
+     * Notify the object that there has been a configuration change.
+     *
+     * @param registry      the registry that was changed
+     * @param propertyName  the property what was changed
+     * @param propertyValue the value the property was changed to
+     * @param oldValue      The value the property had before
+     */
+    void afterConfigurationChange( ConfigRegistry registry, String propertyName, Object propertyValue, Object oldValue );
+}