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);
+ }
}
}