add settings refresher

This commit is contained in:
Jörg Prante 2020-04-22 16:12:25 +02:00
parent ec7fd49baa
commit 0e37917c47
5 changed files with 105 additions and 26 deletions

View file

@ -15,6 +15,8 @@ import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@ -24,23 +26,39 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
*/
public class Settings {
public class Settings implements AutoCloseable {
private static final Logger logger = Logger.getLogger(Settings.class.getName());
public static final Settings EMPTY_SETTINGS = new Builder().build();
public static final String[] EMPTY_ARRAY = new String[0];
public static final int BUFFER_SIZE = 1024 * 8;
private final Map<String, String> map;
private Settings(Map<String, String> settings) {
this.map = new HashMap<>(settings);
public static final String[] EMPTY_ARRAY = new String[0];
public static final int BUFFER_SIZE = 1024 * 8;
private DefaultSettingsRefresher refresher;
private Map<String, String> map;
private Settings(Map<String, String> map) {
this(map, null, 0L, 0L, TimeUnit.SECONDS);
}
private Settings(Map<String, String> map, Path path, long initialDelay, long period, TimeUnit timeUnit) {
this.map = new LinkedHashMap<>(map);
if (path != null && initialDelay >= 0L && period > 0L) {
this.refresher = new DefaultSettingsRefresher(path, initialDelay, period, timeUnit);
}
}
public static Settings readSettingsFromMap(Map<String, Object> map) throws IOException {
@ -175,11 +193,7 @@ public class Settings {
}
public String get(String setting) {
String retVal = map.get(setting);
if (retVal != null) {
return retVal;
}
return null;
return map.get(setting);
}
public String get(String setting, String defaultValue) {
@ -298,11 +312,7 @@ public class Settings {
}
String name = nameValue.substring(0, dotIndex);
String value = nameValue.substring(dotIndex + 1);
Map<String, String> groupSettings = hashMap.get(name);
if (groupSettings == null) {
groupSettings = new LinkedHashMap<>();
hashMap.put(name, groupSettings);
}
Map<String, String> groupSettings = hashMap.computeIfAbsent(name, k -> new LinkedHashMap<>());
groupSettings.put(value, get(setting));
}
}
@ -394,6 +404,13 @@ public class Settings {
return map;
}
@Override
public void close() throws IOException {
if (refresher != null) {
refresher.stop();
}
}
/**
*
*/
@ -401,6 +418,14 @@ public class Settings {
private final Map<String, String> map = new LinkedHashMap<>();
private Path path;
private long initialDelay;
private long period;
private TimeUnit timeUnit;
private Builder() {
}
@ -709,14 +734,54 @@ public class Settings {
public Builder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder,
PlaceholderResolver placeholderResolver) {
for (Map.Entry<String, String> entry : map.entrySet()) {
map.put(entry.getKey(), propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver));
map.replaceAll((k, v) -> propertyPlaceholder.replacePlaceholders(v, placeholderResolver));
return this;
}
public Builder setRefresh(Path path, long initialDelay, long period, TimeUnit timeUnit) {
this.path = path;
this.initialDelay = initialDelay;
this.period = period;
this.timeUnit = timeUnit;
return this;
}
public Settings build() {
return new Settings(map);
return new Settings(map, path, initialDelay, period, timeUnit);
}
}
class DefaultSettingsRefresher implements Runnable {
private final Path path;
private final ScheduledExecutorService executorService;
private final AtomicBoolean closed;
DefaultSettingsRefresher(Path path, long initialDelay, long period, TimeUnit timeUnit) {
this.path = path;
this.executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(this, initialDelay, period, timeUnit);
this.closed = new AtomicBoolean();
}
@Override
public void run() {
try {
if (!closed.get()) {
String settingsSource = Files.readString(path);
SettingsLoader settingsLoader = SettingsLoaderService.loaderFromResource(path.toString());
map = settingsLoader.load(settingsSource);
}
} catch (IOException e) {
throw new RuntimeException("unable to refresh settings from path " + path, e);
}
}
public void stop() {
closed.set(true);
executorService.shutdownNow();
}
}
}

View file

@ -12,12 +12,14 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
@ -114,7 +116,7 @@ public class SettingsTest extends Assert {
Settings settings = Settings.settingsBuilder()
.loadFromSystemEnvironment()
.build();
assertTrue(!settings.getAsMap().isEmpty());
assertFalse(settings.getAsMap().isEmpty());
}
@Test
@ -122,7 +124,7 @@ public class SettingsTest extends Assert {
Settings settings = Settings.settingsBuilder()
.loadFromSystemProperties()
.build();
assertTrue(!settings.getAsMap().isEmpty());
assertFalse(settings.getAsMap().isEmpty());
}
@Test
@ -176,4 +178,14 @@ public class SettingsTest extends Assert {
Map<String, String> result = loader.load(map);
assertEquals("{code.a=b, code.b=c, name.a=b, name.b=c, list.0=a, list.1=b, null=null}", result.toString());
}
@Test
public void testRefresher() throws Exception {
Settings settings = Settings.settingsBuilder()
.setRefresh(Paths.get("src/test/resources/settings.json"), 0L, 1L, TimeUnit.DAYS)
.build();
Thread.sleep(1000L);
assertEquals("Jörg Prante", settings.get("name"));
settings.close();
}
}

View file

@ -0,0 +1,3 @@
{
"name": "Jörg Prante"
}

View file

@ -1,6 +1,6 @@
group = org.xbib
name = content
version = 2.0.5
version = 2.0.6
xbib-net.version = 2.0.3
jackson.version = 2.9.10

View file

@ -1,6 +1,5 @@
#Mon Jan 13 14:36:01 CET 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists