Applied patch (FELIX-983) to support variable substitution in config file.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@758154 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/pom.xml b/fileinstall/pom.xml
index ebb4354..99b8f0f 100644
--- a/fileinstall/pom.xml
+++ b/fileinstall/pom.xml
@@ -50,7 +50,7 @@
<extensions>true</extensions>
<configuration>
<instructions>
- <Export-Package>org.apache.felix.fileinstall,org.osgi.service.cm, org.osgi.service.log</Export-Package>
+ <Export-Package>org.apache.felix.fileinstall.*,org.osgi.service.cm, org.osgi.service.log</Export-Package>
<Bundle-Activator>org.apache.felix.fileinstall.FileInstall</Bundle-Activator>
<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
<Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/FileInstall.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/FileInstall.java
index 48f9369..6d536d3 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/FileInstall.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/FileInstall.java
@@ -20,6 +20,7 @@
import java.util.*;
+import org.apache.felix.fileinstall.util.Util;
import org.osgi.framework.*;
import org.osgi.service.cm.*;
import org.osgi.service.packageadmin.*;
@@ -113,8 +114,20 @@
throws ConfigurationException
{
deleted(pid);
+ performSubstitution( properties );
+
DirectoryWatcher watcher = new DirectoryWatcher(properties, context);
watchers.put(pid, watcher);
watcher.start();
}
+
+ private void performSubstitution( Dictionary properties )
+ {
+ for (Enumeration e = properties.keys(); e.hasMoreElements(); )
+ {
+ String name = (String) e.nextElement();
+ properties.put(name,
+ Util.substVars(( String ) properties.get(name), name, null, properties));
+ }
+ }
}
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/util/Util.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/util/Util.java
new file mode 100644
index 0000000..acb87ce
--- /dev/null
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/util/Util.java
@@ -0,0 +1,143 @@
+/*
+ * 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.fileinstall.util;
+
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+
+public class Util
+{
+ private static final String DELIM_START = "${";
+ private static final String DELIM_STOP = "}";
+
+ /**
+ * <p>
+ * This method performs property variable substitution on the
+ * specified value. If the specified value contains the syntax
+ * <tt>${<prop-name>}</tt>, where <tt><prop-name></tt>
+ * refers to either a configuration property or a system property,
+ * then the corresponding property value is substituted for the variable
+ * placeholder. Multiple variable placeholders may exist in the
+ * specified value as well as nested variable placeholders, which
+ * are substituted from inner most to outer most. Configuration
+ * properties override system properties.
+ * </p>
+ * @param val The string on which to perform property substitution.
+ * @param currentKey The key of the property being evaluated used to
+ * detect cycles.
+ * @param cycleMap Map of variable references used to detect nested cycles.
+ * @param configProps Set of configuration properties.
+ * @return The value of the specified string after system property substitution.
+ * @throws IllegalArgumentException If there was a syntax error in the
+ * property placeholder syntax or a recursive variable reference.
+ **/
+ public static String substVars( String val, String currentKey, Map cycleMap, Dictionary configProps )
+ throws IllegalArgumentException
+ {
+ if ( cycleMap == null )
+ {
+ cycleMap = new HashMap();
+ }
+
+ // Put the current key in the cycle map.
+ cycleMap.put( currentKey, currentKey );
+
+ // Assume we have a value that is something like:
+ // "leading ${foo.${bar}} middle ${baz} trailing"
+
+ // Find the first ending '}' variable delimiter, which
+ // will correspond to the first deepest nested variable
+ // placeholder.
+ int stopDelim = val.indexOf( DELIM_STOP );
+
+ // Find the matching starting "${" variable delimiter
+ // by looping until we find a start delimiter that is
+ // greater than the stop delimiter we have found.
+ int startDelim = val.indexOf( DELIM_START );
+ while ( stopDelim >= 0 )
+ {
+ int idx = val.indexOf( DELIM_START, startDelim + DELIM_START.length() );
+ if ( ( idx < 0 ) || ( idx > stopDelim ) )
+ {
+ break;
+ }
+ else if ( idx < stopDelim )
+ {
+ startDelim = idx;
+ }
+ }
+
+ // If we do not have a start or stop delimiter, then just
+ // return the existing value.
+ if ( ( startDelim < 0 ) && ( stopDelim < 0 ) )
+ {
+ return val;
+ }
+ // At this point, we found a stop delimiter without a start,
+ // so throw an exception.
+ else if ( ( ( startDelim < 0 ) || ( startDelim > stopDelim ) ) && ( stopDelim >= 0 ) )
+ {
+ throw new IllegalArgumentException( "stop delimiter with no start delimiter: " + val );
+ }
+
+ // At this point, we have found a variable placeholder so
+ // we must perform a variable substitution on it.
+ // Using the start and stop delimiter indices, extract
+ // the first, deepest nested variable placeholder.
+ String variable = val.substring( startDelim + DELIM_START.length(), stopDelim );
+
+ // Verify that this is not a recursive variable reference.
+ if ( cycleMap.get( variable ) != null )
+ {
+ throw new IllegalArgumentException( "recursive variable reference: " + variable );
+ }
+
+ // Get the value of the deepest nested variable placeholder.
+ // Try to configuration properties first.
+ String substValue = ( String ) ( ( configProps != null ) ? configProps.get( variable ) : null );
+ if ( substValue == null )
+ {
+ // Ignore unknown property values.
+ substValue = System.getProperty( variable, "" );
+ }
+
+ // Remove the found variable from the cycle map, since
+ // it may appear more than once in the value and we don't
+ // want such situations to appear as a recursive reference.
+ cycleMap.remove( variable );
+
+ // Append the leading characters, the substituted value of
+ // the variable, and the trailing characters to get the new
+ // value.
+ val = val.substring( 0, startDelim ) + substValue
+ + val.substring( stopDelim + DELIM_STOP.length(), val.length() );
+
+ // Now perform substitution again, since there could still
+ // be substitutions to make.
+ val = substVars( val, currentKey, cycleMap, configProps );
+
+ // Return the value.
+ return val;
+ }
+
+}
diff --git a/fileinstall/src/test/java/org/apache/felix/fileinstall/util/UtilTest.java b/fileinstall/src/test/java/org/apache/felix/fileinstall/util/UtilTest.java
new file mode 100644
index 0000000..c74b79e
--- /dev/null
+++ b/fileinstall/src/test/java/org/apache/felix/fileinstall/util/UtilTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.fileinstall.util;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import junit.framework.TestCase;
+
+public class UtilTest extends TestCase
+{
+
+ public void testBasicSubstitution()
+ {
+ System.setProperty( "value1", "sub_value1" );
+ Dictionary props = new Hashtable();
+ props.put( "key0", "value0" );
+ props.put( "key1", "${value1}" );
+ props.put( "key2", "${value2}" );
+
+ for (Enumeration e = props.keys(); e.hasMoreElements(); )
+ {
+ String name = (String) e.nextElement();
+ props.put(name,
+ Util.substVars(( String ) props.get(name), name, null, props));
+ }
+
+ assertEquals( "value0", props.get( "key0" ) );
+ assertEquals( "sub_value1", props.get( "key1" ) );
+ assertEquals( "", props.get( "key2" ) );
+
+ }
+}