Add internal property replacement

E.g. in application.properties (for launcher)

foo: Application
loader.main: my.${foo}
loader.path: etc
This commit is contained in:
Dave Syer 2013-09-24 09:15:24 +01:00
parent a70d293c87
commit a3af83cf96
3 changed files with 62 additions and 13 deletions

View File

@ -25,6 +25,7 @@ import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
@ -69,14 +70,30 @@ public class PropertiesLauncher implements ArchiveFilter {
public static final String MAIN = "loader.main";
/**
* Properties key for classpath entries (directories possibly containing jars)
* Properties key for classpath entries (directories possibly containing jars).
* Defaults to "lib/" (relative to {@link #HOME loader home directory}).
*/
public static final String PATH = "loader.path";
/**
* Properties key for home directory. This is the location of external configuration
* if not on classpath, and also the base path for any relative paths in the
* {@link #PATH loader path}. Defaults to current working directory (
* <code>${user.home}</code>).
*/
public static final String HOME = "loader.home";
/**
* Properties key for name of external configuration file (excluding suffix). Defaults
* to "application". Ignored if {@link #CONFIG_LOCATION loader config location} is
* provided instead.
*/
public static final String CONFIG_NAME = "loader.config.name";
/**
* Properties key for config file location (including optional classpath:, file: or
* URL prefix)
*/
public static final String CONFIG_LOCATION = "loader.config.location";
private static final List<String> DEFAULT_PATHS = Arrays.asList("lib/");
@ -188,6 +205,14 @@ public class PropertiesLauncher implements ArchiveFilter {
finally {
resource.close();
}
for (Object key : Collections.list(this.properties.propertyNames())) {
String text = this.properties.getProperty((String) key);
String value = SystemPropertyUtils.resolvePlaceholders(this.properties,
text);
if (value != null) {
this.properties.put(key, value);
}
}
}
else {
this.logger.info("Not found: " + config);

View File

@ -17,6 +17,7 @@
package org.springframework.boot.loader.util;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
/**
@ -61,13 +62,30 @@ public abstract class SystemPropertyUtils {
*/
public static String resolvePlaceholders(String text) {
if (text == null) {
throw new IllegalArgumentException("Argument 'value' must not be null.");
return text;
}
return parseStringValue(text, text, new HashSet<String>());
return parseStringValue(null, text, text, new HashSet<String>());
}
private static String parseStringValue(String value, String current,
Set<String> visitedPlaceholders) {
/**
* Resolve ${...} placeholders in the given text, replacing them with corresponding
* system property values.
* @param properties a properties instance to use in addition to System
* @param text the String to resolve
* @return the resolved String
* @see #PLACEHOLDER_PREFIX
* @see #PLACEHOLDER_SUFFIX
* @throws IllegalArgumentException if there is an unresolvable placeholder
*/
public static String resolvePlaceholders(Properties properties, String text) {
if (text == null) {
return text;
}
return parseStringValue(properties, text, text, new HashSet<String>());
}
private static String parseStringValue(Properties properties, String value,
String current, Set<String> visitedPlaceholders) {
StringBuilder buf = new StringBuilder(current);
@ -85,9 +103,10 @@ public abstract class SystemPropertyUtils {
// Recursive invocation, parsing placeholders contained in the
// placeholder
// key.
placeholder = parseStringValue(value, placeholder, visitedPlaceholders);
placeholder = parseStringValue(properties, value, placeholder,
visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = resolvePlaceholder(value, placeholder);
String propVal = resolvePlaceholder(properties, value, placeholder);
if (propVal == null && VALUE_SEPARATOR != null) {
int separatorIndex = placeholder.indexOf(VALUE_SEPARATOR);
if (separatorIndex != -1) {
@ -95,7 +114,7 @@ public abstract class SystemPropertyUtils {
separatorIndex);
String defaultValue = placeholder.substring(separatorIndex
+ VALUE_SEPARATOR.length());
propVal = resolvePlaceholder(value, actualPlaceholder);
propVal = resolvePlaceholder(properties, value, actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
@ -104,7 +123,8 @@ public abstract class SystemPropertyUtils {
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(value, propVal, visitedPlaceholders);
propVal = parseStringValue(properties, value, propVal,
visitedPlaceholders);
buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(),
propVal);
startIndex = buf.indexOf(PLACEHOLDER_PREFIX,
@ -125,20 +145,23 @@ public abstract class SystemPropertyUtils {
return buf.toString();
}
private static String resolvePlaceholder(String text, String placeholderName) {
private static String resolvePlaceholder(Properties properties, String text,
String placeholderName) {
try {
String propVal = System.getProperty(placeholderName);
if (propVal == null) {
// Fall back to searching the system environment.
propVal = System.getenv(placeholderName);
}
return propVal;
if (propVal != null) {
return propVal;
}
}
catch (Throwable ex) {
System.err.println("Could not resolve placeholder '" + placeholderName
+ "' in [" + text + "] as system property: " + ex);
return null;
}
return properties.getProperty(placeholderName);
}
private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {

View File

@ -1,2 +1,3 @@
loader.main: my.Application
foo: Application
loader.main: my.${foo}
loader.path: etc