You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by da...@apache.org on 2021/08/03 08:29:01 UTC
[felix-dev] branch master updated: FELIX-6441 Make it possible to
run the Configuration Interpolation independently of Configuration Admin
This is an automated email from the ASF dual-hosted git repository.
davidb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/felix-dev.git
The following commit(s) were added to refs/heads/master by this push:
new bbadfa2 FELIX-6441 Make it possible to run the Configuration Interpolation independently of Configuration Admin
new 67ab32b Merge pull request #83 from bosschaert/FELIX-6441-sq
bbadfa2 is described below
commit bbadfa28bd856c6bfe3e8183514b4fed2bd78284
Author: David Bosschaert <da...@apache.org>
AuthorDate: Fri Jul 30 15:24:41 2021 +0100
FELIX-6441 Make it possible to run the Configuration Interpolation independently of Configuration Admin
The new StandaloneInterpolator class provides the entry-point for using
the interpolator outside of a Configuration Admin environment.
---
configadmin-plugins/interpolation/pom.xml | 2 +-
.../plugin/interpolation/Activator.java | 2 +-
.../InterpolationConfigurationPlugin.java | 11 +-
.../interpolation/StandaloneInterpolator.java | 80 +++++++++++++
.../InterpolationConfigurationPluginTest.java | 12 +-
.../interpolation/StandaloneInterpolatorTest.java | 124 +++++++++++++++++++++
.../interpolation/src/test/resources/res1/my.db | 1 +
7 files changed, 218 insertions(+), 14 deletions(-)
diff --git a/configadmin-plugins/interpolation/pom.xml b/configadmin-plugins/interpolation/pom.xml
index 10563be..203a7ba 100644
--- a/configadmin-plugins/interpolation/pom.xml
+++ b/configadmin-plugins/interpolation/pom.xml
@@ -28,7 +28,7 @@
<artifactId>org.apache.felix.configadmin.plugin.interpolation</artifactId>
<packaging>jar</packaging>
- <version>1.1.5-SNAPSHOT</version>
+ <version>1.2.0-SNAPSHOT</version>
<name>Apache Felix Configuration Admin Values Interpolation Plugin</name>
<description>
diff --git a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java
index c538c7d..c3fcbe9 100644
--- a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java
+++ b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/Activator.java
@@ -51,7 +51,7 @@ public class Activator implements BundleActivator {
}
String encoding = context.getProperty(ENCODING_PROPERTY);
- ConfigurationPlugin plugin = new InterpolationConfigurationPlugin(context, directory, encoding);
+ ConfigurationPlugin plugin = new InterpolationConfigurationPlugin(context::getProperty, directory, encoding);
Dictionary<String, Object> props = new Hashtable<>();
props.put(ConfigurationPlugin.CM_RANKING, PLUGIN_RANKING);
props.put("config.plugin.id", PLUGIN_ID);
diff --git a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
index 4974848..2dae521 100644
--- a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
+++ b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
@@ -30,10 +30,9 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
+import java.util.function.Function;
import java.util.stream.Stream;
-import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.ConfigurationPlugin;
@@ -95,13 +94,13 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin {
TYPE_MAP.put("char[]", char[].class);
}
- private final BundleContext context;
+ private final Function<String, String> propertiesProvider;
private final List<File> directory;
private final Charset encodingCharset;
- InterpolationConfigurationPlugin(BundleContext bc, String dir, String fileEncoding) {
- context = bc;
+ InterpolationConfigurationPlugin(Function<String, String> pp, String dir, String fileEncoding) {
+ propertiesProvider = pp;
if (dir != null) {
directory = Stream.of(dir.split("\\s*,\\s*")).map(File::new).collect(toList());
getLog().info("Configured directory for secrets: {}", dir);
@@ -189,7 +188,7 @@ class InterpolationConfigurationPlugin implements ConfigurationPlugin {
}
String getVariableFromProperty(final String name) {
- return context.getProperty(name);
+ return propertiesProvider.apply(name);
}
String getVariableFromFile(final String key, final String name, final Object pid) {
diff --git a/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolator.java b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolator.java
new file mode 100644
index 0000000..7facda1
--- /dev/null
+++ b/configadmin-plugins/interpolation/src/main/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolator.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.configadmin.plugin.interpolation;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.osgi.framework.Constants;
+
+/**
+ * Entrypoint into the interpolator independent of the OSGi API, so it can be used from outside of an
+ * OSGi Configuration Admin environment.
+ */
+public class StandaloneInterpolator {
+ final InterpolationConfigurationPlugin plugin;
+
+ /**
+ * Constructor.
+ *
+ * @param frameworkProperties Properties to use for framework property substitutions.
+ * @param secretsLocations The directories where secrets files can be found. The platform default
+ * encoding will be used for these files.
+ */
+ public StandaloneInterpolator(Map<String,String> frameworkProperties, File ... secretsLocations) {
+ this(frameworkProperties, null, secretsLocations);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param frameworkProperties Properties to use for framework property substitutions.
+ * @param encoding The file encoding to be used for the files in the secrets locations.
+ * @param secretsLocations The directories where secrets files can be found.
+ */
+ public StandaloneInterpolator(Map<String,String> frameworkProperties, String encoding, File ... secretsLocations) {
+ String locations = Arrays.asList(secretsLocations).stream()
+ .map(File::toString)
+ .collect(Collectors.joining(","));
+ plugin = new InterpolationConfigurationPlugin(frameworkProperties::get, locations, encoding);
+ }
+
+ /**
+ * Perform configuration interpolations.
+ *
+ * @param pid The PID of the configuration.
+ * @param dict The dictionary containing the configuration properties. The dictionary will be updated
+ * by the interpolation substitutions.
+ */
+ public void interpolate(String pid, Dictionary<String, Object> dict) {
+ boolean pidAdded = false;
+ try {
+ if (dict.get(Constants.SERVICE_PID) == null) {
+ dict.put(Constants.SERVICE_PID, pid);
+ pidAdded = true;
+ }
+
+ plugin.modifyConfiguration(null, dict);
+ } finally {
+ if (pidAdded)
+ dict.remove(Constants.SERVICE_PID);
+ }
+ }
+}
diff --git a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
index 888f0a5..8a402e8 100644
--- a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
+++ b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
@@ -69,7 +69,7 @@ public class InterpolationConfigurationPluginTest {
BundleContext bc = Mockito.mock(BundleContext.class);
Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there");
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, null, null);
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty, null, null);
String envUser = System.getenv("USER");
String userVar;
@@ -171,7 +171,7 @@ public class InterpolationConfigurationPluginTest {
public void testReplacementInStringArray() throws IOException {
BundleContext bc = Mockito.mock(BundleContext.class);
Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there");
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, null, null);
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty, null, null);
Dictionary<String, Object> dict = new Hashtable<>();
dict.put("array", new String[] { "1", "$[prop:foo.bar]", "3" });
@@ -191,7 +191,7 @@ public class InterpolationConfigurationPluginTest {
Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there");
String rf = getClass().getResource("/other/testfile.txt").getFile();
File file = new File(rf);
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc,
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty,
file.getParent() + "," + file.getParentFile().getParent(), null);
assertEquals("xxhello thereyyhello therezz",
@@ -206,7 +206,7 @@ public class InterpolationConfigurationPluginTest {
BundleContext bc = Mockito.mock(BundleContext.class);
String rf = getClass().getResource("/other/testfile.txt").getFile();
File file = new File(rf);
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc,
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty,
file.getParent() + "," + file.getParentFile().getParent(), null);
assertEquals("xxhello thereyyhello therezz",
@@ -221,7 +221,7 @@ public class InterpolationConfigurationPluginTest {
BundleContext bc = Mockito.mock(BundleContext.class);
Mockito.when(bc.getProperty("foo.bar")).thenReturn("hello there");
Mockito.when(bc.getProperty("key")).thenReturn("foo.bar");
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, null, null);
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty, null, null);
assertEquals("hello there", plugin.replace("akey", "$[prop:$[prop:key]]", "apid"));
}
@@ -240,7 +240,7 @@ public class InterpolationConfigurationPluginTest {
public void testArrayTypeConversion() throws Exception {
BundleContext bc = Mockito.mock(BundleContext.class);
Mockito.when(bc.getProperty("foo")).thenReturn("2000,3000");
- InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc, null, null);
+ InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(bc::getProperty, null, null);
assertArrayEquals(new Integer[] { 2000, 3000 },
(Integer[]) plugin.replace("key", "$[prop:foo;type=Integer[];delimiter=,]", "somepid"));
diff --git a/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolatorTest.java b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolatorTest.java
new file mode 100644
index 0000000..be250b3
--- /dev/null
+++ b/configadmin-plugins/interpolation/src/test/java/org/apache/felix/configadmin/plugin/interpolation/StandaloneInterpolatorTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.configadmin.plugin.interpolation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class StandaloneInterpolatorTest {
+ @Test
+ public void testFrameworkPropertyInterpolation() {
+ Map<String, String> fprops = new HashMap<>();
+ fprops.put("my.prop", "12345");
+ fprops.put("my.other.prop", "ABCDE");
+
+ StandaloneInterpolator interpolator = new StandaloneInterpolator(fprops);
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("foo", "bar");
+ dict.put("nonsubst", "$[yeah:yeah]");
+ dict.put("prop", "$[prop:my.prop]");
+ interpolator.interpolate("org.foo.bar", dict);
+
+ assertEquals(3, Collections.list(dict.keys()).size());
+ assertEquals("bar", dict.get("foo"));
+ assertEquals("$[yeah:yeah]", dict.get("nonsubst"));
+ assertEquals("12345", dict.get("prop"));
+ }
+
+ @Test
+ public void testEnvVarInterpolation() {
+ String envUser = System.getenv("USER");
+ String userVar;
+ if (envUser == null) {
+ envUser = System.getenv("USERNAME"); // maybe we're on Windows
+ userVar = "USERNAME";
+ } else {
+ userVar = "USER";
+ }
+
+ StandaloneInterpolator interpolator = new StandaloneInterpolator(Collections.emptyMap());
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("someuser", "$[env:" + userVar + "]");
+ dict.put(Constants.SERVICE_PID, "org.foo.bar");
+ interpolator.interpolate("org.foo.bar", dict);
+
+ assertEquals(envUser, dict.get("someuser"));
+ }
+
+ @Test
+ public void testSecretInterpolation() {
+ URL resUrl = getClass().getResource("/res1");
+ File res1Dir = new File(resUrl.getFile());
+ File res0Dir = new File(res1Dir.getParentFile(), "res0");
+
+ StandaloneInterpolator interpolator = new StandaloneInterpolator(Collections.emptyMap(), res0Dir, res1Dir);
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("name", "$[secret:my.db]");
+ dict.put("pass", "$[secret:my.pwd]");
+ interpolator.interpolate("my.pid", dict);
+
+ assertEquals(2, dict.size());
+ assertEquals("tiger", dict.get("name"));
+ assertEquals("$[secret:my.pwd]", dict.get("pass"));
+ }
+
+ @Test
+ public void testSecretInterpolationEncoding() {
+ URL resUrl = getClass().getResource("/res1");
+ File res1Dir = new File(resUrl.getFile());
+ File res0Dir = new File(res1Dir.getParentFile(), "res0");
+
+ StandaloneInterpolator interpolator = new StandaloneInterpolator(Collections.emptyMap(), "UTF-8", res1Dir, res0Dir);
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("name", "$[secret:my.db]");
+ dict.put("pass", "$[secret:my.pwd]");
+ interpolator.interpolate("my.pid", dict);
+
+ assertEquals("tiger", dict.get("name"));
+ }
+
+ @Test
+ public void testSecretInterpolationEncoding2() {
+ URL resUrl = getClass().getResource("/res1");
+ File res1Dir = new File(resUrl.getFile());
+
+ StandaloneInterpolator interpolator = new StandaloneInterpolator(Collections.emptyMap(), "UTF-16", res1Dir);
+
+ Dictionary<String, Object> dict = new Hashtable<>();
+ dict.put("name", "$[secret:my.db]");
+ dict.put("pass", "$[secret:my.pwd]");
+ interpolator.interpolate("my.pid", dict);
+
+ assertNotEquals("tiger", dict.get("name"));
+ assertNotEquals("$[secret:my.db]", dict.get("name"));
+ }
+}
diff --git a/configadmin-plugins/interpolation/src/test/resources/res1/my.db b/configadmin-plugins/interpolation/src/test/resources/res1/my.db
new file mode 100644
index 0000000..5a2c44b
--- /dev/null
+++ b/configadmin-plugins/interpolation/src/test/resources/res1/my.db
@@ -0,0 +1 @@
+tiger
\ No newline at end of file