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

commit 5cd2f362e9c64d628f596cd463a25c6c344c33bc
Author: Martin Stockhammer <[email protected]>
AuthorDate: Mon Feb 18 06:26:31 2019 +0100

    Adding classes for listener implementation
---
 .../redback-common-configuration-acc2/pom.xml      |   6 +
 .../redback/common/config/acc2/CfgListener.java    | 257 +++++++++++++
 .../config/acc2/CommonsConfigurationRegistry.java  | 412 ++++++++++++---------
 .../common/config/acc2/AbstractRegistryTest.java   |   6 +-
 .../acc2/CommonsConfigurationRegistryTest.java     | 202 +++++-----
 .../common/config/acc2/MockChangeListener.java     |  37 ++
 .../src/test/resources/log4j2-test.xml             |  12 +-
 .../redback/common/config/api/AsyncListener.java   |  49 +++
 .../redback/common/config/api/ConfigRegistry.java  |  35 +-
 .../redback/common/config/api/EventType.java       |  28 ++
 .../common/config/api/RegistryListener.java        |  16 +-
 11 files changed, 774 insertions(+), 286 deletions(-)

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
index dcc2fd0..1505040 100644
--- 
a/redback-common/redback-common-configuration/redback-common-configuration-acc2/pom.xml
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/pom.xml
@@ -122,6 +122,12 @@
       <artifactId>log4j-slf4j-impl</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-jcl</artifactId>
+      <scope>test</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/CfgListener.java
 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/java/org/apache/archiva/redback/common/config/acc2/CfgListener.java
