add self property placeholder resolving

This commit is contained in:
Jörg Prante 2025-03-31 11:14:53 +02:00
parent b4b2a84e85
commit ef6e02bccc
4 changed files with 37 additions and 22 deletions
gradle.properties
settings-api/src/main/java/org/xbib/settings
settings-datastructures/src
main/java/org/xbib/settings/datastructures
test/java/org/xbib/settings/datastructures/test

View file

@ -1,3 +1,3 @@
group = org.xbib group = org.xbib
name = datastructures name = datastructures
version = 5.2.4 version = 5.3.0

View file

@ -53,7 +53,7 @@ public class PropertyPlaceholder {
if (endIndex != -1) { if (endIndex != -1) {
String placeholder = sb.substring(startIndex + this.placeholderPrefix.length(), endIndex); String placeholder = sb.substring(startIndex + this.placeholderPrefix.length(), endIndex);
if (!visitedPlaceholders.add(placeholder)) { if (!visitedPlaceholders.add(placeholder)) {
throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in property definitions"); throw new IllegalArgumentException("Circular placeholder reference '" + placeholder + "' in definitions");
} }
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
int defaultValueIdx = placeholder.indexOf(':'); int defaultValueIdx = placeholder.indexOf(':');
@ -71,7 +71,6 @@ public class PropertyPlaceholder {
sb.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); sb.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
startIndex = sb.indexOf(this.placeholderPrefix, startIndex + propVal.length()); startIndex = sb.indexOf(this.placeholderPrefix, startIndex + propVal.length());
} else if (this.ignoreUnresolvablePlaceholders) { } else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = sb.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length()); startIndex = sb.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
} else { } else {
throw new IllegalArgumentException("could not resolve placeholder '" + placeholder + "'"); throw new IllegalArgumentException("could not resolve placeholder '" + placeholder + "'");

View file

@ -15,7 +15,7 @@ import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -23,9 +23,6 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/**
*
*/
public class DatastructureSettingsBuilder implements SettingsBuilder { public class DatastructureSettingsBuilder implements SettingsBuilder {
private final SettingsLoaderService settingsLoaderService; private final SettingsLoaderService settingsLoaderService;
@ -37,10 +34,6 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
this.map = TinyMap.builder(); this.map = TinyMap.builder();
} }
public String remove(String key) {
return map.remove(key);
}
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return map.isEmpty(); return map.isEmpty();
@ -190,7 +183,7 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
if (values[i] == null) { if (values[i] == null) {
continue; continue;
} }
put(settingPrefix + "" + groupName + "." + settings[i], values[i]); put(settingPrefix + groupName + "." + settings[i], values[i]);
} }
return this; return this;
} }
@ -258,7 +251,7 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
} }
/** /**
* Load system properties to this settings. * Load all system properties to this settings.
* *
* @return builder * @return builder
*/ */
@ -271,7 +264,7 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
} }
/** /**
* Load system environment to this settings. * Load all system environment to this settings.
* *
* @return builder * @return builder
*/ */
@ -294,22 +287,30 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
public DatastructureSettingsBuilder replacePropertyPlaceholders() { public DatastructureSettingsBuilder replacePropertyPlaceholders() {
return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false), return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false),
placeholderName -> { placeholderName -> {
// system property // lookup system property, even is not loaded
String value = System.getProperty(placeholderName); String value = System.getProperty(placeholderName);
if (value != null) { if (value != null) {
return value; return value;
} }
// environment // lookup environment, even it is not loaded
value = System.getenv(placeholderName); value = System.getenv(placeholderName);
if (value != null) { if (value != null) {
return value; return value;
} }
// current date // lookup self
try { value = map.get(placeholderName);
return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now()); if (value != null) {
} catch (IllegalArgumentException | DateTimeException e) { return value;
return map.get(placeholderName);
} }
// special case: pattern for current timestamp
if (placeholderName.startsWith("ts_")) {
try {
return DateTimeFormatter.ofPattern(placeholderName.substring(3)).format(LocalDateTime.now());
} catch (IllegalArgumentException | DateTimeException e) {
return LocalDateTime.now().toString();
}
}
throw new IllegalArgumentException("unable to resolve " + placeholderName);
} }
); );
} }
@ -329,4 +330,8 @@ public class DatastructureSettingsBuilder implements SettingsBuilder {
public DatastructureSettings build() { public DatastructureSettings build() {
return new DatastructureSettings(map.build()); return new DatastructureSettings(map.build());
} }
public void remove(String key) {
map.remove(key);
}
} }

View file

@ -84,8 +84,9 @@ public class SettingsTest {
@Test @Test
public void testCurrentYearInSettings() { public void testCurrentYearInSettings() {
// prefix "ts_" is reserved for date/time patterns and will resolve into current timestamp
Settings settings = Settings.settingsBuilder() Settings settings = Settings.settingsBuilder()
.put("date", "${yyyy}") .put("date", "${ts_yyyy}")
.replacePropertyPlaceholders() .replacePropertyPlaceholders()
.build(); .build();
assertEquals(LocalDate.now().getYear(), Integer.parseInt(settings.get("date"))); assertEquals(LocalDate.now().getYear(), Integer.parseInt(settings.get("date")));
@ -131,4 +132,14 @@ public class SettingsTest {
.build(); .build();
assertEquals("{a.b=c}", settings.getAsMap().toString()); assertEquals("{a.b=c}", settings.getAsMap().toString());
} }
@Test
public void testSelfPropertyPlaceHolder() {
Settings settings = Settings.settingsBuilder()
.put("host", "localhost")
.put("anotherhost", "${host}")
.replacePropertyPlaceholders()
.build();
assertEquals("localhost", settings.get("anotherhost"));
}
} }