simplifying the default config admin and dropping felix-utils + making it pluggable
diff --git a/winegrower-core/pom.xml b/winegrower-core/pom.xml
index edb439b..05d0383 100644
--- a/winegrower-core/pom.xml
+++ b/winegrower-core/pom.xml
@@ -55,11 +55,6 @@
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.apache.felix</groupId>
-      <artifactId>org.apache.felix.utils</artifactId>
-      <version>1.11.0</version>
-    </dependency>
 
     <dependency>
       <groupId>org.slf4j</groupId>
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java b/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
index 340b071..60da7b9 100644
--- a/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
+++ b/winegrower-core/src/main/java/org/apache/winegrower/Ripener.java
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
@@ -168,7 +169,7 @@
     class Impl implements Ripener {
         private static final Logger LOGGER = LoggerFactory.getLogger(Ripener.class);
 
-        private final DefaultConfigurationAdmin configurationAdmin = new DefaultConfigurationAdmin();
+        private final ConfigurationAdmin configurationAdmin;
         private final OSGiServices services = new OSGiServices(this);
         private final BundleRegistry registry;
 
@@ -180,6 +181,7 @@
             this.configuration = configuration;
             this.registry = new BundleRegistry(services, configuration);
 
+            this.configurationAdmin = loadConfigurationAdmin();
             this.services.registerService(
                     new String[]{ConfigurationAdmin.class.getName()}, this.configurationAdmin, new Hashtable<>(),
                     this.registry.getBundles().get(0L).getBundle());
@@ -191,6 +193,14 @@
             }
         }
 
