FELIX-6192 Support default values and type conversion

Support type conversions.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk/configadmin-plugins/interpolation@1869604 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 84f0d2e..8407a8d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,11 +106,23 @@
           <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.util.function</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>1.7.26</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.converter</artifactId>
+            <version>1.0.12</version>
+            <scope>provided</scope>
+        </dependency>
 
         <dependency>
             <groupId>junit</groupId>
diff --git a/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java b/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
index f9f0184..5fcc3f1 100644
--- a/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
+++ b/src/main/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPlugin.java
@@ -20,6 +20,7 @@
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.ConfigurationPlugin;
+import org.osgi.util.converter.Converters;
 import org.slf4j.Logger;
 
 import java.io.File;
@@ -45,6 +46,46 @@
     private static final String SECRET_PREFIX = PREFIX + "secret:";
     private static final Pattern SECRET_PATTERN = createPattern(SECRET_PREFIX);
 
+    private static final Map<String, Class<?>> TYPE_MAP = new HashMap<>();
+    static {
+        // scalar types and primitive types
+        TYPE_MAP.put("String", String.class);
+        TYPE_MAP.put("Integer", Integer.class);
+        TYPE_MAP.put("int", Integer.class);
+        TYPE_MAP.put("Long", Long.class);
+        TYPE_MAP.put("long", Long.class);
+        TYPE_MAP.put("Float", Float.class);
+        TYPE_MAP.put("float", Float.class);
+        TYPE_MAP.put("Double", Double.class);
+        TYPE_MAP.put("double", Double.class);
+        TYPE_MAP.put("Byte", Byte.class);
+        TYPE_MAP.put("byte", Byte.class);
+        TYPE_MAP.put("Short", Short.class);
+        TYPE_MAP.put("short", Short.class);
+        TYPE_MAP.put("Character", Character.class);
+        TYPE_MAP.put("char", Character.class);
+        TYPE_MAP.put("Boolean", Boolean.class);
+        TYPE_MAP.put("boolean", Boolean.class);
+         // array of scalar types and primitive types
+        TYPE_MAP.put("String[]", String[].class);
+        TYPE_MAP.put("Integer[]", Integer[].class);
+        TYPE_MAP.put("int[]", int[].class);
+        TYPE_MAP.put("Long[]", Long[].class);
+        TYPE_MAP.put("long[]", long[].class);
+        TYPE_MAP.put("Float[]", Float[].class);
+        TYPE_MAP.put("float[]", float[].class);
+        TYPE_MAP.put("Double[]", Double[].class);
+        TYPE_MAP.put("double[]", double[].class);
+        TYPE_MAP.put("Byte[]", Byte[].class);
+        TYPE_MAP.put("byte[]", byte[].class);
+        TYPE_MAP.put("Short[]", Short[].class);
+        TYPE_MAP.put("short[]", short[].class);
+        TYPE_MAP.put("Boolean[]", Boolean[].class);
+        TYPE_MAP.put("boolean[]", boolean[].class);
+        TYPE_MAP.put("Character[]", Character[].class);
+        TYPE_MAP.put("char[]", char[].class);
+    }
+
     private static Pattern createPattern(String prefix) {
         return Pattern.compile("\\Q" + prefix + "\\E.+?\\Q" + SUFFIX + "\\E");
     }
@@ -139,6 +180,7 @@
             final Function<String, String> valueSource) {
         final Matcher m = pattern.matcher(value);
         final StringBuffer sb = new StringBuffer();
+        String type = null;
         while (m.find()) {
             final String var = m.group();
 
@@ -165,10 +207,11 @@
                     m.appendReplacement(sb, Matcher.quoteReplacement(defVal));
                 }
             }
+            type = directives.get("type");
         }
         m.appendTail(sb);
 
-        return sb.toString();
+        return convertType(type, sb.toString());
     }
 
     private Map<String, String> parseDirectives(String dirString) {
@@ -183,4 +226,18 @@
 
         return dirs;
     }
+
+    private Object convertType(String type, String s) {
+        if (type == null) {
+            return s;
+        }
+
+        Class<?> cls = TYPE_MAP.get(type);
+        if (cls != null) {
+            return Converters.standardConverter().convert(s).to(cls);
+        }
+
+        getLog().warn("Cannot convert to type: " + type);
+        return s;
+    }
 }
diff --git a/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java b/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
index 5db01e7..3a34edc 100644
--- a/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
+++ b/src/test/java/org/apache/felix/configadmin/plugin/interpolation/InterpolationConfigurationPluginTest.java
@@ -142,4 +142,16 @@
 
         assertEquals("foo", dict.get("defaulted"));
     }
+
+    @Test
+    public void testTypeConversion() throws IOException {
+        InterpolationConfigurationPlugin plugin = new InterpolationConfigurationPlugin(null, null);
+
+        Dictionary<String, Object> dict = new Hashtable<>();
+        dict.put("defaulted", "$[env:notset;default=123;type=Integer]");
+
+        plugin.modifyConfiguration(null, dict);
+
+        assertEquals(Integer.valueOf(123), dict.get("defaulted"));
+    }
 }