new file mode 100644
index 0000000..2b1c793
--- /dev/null
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/main/java/org/apache/archiva/redback/common/config/acc2/CfgListener.java
@@ -0,0 +1,257 @@
+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.AsyncListener;
+import org.apache.archiva.redback.common.config.api.ConfigRegistry;
+import org.apache.archiva.redback.common.config.api.EventType;
+import org.apache.archiva.redback.common.config.api.RegistryListener;
+import org.apache.commons.configuration2.event.ConfigurationEvent;
+import org.apache.commons.configuration2.event.Event;
+import org.apache.commons.configuration2.event.EventListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.task.TaskExecutor;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.WeakHashMap;
+
+/**
+ * This class maps apache commons configuration events into redback 
configuration events.
+ *
+ * @author Martin Stockhammer <[email protected]>
+ */
+
+public class CfgListener implements EventListener
+{
+
+    ConfigRegistry registry;
+
+    Map<String, ListenerInfo> listeners = new LinkedHashMap<>( );
+    WeakHashMap<EventInfo, Object> oldValueStore = new WeakHashMap<>( );
+
+    Logger logger = LoggerFactory.getLogger( CfgListener.class );
+
+    CfgListener( ConfigRegistry registry )
+    {
+        this.registry = registry;
+    }
+
+    TaskExecutor defaultExecutor;
+
+    ApplicationContext applicationContext;
+
+    private final class ListenerInfo
+    {
+        final String prefix;
+        final RegistryListener listener;
+        final boolean async;
+        final TaskExecutor executor;
+
+        public ListenerInfo( String prefix, RegistryListener listener )
+        {
+            this.prefix = prefix;
+            this.listener = listener;
+            Class<? extends RegistryListener> clazz = listener.getClass( );
+            boolean async = clazz.isAnnotationPresent( AsyncListener.class );
+            try
+            {
+                AsyncListener classAnnotation = clazz.getAnnotation( 
AsyncListener.class );
+                AsyncListener methodAnnotation = clazz.getMethod( 
"handleConfigurationChangeEvent", ConfigRegistry.class, EventType.class, 
String.class, Object.class, Object.class ).getAnnotation( AsyncListener.class );
+                this.async = methodAnnotation != null || classAnnotation != 
null;
+                String executorString = methodAnnotation != null ? 
methodAnnotation.value( ) : ( classAnnotation != null ? classAnnotation.value( 
) : null );
+                TaskExecutor newExec;
+                if ( executorString == null )
+                {
+                    newExec = defaultExecutor;
+                }
+                else
+                {
+                    newExec = applicationContext.getBean( executorString, 
TaskExecutor.class );
+                    if ( newExec == null )
+                    {
+                        newExec = defaultExecutor;
+                    }
+                }
+                this.executor = newExec;
+            }
+            catch ( NoSuchMethodException e )
+            {
+                throw new RuntimeException( "Fatal error! EventListener 
methods not found. Maybe you have the wrong version of EventLister in your 
classpath." );
+            }
+        }
+
+    }
+
+
+    private final class EventInfo
+    {
+        final org.apache.commons.configuration2.event.EventType type;
+        final String name;
+        final Object value;
+
+        EventInfo( org.apache.commons.configuration2.event.EventType type, 
String name, Object value )
+        {
+            this.type = type;
+            this.name = name;
+            this.value = value;
+        }
+
+        @Override
+        public int hashCode( )
+        {
+            return Objects.hash( type, name, value );
+        }
+
+        public boolean equals( EventInfo obj )
+        {
+            return Objects.equals( this.type, obj.type ) && Objects.equals( 
this.name, obj.name ) && Objects.equals( this.value, obj.value );
+        }
+
+    }
+
+    /**
+     * This method stores old values in the
+     * @param event
+     */
+    public void onEvent( 
org.apache.commons.configuration2.event.ConfigurationEvent event )
+    {
+        logger.debug( "Event " + event.getClass( ).getName( ) + " Source 
Class: " + event.getSource( ).getClass( ).getName( ) );
+        logger.debug( "EventType " + event.getEventType( ) + ", EventProperty: 
" + event.getPropertyName( ) + ", EventValue: " + event.getPropertyValue( ) );
+        if ( event.isBeforeUpdate( ) )
+        {
+            logger.debug( "Event before update" );
+            Object oldValue = registry.getValue( event.getPropertyName( ) );
+            oldValueStore.put( new EventInfo( event.getEventType( ), 
event.getPropertyName( ), event.getPropertyValue( ) ), oldValue );
+        }
+        else
+        {
+            logger.debug( "Event after update" );
+            final EventType type = transformEventType( event.getEventType( ) );
+            final Object oldValue = oldValueStore.remove( new EventInfo( 
event.getEventType( ), event.getPropertyName( ), event.getPropertyValue( ) ) );
+            final String propertyName = event.getPropertyName();
+            final Object newValue = event.getPropertyValue();
+            listeners.entrySet( ).stream( ).filter( entry -> 
event.getPropertyName( ).startsWith( entry.getKey( ) ) ).forEach(
+                entry ->
+                    callListener( entry.getValue(), type, propertyName, 
newValue, oldValue )
+
+            );
+        }
+
+    }
+
+    private void callListener(ListenerInfo li, EventType type, String 
propertyName, Object newValue, Object oldValue) {
+        try
+        {
+            if ( li.async )
+            {
+                li.executor.execute( ( ) -> 
li.listener.handleConfigurationChangeEvent( registry, type, propertyName, 
newValue, oldValue ) );
+            }
+            else
+            {
+                li.listener.handleConfigurationChangeEvent( registry, type, 
propertyName, newValue, oldValue );
+            }
+        } catch (Throwable ex) {
+            logger.error( "Listener exception occured: "+ex.getMessage(), ex);
+            // Exception is catched allow to call the other listeners.
+        }
+    }
+
+    private EventType transformEventType( 
org.apache.commons.configuration2.event.EventType<? extends Event> type )
+    {
+
+        if ( type.equals( ConfigurationEvent.ADD_PROPERTY ) )
+        {
+            return EventType.PROPERTY_ADDED;
+        }
+        else if ( type.equals( ConfigurationEvent.CLEAR_PROPERTY ) )
+        {
+            return EventType.PROPERTY_CLEARED;
+        }
+        else if ( type.equals( ConfigurationEvent.SET_PROPERTY ) )
+        {
+            return EventType.PROPERTY_SET;
+        }
+        else
+        {
+            return EventType.UNDEFINED;
+        }
+    }
+
+    @Override
+    public void onEvent( Event event )
+    {
+        if ( event instanceof ConfigurationEvent )
+        {
+            onEvent( (ConfigurationEvent) event );
+        }
+        else
+        {
+            logger.debug( "Event " + event.getClass( ).getName( ) + " Source 
Class: " + event.getSource( ).getClass( ).getName( ) );
+            logger.debug( "EventType " + event.getEventType( ) );
+        }
+    }
+
+    public void registerChangeListener( RegistryListener listener, String 
prefix )
+    {
+        listeners.put( prefix, new ListenerInfo( prefix, listener ) );
+    }
+
+    public boolean unregisterChangeListener( RegistryListener listener )
+    {
+        boolean found = false;
+        Iterator<Map.Entry<String, ListenerInfo>> it = listeners.entrySet( 
).iterator( );
+        while ( it.hasNext( ) )
+        {
+            Map.Entry<String, ListenerInfo> e = it.next( );
+            if ( e.getValue( ).listener == listener )
+            {
+                it.remove( );
+                found = true;
+            }
+        }
+        return found;
+    }
+
+    public TaskExecutor getDefaultExecutor( )
+    {
+        return defaultExecutor;
+    }
+
+    public void setDefaultExecutor( TaskExecutor defaultExecutor )
+    {
+        this.defaultExecutor = defaultExecutor;
+    }
+
+
+    public ApplicationContext getApplicationContext( )
+    {
+        return applicationContext;
+    }
+
+    public void setApplicationContext( ApplicationContext applicationContext )
+    {
+        this.applicationContext = applicationContext;
+    }
+}
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
index 4d3f758..d9fdc7a 100644
--- 
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
@@ -28,7 +28,10 @@ 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.event.ConfigurationEvent;
+import org.apache.commons.configuration2.event.EventSource;
 import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.commons.configuration2.ex.ConfigurationRuntimeException;
 import org.apache.commons.configuration2.interpol.ConfigurationInterpolator;
 import org.apache.commons.configuration2.interpol.DefaultLookups;
 import org.apache.commons.configuration2.interpol.InterpolatorSpecification;
@@ -51,6 +54,7 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.file.Path;
 import java.util.*;
+import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
@@ -65,9 +69,9 @@ import java.util.stream.StreamSupport;
  * <a 
href="http://commons.apache.org/commons/configuration/howto_configurationbuilder.html";>configuration
  * builder</a>.
  */
-@Service("acc2-configuration")
+@Service( "acc2-configuration" )
 public class CommonsConfigurationRegistry
-        implements ConfigRegistry
+    implements ConfigRegistry
 {
     private static final Pattern DOT_NAME_PATTERN = Pattern.compile( 
"([^.]+)(\\..*)*" );
 
@@ -78,15 +82,17 @@ public class CommonsConfigurationRegistry
 
 
     private ConfigurationBuilder<? extends Configuration> configurationBuilder;
-    boolean combined = true;
-    private Map<String, ConfigurationBuilder<? extends Configuration>> 
builderMap = new HashMap<>( );
+    private boolean combined = true;
+    private final Map<String, ConfigurationBuilder<? extends Configuration>> 
builderMap = new HashMap<>( );
 
-    private Logger logger = LoggerFactory.getLogger( getClass( ) );
+    private final Logger logger = LoggerFactory.getLogger( getClass( ) );
 
     private String propertyDelimiter = ".";
 
     private boolean addSystemProperties = false;
 
+    final CfgListener listener = new CfgListener( this );
+
     /**
      * The configuration properties for the registry. This should take the 
format of an input to the Commons
      * Configuration
@@ -96,12 +102,13 @@ public class CommonsConfigurationRegistry
     private String combinedConfigurationDefinition;
 
 
-    public CommonsConfigurationRegistry()
+    public CommonsConfigurationRegistry( )
     {
         // Default constructor
     }
 
-    public CommonsConfigurationRegistry(CombinedConfiguration configuration, 
ConfigurationBuilder<? extends Configuration> configurationBuilder)
+
+    public CommonsConfigurationRegistry( CombinedConfiguration configuration, 
CombinedConfigurationBuilder configurationBuilder )
     {
         if ( configuration == null )
         {
@@ -112,76 +119,120 @@ public class CommonsConfigurationRegistry
             throw new NullPointerException( "configuration builder cannot be 
null for a combined configuration" );
         }
         this.combined = true;
-        this.configuration = configuration;
+        setConfiguration(configuration);
         this.configurationBuilder = configurationBuilder;
     }
 
-    public CommonsConfigurationRegistry(Configuration configuration, 
ConfigurationBuilder<? extends Configuration> configurationBuilder)
+    @SuppressWarnings( "WeakerAccess" )
+    public CommonsConfigurationRegistry( Configuration configuration, 
ConfigurationBuilder<? extends Configuration> configurationBuilder )
     {
         if ( configuration == null )
         {
             throw new NullPointerException( "configuration can not be null" );
         }
-        this.configuration = configuration;
+        setConfiguration(configuration);
         this.configurationBuilder = configurationBuilder;
+        if (configuration instanceof CombinedConfiguration) {
+            this.combined = true;
+        }
     }
 
-    public String dump()
+    public void setConfiguration( Configuration configuration )
     {
-        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( "\"" );
+        this.configuration = configuration;
+        if (configuration instanceof EventSource ) {
+            EventSource evs = (EventSource) configuration;
+            evs.removeEventListener( ConfigurationEvent.ANY, listener );
+            evs.addEventListener( ConfigurationEvent.ANY, listener );
+            evs.addEventListener( ConfigurationEvent.SUBNODE_CHANGED, listener 
);
         }
-        return buffer.toString( );
     }
 
-    public boolean isEmpty()
+    @Override
+    public String dump( )
+    {
+        StringBuilder buffer = new StringBuilder( "Configuration Dump:\n");
+        Iterable<String> it = () -> configuration.getKeys();
+        return buffer.append(StreamSupport.stream( it.spliterator(), false 
).map( k ->
+            "\""+k+"\" = \""+configuration.getProperty( k ).toString() + 
"\"").collect(Collectors.joining( "\n" ) )).toString();
+    }
+
+    @Override
+    public boolean isEmpty( )
     {
         return configuration.isEmpty( );
     }
 
-    public ConfigRegistry getSubset(String key)
+    @Override
+    public ConfigRegistry getSubset( String key ) throws RegistryException
     {
+        if (configuration instanceof BaseHierarchicalConfiguration) {
+            BaseHierarchicalConfiguration cfg = 
(BaseHierarchicalConfiguration) configuration;
+            if (cfg.containsKey( key ))
+            {
+                try
+                {
+                    return new CommonsConfigurationRegistry( 
cfg.configurationAt( key, true ), null );
+                } catch ( ConfigurationRuntimeException ex ) {
+                    logger.error("There are multiple entries for the given 
key");
+                    throw new RegistryException( "Subset for multiple key 
entries is not possible.");
+                }
+            } else {
+                return new CommonsConfigurationRegistry( cfg.subset( key ), 
null );
+            }
+        }
         return new CommonsConfigurationRegistry( configuration.subset( key ), 
configurationBuilder );
     }
 
-    public List<String> getList(String key)
+    @Override
+    public List<String> getList( String key )
     {
         List<String> result = configuration.getList( String.class, key );
         return result == null ? new ArrayList<>( ) : result;
     }
 
-    public List<ConfigRegistry> getSubsetList(String key)
+    @Override
+    public List<ConfigRegistry> getSubsetList( String key ) throws 
RegistryException
     {
-        List<ConfigRegistry> subsets = new ArrayList<>( );
 
-        boolean done = false;
-        do
+        if (configuration instanceof BaseHierarchicalConfiguration) {
+            BaseHierarchicalConfiguration cfg = 
(BaseHierarchicalConfiguration)configuration;
+            return cfg.configurationsAt( key, true ).stream().map(c -> new 
CommonsConfigurationRegistry( c, null )).collect( Collectors.toList() );
+        } else
         {
-            ConfigRegistry registry = getSubset( key + "(" + subsets.size( ) + 
")" );
-            if ( !registry.isEmpty( ) )
-            {
-                subsets.add( registry );
-            } else
+            List<ConfigRegistry> subsets = new ArrayList<>( );
+            boolean done = false;
+            do
             {
-                done = true;
+                ConfigRegistry registry = null;
+                try
+                {
+                    registry = getSubset( key + "(" + subsets.size( ) + ")" );
+                }
+                catch ( RegistryException e )
+                {
+                    throw new RegistryException( "Could not retrieve subset 
from key "+key+": "+e.getMessage() );
+                }
+                if ( !registry.isEmpty( ) )
+                {
+                    subsets.add( registry );
+                }
+                else
+                {
+                    done = true;
+                }
             }
+            while ( !done );
+            return subsets;
         }
-        while ( !done );
-
-        return subsets;
     }
 
     @Override
-    public ConfigRegistry getPartOfCombined(String name)
+    public ConfigRegistry getPartOfCombined( String name )
     {
         if ( combined )
         {
-            CombinedConfiguration config = ( CombinedConfiguration ) 
configuration;
+            CombinedConfiguration config = (CombinedConfiguration) 
configuration;
             Configuration newCfg = config.getConfiguration( name );
             ConfigurationBuilder<? extends Configuration> cfgBuilder = null;
             try
@@ -189,10 +240,11 @@ public class CommonsConfigurationRegistry
                 if ( builderMap.containsKey( name ) )
                 {
                     cfgBuilder = builderMap.get( name );
-                } else
+                }
+                else
                 {
                     cfgBuilder = configurationBuilder == null ? null :
-                            (( CombinedConfigurationBuilder ) 
configurationBuilder).getNamedBuilder( name );
+                        ( (CombinedConfigurationBuilder) configurationBuilder 
).getNamedBuilder( name );
                     builderMap.put( name, cfgBuilder );
                 }
             }
@@ -205,7 +257,8 @@ public class CommonsConfigurationRegistry
         return null;
     }
 
-    public Map<String, String> getProperties(String key)
+    @Override
+    public Map<String, String> getProperties( String key )
     {
         Configuration configuration = this.configuration.subset( key );
 
@@ -222,18 +275,20 @@ public class CommonsConfigurationRegistry
         return properties;
     }
 
-    public void save()
-            throws RegistryException
+    @Override
+    public void save( )
+        throws RegistryException
     {
         if ( configuration instanceof FileBasedConfiguration )
         {
-            FileBasedConfiguration fileConfiguration = ( 
FileBasedConfiguration ) configuration;
+            FileBasedConfiguration fileConfiguration = 
(FileBasedConfiguration) configuration;
             FileHandler fileHandler;
             if ( configurationBuilder != null && configurationBuilder 
instanceof FileBasedConfigurationBuilder )
             {
-                FileBasedConfigurationBuilder cfgBuilder = ( 
FileBasedConfigurationBuilder ) configurationBuilder;
+                FileBasedConfigurationBuilder cfgBuilder = 
(FileBasedConfigurationBuilder) configurationBuilder;
                 fileHandler = cfgBuilder.getFileHandler( );
-            } else
+            }
+            else
             {
                 fileHandler = new FileHandler( fileConfiguration );
             }
@@ -245,177 +300,198 @@ public class CommonsConfigurationRegistry
             {
                 throw new RegistryException( e.getMessage( ), e );
             }
-        } else
+        }
+        else
         {
             throw new RegistryException( "Can only save file-based 
configurations" );
         }
     }
 
     @Override
-    public void registerChangeListener(RegistryListener listener, Pattern... 
filter)
+    public void registerChangeListener( RegistryListener listener, String 
prefix)
     {
-
+        this.listener.registerChangeListener(listener, prefix);
     }
 
     @Override
-    public boolean unregisterChangeListener(RegistryListener listener)
+    public boolean unregisterChangeListener( RegistryListener listener )
     {
-        return false;
+        return this.listener.unregisterChangeListener(listener);
     }
 
-
-    public Collection<String> getKeys()
+    @Override
+    public Collection<String> getBaseKeys( )
     {
-        Iterable<String> iterable = () -> configuration.getKeys( );
-        return StreamSupport.stream( iterable.spliterator( ), false )
-                .map( k -> DOT_NAME_PATTERN.matcher( k ) )
-                .filter( k -> k.matches( ) )
-                .map( k -> k.group( 1 ) ).collect( Collectors.toSet( ) );
+        Iterable<String> iterable = ( ) -> configuration.getKeys( );
+        return StreamSupport.stream( iterable.spliterator( ), true )
+            .map( DOT_NAME_PATTERN::matcher )
+            .filter( Matcher::matches )
+            .map( k -> k.group( 1 ) ).collect( Collectors.toSet( ) );
 
     }
 
-    public Collection getFullKeys()
+    @Override
+    public Collection<String> getKeys( )
     {
-        Iterable<String> iterable = () -> configuration.getKeys( );
-        return StreamSupport.stream( iterable.spliterator( ), false ).collect( 
Collectors.toSet( ) );
+        Iterable<String> iterable = ( ) -> configuration.getKeys( );
+        return StreamSupport.stream( iterable.spliterator( ), true ).collect( 
Collectors.toSet( ) );
     }
 
-    public void remove(String key)
+    @Override
+    public Collection<String> getKeys( String prefix )
+    {
+        Iterable<String> iterable = ( ) -> configuration.getKeys( prefix );
+        return StreamSupport.stream( iterable.spliterator( ), true ).collect( 
Collectors.toSet( ) );
+    }
+
+    @Override
+    public void remove( String key )
     {
         configuration.clearProperty( key );
     }
 
-    public void removeSubset(String key)
+    @Override
+    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( ) );
-        }
+        getKeys( key ).forEach( k -> configuration.clearProperty( k ) );
+    }
 
-        for ( Iterator i = keys.iterator( ); i.hasNext( ); )
-        {
-            configuration.clearProperty( ( String ) i.next( ) );
-        }
+    @Override
+    public Object getValue( String key ) {
+        return configuration.getProperty(  key );
     }
 
-    public String getString(String key)
+    @Override
+    public String getString( String key )
     {
         return configuration.getString( key );
     }
 
-    public String getString(String key, String defaultValue)
+    @Override
+    public String getString( String key, String defaultValue )
     {
         return configuration.getString( key, defaultValue );
     }
 
-    public void setString(String key, String value)
+    @Override
+    public void setString( String key, String value )
     {
         configuration.setProperty( key, value );
     }
 
-    public int getInt(String key)
+    @Override
+    public int getInt( String key )
     {
         return configuration.getInt( key );
     }
 
-    public int getInt(String key, int defaultValue)
+    @Override
+    public int getInt( String key, int defaultValue )
     {
         return configuration.getInt( key, defaultValue );
     }
 
-    public void setInt(String key, int value)
+    @Override
+    public void setInt( String key, int value )
     {
-        configuration.setProperty( key, Integer.valueOf( value ) );
+        configuration.setProperty( key, value );
     }
 
-    public boolean getBoolean(String key)
+    @Override
+    public boolean getBoolean( String key )
     {
         return configuration.getBoolean( key );
     }
 
-    public boolean getBoolean(String key, boolean defaultValue)
+    @Override
+    public boolean getBoolean( String key, boolean defaultValue )
     {
         return configuration.getBoolean( key, defaultValue );
     }
 
-    public void setBoolean(String key, boolean value)
+    @Override
+    public void setBoolean( String key, boolean value )
     {
-        configuration.setProperty( key, Boolean.valueOf( value ) );
+        configuration.setProperty( key, value );
     }
 
-    public void addConfigurationFromResource(String name, String resource)
-            throws RegistryException
+    @Override
+    public void addConfigurationFromResource( String name, String resource )
+        throws RegistryException
     {
         addConfigurationFromResource( name, resource, null );
     }
 
-    public void addConfigurationFromResource(String name, String resource, 
String prefix)
-            throws RegistryException
+    @Override
+    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;
+            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 ) );
+                        .configure( new Parameters( ).properties( )
+                            .setLocationStrategy( new 
ClasspathLocationStrategy( ) )
+                            .setFileName( resource ) );
                     builderMap.put( name, builder );
                     configuration.addConfiguration( builder.getConfiguration( 
), name, atPrefix );
                 }
                 catch ( ConfigurationException e )
                 {
                     throw new RegistryException(
-                            "Unable to add configuration from resource '" + 
resource + "': " + e.getMessage( ), e );
+                        "Unable to add configuration from resource '" + 
resource + "': " + e.getMessage( ), e );
                 }
-            } else if ( resource.endsWith( ".xml" ) )
+            }
+            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 ) );
+                        .configure( new Parameters( ).xml( )
+                            .setLocationStrategy( new 
ClasspathLocationStrategy( ) )
+                            .setFileName( resource ) );
                     builderMap.put( name, builder );
                     configuration.addConfiguration( builder.getConfiguration( 
), name, atPrefix );
                 }
                 catch ( ConfigurationException e )
                 {
                     throw new RegistryException(
-                            "Unable to add configuration from resource '" + 
resource + "': " + e.getMessage( ), e );
+                        "Unable to add configuration from resource '" + 
resource + "': " + e.getMessage( ), e );
                 }
-            } else
+            }
+            else
             {
                 throw new RegistryException(
-                        "Unable to add configuration from resource '" + 
resource + "': unrecognised type" );
+                    "Unable to add configuration from resource '" + resource + 
"': unrecognised type" );
             }
-        } else
+        }
+        else
         {
             throw new RegistryException( "The underlying configuration object 
is not a combined configuration " );
         }
     }
 
     @Override
-    public void addConfigurationFromFile(String name, Path file) throws 
RegistryException
+    public void addConfigurationFromFile( String name, Path file ) throws 
RegistryException
     {
         addConfigurationFromFile( name, file, "" );
     }
 
-    public void addConfigurationFromFile(String name, Path file, String prefix)
-            throws RegistryException
+    @Override
+    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;
+            CombinedConfiguration configuration = (CombinedConfiguration) 
this.configuration;
             String fileName = file.getFileName( ).toString( );
             if ( fileName.endsWith( ".properties" ) )
             {
@@ -423,10 +499,10 @@ public class CommonsConfigurationRegistry
                 {
                     logger.debug( "Loading properties configuration from file: 
{}", file );
                     FileBasedConfigurationBuilder<PropertiesConfiguration> 
builder = new FileBasedConfigurationBuilder<>( PropertiesConfiguration.class )
-                            .configure( new Parameters( ).properties( )
-                                    .setFileSystem( 
FileLocatorUtils.DEFAULT_FILE_SYSTEM )
-                                    .setLocationStrategy( 
FileLocatorUtils.DEFAULT_LOCATION_STRATEGY )
-                                    .setFile( file.toFile( ) ) );
+                        .configure( new Parameters( ).properties( )
+                            .setFileSystem( 
FileLocatorUtils.DEFAULT_FILE_SYSTEM )
+                            .setLocationStrategy( 
FileLocatorUtils.DEFAULT_LOCATION_STRATEGY )
+                            .setFile( file.toFile( ) ) );
                     // builder is needed for save
                     builderMap.put( name, builder );
                     configuration.addConfiguration( builder.getConfiguration( 
), name, atPrefix );
@@ -434,32 +510,35 @@ public class CommonsConfigurationRegistry
                 catch ( ConfigurationException e )
                 {
                     throw new RegistryException(
-                            "Unable to add configuration from file '" + 
file.getFileName( ) + "': " + e.getMessage( ), e );
+                        "Unable to add configuration from file '" + 
file.getFileName( ) + "': " + e.getMessage( ), e );
                 }
-            } else if ( fileName.endsWith( ".xml" ) )
+            }
+            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( )
-                                    .setFileSystem( 
FileLocatorUtils.DEFAULT_FILE_SYSTEM )
-                                    .setLocationStrategy( 
FileLocatorUtils.DEFAULT_LOCATION_STRATEGY )
-                                    .setFile( file.toFile( ) ) );
+                        .configure( new Parameters( ).xml( )
+                            .setFileSystem( 
FileLocatorUtils.DEFAULT_FILE_SYSTEM )
+                            .setLocationStrategy( 
FileLocatorUtils.DEFAULT_LOCATION_STRATEGY )
+                            .setFile( file.toFile( ) ) );
                     builderMap.put( name, builder );
                     configuration.addConfiguration( builder.getConfiguration( 
), name, atPrefix );
                 }
                 catch ( ConfigurationException e )
                 {
                     throw new RegistryException(
-                            "Unable to add configuration from file '" + 
file.getFileName( ) + "': " + e.getMessage( ), e );
+                        "Unable to add configuration from file '" + 
file.getFileName( ) + "': " + e.getMessage( ), e );
                 }
-            } else
+            }
+            else
             {
                 throw new RegistryException(
-                        "Unable to add configuration from file '" + 
file.getFileName( ) + "': unrecognised type" );
+                    "Unable to add configuration from file '" + 
file.getFileName( ) + "': unrecognised type" );
             }
-        } else
+        }
+        else
         {
             throw new RegistryException( "The underlying configuration is not 
a combined configuration object." );
         }
@@ -471,22 +550,24 @@ public class CommonsConfigurationRegistry
     class StringFileSystem extends FileSystem
     {
 
-        String content;
+        final String content;
         String encoding = "UTF-8";
 
-        StringFileSystem(String content)
+        StringFileSystem( String content )
         {
             this.content = content;
         }
 
-        StringFileSystem(String encoding, String content)
+
+        @SuppressWarnings( "unused" )
+        StringFileSystem( String encoding, String content )
         {
             this.encoding = encoding;
             this.content = content;
         }
 
         @Override
-        public InputStream getInputStream(URL url) throws 
ConfigurationException
+        public InputStream getInputStream( URL url ) throws 
ConfigurationException
         {
             try
             {
@@ -500,37 +581,37 @@ public class CommonsConfigurationRegistry
         }
 
         @Override
-        public OutputStream getOutputStream(URL url) throws 
ConfigurationException
+        public OutputStream getOutputStream( URL url )
         {
             return new ByteArrayOutputStream( 0 );
         }
 
         @Override
-        public OutputStream getOutputStream(File file) throws 
ConfigurationException
+        public OutputStream getOutputStream( File file )
         {
             return new ByteArrayOutputStream( 0 );
         }
 
         @Override
-        public String getPath(File file, URL url, String basePath, String 
fileName)
+        public String getPath( File file, URL url, String basePath, String 
fileName )
         {
             return basePath + "/" + fileName;
         }
 
         @Override
-        public String getBasePath(String path)
+        public String getBasePath( String path )
         {
             return path;
         }
 
         @Override
-        public String getFileName(String path)
+        public String getFileName( String path )
         {
             return path;
         }
 
         @Override
-        public URL locateFromURL(String basePath, String fileName)
+        public URL locateFromURL( String basePath, String fileName )
         {
             try
             {
@@ -544,24 +625,17 @@ public class CommonsConfigurationRegistry
         }
 
         @Override
-        public URL getURL(String basePath, String fileName) throws 
MalformedURLException
+        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;
-            }
+            return new URL( "file://" + getPath( null, null, basePath, 
fileName ) );
         }
 
     }
 
+    @Override
     @PostConstruct
-    public void initialize()
-            throws RegistryException
+    public void initialize( )
+        throws RegistryException
     {
         try
         {
@@ -571,11 +645,11 @@ public class CommonsConfigurationRegistry
                 String interpolatedProps;
                 Parameters params = new Parameters( );
                 DefaultExpressionEngineSymbols symbols = new 
DefaultExpressionEngineSymbols.Builder( 
DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS )
-                        .setPropertyDelimiter( propertyDelimiter )
-                        .setIndexStart( "(" )
-                        .setIndexEnd( ")" )
-                        .setEscapedDelimiter( "\\" + propertyDelimiter )
-                        .create( );
+                    .setPropertyDelimiter( propertyDelimiter )
+                    .setIndexStart( "(" )
+                    .setIndexEnd( ")" )
+                    .setEscapedDelimiter( "\\" + propertyDelimiter )
+                    .create( );
                 DefaultExpressionEngine expressionEngine = new 
DefaultExpressionEngine( symbols );
 
                 // It allows to use system properties in the XML declaration.
@@ -587,24 +661,25 @@ public class CommonsConfigurationRegistry
                 // for the sources that are used for the CombinedConfiguration.
                 FileSystem fs = new StringFileSystem( interpolatedProps );
                 FileBasedConfigurationBuilder<XMLConfiguration> cfgBuilder =
-                        new FileBasedConfigurationBuilder<>(
-                                XMLConfiguration.class )
-                                .configure( params.xml( )
-                                        .setFileSystem( fs )
-                                        .setFileName( "config.xml" )
-                                        .setListDelimiterHandler(
-                                                new 
DefaultListDelimiterHandler( ',' ) )
-                                        .setExpressionEngine( expressionEngine 
)
-                                        .setThrowExceptionOnMissing( false ) );
+                    new FileBasedConfigurationBuilder<>(
+                        XMLConfiguration.class )
+                        .configure( params.xml( )
+                            .setFileSystem( fs )
+                            .setFileName( "config.xml" )
+                            .setListDelimiterHandler(
+                                new DefaultListDelimiterHandler( ',' ) )
+                            .setExpressionEngine( expressionEngine )
+                            .setThrowExceptionOnMissing( false ) );
 
                 CombinedConfigurationBuilder builder = new 
CombinedConfigurationBuilder( ).
-                        configure( params.combined( ).setDefinitionBuilder( 
cfgBuilder ) );
+                    configure( params.combined( ).setDefinitionBuilder( 
cfgBuilder ) );
                 // The builder is needed later for saving of the file parts in 
the combined configuration.
                 this.configurationBuilder = builder;
                 configuration = builder.getConfiguration( );
 
 
-            } else
+            }
+            else
             {
                 logger.debug( "Creating a default configuration - no 
configuration was provided" );
                 NodeCombiner combiner = new UnionCombiner( );
@@ -625,43 +700,38 @@ public class CommonsConfigurationRegistry
             logger.error( "Fatal error, while reading the configuration 
definition: " + e.getMessage( ) );
             logger.error( "The definition was:" );
             logger.error( combinedConfigurationDefinition );
-            throw new RuntimeException( e.getMessage( ), e );
+            throw new RegistryException( e.getMessage( ), e );
         }
     }
 
-    public void setCombinedConfigurationDefinition(String 
combinedConfigurationDefinition)
+    public void setCombinedConfigurationDefinition( String 
combinedConfigurationDefinition )
     {
         this.combinedConfigurationDefinition = combinedConfigurationDefinition;
     }
 
-    public String getPropertyDelimiter()
+    public String getPropertyDelimiter( )
     {
         return propertyDelimiter;
     }
 
-    public void setPropertyDelimiter(String propertyDelimiter)
+    public void setPropertyDelimiter( String propertyDelimiter )
     {
         this.propertyDelimiter = propertyDelimiter;
     }
 
 
-    public ConfigurationBuilder<? extends Configuration> 
getConfigurationBuilder()
+    public ConfigurationBuilder<? extends Configuration> 
getConfigurationBuilder( )
     {
         return configurationBuilder;
     }
 
-    public void setConfigurationBuilder(ConfigurationBuilder<? extends 
Configuration> configurationBuilder)
-    {
-        this.configurationBuilder = configurationBuilder;
-    }
-
     /**
      * Returns true, if the system properties are added to the base 
configuration. Otherwise system properties
-     * can be interpolated by ${sys:var} syntax.
+     * can still be interpolated by ${sys:var} syntax.
      *
-     * @return
+     * @return True, if system properties are added to the configuration root
      */
-    public boolean isAddSystemProperties()
+    public boolean isAddSystemProperties( )
     {
         return addSystemProperties;
     }
@@ -670,9 +740,9 @@ public class CommonsConfigurationRegistry
      * Set to true, if the system properties should be added to the base 
configuration.
      * If set to false, system properties are no direct part of the 
configuration.
      *
-     * @param addSystemProperties
+     * @param addSystemProperties True, or false.
      */
-    public void setAddSystemProperties(boolean addSystemProperties)
+    public void setAddSystemProperties( boolean addSystemProperties )
     {
         this.addSystemProperties = addSystemProperties;
     }
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
index a51ff77..e08bdfb 100644
--- 
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
@@ -82,7 +82,7 @@ public abstract class AbstractRegistryTest
         try
         {
             registry.getInt( "unknown" );
-            assertTrue( "no NoSuchElementException", false );
+            fail( "no NoSuchElementException" );
         }
         catch ( NoSuchElementException e )
         {
@@ -113,7 +113,7 @@ public abstract class AbstractRegistryTest
         throws Exception
     {
         ConfigRegistry registry = getRegistry();
-        assertEquals( "not true ", true, registry.getBoolean( "boolean" ) );
+        assertTrue( "not true ", registry.getBoolean( "boolean" ) );
     }
 
     @Test
@@ -124,7 +124,7 @@ public abstract class AbstractRegistryTest
         try
         {
             registry.getBoolean( "unknown" );
-            assertTrue( "no NoSuchElementException", false );
+            fail( "no NoSuchElementException" );
         }
         catch ( NoSuchElementException e )
         {
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
index 778dc45..6dd854c 100644
--- 
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
@@ -32,7 +32,6 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
-import java.rmi.registry.Registry;
 import java.util.*;
 
 /**
@@ -48,84 +47,108 @@ public class CommonsConfigurationRegistryTest
 
     private static final int INT_TEST_VALUE = 8080;
 
-    public String getRoleHint()
+    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 );
+    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()
+    public void testDefaultConfiguration( )
         throws Exception
     {
-        registry = getRegistry( "default" , true);
+        registry = getRegistry( "default", true );
 
         assertEquals( "Check system property override", System.getProperty( 
"user.dir" ),
-                      registry.getString( "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 testGetKeys() throws Exception
+    public void testGetKeys( ) throws Exception
     {
         registry = getRegistry( "builder" );
-        Collection<String> keys = registry.getKeys( );
+        Collection<String> keys = registry.getBaseKeys( );
         HashSet<Object> expectedKeySet = new HashSet<>( );
-        expectedKeySet.add("test");
-        expectedKeySet.add("repository");
-        expectedKeySet.add("objects");
-        expectedKeySet.add("properties");
-        expectedKeySet.add("strings");
-        expectedKeySet.add("user");
-        expectedKeySet.add("foo");
-        expectedKeySet.add("string");
-        expectedKeySet.add("boolean");
-        expectedKeySet.add("subOne");
+        expectedKeySet.add( "test" );
+        expectedKeySet.add( "repository" );
+        expectedKeySet.add( "objects" );
+        expectedKeySet.add( "properties" );
+        expectedKeySet.add( "strings" );
+        expectedKeySet.add( "user" );
+        expectedKeySet.add( "foo" );
+        expectedKeySet.add( "string" );
+        expectedKeySet.add( "boolean" );
+        expectedKeySet.add( "subOne" );
         expectedKeySet.add( "two" );
         assertEquals( expectedKeySet, keys );
+    }
 
-
-        expectedKeySet.clear();
-
-
+    @Test
+    public void testGetFullKeys( ) throws Exception
+    {
+        registry = getRegistry( "builder" );
+        Collection<String> keys = registry.getKeys( );
+        HashSet<Object> expectedKeySet = new HashSet<>( );
+        String[] expStrings = new String[]{
+            "test.value",
+            "test.number",
+            "test.boolean",
+            "test.interpolation",
+            "repository",
+            "objects.object.foo",
+            "properties.foo",
+            "properties.bar",
+            "strings.string",
+            "user.dir",
+            "foo.bar",
+            "subOne.firstEntry",
+            "subOne.secondEntry",
+            "two",
+            "string",
+            "boolean"
+        };
+        Collections.addAll( expectedKeySet, expStrings );
+        assertEquals( expectedKeySet, keys );
     }
 
     @Test
-    public void testBuilderConfiguration()
+    public void testBuilderConfiguration( )
         throws Exception
     {
         registry = getRegistry( "builder", true );
 
         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" ) );
+            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()
+    public void testDump( )
         throws Exception
     {
-        registry = getRegistry( "default" );
-
-        String dump = registry.dump();
-        System.out.println( dump );
-        assertTrue( dump.startsWith( "Configuration Dump." ) );
+        registry = getRegistry( "builder" );
+        String dump = registry.dump( );
+        System.out.println(dump);
+        assertTrue( dump.startsWith( "Configuration Dump:" ) );
+        assertTrue( dump.contains( "\"properties.foo\" = \"bar\"" ));
     }
 
     @Test
-    public void testDefaults()
+    public void testDefaults( )
         throws Exception
     {
         registry = getRegistry( "builder" );
@@ -136,7 +159,7 @@ public class CommonsConfigurationRegistryTest
         try
         {
             registry.getInt( "foo" );
-            fail();
+            fail( );
         }
         catch ( NoSuchElementException e )
         {
@@ -148,7 +171,7 @@ public class CommonsConfigurationRegistryTest
         try
         {
             registry.getBoolean( "foo" );
-            fail();
+            fail( );
         }
         catch ( NoSuchElementException e )
         {
@@ -159,60 +182,60 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testInterpolation()
+    public void testInterpolation( )
         throws Exception
     {
-        registry = getRegistry( "builder" , true );
+        registry = getRegistry( "builder", true );
 
         assertEquals( "Check system property interpolation", 
System.getProperty( "user.home" ) + "/.m2/repository",
-                      registry.getString( "repository" ) );
+            registry.getString( "repository" ) );
 
         assertEquals( "Check configuration value interpolation", "foo/bar",
-                      registry.getString( "test.interpolation" ) );
+            registry.getString( "test.interpolation" ) );
     }
 
     @Test
-    public void testAddConfigurationXmlFile()
+    public void testAddConfigurationXmlFile( )
         throws Exception
     {
-        registry = getRegistry( "default" , true);
+        registry = getRegistry( "default", true );
 
         registry.addConfigurationFromFile( "test.xml", Paths.get( 
"src/test/resources/test.xml" ) );
         assertEquals( "Check system property default", System.getProperty( 
"user.dir" ),
-                      registry.getString( "user.dir" ) );
+            registry.getString( "user.dir" ) );
         assertEquals( "Check other properties are loaded", "foo", 
registry.getString( "test.value" ) );
     }
 
     @Test
-    public void testAddConfigurationPropertiesFile()
+    public void testAddConfigurationPropertiesFile( )
         throws Exception
     {
         registry = getRegistry( "default", true );
 
         registry.addConfigurationFromFile(
-            "test.properties", Paths.get("src/test/resources/test.properties" 
) );
+            "test.properties", Paths.get( "src/test/resources/test.properties" 
) );
 
         assertEquals( "Check system property default", System.getProperty( 
"user.dir" ),
-                      registry.getString( "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()
+    public void testAddConfigurationXmlResource( )
         throws Exception
     {
-        registry = getRegistry( "default" , true);
+        registry = getRegistry( "default", true );
 
         registry.addConfigurationFromResource( "test.xml-r", "test.xml" );
 
         assertEquals( "Check system property default", System.getProperty( 
"user.dir" ),
-                      registry.getString( "user.dir" ) );
+            registry.getString( "user.dir" ) );
         assertEquals( "Check other properties are loaded", "foo", 
registry.getString( "test.value" ) );
     }
 
     @Test
-    public void testAddConfigurationPropertiesResource()
+    public void testAddConfigurationPropertiesResource( )
         throws Exception
     {
         registry = getRegistry( "default", true );
@@ -220,13 +243,13 @@ public class CommonsConfigurationRegistryTest
         registry.addConfigurationFromResource( "test.properties-r", 
"test.properties" );
 
         assertEquals( "Check system property default", System.getProperty( 
"user.dir" ),
-                      registry.getString( "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()
+    public void testAddConfigurationUnrecognisedType( )
         throws Exception
     {
         registry = getRegistry( "default" );
@@ -234,7 +257,7 @@ public class CommonsConfigurationRegistryTest
         try
         {
             registry.addConfigurationFromResource( "test.foo", "test.foo" );
-            fail();
+            fail( );
         }
         catch ( RegistryException e )
         {
@@ -245,7 +268,7 @@ public class CommonsConfigurationRegistryTest
         {
             registry.addConfigurationFromFile( "test.foo-file",
                 Paths.get( "src/test/resources/test.foo" ) );
-            fail();
+            fail( );
         }
         catch ( RegistryException e )
         {
@@ -254,26 +277,25 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testIsEmpty()
+    public void testIsEmpty( )
         throws Exception
     {
         registry = getRegistry( "default", true );
-
-        assertFalse( registry.isEmpty() );
-        assertTrue( registry.getSubset( "foo" ).isEmpty() );
+        assertFalse( registry.isEmpty( ) );
+        assertTrue( registry.getSubset( "foo" ).isEmpty( ) );
     }
 
     @Test
-    public void testIsEmptyWithoutSysProps()
-            throws Exception
+    public void testIsEmptyWithoutSysProps( )
+        throws Exception
     {
-        registry = getRegistry( "default");
+        registry = getRegistry( "default" );
 
-        assertTrue( registry.isEmpty() );
+        assertTrue( registry.isEmpty( ) );
     }
 
     @Test
-    public void testGetSubset()
+    public void testGetSubset( )
         throws Exception
     {
         registry = getRegistry( "builder" );
@@ -285,13 +307,13 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testGetSubsetList()
+    public void testGetSubsetList( )
         throws Exception
     {
         registry = getRegistry( "builder" );
 
         List list = registry.getSubsetList( "objects.object" );
-        assertEquals( 2, list.size() );
+        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 );
@@ -299,47 +321,47 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testGetProperties()
+    public void testGetProperties( )
         throws Exception
     {
         registry = getRegistry( "builder" );
 
-        Map<String,String> properties = registry.getProperties( "properties" );
-        assertEquals( 2, properties.size() );
+        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()
+    public void testGetList( )
         throws Exception
     {
         registry = getRegistry( "builder" );
 
         List list = registry.getList( "strings.string" );
-        assertEquals( 3, list.size() );
+        assertEquals( 3, list.size( ) );
         assertEquals( "s1", list.get( 0 ) );
         assertEquals( "s2", list.get( 1 ) );
         assertEquals( "s3", list.get( 2 ) );
     }
 
     @Test
-    public void testGetSection()
+    public void testGetSection( )
         throws Exception
     {
         this.registry = getRegistry( "builder" );
         ConfigRegistry registry = this.registry.getPartOfCombined( 
"properties" );
-        assertNotNull(registry);
+        assertNotNull( registry );
         assertNull( registry.getString( "test.value" ) );
         assertEquals( "baz", registry.getString( "foo.bar" ) );
     }
 
     @Test
-    public void testRemoveKey()
+    public void testRemoveKey( )
         throws Exception
     {
         registry = getRegistry( "builder" );
-        assertNotNull(registry);
+        assertNotNull( registry );
         ConfigRegistry registry = this.registry.getPartOfCombined( 
"properties" );
         assertEquals( "baz", registry.getString( "foo.bar" ) );
         registry.remove( "foo.bar" );
@@ -347,11 +369,11 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testRemoveSubset()
+    public void testRemoveSubset( )
         throws Exception
     {
         registry = getRegistry( "builder" );
-        assertNotNull(registry);
+        assertNotNull( registry );
 
         registry.removeSubset( "strings" );
         assertEquals( Collections.EMPTY_LIST, registry.getList( 
"strings.string" ) );
@@ -378,7 +400,7 @@ public class CommonsConfigurationRegistryTest
 */
 
     @Test
-    public void testGetDontForceCreateByName()
+    public void testGetDontForceCreateByName( )
         throws Exception
     {
         registry = getRegistry( "noForceCreate" );
@@ -387,7 +409,7 @@ public class CommonsConfigurationRegistryTest
     }
 
     @Test
-    public void testSaveSection()
+    public void testSaveSection( )
         throws Exception
     {
         Path src = Paths.get( "src/test/resources/test-save.xml" );
@@ -397,24 +419,24 @@ public class CommonsConfigurationRegistryTest
         registry = getRegistry( "test-save" );
 
         ConfigRegistry registry = this.registry.getPartOfCombined( 
"org.codehaus.plexus.registry" );
-        assertEquals( "check list elements", Arrays.asList( new String[]{ "1", 
"2", "3" } ),
-                      registry.getList( "listElements.listElement" ) );
+        assertEquals( "check list elements", Arrays.asList( new String[]{"1", 
"2", "3"} ),
+            registry.getList( "listElements.listElement" ) );
 
         registry.remove( "listElements.listElement(1)" );
-        registry.save();
+        registry.save( );
 
-        FileBasedConfigurationBuilder<XMLConfiguration> builder = new 
FileBasedConfigurationBuilder<>( XMLConfiguration.class)
-                .configure( new Parameters().xml().setFile(dest.toFile()) );
-        XMLConfiguration configuration = builder.getConfiguration();
-        assertEquals( Arrays.asList( new String[]{ "1", "3" } ), 
configuration.getList( "listElements.listElement" ) );
+        FileBasedConfigurationBuilder<XMLConfiguration> builder = new 
FileBasedConfigurationBuilder<>( XMLConfiguration.class )
+            .configure( new Parameters( ).xml( ).setFile( dest.toFile( ) ) );
+        XMLConfiguration configuration = builder.getConfiguration( );
+        assertEquals( Arrays.asList( new String[]{"1", "3"} ), 
configuration.getList( "listElements.listElement" ) );
 
         // file in ${basedir}/target/conf/shared.xml
         ConfigRegistry section = this.registry.getPartOfCombined( 
"org.apache.maven.shared.app.user" );
         section.setString( "foo", "zloug" );
-        section.save();
-        builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class)
-                .configure( new Parameters().xml().setFile( 
Paths.get("target/conf/shared.xml").toFile() ) );
-        configuration = builder.getConfiguration();
+        section.save( );
+        builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class )
+            .configure( new Parameters( ).xml( ).setFile( Paths.get( 
"target/conf/shared.xml" ).toFile( ) ) );
+        configuration = builder.getConfiguration( );
         assertNotNull( configuration.getString( "foo" ) );
 
     }
diff --git 
a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/MockChangeListener.java
 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/MockChangeListener.java
new file mode 100644
index 0000000..f68491a
--- /dev/null
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/java/org/apache/archiva/redback/common/config/acc2/MockChangeListener.java
@@ -0,0 +1,37 @@
+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.EventType;
+import org.apache.archiva.redback.common.config.api.RegistryListener;
+
+/**
+ * @author Martin Stockhammer <[email protected]>
+ */
+public class MockChangeListener implements RegistryListener
+{
+    @Override
+    public void handleConfigurationChangeEvent( ConfigRegistry registry, 
EventType eventType, String propertyName, Object propertyValue, Object oldValue 
)
+    {
+
+    }
+
+}
diff --git 
a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/log4j2-test.xml
 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/log4j2-test.xml
index 7fe2214..72c85db 100644
--- 
a/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/log4j2-test.xml
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-acc2/src/test/resources/log4j2-test.xml
@@ -26,13 +26,17 @@
   </appenders>
 
   <loggers>
+    <logger name="org.apache.archiva.redback" level="INFO" />
+    <logger name="commons.beanutils" level="ERROR" />
+    <logger name="commons.beanutils.FluentPropertyBeanIntrospector" 
level="ERROR" />
     <logger name="org.apache.cxf" level="info"/>
-    <logger name="org.springframework" level="error"/>
-    <logger name="org.apache.archiva.redback.components.cache" level="error"/>
-    <logger name="org.apache.archiva.redback.rest" level="error"/>
+    <logger name="org.springframework" level="ERROR"/>
+    <logger name="org.apache.archiva.redback.components.cache" level="ERROR"/>
+    <logger name="org.apache.archiva.redback.rest" level="ERROR"/>
     <logger name="org.apache.catalina" level="off" />
     <logger name="JPOX" level="ERROR"/>
-    <root level="info">
+    <logger name="org.apache.archiva.redback.common.config.acc2.CfgListener" 
level="DEBUG" />
+    <root level="ERROR">
       <appender-ref ref="console"/>
     </root>
   </loggers>
diff --git 
a/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/AsyncListener.java
 
b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/AsyncListener.java
new file mode 100644
index 0000000..21627ac
--- /dev/null
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/AsyncListener.java
@@ -0,0 +1,49 @@
+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.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ *
+ * A annotation that marks a event listener method as asynchronous. That means 
the listener event methods
+ * are run in a separated thread. How tasks are executed is dependent on the 
implementation.
+ *
+ * @author Martin Stockhammer <[email protected]>
+ * @since 3.0
+ */
+
+@Target(value={METHOD, TYPE})
+@Retention(value=RUNTIME)
+@Documented
+public @interface AsyncListener
+{
+    /**
+     * May be set to set the executor. The meaning of this value is 
implementation specific.
+     * @return The value.
+     */
+    String value() default "";
+}
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
index 1946cbe..6955e7c 100644
--- 
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
@@ -23,6 +23,7 @@ import java.nio.file.Path;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.regex.Pattern;
 
 /**
@@ -49,6 +50,14 @@ public interface ConfigRegistry
     String dump( );
 
     /**
+     * Get the original value stored in the registry. If not found, 
<code>null</code> is returned.
+     *
+     * @param key The key in the registry.
+     * @return The value.
+     */
+    Object getValue( String key);
+
+    /**
      * Get a string value from the registry. If not found, <code>null</code> 
is returned.
      *
      * @param key the key in the registry
@@ -81,7 +90,7 @@ public interface ConfigRegistry
      * @throws java.util.NoSuchElementException
      *          if the key is not found
      */
-    int getInt( String key );
+    int getInt( String key ) throws NoSuchElementException;
 
     /**
      * Get an integer value from the registry. If not found, the default value 
is used.
@@ -108,7 +117,7 @@ public interface ConfigRegistry
      * @throws java.util.NoSuchElementException
      *          if the key is not found
      */
-    boolean getBoolean( String key );
+    boolean getBoolean( String key ) throws NoSuchElementException;
 
     /**
      * Get a boolean value from the registry. If not found, the default value 
is used.
@@ -177,7 +186,7 @@ public interface ConfigRegistry
     boolean isEmpty( );
 
     /**
-     * Get a list of strings at the given key in the registry.
+     * Get a list of strings at the given key in the registry. If not found a 
empty list will be returned.
      *
      * @param key the key to lookup
      * @return the list of strings
@@ -198,7 +207,7 @@ public interface ConfigRegistry
      * @param key the key to take the subset from
      * @return the registry subset
      */
-    ConfigRegistry getSubset( String key );
+    ConfigRegistry getSubset( String key ) throws RegistryException;
 
     /**
      * Get a list of subsets of the registry, for all keys descended from the 
given key.
@@ -206,7 +215,7 @@ public interface ConfigRegistry
      * @param key the key to take the subsets from
      * @return the registry subsets
      */
-    List<ConfigRegistry> getSubsetList( String key );
+    List<ConfigRegistry> getSubsetList( String key ) throws RegistryException;
 
     /**
      * Get a configuration source part of the registry, identified by the 
given name. If it doesn't exist, <code>null</code> will be
@@ -234,7 +243,7 @@ public interface ConfigRegistry
      *
      * @param listener the listener
      */
-    void registerChangeListener( RegistryListener listener, Pattern... filter 
);
+    void registerChangeListener( RegistryListener listener, String prefix );
 
     /**
      * Unregister the change listener for all events.
@@ -245,17 +254,25 @@ public interface ConfigRegistry
     boolean unregisterChangeListener( RegistryListener listener );
 
     /**
-     * Get all the keys in this registry. Keys are only retrieved at a depth 
of 1.
+     * Get all keys on the base level in this registry. Keys are only 
retrieved at a depth of 1.
      *
      * @return the set of keys
      */
-    Collection<String> getKeys( );
+    Collection<String> getBaseKeys( );
 
     /**
      * Get all the keys in this registry.
      * @return the set of keys
      */
-    Collection<String> getFullKeys( );
+    Collection<String> getKeys( );
+
+    /**
+     * Return the keys that match the given prefix.
+     *
+     * @param prefix The prefix
+     * @return A collection of keys
+     */
+    Collection<String> getKeys( String prefix);
 
     /**
      * Remove a keyed element from the registry.
diff --git 
a/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/EventType.java
 
b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/EventType.java
new file mode 100644
index 0000000..e7c69f7
--- /dev/null
+++ 
b/redback-common/redback-common-configuration/redback-common-configuration-api/src/main/java/org/apache/archiva/redback/common/config/api/EventType.java
@@ -0,0 +1,28 @@
+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.
+ */
+
+/**
+ * @author Martin Stockhammer <[email protected]>
+ */
+public enum EventType
+{
+    PROPERTY_SET,PROPERTY_CLEARED,PROPERTY_ADDED,UNDEFINED
+}
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
index a76d6df..698aa05 100644
--- 
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
@@ -24,22 +24,20 @@ package org.apache.archiva.redback.common.config.api;
  */
 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.
      *
+     * The method may be annotated by the {@link AsyncListener @AsyncListener} 
annotation. Which means the method will be
+     * executed asynchronously.
+     *
      * @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 );
+    void handleConfigurationChangeEvent( ConfigRegistry registry, EventType 
eventType, String propertyName, Object propertyValue, Object oldValue );
+
+
+
 }

Reply via email to