+        private ConfigurationAdmin loadConfigurationAdmin() {
+            final Iterator<ConfigurationAdmin> configurationAdminIterator = ServiceLoader.load(ConfigurationAdmin.class).iterator();
+            if (configurationAdminIterator.hasNext()) {
+                return configurationAdminIterator.next();
+            }
+            return new DefaultConfigurationAdmin();
+        }
+
         public void loadConfiguration(final InputStream stream) throws IOException {
             final Properties embedConfig = new Properties();
             if (stream != null) {
diff --git a/winegrower-core/src/main/java/org/apache/winegrower/service/DefaultConfigurationAdmin.java b/winegrower-core/src/main/java/org/apache/winegrower/service/DefaultConfigurationAdmin.java
index 0ff29e2..c450d95 100644
--- a/winegrower-core/src/main/java/org/apache/winegrower/service/DefaultConfigurationAdmin.java
+++ b/winegrower-core/src/main/java/org/apache/winegrower/service/DefaultConfigurationAdmin.java
@@ -14,18 +14,23 @@
 package org.apache.winegrower.service;
 
 import static java.util.Collections.list;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toMap;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Date;
 import java.util.Dictionary;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.Properties;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.apache.felix.utils.properties.Properties;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
@@ -74,6 +79,8 @@
     private static class DefaultConfiguration implements Configuration {
         private final String factoryPid;
         private final String pid;
+        private final Map<String, String> defaultConfig = new HashMap<>();
+        private final File defaultExternalConfigLocation;
         private String location;
         private final Hashtable<String, Object> properties;
         private final AtomicLong changeCount = new AtomicLong();
@@ -83,34 +90,43 @@
             this.pid = pid;
             this.location = location;
             this.properties = new Hashtable<>();
-            // try to load properties for external file
-            // first check using the winegrower.config.path system properties
-            if (System.getProperty(WINEGROWER_CONFIG_PATH) != null) {
-                File file = new File(System.getProperty(WINEGROWER_CONFIG_PATH), pid + WINEGROWER_CONFIG_EXTENSION);
-                if (file.exists()) {
-                    try {
-                        Properties properties = new Properties(file);
-                        this.properties.putAll(properties);
-                    } catch (IOException ioe) {
-                        ioe.printStackTrace();
-                    }
+            this.defaultExternalConfigLocation = new File(
+                    // support a cascade of known "homes"
+                    System.getProperty(WINEGROWER_CONFIG_PATH,
+                            System.getProperty("karaf.base",
+                                    System.getProperty("catalina.base",
+                                            System.getProperty("karaf.home")))),
+                    pid + WINEGROWER_CONFIG_EXTENSION);
+            loadConfig(pid);
+
+        }
+
+        private void loadConfig(final String pid) {
+            // we first read the config from the classpath (lowest priority)
+            try (final InputStream embedConfig = Thread.currentThread().getContextClassLoader()
+                                                       .getResourceAsStream(pid + WINEGROWER_CONFIG_EXTENSION)) {
+                if (embedConfig != null) {
+                    defaultConfig.putAll(load(embedConfig));
                 }
-            // second, we fallback to look for the config file in the classpath
-            } else if (this.getClass().getResourceAsStream("/" + pid + WINEGROWER_CONFIG_EXTENSION) != null) {
-                Properties properties = new Properties();
-                try {
-                    properties.load(this.getClass().getResourceAsStream("/" + pid + WINEGROWER_CONFIG_EXTENSION));
-                    this.properties.putAll(properties);
-                } catch (IOException ioe) {
-                    ioe.printStackTrace();
-                }
-            // finally, we fallback to system properties
-            } else {
-                final String prefix = "winegrower.service." + pid + ".";
-                System.getProperties().stringPropertyNames().stream()
-                    .filter(it -> it.startsWith(prefix))
-                    .forEach(key -> properties.put(key.substring(prefix.length()), System.getProperty(key)));
+            } catch (final IOException e) {
+                throw new IllegalArgumentException(e);
             }
+            properties.putAll(defaultConfig);
+
+            // then from an external file
+            if (defaultExternalConfigLocation.isFile()) {
+                try (final InputStream stream = new FileInputStream(defaultExternalConfigLocation)) {
+                    this.properties.putAll(load(stream));
+                } catch (final IOException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+
+            // and finally from system properties
+            final String prefix = "winegrower.service." + pid + ".";
+            System.getProperties().stringPropertyNames().stream()
+                  .filter(it -> it.startsWith(prefix))
+                  .forEach(key -> properties.put(key.substring(prefix.length()), System.getProperty(key)));
         }
 
         @Override
@@ -126,39 +142,11 @@
         @Override
         public void update(final Dictionary<String, ?> properties) {
             this.properties.clear();
-            if (System.getProperty(WINEGROWER_CONFIG_PATH) != null) {
-                File file = new File(System.getProperty(WINEGROWER_CONFIG_PATH, pid + WINEGROWER_CONFIG_EXTENSION));
-                try {
-                    Properties prop = new Properties(file);
-                    prop.update(converter(properties));
-                    prop.store(new FileOutputStream(file), null);
-                } catch (IOException ioe) {
-                    ioe.printStackTrace();
-                }
-            } else if (this.getClass().getResourceAsStream("/" + pid + ".cfg") != null) {
-                Properties prop = new Properties();
-                try {
-                    prop.load(this.getClass().getResourceAsStream("/" + pid + ".cfg"));
-                    prop.update(converter(properties));
-                } catch (IOException ioe) {
-                    ioe.printStackTrace();
-                }
-            } else {
-                list(properties.keys()).forEach(key -> this.properties.put(key, properties.get(key)));
-            }
+            loadConfig(pid);
+            this.properties.putAll(converter(properties));
             this.changeCount.incrementAndGet();
         }
 
-        private Map<String, String> converter(Dictionary<String, ?> properties) {
-            Map<String, String> map = new HashMap<>();
-            Enumeration<String> keys = properties.keys();
-            while (keys.hasMoreElements()) {
-                String key = keys.nextElement();
-                map.put(key, properties.get(key).toString());
-            }
-            return map;
-        }
-
         @Override
         public void delete() {
             // no-op
@@ -171,24 +159,16 @@
 
         @Override
         public void update() {
-            if (System.getProperty(WINEGROWER_CONFIG_PATH) != null) {
-                File file = new File(System.getProperty(WINEGROWER_CONFIG_PATH, pid + WINEGROWER_CONFIG_EXTENSION));
-                try {
-                    Properties prop = new Properties(file);
-                    prop.update(converter(properties));
-                    prop.store(new FileOutputStream(file), null);
-                } catch (IOException ioe) {
-                    ioe.printStackTrace();
+            update(new Hashtable<>());
+            if (defaultExternalConfigLocation.isFile()) {
+                final Properties output = new Properties();
+                output.putAll(properties);
+                try (final OutputStream outputStream = new FileOutputStream(defaultExternalConfigLocation)) {
+                    output.store(outputStream, "Updated configuration on " + new Date());
+                } catch (final IOException e) {
+                    throw new IllegalArgumentException(e);
                 }
-            } else if (this.getClass().getResourceAsStream("/" + pid + ".cfg") != null) {
-                Properties prop = new Properties();
-                try {
-                    prop.load(this.getClass().getResourceAsStream("/" + pid + ".cfg"));
-                    prop.update(converter(properties));
-                } catch (IOException ioe) {
-                    ioe.printStackTrace();
-                }
-            }
+            } // else: don't modify neither the classpath nor system properties - this would be insane even if doable
             this.changeCount.incrementAndGet();
         }
 
@@ -206,5 +186,19 @@
         public long getChangeCount() {
             return changeCount.get();
         }
+
+        private Map<String, String> converter(final Dictionary<String, ?> properties) {
+            return list(properties.keys()).stream().collect(toMap(identity(), it -> properties.get(it).toString()));
+        }
+
+        private Map<String, String> load(final InputStream stream) {
+            final Properties properties = new Properties();
+            try {
+                properties.load(stream);
+            } catch (final IOException e) {
+                throw new IllegalArgumentException(e);
+            }
+            return Map.class.cast(properties);
+        }
     }
 }