From 9411e901be58710658ac613ae7116588d5268d33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rg=20Prante?= Date: Wed, 13 Oct 2021 15:33:08 +0200 Subject: [PATCH] move Settings, SettingsBuilder, SettingsLoader to API package, make SettingsBuilder to be loadable by ServiceLoader --- content-api/build.gradle | 3 + content-api/src/main/java/module-info.java | 9 +- .../xbib/content}/PlaceholderResolver.java | 2 +- .../xbib/content}/PropertyPlaceholder.java | 2 +- .../main/java/org/xbib/content/Settings.java | 65 ++ .../org/xbib/content/SettingsBuilder.java | 73 ++ .../org/xbib/content}/SettingsException.java | 2 +- .../xbib/content}/SettingsLoaderService.java | 19 +- .../java/org/xbib/content/package-info.java | 4 + content-config/src/main/java/module-info.java | 3 +- .../org/xbib/content/config/ConfigFinder.java | 3 +- .../org/xbib/content/config/ConfigLoader.java | 66 +- .../org/xbib/content/config/ConfigParams.java | 7 +- .../content/config/test/ConfigLoaderTest.java | 17 +- .../content/config/test/package-info.java | 4 + ...Loader => org.xbib.content.SettingsLoader} | 0 content-core/src/main/java/module-info.java | 8 +- .../content/core/DefaultXContentBuilder.java | 5 +- .../org/xbib/content/core/XContentHelper.java | 1 - .../xbib/content/core/XContentService.java | 1 - .../xbib/content/properties/package-info.java | 4 - .../xbib/content/util/unit/ByteSizeUnit.java | 233 ------- .../xbib/content/util/unit/ByteSizeValue.java | 228 ------ .../org/xbib/content/util/unit/SizeUnit.java | 229 ------ .../org/xbib/content/util/unit/TimeValue.java | 259 ------- .../xbib/content/util/unit/package-info.java | 4 - .../services/org.xbib.content.SettingsLoader | 1 - .../src/main/java/module-info.java | 3 +- ...Loader => org.xbib.content.SettingsLoader} | 0 .../json/test/JsonSettingsTest.java | 4 +- .../src/main/java/module-info.java | 3 +- .../yaml/test/YamlSettingsTest.java | 4 +- content-settings-datastructures/build.gradle | 2 +- .../src/main/java/module-info.java | 8 +- .../AbstractSettingsLoader.java | 1 + .../datastructures/DatastructureSettings.java | 357 ++++++++++ .../DatastructureSettingsBuilder.java | 355 ++++++++++ .../datastructures/ExceptionFormatter.java | 56 -- .../datastructures/PlaceholderResolver.java | 16 - .../PropertiesSettingsLoader.java | 2 +- .../settings/datastructures/Settings.java | 656 ------------------ .../datastructures/SettingsLoader.java | 30 - .../services/org.xbib.content.SettingsBuilder | 1 + ...Loader => org.xbib.content.SettingsLoader} | 0 .../datastructures/test/SettingsTest.java | 6 +- .../src/main/java/module-info.java | 11 +- .../{Settings.java => ContentSettings.java} | 414 ++--------- .../settings/ContentSettingsBuilder.java | 363 ++++++++++ .../settings}/PropertiesSettingsLoader.java | 25 +- .../content/settings/PropertyPlaceholder.java | 120 ---- .../content/settings/SettingsException.java | 17 - .../settings/SettingsLoaderService.java | 57 -- .../services/org.xbib.content.SettingsBuilder | 1 + .../services/org.xbib.content.SettingsLoader | 1 + .../content/settings/test/SettingsTest.java | 8 +- content-yaml/src/test/java/YamlTest.java | 2 - gradle/quality/pmd.gradle | 2 +- 57 files changed, 1381 insertions(+), 2396 deletions(-) create mode 100644 content-api/build.gradle rename {content-settings/src/main/java/org/xbib/content/settings => content-api/src/main/java/org/xbib/content}/PlaceholderResolver.java (93%) rename {content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures => content-api/src/main/java/org/xbib/content}/PropertyPlaceholder.java (99%) create mode 100644 content-api/src/main/java/org/xbib/content/Settings.java create mode 100644 content-api/src/main/java/org/xbib/content/SettingsBuilder.java rename {content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures => content-api/src/main/java/org/xbib/content}/SettingsException.java (86%) rename {content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures => content-api/src/main/java/org/xbib/content}/SettingsLoaderService.java (73%) create mode 100644 content-api/src/main/java/org/xbib/content/package-info.java create mode 100644 content-config/src/test/java/org/xbib/content/config/test/package-info.java rename content-config/src/test/resources/META-INF/services/{org.xbib.content.settings.datastructures.SettingsLoader => org.xbib.content.SettingsLoader} (100%) delete mode 100644 content-core/src/main/java/org/xbib/content/properties/package-info.java delete mode 100644 content-core/src/main/java/org/xbib/content/util/unit/ByteSizeUnit.java delete mode 100644 content-core/src/main/java/org/xbib/content/util/unit/ByteSizeValue.java delete mode 100644 content-core/src/main/java/org/xbib/content/util/unit/SizeUnit.java delete mode 100644 content-core/src/main/java/org/xbib/content/util/unit/TimeValue.java delete mode 100644 content-core/src/main/java/org/xbib/content/util/unit/package-info.java delete mode 100644 content-core/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader rename content-settings-datastructures-json/src/main/resources/META-INF.services/{org.xbib.content.settings.datastructures.SettingsLoader => org.xbib.content.SettingsLoader} (100%) create mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettings.java create mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettingsBuilder.java delete mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/ExceptionFormatter.java delete mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PlaceholderResolver.java delete mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/Settings.java delete mode 100644 content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoader.java create mode 100644 content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder rename content-settings-datastructures/src/main/resources/META-INF/services/{org.xbib.content.settings.datastructures.SettingsLoader => org.xbib.content.SettingsLoader} (100%) rename content-settings/src/main/java/org/xbib/content/settings/{Settings.java => ContentSettings.java} (52%) create mode 100644 content-settings/src/main/java/org/xbib/content/settings/ContentSettingsBuilder.java rename {content-core/src/main/java/org/xbib/content/properties => content-settings/src/main/java/org/xbib/content/settings}/PropertiesSettingsLoader.java (98%) delete mode 100644 content-settings/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java delete mode 100644 content-settings/src/main/java/org/xbib/content/settings/SettingsException.java delete mode 100644 content-settings/src/main/java/org/xbib/content/settings/SettingsLoaderService.java create mode 100644 content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder create mode 100644 content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader delete mode 100644 content-yaml/src/test/java/YamlTest.java diff --git a/content-api/build.gradle b/content-api/build.gradle new file mode 100644 index 0000000..aed7a6e --- /dev/null +++ b/content-api/build.gradle @@ -0,0 +1,3 @@ +dependencies { + api "org.xbib:datastructures-api:${project.property('xbib-datastructures.version')}" +} \ No newline at end of file diff --git a/content-api/src/main/java/module-info.java b/content-api/src/main/java/module-info.java index 865cb61..cfa7d30 100644 --- a/content-api/src/main/java/module-info.java +++ b/content-api/src/main/java/module-info.java @@ -1,3 +1,8 @@ -module org.xbib.content { +import org.xbib.content.SettingsBuilder; + +module org.xbib.content.api { exports org.xbib.content; -} \ No newline at end of file + requires transitive org.xbib.datastructures.api; + requires java.sql; + uses SettingsBuilder; +} diff --git a/content-settings/src/main/java/org/xbib/content/settings/PlaceholderResolver.java b/content-api/src/main/java/org/xbib/content/PlaceholderResolver.java similarity index 93% rename from content-settings/src/main/java/org/xbib/content/settings/PlaceholderResolver.java rename to content-api/src/main/java/org/xbib/content/PlaceholderResolver.java index 372857d..1f68071 100644 --- a/content-settings/src/main/java/org/xbib/content/settings/PlaceholderResolver.java +++ b/content-api/src/main/java/org/xbib/content/PlaceholderResolver.java @@ -1,4 +1,4 @@ -package org.xbib.content.settings; +package org.xbib.content; /** * Strategy interface used to resolve replacement values for placeholders contained in Strings. diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertyPlaceholder.java b/content-api/src/main/java/org/xbib/content/PropertyPlaceholder.java similarity index 99% rename from content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertyPlaceholder.java rename to content-api/src/main/java/org/xbib/content/PropertyPlaceholder.java index 4f3efa4..83a977c 100644 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertyPlaceholder.java +++ b/content-api/src/main/java/org/xbib/content/PropertyPlaceholder.java @@ -1,4 +1,4 @@ -package org.xbib.content.settings.datastructures; +package org.xbib.content; import java.util.HashSet; import java.util.Set; diff --git a/content-api/src/main/java/org/xbib/content/Settings.java b/content-api/src/main/java/org/xbib/content/Settings.java new file mode 100644 index 0000000..9e9d489 --- /dev/null +++ b/content-api/src/main/java/org/xbib/content/Settings.java @@ -0,0 +1,65 @@ +package org.xbib.content; + +import org.xbib.datastructures.api.ByteSizeValue; +import org.xbib.datastructures.api.TimeValue; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; + +public interface Settings extends AutoCloseable { + + class Holder { + + private static SettingsBuilder createBuilder() { + ServiceLoader serviceLoader = ServiceLoader.load(SettingsBuilder.class); + Optional optionalConfigLogger = serviceLoader.findFirst(); + return optionalConfigLogger.orElse(null); + } + + private static final Settings emptySettings = createBuilder().build(); + } + + static SettingsBuilder settingsBuilder() { + return Holder.createBuilder(); + } + + static Settings emptySettings() { + return Holder.emptySettings; + } + + boolean isEmpty(); + + String get(String setting); + + String get(String setting, String defaultValue); + + Float getAsFloat(String setting, Float defaultValue); + + Double getAsDouble(String setting, Double defaultValue); + + Integer getAsInt(String setting, Integer defaultValue); + + Long getAsLong(String setting, Long defaultValue); + + Boolean getAsBoolean(String setting, Boolean defaultValue); + + TimeValue getAsTime(String setting, TimeValue defaultValue); + + ByteSizeValue getAsBytesSize(String setting, ByteSizeValue defaultValue); + + String[] getAsArray(String settingPrefix); + + String[] getAsArray(String settingPrefix, String[] defaultArray); + + Map getAsMap(); + + Map getAsStructuredMap(); + + Map getGroups(String prefix); + + Settings getAsSettings(String setting); + + Settings getByPrefix(String prefix); + + boolean containsSetting(String setting); +} diff --git a/content-api/src/main/java/org/xbib/content/SettingsBuilder.java b/content-api/src/main/java/org/xbib/content/SettingsBuilder.java new file mode 100644 index 0000000..ac52c42 --- /dev/null +++ b/content-api/src/main/java/org/xbib/content/SettingsBuilder.java @@ -0,0 +1,73 @@ +package org.xbib.content; + +import java.io.InputStream; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public interface SettingsBuilder { + + SettingsBuilder put(String setting, String value); + + SettingsBuilder put(String setting, Class clazz); + + SettingsBuilder put(String setting, boolean value); + + SettingsBuilder put(String setting, int value); + + SettingsBuilder put(String setting, long value); + + SettingsBuilder put(String setting, float value); + + SettingsBuilder put(String setting, double value); + + SettingsBuilder putArray(String setting, String... values); + + SettingsBuilder putArray(String setting, List values); + + SettingsBuilder put(String settingPrefix, String groupName, String[] settings, String[] values) + throws SettingsException; + + SettingsBuilder put(Settings settings); + + SettingsBuilder put(Map settings); + + SettingsBuilder loadFromString(String source); + + SettingsBuilder loadFromResource(String resourceName, InputStream inputStream) throws SettingsException; + + default SettingsBuilder fromJdbcConfTable(Connection connection, String id, String type) throws SQLException { + try (PreparedStatement statement = connection.prepareStatement("select key, value from conf where id = ? and type = ?", + new String[]{id, type}); ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + String key = resultSet.getString("key"); + String value = resultSet.getString("value"); + put(key, value); + } + } + return this; + } + + SettingsBuilder loadFromSystemProperties(); + + SettingsBuilder loadFromSystemEnvironment(); + + SettingsBuilder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder, + PlaceholderResolver placeholderResolver); + + SettingsBuilder replacePropertyPlaceholders(); + + SettingsBuilder setRefresh(Path path, long initialDelay, long period, TimeUnit timeUnit); + + Settings build(); + + boolean isEmpty(); + + Map map(); + +} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsException.java b/content-api/src/main/java/org/xbib/content/SettingsException.java similarity index 86% rename from content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsException.java rename to content-api/src/main/java/org/xbib/content/SettingsException.java index 9de33e4..f5c70c6 100644 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsException.java +++ b/content-api/src/main/java/org/xbib/content/SettingsException.java @@ -1,4 +1,4 @@ -package org.xbib.content.settings.datastructures; +package org.xbib.content; /** * A generic failure to handle settings. diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoaderService.java b/content-api/src/main/java/org/xbib/content/SettingsLoaderService.java similarity index 73% rename from content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoaderService.java rename to content-api/src/main/java/org/xbib/content/SettingsLoaderService.java index 7f397c2..7535914 100644 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoaderService.java +++ b/content-api/src/main/java/org/xbib/content/SettingsLoaderService.java @@ -1,9 +1,7 @@ package org.xbib.content.settings.datastructures; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import org.xbib.content.SettingsLoader; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -69,17 +67,4 @@ public final class SettingsLoaderService { } return suffixes; } - - public static Settings fromJdbcConfTable(Connection connection, String id, String type) throws SQLException { - Settings.Builder settingsBuilder = Settings.settingsBuilder(); - try (PreparedStatement statement = connection.prepareStatement("select key, value from conf where id = ? and type = ?", - new String[]{id, type}); ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - String key = resultSet.getString("key"); - String value = resultSet.getString("value"); - settingsBuilder.put(key, value); - } - } - return settingsBuilder.build(); - } } diff --git a/content-api/src/main/java/org/xbib/content/package-info.java b/content-api/src/main/java/org/xbib/content/package-info.java new file mode 100644 index 0000000..e597896 --- /dev/null +++ b/content-api/src/main/java/org/xbib/content/package-info.java @@ -0,0 +1,4 @@ +/** + * Content API. + */ +package org.xbib.content; diff --git a/content-config/src/main/java/module-info.java b/content-config/src/main/java/module-info.java index daad3bc..0e1b527 100644 --- a/content-config/src/main/java/module-info.java +++ b/content-config/src/main/java/module-info.java @@ -1,10 +1,11 @@ import org.xbib.content.config.ConfigLogger; -import org.xbib.content.settings.datastructures.SettingsLoader; +import org.xbib.content.SettingsLoader; module org.xbib.content.config { exports org.xbib.content.config; uses ConfigLogger; uses SettingsLoader; provides ConfigLogger with org.xbib.content.config.SystemConfigLogger; + requires org.xbib.content.api; requires transitive org.xbib.content.settings.datastructures; } diff --git a/content-config/src/main/java/org/xbib/content/config/ConfigFinder.java b/content-config/src/main/java/org/xbib/content/config/ConfigFinder.java index b4c5655..8520fb3 100644 --- a/content-config/src/main/java/org/xbib/content/config/ConfigFinder.java +++ b/content-config/src/main/java/org/xbib/content/config/ConfigFinder.java @@ -161,7 +161,8 @@ public class ConfigFinder { return Files.getLastModifiedTime(p); } catch (IOException e) { return null; - }}); + } + }); private static final Comparator PATH_NAME_COMPARATOR = Comparator.comparing(Path::toString); } diff --git a/content-config/src/main/java/org/xbib/content/config/ConfigLoader.java b/content-config/src/main/java/org/xbib/content/config/ConfigLoader.java index bcd13bd..2844ac3 100644 --- a/content-config/src/main/java/org/xbib/content/config/ConfigLoader.java +++ b/content-config/src/main/java/org/xbib/content/config/ConfigLoader.java @@ -1,9 +1,9 @@ package org.xbib.content.config; -import org.xbib.content.settings.datastructures.SettingsLoader; -import org.xbib.content.settings.datastructures.Settings; +import org.xbib.content.Settings; +import org.xbib.content.SettingsBuilder; +import org.xbib.content.SettingsLoader; import org.xbib.content.settings.datastructures.SettingsLoaderService; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -42,11 +42,12 @@ public class ConfigLoader { Optional optionalConfigLogger = serviceLoader.findFirst(); return optionalConfigLogger.orElse(new SystemConfigLogger()); } - static ConfigLoader LOADER = new ConfigLoader().withLogger(createConfigLogger()); + + private static final ConfigLoader configLoader = new ConfigLoader().withLogger(createConfigLogger()); } public static ConfigLoader getInstance() { - return Holder.LOADER; + return Holder.configLoader; } public ConfigLoader withLogger(ConfigLogger logger) { @@ -59,8 +60,8 @@ public class ConfigLoader { return map.get(configParams); } - private Settings.Builder internalLoad(ConfigParams params) throws ConfigException { - Settings.Builder settings = Settings.settingsBuilder(); + private SettingsBuilder internalLoad(ConfigParams params) throws ConfigException { + SettingsBuilder settings = Settings.settingsBuilder(); if (params.withSystemEnvironment) { settings.loadFromSystemEnvironment(); } @@ -74,7 +75,7 @@ public class ConfigLoader { } if (!params.reader.isEmpty()) { for (ConfigParams.SuffixedReader reader : params.reader) { - Settings.Builder readerSettings = createSettingsFromReader(reader.reader, reader.suffix); + SettingsBuilder readerSettings = createSettingsFromReader(reader.reader, reader.suffix); if (readerSettings != null) { settings.put(readerSettings.build()); if (!params.includeAll) { @@ -84,7 +85,7 @@ public class ConfigLoader { } } if (params.args != null) { - Settings.Builder argsSettings = createSettingsFromArgs(params); + SettingsBuilder argsSettings = createSettingsFromArgs(params); if (argsSettings != null) { settings.put(argsSettings.build()); if (!params.includeAll) { @@ -93,7 +94,7 @@ public class ConfigLoader { } } if (params.withStdin) { - Settings.Builder stdinSettings = createSettingsFromStdin(); + SettingsBuilder stdinSettings = createSettingsFromStdin(); if (stdinSettings != null) { settings.put(stdinSettings.build()); if (!params.includeAll) { @@ -102,7 +103,7 @@ public class ConfigLoader { } } if (!params.fileLocations.isEmpty()) { - Settings.Builder fileSettings = createSettingsFromFile(params.fileLocations); + SettingsBuilder fileSettings = createSettingsFromFile(params.fileLocations); if (fileSettings != null) { settings.put(fileSettings.build()); if (!params.includeAll) { @@ -112,7 +113,7 @@ public class ConfigLoader { } if (!params.fileNamesWithoutSuffix.isEmpty()) { for (String fileNameWithoutSuffix : params.fileNamesWithoutSuffix) { - Settings.Builder fileSettings = createSettingsFromFile(createListOfLocations(params, fileNameWithoutSuffix)); + SettingsBuilder fileSettings = createSettingsFromFile(createListOfLocations(params, fileNameWithoutSuffix)); if (fileSettings != null) { settings.put(fileSettings.build()); if (!params.includeAll) { @@ -124,7 +125,7 @@ public class ConfigLoader { if (params.classLoaders != null) { for (ClassLoader cl : params.classLoaders) { if (cl != null) { - Settings.Builder classpathSettings = createClasspathSettings(params, cl, fileNameWithoutSuffix); + SettingsBuilder classpathSettings = createClasspathSettings(params, cl, fileNameWithoutSuffix); if (classpathSettings != null) { settings.put(classpathSettings.build()); if (!params.includeAll) { @@ -142,14 +143,15 @@ public class ConfigLoader { throw new ConfigException("no config found"); } - private Settings.Builder createSettingsFromArgs(ConfigParams params) throws ConfigException { + private SettingsBuilder createSettingsFromArgs(ConfigParams params) throws ConfigException { if (!params.fileNamesWithoutSuffix.isEmpty() && params.args != null) { for (String fileNameWithoutSuffix : params.fileNamesWithoutSuffix) { for (String suffix : SettingsLoaderService.getInstance().getSuffixes()) { for (int i = 0; i < params.args.size() - 1; i++) { String arg = params.args.get(i); String s = params.directoryName != null ? - "--" + params.directoryName + "-" + fileNameWithoutSuffix + suffix : "--" + fileNameWithoutSuffix + suffix; + "--" + params.directoryName + "-" + fileNameWithoutSuffix + suffix : + "--" + fileNameWithoutSuffix + suffix; if (arg.equals(s)) { return createSettingsFromReader(new StringReader(params.args.get(i + 1)), suffix); } @@ -160,7 +162,7 @@ public class ConfigLoader { return null; } - private Settings.Builder createSettingsFromStdin() throws ConfigException { + private SettingsBuilder createSettingsFromStdin() throws ConfigException { if (System.in != null) { try { int numBytesWaiting = System.in.available(); @@ -175,8 +177,8 @@ public class ConfigLoader { return null; } - private Settings.Builder createSettingsFromFile(List settingsFileNames) throws ConfigException { - Settings.Builder settings = Settings.settingsBuilder(); + private SettingsBuilder createSettingsFromFile(List settingsFileNames) throws ConfigException { + SettingsBuilder settings = Settings.settingsBuilder(); for (String settingsFileName: settingsFileNames) { int pos = settingsFileName.lastIndexOf('.'); String suffix = (pos > 0 ? settingsFileName.substring(pos + 1) : "").toLowerCase(Locale.ROOT); @@ -191,7 +193,7 @@ public class ConfigLoader { System.setProperty("config.path", path.getParent().toString()); try { InputStream inputStream = Files.newInputStream(path); - Settings.Builder fileSettings = createSettingsFromStream(inputStream, suffix); + SettingsBuilder fileSettings = createSettingsFromStream(inputStream, suffix); if (fileSettings != null) { settings.put(fileSettings.build()); } @@ -203,10 +205,10 @@ public class ConfigLoader { return settings.isEmpty() ? null : settings; } - private Settings.Builder createClasspathSettings(ConfigParams params, - ClassLoader classLoader, - String fileNameWithoutSuffix) throws ConfigException { - Settings.Builder settings = Settings.settingsBuilder(); + private SettingsBuilder createClasspathSettings(ConfigParams params, + ClassLoader classLoader, + String fileNameWithoutSuffix) throws ConfigException { + SettingsBuilder settings = Settings.settingsBuilder(); for (String suffix : SettingsLoaderService.getInstance().getSuffixes()) { String path = params.directoryName != null ? params.directoryName + '-' + fileNameWithoutSuffix + suffix : fileNameWithoutSuffix + suffix; @@ -215,7 +217,7 @@ public class ConfigLoader { if (logger != null) { logger.info("found resource: " + path); } - Settings.Builder streamSettings = createSettingsFromStream(inputStream, suffix); + SettingsBuilder streamSettings = createSettingsFromStream(inputStream, suffix); if (streamSettings != null) { settings.put(streamSettings.build()); } @@ -224,8 +226,8 @@ public class ConfigLoader { return settings.isEmpty() ? null : settings; } - private Settings.Builder createSettingsFromStream(InputStream inputStream, - String suffix) throws ConfigException { + private SettingsBuilder createSettingsFromStream(InputStream inputStream, + String suffix) throws ConfigException { if (inputStream == null) { if (logger != null) { logger.error("unable to open input stream"); @@ -235,8 +237,8 @@ public class ConfigLoader { return createSettingsFromReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8), suffix); } - private Settings.Builder createSettingsFromReader(Reader reader, - String suffix) throws ConfigException { + private SettingsBuilder createSettingsFromReader(Reader reader, + String suffix) throws ConfigException { if (reader == null) { if (logger != null) { logger.error("unable to open reader"); @@ -245,7 +247,7 @@ public class ConfigLoader { } SettingsLoader settingsLoader = SettingsLoaderService.getInstance().loaderFromResource(suffix); if (settingsLoader != null) { - Settings.Builder settings; + SettingsBuilder settings; try (BufferedReader bufferedReader = new BufferedReader(reader)) { String content = bufferedReader.lines().collect(Collectors.joining("\n")); settings = Settings.settingsBuilder().put(settingsLoader.load(content)); @@ -261,8 +263,8 @@ public class ConfigLoader { return null; } - private Settings.Builder overrideFromProperties(ConfigParams params, - Settings.Builder settings) { + private SettingsBuilder overrideFromProperties(ConfigParams params, + SettingsBuilder settings) { for (String key : settings.map().keySet()) { String value = System.getProperty(params.directoryName != null ? params.directoryName + '.' + key : key); if (value != null) { @@ -282,7 +284,7 @@ public class ConfigLoader { } if (params.directoryName != null) { list.add(params.directoryName + '-' + fileNameWithoutSuffix + "." + suffix); - list.add(xdgConfigHome + '/' + params.directoryName + '/' + fileNameWithoutSuffix + "." +suffix); + list.add(xdgConfigHome + '/' + params.directoryName + '/' + fileNameWithoutSuffix + "." + suffix); list.add("/etc/" + params.directoryName + '/' + fileNameWithoutSuffix + "." + suffix); } else { list.add(fileNameWithoutSuffix + "." + suffix); diff --git a/content-config/src/main/java/org/xbib/content/config/ConfigParams.java b/content-config/src/main/java/org/xbib/content/config/ConfigParams.java index a23b749..8b5ce77 100644 --- a/content-config/src/main/java/org/xbib/content/config/ConfigParams.java +++ b/content-config/src/main/java/org/xbib/content/config/ConfigParams.java @@ -1,7 +1,6 @@ package org.xbib.content.config; -import org.xbib.content.settings.datastructures.Settings; - +import org.xbib.content.settings.datastructures.DatastructureSettings; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; @@ -26,7 +25,7 @@ public class ConfigParams implements Comparable { final List reader = new ArrayList<>(); - final List settings = new ArrayList<>(); + final List settings = new ArrayList<>(); List args = null; @@ -77,7 +76,7 @@ public class ConfigParams implements Comparable { return this; } - public ConfigParams withSettings(Settings settings) { + public ConfigParams withSettings(DatastructureSettings settings) { this.settings.add(settings); return this; } diff --git a/content-config/src/test/java/org/xbib/content/config/test/ConfigLoaderTest.java b/content-config/src/test/java/org/xbib/content/config/test/ConfigLoaderTest.java index da83e0d..4ea27f4 100644 --- a/content-config/src/test/java/org/xbib/content/config/test/ConfigLoaderTest.java +++ b/content-config/src/test/java/org/xbib/content/config/test/ConfigLoaderTest.java @@ -1,17 +1,13 @@ package org.xbib.content.config.test; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; +import org.xbib.content.Settings; import org.xbib.content.config.ConfigLoader; import org.xbib.content.config.ConfigParams; -import org.xbib.content.settings.datastructures.Settings; - import java.io.IOException; import java.io.Reader; import java.io.StringReader; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.junit.jupiter.api.Assertions.assertEquals; public class ConfigLoaderTest { @@ -33,13 +29,4 @@ public class ConfigLoaderTest { assertEquals("world2", settings.get("hello2")); } - - @Test - public void configInterlibraryTest() { - Settings settings = ConfigLoader.getInstance() - .load(new ConfigParams() - .withDirectoryName("interlibrary") - .withFileNamesWithoutSuffix("test")); - Logger.getAnonymousLogger().log(Level.INFO, settings.getAsMap().toString()); - } } diff --git a/content-config/src/test/java/org/xbib/content/config/test/package-info.java b/content-config/src/test/java/org/xbib/content/config/test/package-info.java new file mode 100644 index 0000000..3527751 --- /dev/null +++ b/content-config/src/test/java/org/xbib/content/config/test/package-info.java @@ -0,0 +1,4 @@ +/** + * Test classes for content config. + */ +package org.xbib.content.config.test; diff --git a/content-config/src/test/resources/META-INF/services/org.xbib.content.settings.datastructures.SettingsLoader b/content-config/src/test/resources/META-INF/services/org.xbib.content.SettingsLoader similarity index 100% rename from content-config/src/test/resources/META-INF/services/org.xbib.content.settings.datastructures.SettingsLoader rename to content-config/src/test/resources/META-INF/services/org.xbib.content.SettingsLoader diff --git a/content-core/src/main/java/module-info.java b/content-core/src/main/java/module-info.java index c6172b4..428e432 100644 --- a/content-core/src/main/java/module-info.java +++ b/content-core/src/main/java/module-info.java @@ -1,16 +1,10 @@ import org.xbib.content.XContent; -import org.xbib.content.SettingsLoader; -import org.xbib.content.properties.PropertiesSettingsLoader; module org.xbib.content.core { uses XContent; - uses SettingsLoader; exports org.xbib.content.io; - exports org.xbib.content.properties; exports org.xbib.content.util.geo; - exports org.xbib.content.util.unit; exports org.xbib.content.core; - requires transitive org.xbib.content; + requires transitive org.xbib.content.api; requires com.fasterxml.jackson.core; - provides SettingsLoader with PropertiesSettingsLoader; } diff --git a/content-core/src/main/java/org/xbib/content/core/DefaultXContentBuilder.java b/content-core/src/main/java/org/xbib/content/core/DefaultXContentBuilder.java index d6e2522..2a88d45 100644 --- a/content-core/src/main/java/org/xbib/content/core/DefaultXContentBuilder.java +++ b/content-core/src/main/java/org/xbib/content/core/DefaultXContentBuilder.java @@ -8,7 +8,6 @@ import org.xbib.content.XContentParser; import org.xbib.content.io.BytesReference; import org.xbib.content.io.BytesStreamOutput; import org.xbib.content.util.geo.GeoPoint; - import java.io.IOException; import java.io.OutputStream; import java.math.BigDecimal; @@ -136,6 +135,7 @@ public final class DefaultXContentBuilder implements XContentBuilder { return this; } + @Override public XContentBuilder field(String name, Integer value) throws IOException { field(name); if (value == null) { @@ -146,6 +146,7 @@ public final class DefaultXContentBuilder implements XContentBuilder { return this; } + @Override public XContentBuilder field(String name, int value) throws IOException { field(name); generator.writeNumber(value); @@ -289,6 +290,7 @@ public final class DefaultXContentBuilder implements XContentBuilder { return this; } + @Override public XContentBuilder field(String name, int... value) throws IOException { startArray(name); for (Object o : value) { @@ -505,6 +507,7 @@ public final class DefaultXContentBuilder implements XContentBuilder { return this; } + @Override public XContentBuilder value(byte[] value) throws IOException { if (value == null) { return nullValue(); diff --git a/content-core/src/main/java/org/xbib/content/core/XContentHelper.java b/content-core/src/main/java/org/xbib/content/core/XContentHelper.java index c9dde04..da17c36 100644 --- a/content-core/src/main/java/org/xbib/content/core/XContentHelper.java +++ b/content-core/src/main/java/org/xbib/content/core/XContentHelper.java @@ -5,7 +5,6 @@ import org.xbib.content.XContentBuilder; import org.xbib.content.XContentGenerator; import org.xbib.content.XContentParser; import org.xbib.content.io.BytesReference; - import java.io.IOException; import java.io.Reader; import java.util.Map; diff --git a/content-core/src/main/java/org/xbib/content/core/XContentService.java b/content-core/src/main/java/org/xbib/content/core/XContentService.java index 609fc08..69bb2f8 100644 --- a/content-core/src/main/java/org/xbib/content/core/XContentService.java +++ b/content-core/src/main/java/org/xbib/content/core/XContentService.java @@ -3,7 +3,6 @@ package org.xbib.content.core; import org.xbib.content.XContent; import org.xbib.content.XContentBuilder; import org.xbib.content.io.BytesArray; - import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; diff --git a/content-core/src/main/java/org/xbib/content/properties/package-info.java b/content-core/src/main/java/org/xbib/content/properties/package-info.java deleted file mode 100644 index 3858ae9..0000000 --- a/content-core/src/main/java/org/xbib/content/properties/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Classes for properties-based content. - */ -package org.xbib.content.properties; diff --git a/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeUnit.java b/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeUnit.java deleted file mode 100644 index d42c518..0000000 --- a/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeUnit.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.xbib.content.util.unit; - -/** - * A {@code SizeUnit} represents size at a given unit of - * granularity and provides utility methods to convert across units. - * A {@code SizeUnit} does not maintain size information, but only - * helps organize and use size representations that may be maintained - * separately across various contexts. - */ -public enum ByteSizeUnit { - BYTES { - @Override - public long toBytes(long size) { - return size; - } - - @Override - public long toKB(long size) { - return size / (C1 / C0); - } - - @Override - public long toMB(long size) { - return size / (C2 / C0); - } - - @Override - public long toGB(long size) { - return size / (C3 / C0); - } - - @Override - public long toTB(long size) { - return size / (C4 / C0); - } - - @Override - public long toPB(long size) { - return size / (C5 / C0); - } - }, - KB { - @Override - public long toBytes(long size) { - return x(size, C1 / C0, MAX / (C1 / C0)); - } - - @Override - public long toKB(long size) { - return size; - } - - @Override - public long toMB(long size) { - return size / (C2 / C1); - } - - @Override - public long toGB(long size) { - return size / (C3 / C1); - } - - @Override - public long toTB(long size) { - return size / (C4 / C1); - } - - @Override - public long toPB(long size) { - return size / (C5 / C1); - } - }, - MB { - @Override - public long toBytes(long size) { - return x(size, C2 / C0, MAX / (C2 / C0)); - } - - @Override - public long toKB(long size) { - return x(size, C2 / C1, MAX / (C2 / C1)); - } - - @Override - public long toMB(long size) { - return size; - } - - @Override - public long toGB(long size) { - return size / (C3 / C2); - } - - @Override - public long toTB(long size) { - return size / (C4 / C2); - } - - @Override - public long toPB(long size) { - return size / (C5 / C2); - } - }, - GB { - @Override - public long toBytes(long size) { - return x(size, C3 / C0, MAX / (C3 / C0)); - } - - @Override - public long toKB(long size) { - return x(size, C3 / C1, MAX / (C3 / C1)); - } - - @Override - public long toMB(long size) { - return x(size, C3 / C2, MAX / (C3 / C2)); - } - - @Override - public long toGB(long size) { - return size; - } - - @Override - public long toTB(long size) { - return size / (C4 / C3); - } - - @Override - public long toPB(long size) { - return size / (C5 / C3); - } - }, - TB { - @Override - public long toBytes(long size) { - return x(size, C4 / C0, MAX / (C4 / C0)); - } - - @Override - public long toKB(long size) { - return x(size, C4 / C1, MAX / (C4 / C1)); - } - - @Override - public long toMB(long size) { - return x(size, C4 / C2, MAX / (C4 / C2)); - } - - @Override - public long toGB(long size) { - return x(size, C4 / C3, MAX / (C4 / C3)); - } - - @Override - public long toTB(long size) { - return size; - } - - @Override - public long toPB(long size) { - return size / (C5 / C4); - } - }, - PB { - @Override - public long toBytes(long size) { - return x(size, C5 / C0, MAX / (C5 / C0)); - } - - @Override - public long toKB(long size) { - return x(size, C5 / C1, MAX / (C5 / C1)); - } - - @Override - public long toMB(long size) { - return x(size, C5 / C2, MAX / (C5 / C2)); - } - - @Override - public long toGB(long size) { - return x(size, C5 / C3, MAX / (C5 / C3)); - } - - @Override - public long toTB(long size) { - return x(size, C5 / C4, MAX / (C5 / C4)); - } - - @Override - public long toPB(long size) { - return size; - } - }; - - static final long C0 = 1L; - static final long C1 = C0 * 1024L; - static final long C2 = C1 * 1024L; - static final long C3 = C2 * 1024L; - static final long C4 = C3 * 1024L; - static final long C5 = C4 * 1024L; - - static final long MAX = Long.MAX_VALUE; - - /** - * Scale d by m, checking for overflow. - * This has a short name to make above code more readable. - */ - static long x(long d, long m, long over) { - if (d > over) { - return Long.MAX_VALUE; - } - if (d < -over) { - return Long.MIN_VALUE; - } - return d * m; - } - - - public abstract long toBytes(long size); - - public abstract long toKB(long size); - - public abstract long toMB(long size); - - public abstract long toGB(long size); - - public abstract long toTB(long size); - - public abstract long toPB(long size); -} diff --git a/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeValue.java b/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeValue.java deleted file mode 100644 index b219a40..0000000 --- a/content-core/src/main/java/org/xbib/content/util/unit/ByteSizeValue.java +++ /dev/null @@ -1,228 +0,0 @@ -package org.xbib.content.util.unit; - -import java.util.Locale; - -/** - * - */ -public class ByteSizeValue { - - private long size; - - private ByteSizeUnit sizeUnit; - - private ByteSizeValue() { - } - - public ByteSizeValue(long size, ByteSizeUnit sizeUnit) { - this.size = size; - this.sizeUnit = sizeUnit; - } - - /** - * Format the double value with a single decimal points, trimming trailing '.0'. - * @param value value - * @param suffix suffix - * @return formatted decimal - */ - public static String format1Decimals(double value, String suffix) { - String p = String.valueOf(value); - int ix = p.indexOf('.') + 1; - int ex = p.indexOf('E'); - char fraction = p.charAt(ix); - if (fraction == '0') { - if (ex != -1) { - return p.substring(0, ix - 1) + p.substring(ex) + suffix; - } else { - return p.substring(0, ix - 1) + suffix; - } - } else { - if (ex != -1) { - return p.substring(0, ix) + fraction + p.substring(ex) + suffix; - } else { - return p.substring(0, ix) + fraction + suffix; - } - } - } - - public static ByteSizeValue parseBytesSizeValue(String sValue) { - return parseBytesSizeValue(sValue, null); - } - - public static ByteSizeValue parseBytesSizeValue(String sValue, ByteSizeValue defaultValue) { - if (sValue == null) { - return defaultValue; - } - long bytes; - try { - String lastTwoChars = sValue.substring(sValue.length() - Math.min(2, sValue.length())).toLowerCase(Locale.ROOT); - if (lastTwoChars.endsWith("k")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * ByteSizeUnit.C1); - } else if (lastTwoChars.endsWith("kb")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2)) * ByteSizeUnit.C1); - } else if (lastTwoChars.endsWith("m")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * ByteSizeUnit.C2); - } else if (lastTwoChars.endsWith("mb")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2)) * ByteSizeUnit.C2); - } else if (lastTwoChars.endsWith("g")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * ByteSizeUnit.C3); - } else if (lastTwoChars.endsWith("gb")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2)) * ByteSizeUnit.C3); - } else if (lastTwoChars.endsWith("t")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * ByteSizeUnit.C4); - } else if (lastTwoChars.endsWith("tb")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2)) * ByteSizeUnit.C4); - } else if (lastTwoChars.endsWith("p")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * ByteSizeUnit.C5); - } else if (lastTwoChars.endsWith("pb")) { - bytes = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2)) * ByteSizeUnit.C5); - } else if (lastTwoChars.endsWith("b")) { - bytes = Long.parseLong(sValue.substring(0, sValue.length() - 1)); - } else { - bytes = Long.parseLong(sValue); - } - } catch (NumberFormatException e) { - return defaultValue; - } - return new ByteSizeValue(bytes, ByteSizeUnit.BYTES); - } - - public int bytesAsInt() throws IllegalArgumentException { - long bytes = bytes(); - if (bytes > Integer.MAX_VALUE) { - throw new IllegalArgumentException("size [" + toString() + "] is bigger than max int"); - } - return (int) bytes; - } - - public long bytes() { - return sizeUnit.toBytes(size); - } - - public long getBytes() { - return bytes(); - } - - public long kb() { - return sizeUnit.toKB(size); - } - - public long getKb() { - return kb(); - } - - public long mb() { - return sizeUnit.toMB(size); - } - - public long getMb() { - return mb(); - } - - public long gb() { - return sizeUnit.toGB(size); - } - - public long getGb() { - return gb(); - } - - public long tb() { - return sizeUnit.toTB(size); - } - - public long getTb() { - return tb(); - } - - public long pb() { - return sizeUnit.toPB(size); - } - - public long getPb() { - return pb(); - } - - public double kbFrac() { - return ((double) bytes()) / ByteSizeUnit.C1; - } - - public double getKbFrac() { - return kbFrac(); - } - - public double mbFrac() { - return ((double) bytes()) / ByteSizeUnit.C2; - } - - public double getMbFrac() { - return mbFrac(); - } - - public double gbFrac() { - return ((double) bytes()) / ByteSizeUnit.C3; - } - - public double getGbFrac() { - return gbFrac(); - } - - public double tbFrac() { - return ((double) bytes()) / ByteSizeUnit.C4; - } - - public double getTbFrac() { - return tbFrac(); - } - - public double pbFrac() { - return ((double) bytes()) / ByteSizeUnit.C5; - } - - public double getPbFrac() { - return pbFrac(); - } - - @Override - public String toString() { - long bytes = bytes(); - double value = bytes; - String suffix = "b"; - if (bytes >= ByteSizeUnit.C5) { - value = pbFrac(); - suffix = "pb"; - } else if (bytes >= ByteSizeUnit.C4) { - value = tbFrac(); - suffix = "tb"; - } else if (bytes >= ByteSizeUnit.C3) { - value = gbFrac(); - suffix = "gb"; - } else if (bytes >= ByteSizeUnit.C2) { - value = mbFrac(); - suffix = "mb"; - } else if (bytes >= ByteSizeUnit.C1) { - value = kbFrac(); - suffix = "kb"; - } - return format1Decimals(value, suffix); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ByteSizeValue sizeValue = (ByteSizeValue) o; - return size == sizeValue.size && sizeUnit == sizeValue.sizeUnit; - } - - @Override - public int hashCode() { - int result = (int) (size ^ (size >>> 32)); - result = 31 * result + (sizeUnit != null ? sizeUnit.hashCode() : 0); - return result; - } -} diff --git a/content-core/src/main/java/org/xbib/content/util/unit/SizeUnit.java b/content-core/src/main/java/org/xbib/content/util/unit/SizeUnit.java deleted file mode 100644 index bcd16e1..0000000 --- a/content-core/src/main/java/org/xbib/content/util/unit/SizeUnit.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.xbib.content.util.unit; - -/** - * - */ -public enum SizeUnit { - SCALAR { - @Override - public long toScalar(long size) { - return size; - } - - @Override - public long toKilo(long size) { - return size / (C1 / C0); - } - - @Override - public long toMega(long size) { - return size / (C2 / C0); - } - - @Override - public long toGiga(long size) { - return size / (C3 / C0); - } - - @Override - public long toTera(long size) { - return size / (C4 / C0); - } - - @Override - public long toPeta(long size) { - return size / (C5 / C0); - } - }, - KILO { - @Override - public long toScalar(long size) { - return x(size, C1 / C0, MAX / (C1 / C0)); - } - - @Override - public long toKilo(long size) { - return size; - } - - @Override - public long toMega(long size) { - return size / (C2 / C1); - } - - @Override - public long toGiga(long size) { - return size / (C3 / C1); - } - - @Override - public long toTera(long size) { - return size / (C4 / C1); - } - - @Override - public long toPeta(long size) { - return size / (C5 / C1); - } - }, - MEGA { - @Override - public long toScalar(long size) { - return x(size, C2 / C0, MAX / (C2 / C0)); - } - - @Override - public long toKilo(long size) { - return x(size, C2 / C1, MAX / (C2 / C1)); - } - - @Override - public long toMega(long size) { - return size; - } - - @Override - public long toGiga(long size) { - return size / (C3 / C2); - } - - @Override - public long toTera(long size) { - return size / (C4 / C2); - } - - @Override - public long toPeta(long size) { - return size / (C5 / C2); - } - }, - GIGA { - @Override - public long toScalar(long size) { - return x(size, C3 / C0, MAX / (C3 / C0)); - } - - @Override - public long toKilo(long size) { - return x(size, C3 / C1, MAX / (C3 / C1)); - } - - @Override - public long toMega(long size) { - return x(size, C3 / C2, MAX / (C3 / C2)); - } - - @Override - public long toGiga(long size) { - return size; - } - - @Override - public long toTera(long size) { - return size / (C4 / C3); - } - - @Override - public long toPeta(long size) { - return size / (C5 / C3); - } - }, - TERA { - @Override - public long toScalar(long size) { - return x(size, C4 / C0, MAX / (C4 / C0)); - } - - @Override - public long toKilo(long size) { - return x(size, C4 / C1, MAX / (C4 / C1)); - } - - @Override - public long toMega(long size) { - return x(size, C4 / C2, MAX / (C4 / C2)); - } - - @Override - public long toGiga(long size) { - return x(size, C4 / C3, MAX / (C4 / C3)); - } - - @Override - public long toTera(long size) { - return size; - } - - @Override - public long toPeta(long size) { - return size / (C5 / C0); - } - }, - PETA { - @Override - public long toScalar(long size) { - return x(size, C5 / C0, MAX / (C5 / C0)); - } - - @Override - public long toKilo(long size) { - return x(size, C5 / C1, MAX / (C5 / C1)); - } - - @Override - public long toMega(long size) { - return x(size, C5 / C2, MAX / (C5 / C2)); - } - - @Override - public long toGiga(long size) { - return x(size, C5 / C3, MAX / (C5 / C3)); - } - - @Override - public long toTera(long size) { - return x(size, C5 / C4, MAX / (C5 / C4)); - } - - @Override - public long toPeta(long size) { - return size; - } - }; - - static final long C0 = 1L; - static final long C1 = C0 * 1000L; - static final long C2 = C1 * 1000L; - static final long C3 = C2 * 1000L; - static final long C4 = C3 * 1000L; - static final long C5 = C4 * 1000L; - - static final long MAX = Long.MAX_VALUE; - - /** - * Scale d by m, checking for overflow. - * This has a short name to make above code more readable. - */ - static long x(long d, long m, long over) { - if (d > over) { - return Long.MAX_VALUE; - } - if (d < -over) { - return Long.MIN_VALUE; - } - return d * m; - } - - - public abstract long toScalar(long size); - - public abstract long toKilo(long size); - - public abstract long toMega(long size); - - public abstract long toGiga(long size); - - public abstract long toTera(long size); - - public abstract long toPeta(long size); -} diff --git a/content-core/src/main/java/org/xbib/content/util/unit/TimeValue.java b/content-core/src/main/java/org/xbib/content/util/unit/TimeValue.java deleted file mode 100644 index e5ee83f..0000000 --- a/content-core/src/main/java/org/xbib/content/util/unit/TimeValue.java +++ /dev/null @@ -1,259 +0,0 @@ -package org.xbib.content.util.unit; - -import java.util.concurrent.TimeUnit; - -/** - * - */ -public class TimeValue { - - private static final long C0 = 1L; - private static final long C1 = C0 * 1000L; - private static final long C2 = C1 * 1000L; - private static final long C3 = C2 * 1000L; - private static final long C4 = C3 * 60L; - private static final long C5 = C4 * 60L; - private static final long C6 = C5 * 24L; - private long duration; - private TimeUnit timeUnit; - - private TimeValue() { - } - - public TimeValue(long millis) { - this(millis, TimeUnit.MILLISECONDS); - } - - public TimeValue(long duration, TimeUnit timeUnit) { - this.duration = duration; - this.timeUnit = timeUnit; - } - - public static TimeValue timeValueNanos(long nanos) { - return new TimeValue(nanos, TimeUnit.NANOSECONDS); - } - - public static TimeValue timeValueMillis(long millis) { - return new TimeValue(millis, TimeUnit.MILLISECONDS); - } - - public static TimeValue timeValueSeconds(long seconds) { - return new TimeValue(seconds, TimeUnit.SECONDS); - } - - public static TimeValue timeValueMinutes(long minutes) { - return new TimeValue(minutes, TimeUnit.MINUTES); - } - - public static TimeValue timeValueHours(long hours) { - return new TimeValue(hours, TimeUnit.HOURS); - } - - /** - * Format the double value with a single decimal points, trimming trailing '.0'. - * - * @param value value - * @param suffix suffix - * @return string - */ - public static String format1Decimals(double value, String suffix) { - String p = String.valueOf(value); - int ix = p.indexOf('.') + 1; - int ex = p.indexOf('E'); - char fraction = p.charAt(ix); - if (fraction == '0') { - if (ex != -1) { - return p.substring(0, ix - 1) + p.substring(ex) + suffix; - } else { - return p.substring(0, ix - 1) + suffix; - } - } else { - if (ex != -1) { - return p.substring(0, ix) + fraction + p.substring(ex) + suffix; - } else { - return p.substring(0, ix) + fraction + suffix; - } - } - } - - public static TimeValue parseTimeValue(String sValue, TimeValue defaultValue) { - if (sValue == null) { - return defaultValue; - } - long millis; - if (sValue.endsWith("S")) { - millis = Long.parseLong(sValue.substring(0, sValue.length() - 1)); - } else if (sValue.endsWith("ms")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 2))); - } else if (sValue.endsWith("s")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 1000); - } else if (sValue.endsWith("m")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60 * 1000); - } else if (sValue.endsWith("H") || sValue.endsWith("h")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 60 * 60 * 1000); - } else if (sValue.endsWith("d")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 24 * 60 * 60 * 1000); - } else if (sValue.endsWith("w")) { - millis = (long) (Double.parseDouble(sValue.substring(0, sValue.length() - 1)) * 7 * 24 * 60 * 60 * 1000); - } else { - millis = Long.parseLong(sValue); - } - return new TimeValue(millis, TimeUnit.MILLISECONDS); - } - - public long nanos() { - return timeUnit.toNanos(duration); - } - - public long getNanos() { - return nanos(); - } - - public long micros() { - return timeUnit.toMicros(duration); - } - - public long getMicros() { - return micros(); - } - - public long millis() { - return timeUnit.toMillis(duration); - } - - public long getMillis() { - return millis(); - } - - public long seconds() { - return timeUnit.toSeconds(duration); - } - - public long getSeconds() { - return seconds(); - } - - public long minutes() { - return timeUnit.toMinutes(duration); - } - - public long getMinutes() { - return minutes(); - } - - public long hours() { - return timeUnit.toHours(duration); - } - - public long getHours() { - return hours(); - } - - public long days() { - return timeUnit.toDays(duration); - } - - public long getDays() { - return days(); - } - - public double microsFrac() { - return ((double) nanos()) / C1; - } - - public double getMicrosFrac() { - return microsFrac(); - } - - public double millisFrac() { - return ((double) nanos()) / C2; - } - - public double getMillisFrac() { - return millisFrac(); - } - - public double secondsFrac() { - return ((double) nanos()) / C3; - } - - public double getSecondsFrac() { - return secondsFrac(); - } - - public double minutesFrac() { - return ((double) nanos()) / C4; - } - - public double getMinutesFrac() { - return minutesFrac(); - } - - public double hoursFrac() { - return ((double) nanos()) / C5; - } - - public double getHoursFrac() { - return hoursFrac(); - } - - public double daysFrac() { - return ((double) nanos()) / C6; - } - - public double getDaysFrac() { - return daysFrac(); - } - - @Override - public String toString() { - if (duration < 0) { - return Long.toString(duration); - } - long nanos = nanos(); - if (nanos == 0) { - return "0s"; - } - double value = nanos; - String suffix = "nanos"; - if (nanos >= C6) { - value = daysFrac(); - suffix = "d"; - } else if (nanos >= C5) { - value = hoursFrac(); - suffix = "h"; - } else if (nanos >= C4) { - value = minutesFrac(); - suffix = "m"; - } else if (nanos >= C3) { - value = secondsFrac(); - suffix = "s"; - } else if (nanos >= C2) { - value = millisFrac(); - suffix = "ms"; - } else if (nanos >= C1) { - value = microsFrac(); - suffix = "micros"; - } - return format1Decimals(value, suffix); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TimeValue timeValue = (TimeValue) o; - return duration == timeValue.duration && timeUnit == timeValue.timeUnit; - } - - @Override - public int hashCode() { - int result = (int) (duration ^ (duration >>> 32)); - result = 31 * result + (timeUnit != null ? timeUnit.hashCode() : 0); - return result; - } -} diff --git a/content-core/src/main/java/org/xbib/content/util/unit/package-info.java b/content-core/src/main/java/org/xbib/content/util/unit/package-info.java deleted file mode 100644 index 6f22b06..0000000 --- a/content-core/src/main/java/org/xbib/content/util/unit/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Classes for units. - */ -package org.xbib.content.util.unit; diff --git a/content-core/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader b/content-core/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader deleted file mode 100644 index 561e5b9..0000000 --- a/content-core/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader +++ /dev/null @@ -1 +0,0 @@ -org.xbib.content.properties.PropertiesSettingsLoader diff --git a/content-settings-datastructures-json/src/main/java/module-info.java b/content-settings-datastructures-json/src/main/java/module-info.java index 3a2c891..9f4ee0e 100644 --- a/content-settings-datastructures-json/src/main/java/module-info.java +++ b/content-settings-datastructures-json/src/main/java/module-info.java @@ -1,9 +1,10 @@ -import org.xbib.content.settings.datastructures.SettingsLoader; +import org.xbib.content.SettingsLoader; import org.xbib.content.settings.datastructures.json.JsonSettingsLoader; module org.xbib.content.settings.datastructures.json { exports org.xbib.content.settings.datastructures.json; requires transitive org.xbib.content.settings.datastructures; requires org.xbib.datastructures.json.tiny; + uses SettingsLoader; provides SettingsLoader with JsonSettingsLoader; } diff --git a/content-settings-datastructures-json/src/main/resources/META-INF.services/org.xbib.content.settings.datastructures.SettingsLoader b/content-settings-datastructures-json/src/main/resources/META-INF.services/org.xbib.content.SettingsLoader similarity index 100% rename from content-settings-datastructures-json/src/main/resources/META-INF.services/org.xbib.content.settings.datastructures.SettingsLoader rename to content-settings-datastructures-json/src/main/resources/META-INF.services/org.xbib.content.SettingsLoader diff --git a/content-settings-datastructures-json/src/test/java/org/xbib/content/settings/datastructures/json/test/JsonSettingsTest.java b/content-settings-datastructures-json/src/test/java/org/xbib/content/settings/datastructures/json/test/JsonSettingsTest.java index fa03784..0b8efe4 100644 --- a/content-settings-datastructures-json/src/test/java/org/xbib/content/settings/datastructures/json/test/JsonSettingsTest.java +++ b/content-settings-datastructures-json/src/test/java/org/xbib/content/settings/datastructures/json/test/JsonSettingsTest.java @@ -1,8 +1,8 @@ package org.xbib.content.settings.datastructures.json.test; import org.junit.jupiter.api.Test; -import org.xbib.content.settings.datastructures.Settings; -import org.xbib.content.settings.datastructures.SettingsLoader; +import org.xbib.content.Settings; +import org.xbib.content.SettingsLoader; import org.xbib.content.settings.datastructures.json.JsonSettingsLoader; import java.io.IOException; import java.util.Arrays; diff --git a/content-settings-datastructures-yaml/src/main/java/module-info.java b/content-settings-datastructures-yaml/src/main/java/module-info.java index 54ed1ec..b274ea4 100644 --- a/content-settings-datastructures-yaml/src/main/java/module-info.java +++ b/content-settings-datastructures-yaml/src/main/java/module-info.java @@ -1,9 +1,10 @@ -import org.xbib.content.settings.datastructures.SettingsLoader; +import org.xbib.content.SettingsLoader; import org.xbib.content.settings.datastructures.yaml.YamlSettingsLoader; module org.xbib.content.settings.datastructures.yaml { exports org.xbib.content.settings.datastructures.yaml; requires transitive org.xbib.content.settings.datastructures; requires org.xbib.datastructures.yaml.tiny; + uses SettingsLoader; provides SettingsLoader with YamlSettingsLoader; } diff --git a/content-settings-datastructures-yaml/src/test/java/org/xbib/content/settings/datastructures/yaml/test/YamlSettingsTest.java b/content-settings-datastructures-yaml/src/test/java/org/xbib/content/settings/datastructures/yaml/test/YamlSettingsTest.java index 52afb06..1996fb3 100644 --- a/content-settings-datastructures-yaml/src/test/java/org/xbib/content/settings/datastructures/yaml/test/YamlSettingsTest.java +++ b/content-settings-datastructures-yaml/src/test/java/org/xbib/content/settings/datastructures/yaml/test/YamlSettingsTest.java @@ -3,8 +3,8 @@ package org.xbib.content.settings.datastructures.yaml.test; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; -import org.xbib.content.settings.datastructures.Settings; -import org.xbib.content.settings.datastructures.SettingsLoader; +import org.xbib.content.Settings; +import org.xbib.content.SettingsLoader; import org.xbib.content.settings.datastructures.yaml.YamlSettingsLoader; import java.io.IOException; import java.util.Arrays; diff --git a/content-settings-datastructures/build.gradle b/content-settings-datastructures/build.gradle index 3affdcc..3b92ad5 100644 --- a/content-settings-datastructures/build.gradle +++ b/content-settings-datastructures/build.gradle @@ -1,4 +1,4 @@ dependencies { - api "org.xbib:datastructures-api:${project.property('xbib-datastructures.version')}" + api project(':content-api') api "org.xbib:datastructures-tiny:${project.property('xbib-datastructures.version')}" } diff --git a/content-settings-datastructures/src/main/java/module-info.java b/content-settings-datastructures/src/main/java/module-info.java index b56ec02..b03f0d5 100644 --- a/content-settings-datastructures/src/main/java/module-info.java +++ b/content-settings-datastructures/src/main/java/module-info.java @@ -1,11 +1,15 @@ +import org.xbib.content.SettingsBuilder; +import org.xbib.content.SettingsLoader; +import org.xbib.content.settings.datastructures.DatastructureSettingsBuilder; import org.xbib.content.settings.datastructures.PropertiesSettingsLoader; -import org.xbib.content.settings.datastructures.SettingsLoader; module org.xbib.content.settings.datastructures { uses SettingsLoader; provides SettingsLoader with PropertiesSettingsLoader; + uses SettingsBuilder; + provides SettingsBuilder with DatastructureSettingsBuilder; exports org.xbib.content.settings.datastructures; + requires transitive org.xbib.content.api; requires org.xbib.datastructures.tiny; requires transitive org.xbib.datastructures.api; - requires transitive java.sql; } diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/AbstractSettingsLoader.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/AbstractSettingsLoader.java index 47e419f..6759389 100644 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/AbstractSettingsLoader.java +++ b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/AbstractSettingsLoader.java @@ -1,5 +1,6 @@ package org.xbib.content.settings.datastructures; +import org.xbib.content.SettingsLoader; import org.xbib.datastructures.api.Builder; import org.xbib.datastructures.api.DataStructure; import org.xbib.datastructures.api.ListNode; diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettings.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettings.java new file mode 100644 index 0000000..63793bf --- /dev/null +++ b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettings.java @@ -0,0 +1,357 @@ +package org.xbib.content.settings.datastructures; + +import org.xbib.content.Settings; +import org.xbib.content.SettingsException; +import org.xbib.datastructures.api.ByteSizeValue; +import org.xbib.datastructures.api.TimeValue; +import org.xbib.datastructures.tiny.TinyMap; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class DatastructureSettings implements Settings { + + private static final String[] EMPTY_ARRAY = new String[0]; + + private final TinyMap map; + + protected DatastructureSettings(TinyMap map) { + this.map = map; + } + + public static DatastructureSettings fromMap(Map map) { + DatastructureSettingsBuilder builder = new DatastructureSettingsBuilder(); + for (Map.Entry entry : map.entrySet()) { + builder.put(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : null); + } + return builder.build(); + } + + public static void toMap(DatastructureSettings settings, Map map) { + for (String key : settings.getAsMap().keySet()) { + map.put(key, settings.get(key)); + } + } + + public static String[] splitStringByCommaToArray(final String s) { + return splitStringToArray(s, ','); + } + + public static String[] splitStringToArray(final String s, final char c) { + if (s.length() == 0) { + return EMPTY_ARRAY; + } + final char[] chars = s.toCharArray(); + int count = 1; + for (final char x : chars) { + if (x == c) { + count++; + } + } + final String[] result = new String[count]; + final int len = chars.length; + int start = 0; + int pos = 0; + int i = 0; + for (; pos < len; pos++) { + if (chars[pos] == c) { + int size = pos - start; + if (size > 0) { + result[i++] = new String(chars, start, size); + } + start = pos + 1; + } + } + int size = pos - start; + if (size > 0) { + result[i++] = new String(chars, start, size); + } + if (i != count) { + String[] result1 = new String[i]; + System.arraycopy(result, 0, result1, 0, i); + return result1; + } + return result; + } + + @Override + public Map getAsMap() { + return this.map; + } + + @Override + public Map getAsStructuredMap() { + TinyMap.Builder stringObjectMap = TinyMap.builder(); + for (String key : map.keySet()) { + String value = map.get(key); + processSetting(stringObjectMap, "", key, value); + } + for (String key : stringObjectMap.keySet()) { + Object object = stringObjectMap.get(key); + if (object instanceof Map) { + @SuppressWarnings("unchecked") + Map valMap = (Map) object; + stringObjectMap.put(key, convertMapsToArrays(valMap)); + } + } + return stringObjectMap.build(); + } + + @Override + public Settings getByPrefix(String prefix) { + DatastructureSettingsBuilder builder = new DatastructureSettingsBuilder(); + for (String key : map.keySet()) { + String value = map.get(key); + if (key.startsWith(prefix)) { + if (key.length() < prefix.length()) { + continue; + } + builder.put(key.substring(prefix.length()), value); + } + } + return builder.build(); + } + + @Override + public Settings getAsSettings(String setting) { + return getByPrefix(setting + "."); + } + + @Override + public boolean containsSetting(String setting) { + if (map.containsKey(setting)) { + return true; + } + for (String key : map.keySet()) { + if (key.startsWith(setting)) { + return true; + } + } + return false; + } + + @Override + public String get(String setting) { + return map.get(setting); + } + + @Override + public String get(String setting, String defaultValue) { + String s = map.get(setting); + return s == null ? defaultValue : s; + } + + @Override + public Float getAsFloat(String setting, Float defaultValue) { + String s = get(setting); + try { + return s == null ? defaultValue : Float.parseFloat(s); + } catch (NumberFormatException e) { + throw new SettingsException("Failed to parse float setting [" + setting + "] with value [" + s + "]", e); + } + } + + @Override + public Double getAsDouble(String setting, Double defaultValue) { + String s = get(setting); + try { + return s == null ? defaultValue : Double.parseDouble(s); + } catch (NumberFormatException e) { + throw new SettingsException("Failed to parse double setting [" + setting + "] with value [" + s + "]", e); + } + } + + @Override + public Integer getAsInt(String setting, Integer defaultValue) { + String s = get(setting); + try { + return s == null ? defaultValue : Integer.parseInt(s); + } catch (NumberFormatException e) { + throw new SettingsException("Failed to parse int setting [" + setting + "] with value [" + s + "]", e); + } + } + + @Override + public Long getAsLong(String setting, Long defaultValue) { + String s = get(setting); + try { + return s == null ? defaultValue : Long.parseLong(s); + } catch (NumberFormatException e) { + throw new SettingsException("Failed to parse long setting [" + setting + "] with value [" + s + "]", e); + } + } + + @Override + public Boolean getAsBoolean(String setting, Boolean defaultValue) { + String value = get(setting); + if (value == null) { + return defaultValue; + } + return !("false".equals(value) || "0".equals(value) || "off".equals(value) || "no".equals(value)); + } + + @Override + public TimeValue getAsTime(String setting, TimeValue defaultValue) { + return TimeValue.parseTimeValue(get(setting), defaultValue); + } + + @Override + public ByteSizeValue getAsBytesSize(String setting, ByteSizeValue defaultValue) { + return ByteSizeValue.parseBytesSizeValue(get(setting), defaultValue); + } + + @Override + public String[] getAsArray(String settingPrefix) { + return getAsArray(settingPrefix, EMPTY_ARRAY); + } + + @Override + public String[] getAsArray(String settingPrefix, String[] defaultArray) { + List result = new ArrayList<>(); + if (get(settingPrefix) != null) { + String[] strings = splitStringByCommaToArray(get(settingPrefix)); + if (strings.length > 0) { + for (String string : strings) { + result.add(string.trim()); + } + } + } + int counter = 0; + while (true) { + String value = get(settingPrefix + '.' + (counter++)); + if (value == null) { + break; + } + result.add(value.trim()); + } + if (result.isEmpty()) { + return defaultArray; + } + return result.toArray(new String[0]); + } + + @Override + public Map getGroups(String prefix) { + String settingPrefix = prefix; + if (settingPrefix.charAt(settingPrefix.length() - 1) != '.') { + settingPrefix = settingPrefix + "."; + } + // we don't really care that it might happen twice + TinyMap.Builder> hashMap = TinyMap.builder(); + for (String o : this.map.keySet()) { + if (o.startsWith(settingPrefix)) { + String nameValue = o.substring(settingPrefix.length()); + int dotIndex = nameValue.indexOf('.'); + if (dotIndex == -1) { + throw new SettingsException("failed to get setting group for [" + + settingPrefix + + "] setting prefix and setting [" + o + "] because of a missing '.'"); + } + String name = nameValue.substring(0, dotIndex); + String value = nameValue.substring(dotIndex + 1); + Map groupSettings = hashMap.computeIfAbsent(name, k -> TinyMap.builder()); + groupSettings.put(value, get(o)); + } + } + TinyMap.Builder retVal = TinyMap.builder(); + for (String key : hashMap.keySet()) { + TinyMap.Builder value = hashMap.get(key); + retVal.put(key, new DatastructureSettings(value.build())); + } + return retVal.build(); + } + + @Override + public boolean equals(Object o) { + return this == o || !(o == null || getClass() != o.getClass()) && map.equals(((DatastructureSettings) o).map); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + private void processSetting(Map map, String prefix, String setting, String value) { + int prefixLength = setting.indexOf('.'); + if (prefixLength == -1) { + @SuppressWarnings("unchecked") + Map innerMap = (Map) map.get(prefix + setting); + if (innerMap != null) { + for (String k : innerMap.keySet()) { + Object v = innerMap.get(k); + map.put(prefix + setting + "." + k, v); + } + } + map.put(prefix + setting, value); + } else { + String key = setting.substring(0, prefixLength); + String rest = setting.substring(prefixLength + 1); + Object existingValue = map.get(prefix + key); + if (existingValue == null) { + Map newMap = TinyMap.builder(); + processSetting(newMap, "", rest, value); + map.put(key, newMap); + } else { + if (existingValue instanceof Map) { + @SuppressWarnings("unchecked") + Map innerMap = (Map) existingValue; + processSetting(innerMap, "", rest, value); + map.put(key, innerMap); + } else { + processSetting(map, prefix + key + ".", rest, value); + } + } + } + } + + private Object convertMapsToArrays(Map map) { + if (map.isEmpty()) { + return map; + } + boolean isArray = true; + int maxIndex = -1; + for (String key : map.keySet()) { + Object value = map.get(key); + if (isArray) { + try { + int index = Integer.parseInt(key); + if (index >= 0) { + maxIndex = Math.max(maxIndex, index); + } else { + isArray = false; + } + } catch (NumberFormatException ex) { + isArray = false; + } + } + if (value instanceof Map) { + @SuppressWarnings("unchecked") + Map valMap = (Map) value; + map.put(key, convertMapsToArrays(valMap)); + } + } + if (isArray && (maxIndex + 1) == map.size()) { + ArrayList newValue = new ArrayList<>(maxIndex + 1); + for (int i = 0; i <= maxIndex; i++) { + Object obj = map.get(Integer.toString(i)); + if (obj == null) { + return map; + } + newValue.add(obj); + } + return newValue; + } + return map; + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public void close() throws IOException { + } + +} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettingsBuilder.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettingsBuilder.java new file mode 100644 index 0000000..b57c265 --- /dev/null +++ b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/DatastructureSettingsBuilder.java @@ -0,0 +1,355 @@ +package org.xbib.content.settings.datastructures; + +import org.xbib.content.PlaceholderResolver; +import org.xbib.content.PropertyPlaceholder; +import org.xbib.content.Settings; +import org.xbib.content.SettingsBuilder; +import org.xbib.content.SettingsException; +import org.xbib.content.SettingsLoader; +import org.xbib.datastructures.tiny.TinyMap; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * + */ +public class DatastructureSettingsBuilder implements SettingsBuilder { + + private final SettingsLoaderService settingsLoaderService = SettingsLoaderService.getInstance(); + + private final TinyMap.Builder map; + + public DatastructureSettingsBuilder() { + map = TinyMap.builder(); + } + + public Map map() { + return map; + } + + public String remove(String key) { + return map.remove(key); + } + + public String get(String key) { + return map.get(key); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Sets a setting with the provided setting key and value. + * + * @param key The setting key + * @param value The setting value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String key, String value) { + map.put(key, value); + return this; + } + + /** + * Sets a setting with the provided setting key and class as value. + * + * @param key The setting key + * @param clazz The setting class value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String key, Class clazz) { + map.put(key, clazz.getName()); + return this; + } + + /** + * Sets the setting with the provided setting key and the boolean value. + * + * @param setting The setting key + * @param value The boolean value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String setting, boolean value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the int value. + * + * @param setting The setting key + * @param value The int value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String setting, int value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the long value. + * + * @param setting The setting key + * @param value The long value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String setting, long value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the float value. + * + * @param setting The setting key + * @param value The float value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String setting, float value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the double value. + * + * @param setting The setting key + * @param value The double value + * @return The builder + */ + @Override + public DatastructureSettingsBuilder put(String setting, double value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and an array of values. + * + * @param setting The setting key + * @param values The values + * @return The builder + */ + @Override + public DatastructureSettingsBuilder putArray(String setting, String... values) { + remove(setting); + int counter = 0; + while (true) { + String value = map.remove(setting + '.' + (counter++)); + if (value == null) { + break; + } + } + for (int i = 0; i < values.length; i++) { + put(setting + '.' + i, values[i]); + } + return this; + } + + /** + * Sets the setting with the provided setting key and an array of values. + * + * @param setting The setting key + * @param values The values + * @return The builder + */ + @Override + public DatastructureSettingsBuilder putArray(String setting, List values) { + remove(setting); + int counter = 0; + while (true) { + String value = map.remove(setting + '.' + (counter++)); + if (value == null) { + break; + } + } + for (int i = 0; i < values.size(); i++) { + put(setting + '.' + i, values.get(i)); + } + return this; + } + + /** + * Sets the setting group. + * + * @param settingPrefix setting prefix + * @param groupName group name + * @param settings settings + * @param values values + * @return a builder + * @throws SettingsException if setting fails + */ + @Override + public DatastructureSettingsBuilder put(String settingPrefix, String groupName, String[] settings, String[] values) + throws SettingsException { + if (settings.length != values.length) { + throw new SettingsException("the settings length must match the value length"); + } + for (int i = 0; i < settings.length; i++) { + if (values[i] == null) { + continue; + } + put(settingPrefix + "" + groupName + "." + settings[i], values[i]); + } + return this; + } + + /** + * Sets all the provided settings. + * + * @param settings settings + * @return builder + */ + @Override + public DatastructureSettingsBuilder put(Settings settings) { + map.putAll(settings.getAsMap()); + return this; + } + + /** + * Sets all the provided settings. + * + * @param settings settings + * @return a builder + */ + @Override + public DatastructureSettingsBuilder put(Map settings) { + map.putAll(settings); + return this; + } + + /** + * Loads settings from the actual string content that represents them using the + * {@link SettingsLoaderService#loaderFromString(String)}. + * + * @param source source + * @return builder + */ + @Override + public DatastructureSettingsBuilder loadFromString(String source) { + SettingsLoader settingsLoader = settingsLoaderService.loaderFromString(source); + try { + Map loadedSettings = settingsLoader.load(source); + put(loadedSettings); + } catch (Exception e) { + throw new SettingsException("failed to load settings from [" + source + "]", e); + } + return this; + } + + /** + * Loads settings from a resource. + * + * @param resourceName resource name + * @param inputStream input stream + * @return builder + */ + @Override + public DatastructureSettingsBuilder loadFromResource(String resourceName, InputStream inputStream) throws SettingsException { + SettingsLoader settingsLoader = settingsLoaderService.loaderFromResource(resourceName); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + Map loadedSettings = settingsLoader.load(bufferedReader.lines().collect(Collectors.joining())); + put(loadedSettings); + } catch (Exception e) { + throw new SettingsException("failed to load settings from [" + resourceName + "]", e); + } + return this; + } + + /** + * Load system properties to this settings. + * + * @return builder + */ + @Override + public DatastructureSettingsBuilder loadFromSystemProperties() { + for (Map.Entry entry : System.getProperties().entrySet()) { + put((String) entry.getKey(), (String) entry.getValue()); + } + return this; + } + + /** + * Load system environment to this settings. + * + * @return builder + */ + @Override + public DatastructureSettingsBuilder loadFromSystemEnvironment() { + for (Map.Entry entry : System.getenv().entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + @Override + public DatastructureSettingsBuilder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder, + PlaceholderResolver placeholderResolver) { + map.replaceAll((k, v) -> propertyPlaceholder.replacePlaceholders(v, placeholderResolver)); + return this; + } + + /** + * Runs across all the settings set on this builder and replaces {@code ${...}} elements in the + * each setting value according to the following logic: + *

+ * First, tries to resolve it against a System property ({@link System#getProperty(String)}), next, + * tries and resolve it against an environment variable ({@link System#getenv(String)}), next, + * tries and resolve it against a date pattern to resolve the current date, + * and last, tries and replace it with another setting already set on this builder. + * + * @return builder + */ + @Override + public DatastructureSettingsBuilder replacePropertyPlaceholders() { + return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false), + placeholderName -> { + // system property + String value = System.getProperty(placeholderName); + if (value != null) { + return value; + } + // environment + value = System.getenv(placeholderName); + if (value != null) { + return value; + } + // current date + try { + return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now()); + } catch (IllegalArgumentException | DateTimeException e) { + return map.get(placeholderName); + } + } + ); + } + + @Override + public DatastructureSettingsBuilder setRefresh(Path path, long initialDelay, long period, TimeUnit timeUnit) { + return this; + } + + @Override + public DatastructureSettings build() { + return new DatastructureSettings(map.build()); + } +} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/ExceptionFormatter.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/ExceptionFormatter.java deleted file mode 100644 index 90a944e..0000000 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/ExceptionFormatter.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.xbib.content.settings.datastructures; - -import java.io.PrintWriter; -import java.io.StringWriter; - -/** - * Format java exception messages and stack traces. - */ -public final class ExceptionFormatter { - - private ExceptionFormatter() { - } - - /** - * Format exception with stack trace. - * - * @param t the thrown object - * @return the formatted exception - */ - public static String format(Throwable t) { - StringBuilder sb = new StringBuilder(); - append(sb, t, 0, true); - return sb.toString(); - } - - /** - * Append Exception to string builder. - */ - private static void append(StringBuilder sb, Throwable t, int level, boolean details) { - if (((t != null) && (t.getMessage() != null)) && (!t.getMessage().isEmpty())) { - if (details && (level > 0)) { - sb.append("\n\nCaused by\n"); - } - sb.append(t.getMessage()); - } - if (details) { - if (t != null) { - if ((t.getMessage() != null) && (t.getMessage().isEmpty())) { - sb.append("\n\nCaused by "); - } else { - sb.append("\n\n"); - } - } - StringWriter sw = new StringWriter(); - if (t != null) { - t.printStackTrace(new PrintWriter(sw)); - } - sb.append(sw.toString()); - } - if (t != null) { - if (t.getCause() != null) { - append(sb, t.getCause(), level + 1, details); - } - } - } -} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PlaceholderResolver.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PlaceholderResolver.java deleted file mode 100644 index 578b79f..0000000 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PlaceholderResolver.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.xbib.content.settings.datastructures; - -/** - * Strategy interface used to resolve replacement values for placeholders contained in Strings. - */ -@FunctionalInterface -public interface PlaceholderResolver { - - /** - * Resolves the supplied placeholder name into the replacement value. - * - * @param placeholderName the name of the placeholder to resolve. - * @return the replacement value or null if no replacement is to be made. - */ - String resolvePlaceholder(String placeholderName); -} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertiesSettingsLoader.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertiesSettingsLoader.java index f00a51a..4aa4f32 100644 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertiesSettingsLoader.java +++ b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/PropertiesSettingsLoader.java @@ -1,7 +1,7 @@ package org.xbib.content.settings.datastructures; +import org.xbib.content.SettingsLoader; import org.xbib.datastructures.tiny.TinyMap; - import java.io.IOException; import java.io.StringReader; import java.util.Map; diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/Settings.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/Settings.java deleted file mode 100644 index 17d7ec6..0000000 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/Settings.java +++ /dev/null @@ -1,656 +0,0 @@ -package org.xbib.content.settings.datastructures; - -import org.xbib.datastructures.api.ByteSizeValue; -import org.xbib.datastructures.api.TimeValue; -import org.xbib.datastructures.tiny.TinyMap; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.time.DateTimeException; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -public class Settings implements AutoCloseable { - - public static final Settings EMPTY_SETTINGS = new Builder().build(); - - public static final String[] EMPTY_ARRAY = new String[0]; - - private final TinyMap map; - - private Settings(TinyMap map) { - this.map = map; - } - - public static Settings fromMap(Map map) { - Builder builder = new Builder(); - for (Map.Entry entry : map.entrySet()) { - builder.put(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : null); - } - return builder.build(); - } - - public static void toMap(Settings settings, Map map) { - for (String key : settings.getAsMap().keySet()) { - map.put(key, settings.get(key)); - } - } - - /** - * Returns a builder to be used in order to build settings. - * @return a builder - */ - public static Builder settingsBuilder() { - return new Builder(); - } - - public static String[] splitStringByCommaToArray(final String s) { - return splitStringToArray(s, ','); - } - - public static String[] splitStringToArray(final String s, final char c) { - if (s.length() == 0) { - return EMPTY_ARRAY; - } - final char[] chars = s.toCharArray(); - int count = 1; - for (final char x : chars) { - if (x == c) { - count++; - } - } - final String[] result = new String[count]; - final int len = chars.length; - int start = 0; - int pos = 0; - int i = 0; - for (; pos < len; pos++) { - if (chars[pos] == c) { - int size = pos - start; - if (size > 0) { - result[i++] = new String(chars, start, size); - } - start = pos + 1; - } - } - int size = pos - start; - if (size > 0) { - result[i++] = new String(chars, start, size); - } - if (i != count) { - String[] result1 = new String[i]; - System.arraycopy(result, 0, result1, 0, i); - return result1; - } - return result; - } - - public Map getAsMap() { - return this.map; - } - - public Map getAsStructuredMap() { - TinyMap.Builder stringObjectMap = TinyMap.builder(); - for (String key : map.keySet()) { - String value = map.get(key); - processSetting(stringObjectMap, "", key, value); - } - for (String key : stringObjectMap.keySet()) { - Object object = stringObjectMap.get(key); - if (object instanceof Map) { - @SuppressWarnings("unchecked") - Map valMap = (Map) object; - stringObjectMap.put(key, convertMapsToArrays(valMap)); - } - } - return stringObjectMap.build(); - } - - public Settings getByPrefix(String prefix) { - Builder builder = new Builder(); - for (String key : map.keySet()) { - String value = map.get(key); - if (key.startsWith(prefix)) { - if (key.length() < prefix.length()) { - continue; - } - builder.put(key.substring(prefix.length()), value); - } - } - return builder.build(); - } - - public Settings getAsSettings(String setting) { - return getByPrefix(setting + "."); - } - - public boolean containsSetting(String setting) { - if (map.containsKey(setting)) { - return true; - } - for (String key : map.keySet()) { - if (key.startsWith(setting)) { - return true; - } - } - return false; - } - - public String get(String setting) { - return map.get(setting); - } - - public String get(String setting, String defaultValue) { - String s = map.get(setting); - return s == null ? defaultValue : s; - } - - public Float getAsFloat(String setting, Float defaultValue) { - String s = get(setting); - try { - return s == null ? defaultValue : Float.parseFloat(s); - } catch (NumberFormatException e) { - throw new SettingsException("Failed to parse float setting [" + setting + "] with value [" + s + "]", e); - } - } - - public Double getAsDouble(String setting, Double defaultValue) { - String s = get(setting); - try { - return s == null ? defaultValue : Double.parseDouble(s); - } catch (NumberFormatException e) { - throw new SettingsException("Failed to parse double setting [" + setting + "] with value [" + s + "]", e); - } - } - - public Integer getAsInt(String setting, Integer defaultValue) { - String s = get(setting); - try { - return s == null ? defaultValue : Integer.parseInt(s); - } catch (NumberFormatException e) { - throw new SettingsException("Failed to parse int setting [" + setting + "] with value [" + s + "]", e); - } - } - - public Long getAsLong(String setting, Long defaultValue) { - String s = get(setting); - try { - return s == null ? defaultValue : Long.parseLong(s); - } catch (NumberFormatException e) { - throw new SettingsException("Failed to parse long setting [" + setting + "] with value [" + s + "]", e); - } - } - - public Boolean getAsBoolean(String setting, Boolean defaultValue) { - String value = get(setting); - if (value == null) { - return defaultValue; - } - return !("false".equals(value) || "0".equals(value) || "off".equals(value) || "no".equals(value)); - } - - public TimeValue getAsTime(String setting, TimeValue defaultValue) { - return TimeValue.parseTimeValue(get(setting), defaultValue); - } - - public ByteSizeValue getAsBytesSize(String setting, ByteSizeValue defaultValue) { - return ByteSizeValue.parseBytesSizeValue(get(setting), defaultValue); - } - - public String[] getAsArray(String settingPrefix) { - return getAsArray(settingPrefix, EMPTY_ARRAY); - } - - public String[] getAsArray(String settingPrefix, String[] defaultArray) { - List result = new ArrayList<>(); - if (get(settingPrefix) != null) { - String[] strings = splitStringByCommaToArray(get(settingPrefix)); - if (strings.length > 0) { - for (String string : strings) { - result.add(string.trim()); - } - } - } - int counter = 0; - while (true) { - String value = get(settingPrefix + '.' + (counter++)); - if (value == null) { - break; - } - result.add(value.trim()); - } - if (result.isEmpty()) { - return defaultArray; - } - return result.toArray(new String[0]); - } - - public Map getGroups(String prefix) { - String settingPrefix = prefix; - if (settingPrefix.charAt(settingPrefix.length() - 1) != '.') { - settingPrefix = settingPrefix + "."; - } - // we don't really care that it might happen twice - TinyMap.Builder> hashMap = TinyMap.builder(); - for (String o : this.map.keySet()) { - if (o.startsWith(settingPrefix)) { - String nameValue = o.substring(settingPrefix.length()); - int dotIndex = nameValue.indexOf('.'); - if (dotIndex == -1) { - throw new SettingsException("failed to get setting group for [" - + settingPrefix - + "] setting prefix and setting [" + o + "] because of a missing '.'"); - } - String name = nameValue.substring(0, dotIndex); - String value = nameValue.substring(dotIndex + 1); - Map groupSettings = hashMap.computeIfAbsent(name, k -> TinyMap.builder()); - groupSettings.put(value, get(o)); - } - } - TinyMap.Builder retVal = TinyMap.builder(); - for (String key : hashMap.keySet()) { - TinyMap.Builder value = hashMap.get(key); - retVal.put(key, new Settings(value.build())); - } - return retVal.build(); - } - - @Override - public boolean equals(Object o) { - return this == o || !(o == null || getClass() != o.getClass()) && map.equals(((Settings) o).map); - } - - @Override - public int hashCode() { - return map.hashCode(); - } - - private void processSetting(Map map, String prefix, String setting, String value) { - int prefixLength = setting.indexOf('.'); - if (prefixLength == -1) { - @SuppressWarnings("unchecked") - Map innerMap = (Map) map.get(prefix + setting); - if (innerMap != null) { - for (String k : innerMap.keySet()) { - Object v = innerMap.get(k); - map.put(prefix + setting + "." + k, v); - } - } - map.put(prefix + setting, value); - } else { - String key = setting.substring(0, prefixLength); - String rest = setting.substring(prefixLength + 1); - Object existingValue = map.get(prefix + key); - if (existingValue == null) { - Map newMap = TinyMap.builder(); - processSetting(newMap, "", rest, value); - map.put(key, newMap); - } else { - if (existingValue instanceof Map) { - @SuppressWarnings("unchecked") - Map innerMap = (Map) existingValue; - processSetting(innerMap, "", rest, value); - map.put(key, innerMap); - } else { - processSetting(map, prefix + key + ".", rest, value); - } - } - } - } - - private Object convertMapsToArrays(Map map) { - if (map.isEmpty()) { - return map; - } - boolean isArray = true; - int maxIndex = -1; - for (String key : map.keySet()) { - Object value = map.get(key); - if (isArray) { - try { - int index = Integer.parseInt(key); - if (index >= 0) { - maxIndex = Math.max(maxIndex, index); - } else { - isArray = false; - } - } catch (NumberFormatException ex) { - isArray = false; - } - } - if (value instanceof Map) { - @SuppressWarnings("unchecked") - Map valMap = (Map) value; - map.put(key, convertMapsToArrays(valMap)); - } - } - if (isArray && (maxIndex + 1) == map.size()) { - ArrayList newValue = new ArrayList<>(maxIndex + 1); - for (int i = 0; i <= maxIndex; i++) { - Object obj = map.get(Integer.toString(i)); - if (obj == null) { - return map; - } - newValue.add(obj); - } - return newValue; - } - return map; - } - - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public void close() { - } - - /** - * - */ - public static class Builder { - - private final SettingsLoaderService settingsLoaderService = SettingsLoaderService.getInstance(); - - private final TinyMap.Builder map; - - private Builder() { - map = TinyMap.builder(); - } - - public Map map() { - return map; - } - - public String remove(String key) { - return map.remove(key); - } - - public String get(String key) { - return map.get(key); - } - - public boolean isEmpty() { - return map.isEmpty(); - } - - /** - * Sets a setting with the provided setting key and value. - * - * @param key The setting key - * @param value The setting value - * @return The builder - */ - public Builder put(String key, String value) { - map.put(key, value); - return this; - } - - /** - * Sets a setting with the provided setting key and class as value. - * - * @param key The setting key - * @param clazz The setting class value - * @return The builder - */ - public Builder put(String key, Class clazz) { - map.put(key, clazz.getName()); - return this; - } - - /** - * Sets the setting with the provided setting key and the boolean value. - * - * @param setting The setting key - * @param value The boolean value - * @return The builder - */ - public Builder put(String setting, boolean value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the int value. - * - * @param setting The setting key - * @param value The int value - * @return The builder - */ - public Builder put(String setting, int value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the long value. - * - * @param setting The setting key - * @param value The long value - * @return The builder - */ - public Builder put(String setting, long value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the float value. - * - * @param setting The setting key - * @param value The float value - * @return The builder - */ - public Builder put(String setting, float value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the double value. - * - * @param setting The setting key - * @param value The double value - * @return The builder - */ - public Builder put(String setting, double value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and an array of values. - * - * @param setting The setting key - * @param values The values - * @return The builder - */ - public Builder putArray(String setting, String... values) { - remove(setting); - int counter = 0; - while (true) { - String value = map.remove(setting + '.' + (counter++)); - if (value == null) { - break; - } - } - for (int i = 0; i < values.length; i++) { - put(setting + '.' + i, values[i]); - } - return this; - } - - /** - * Sets the setting with the provided setting key and an array of values. - * - * @param setting The setting key - * @param values The values - * @return The builder - */ - public Builder putArray(String setting, List values) { - remove(setting); - int counter = 0; - while (true) { - String value = map.remove(setting + '.' + (counter++)); - if (value == null) { - break; - } - } - for (int i = 0; i < values.size(); i++) { - put(setting + '.' + i, values.get(i)); - } - return this; - } - - /** - * Sets the setting group. - * @param settingPrefix setting prefix - * @param groupName group name - * @param settings settings - * @param values values - * @return a builder - * @throws SettingsException if setting fails - */ - public Builder put(String settingPrefix, String groupName, String[] settings, String[] values) - throws SettingsException { - if (settings.length != values.length) { - throw new SettingsException("the settings length must match the value length"); - } - for (int i = 0; i < settings.length; i++) { - if (values[i] == null) { - continue; - } - put(settingPrefix + "" + groupName + "." + settings[i], values[i]); - } - return this; - } - - /** - * Sets all the provided settings. - * @param settings settings - * @return builder - */ - public Builder put(Settings settings) { - map.putAll(settings.getAsMap()); - return this; - } - - /** - * Sets all the provided settings. - * - * @param settings settings - * @return a builder - */ - public Builder put(Map settings) { - map.putAll(settings); - return this; - } - - /** - * Loads settings from the actual string content that represents them using the - * {@link SettingsLoaderService#loaderFromString(String)}. - * - * @param source source - * @return builder - */ - public Builder loadFromString(String source) { - SettingsLoader settingsLoader = settingsLoaderService.loaderFromString(source); - try { - Map loadedSettings = settingsLoader.load(source); - put(loadedSettings); - } catch (Exception e) { - throw new SettingsException("failed to load settings from [" + source + "]", e); - } - return this; - } - - /** - * Loads settings from a resource. - * @param resourceName resource name - * @param inputStream input stream - * @return builder - */ - public Builder loadFromResource(String resourceName, InputStream inputStream) throws SettingsException { - SettingsLoader settingsLoader = settingsLoaderService.loaderFromResource(resourceName); - try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { - Map loadedSettings = settingsLoader.load(bufferedReader.lines().collect(Collectors.joining())); - put(loadedSettings); - } catch (Exception e) { - throw new SettingsException("failed to load settings from [" + resourceName + "]", e); - } - return this; - } - - /** - * Load system properties to this settings. - * @return builder - */ - public Builder loadFromSystemProperties() { - for (Map.Entry entry : System.getProperties().entrySet()) { - put((String) entry.getKey(), (String) entry.getValue()); - } - return this; - } - - /** - * Load system environment to this settings. - * @return builder - */ - public Builder loadFromSystemEnvironment() { - for (Map.Entry entry : System.getenv().entrySet()) { - put(entry.getKey(), entry.getValue()); - } - return this; - } - - public Builder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder, - PlaceholderResolver placeholderResolver) { - map.replaceAll((k, v) -> propertyPlaceholder.replacePlaceholders(v, placeholderResolver)); - return this; - } - - /** - * Runs across all the settings set on this builder and replaces {@code ${...}} elements in the - * each setting value according to the following logic: - * - * First, tries to resolve it against a System property ({@link System#getProperty(String)}), next, - * tries and resolve it against an environment variable ({@link System#getenv(String)}), next, - * tries and resolve it against a date pattern to resolve the current date, - * and last, tries and replace it with another setting already set on this builder. - * @return builder - */ - public Builder replacePropertyPlaceholders() { - return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false), - placeholderName -> { - // system property - String value = System.getProperty(placeholderName); - if (value != null) { - return value; - } - // environment - value = System.getenv(placeholderName); - if (value != null) { - return value; - } - // current date - try { - return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now()); - } catch (IllegalArgumentException | DateTimeException e) { - return map.get(placeholderName); - } - } - ); - } - - public Settings build() { - return new Settings(map.build()); - } - } -} diff --git a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoader.java b/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoader.java deleted file mode 100644 index 372d004..0000000 --- a/content-settings-datastructures/src/main/java/org/xbib/content/settings/datastructures/SettingsLoader.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.xbib.content.settings.datastructures; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; - -/** - * Provides the ability to load settings from - * the actual source content that represents them. - */ -public interface SettingsLoader { - - /** - * Suffices for file names to load from. - * @return a set of suffices - */ - Set suffixes(); - - /** - * Loads the settings from a source string. - * @param source the source - * @return a Map - * @throws IOException if load fails - */ - Map load(String source) throws IOException; - - Map load(Map source) throws IOException; - - boolean canLoad(String source); -} diff --git a/content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder b/content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder new file mode 100644 index 0000000..354f4a3 --- /dev/null +++ b/content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder @@ -0,0 +1 @@ +org.xbib.content.settings.datastructures.DatastructureSettingsBuilder \ No newline at end of file diff --git a/content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.settings.datastructures.SettingsLoader b/content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader similarity index 100% rename from content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.settings.datastructures.SettingsLoader rename to content-settings-datastructures/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader diff --git a/content-settings-datastructures/src/test/java/org/xbib/content/settings/datastructures/test/SettingsTest.java b/content-settings-datastructures/src/test/java/org/xbib/content/settings/datastructures/test/SettingsTest.java index f678623..ee75865 100644 --- a/content-settings-datastructures/src/test/java/org/xbib/content/settings/datastructures/test/SettingsTest.java +++ b/content-settings-datastructures/src/test/java/org/xbib/content/settings/datastructures/test/SettingsTest.java @@ -1,7 +1,7 @@ package org.xbib.content.settings.datastructures.test; import org.junit.jupiter.api.Test; -import org.xbib.content.settings.datastructures.Settings; +import org.xbib.content.Settings; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -18,8 +18,8 @@ public class SettingsTest { @Test public void testEmpty() { - Settings settings = Settings.EMPTY_SETTINGS; - assertTrue(settings.getAsMap().isEmpty()); + Settings settings = Settings.emptySettings(); + assertTrue(settings.isEmpty()); } @Test diff --git a/content-settings/src/main/java/module-info.java b/content-settings/src/main/java/module-info.java index ae72259..620620f 100644 --- a/content-settings/src/main/java/module-info.java +++ b/content-settings/src/main/java/module-info.java @@ -1,6 +1,15 @@ +import org.xbib.content.SettingsBuilder; +import org.xbib.content.SettingsLoader; +import org.xbib.content.settings.ContentSettingsBuilder; +import org.xbib.content.settings.PropertiesSettingsLoader; + module org.xbib.content.settings { - uses org.xbib.content.SettingsLoader; + uses SettingsLoader; + provides SettingsLoader with PropertiesSettingsLoader; + uses SettingsBuilder; + provides SettingsBuilder with ContentSettingsBuilder; exports org.xbib.content.settings; requires org.xbib.content.core; + requires org.xbib.datastructures.api; requires transitive org.xbib.datastructures.tiny; } diff --git a/content-settings/src/main/java/org/xbib/content/settings/Settings.java b/content-settings/src/main/java/org/xbib/content/settings/ContentSettings.java similarity index 52% rename from content-settings/src/main/java/org/xbib/content/settings/Settings.java rename to content-settings/src/main/java/org/xbib/content/settings/ContentSettings.java index 172295b..de5435d 100644 --- a/content-settings/src/main/java/org/xbib/content/settings/Settings.java +++ b/content-settings/src/main/java/org/xbib/content/settings/ContentSettings.java @@ -1,22 +1,16 @@ package org.xbib.content.settings; +import org.xbib.content.Settings; import org.xbib.content.SettingsLoader; +import org.xbib.datastructures.api.ByteSizeValue; +import org.xbib.datastructures.api.TimeValue; import org.xbib.datastructures.tiny.TinyMap; -import org.xbib.content.util.unit.ByteSizeValue; -import org.xbib.content.util.unit.TimeValue; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Reader; 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; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -25,12 +19,9 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -/** - * - */ -public class Settings implements AutoCloseable { +public class ContentSettings implements Settings, AutoCloseable { - public static final Settings EMPTY_SETTINGS = new Builder().build(); + public static final ContentSettings EMPTY_SETTINGS = new ContentSettingsBuilder().build(); public static final String[] EMPTY_ARRAY = new String[0]; @@ -40,11 +31,11 @@ public class Settings implements AutoCloseable { private Map map; - private Settings(Map map) { + protected ContentSettings(Map map) { this(map, null, 0L, 0L, TimeUnit.SECONDS); } - private Settings(Map map, Path path, long initialDelay, long period, TimeUnit timeUnit) { + protected ContentSettings(Map map, Path path, long initialDelay, long period, TimeUnit timeUnit) { TinyMap.Builder builder = TinyMap.builder(); builder.putAll(map); this.map = builder.build(); @@ -53,28 +44,20 @@ public class Settings implements AutoCloseable { } } - public static Settings readSettingsFromMap(Map map) { - Builder builder = new Builder(); + public static ContentSettings readSettingsFromMap(Map map) { + ContentSettingsBuilder builder = new ContentSettingsBuilder(); for (Map.Entry entry : map.entrySet()) { builder.put(entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : null); } return builder.build(); } - public static void writeSettingsToMap(Settings settings, Map map) { + public static void writeSettingsToMap(ContentSettings settings, Map map) { for (String key : settings.getAsMap().keySet()) { map.put(key, settings.get(key)); } } - /** - * Returns a builder to be used in order to build settings. - * @return a builder - */ - public static Builder settingsBuilder() { - return new Builder(); - } - public static String[] splitStringByCommaToArray(final String s) { return splitStringToArray(s, ','); } @@ -136,10 +119,12 @@ public class Settings implements AutoCloseable { } } + @Override public Map getAsMap() { return this.map; } + @Override public Map getAsStructuredMap() { TinyMap.Builder stringObjectMap = TinyMap.builder(); for (Map.Entry entry : this.map.entrySet()) { @@ -155,8 +140,9 @@ public class Settings implements AutoCloseable { return stringObjectMap.build(); } - public Settings getByPrefix(String prefix) { - Builder builder = new Builder(); + @Override + public ContentSettings getByPrefix(String prefix) { + ContentSettingsBuilder builder = new ContentSettingsBuilder(); for (Map.Entry entry : map.entrySet()) { if (entry.getKey().startsWith(prefix)) { if (entry.getKey().length() < prefix.length()) { @@ -168,10 +154,12 @@ public class Settings implements AutoCloseable { return builder.build(); } - public Settings getAsSettings(String setting) { + @Override + public ContentSettings getAsSettings(String setting) { return getByPrefix(setting + "."); } + @Override public boolean containsSetting(String setting) { if (map.containsKey(setting)) { return true; @@ -184,15 +172,23 @@ public class Settings implements AutoCloseable { return false; } + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override public String get(String setting) { return map.get(setting); } + @Override public String get(String setting, String defaultValue) { String retVal = map.get(setting); return retVal == null ? defaultValue : retVal; } + @Override public Float getAsFloat(String setting, Float defaultValue) { String sValue = get(setting); if (sValue == null) { @@ -205,6 +201,7 @@ public class Settings implements AutoCloseable { } } + @Override public Double getAsDouble(String setting, Double defaultValue) { String sValue = get(setting); if (sValue == null) { @@ -217,6 +214,7 @@ public class Settings implements AutoCloseable { } } + @Override public Integer getAsInt(String setting, Integer defaultValue) { String sValue = get(setting); if (sValue == null) { @@ -229,6 +227,7 @@ public class Settings implements AutoCloseable { } } + @Override public Long getAsLong(String setting, Long defaultValue) { String sValue = get(setting); if (sValue == null) { @@ -241,6 +240,7 @@ public class Settings implements AutoCloseable { } } + @Override public Boolean getAsBoolean(String setting, Boolean defaultValue) { String value = get(setting); if (value == null) { @@ -249,18 +249,22 @@ public class Settings implements AutoCloseable { return !("false".equals(value) || "0".equals(value) || "off".equals(value) || "no".equals(value)); } + @Override public TimeValue getAsTime(String setting, TimeValue defaultValue) { return TimeValue.parseTimeValue(get(setting), defaultValue); } + @Override public ByteSizeValue getAsBytesSize(String setting, ByteSizeValue defaultValue) { return ByteSizeValue.parseBytesSizeValue(get(setting), defaultValue); } + @Override public String[] getAsArray(String settingPrefix) { return getAsArray(settingPrefix, EMPTY_ARRAY); } + @Override public String[] getAsArray(String settingPrefix, String[] defaultArray) { List result = new ArrayList<>(); if (get(settingPrefix) != null) { @@ -285,7 +289,8 @@ public class Settings implements AutoCloseable { return result.toArray(new String[result.size()]); } - public Map getGroups(String prefix) { + @Override + public Map getGroups(String prefix) { String settingPrefix = prefix; if (settingPrefix.charAt(settingPrefix.length() - 1) != '.') { settingPrefix = settingPrefix + "."; @@ -308,16 +313,16 @@ public class Settings implements AutoCloseable { groupSettings.put(value, get(setting)); } } - TinyMap.Builder retVal = TinyMap.builder(); + TinyMap.Builder retVal = TinyMap.builder(); for (Map.Entry> entry : hashMap.entrySet()) { - retVal.put(entry.getKey(), new Settings(entry.getValue())); + retVal.put(entry.getKey(), new ContentSettings(entry.getValue())); } return retVal.build(); } @Override public boolean equals(Object o) { - return this == o || !(o == null || getClass() != o.getClass()) && map.equals(((Settings) o).map); + return this == o || !(o == null || getClass() != o.getClass()) && map.equals(((ContentSettings) o).map); } @Override @@ -325,6 +330,13 @@ public class Settings implements AutoCloseable { return map.hashCode(); } + @Override + public void close() throws IOException { + if (refresher != null) { + refresher.stop(); + } + } + private void processSetting(Map map, String prefix, String setting, String value) { int prefixLength = setting.indexOf('.'); if (prefixLength == -1) { @@ -396,340 +408,6 @@ public class Settings implements AutoCloseable { return map; } - @Override - public void close() throws IOException { - if (refresher != null) { - refresher.stop(); - } - } - - /** - * - */ - public static class Builder { - - private final Map map; - - private Path path; - - private long initialDelay; - - private long period; - - private TimeUnit timeUnit; - - private Builder() { - map = TinyMap.builder(); - } - - public Map map() { - return map; - } - - public String remove(String key) { - return map.remove(key); - } - - public String get(String key) { - return map.get(key); - } - - /** - * Sets a setting with the provided setting key and value. - * - * @param key The setting key - * @param value The setting value - * @return The builder - */ - public Builder put(String key, String value) { - map.put(key, value); - return this; - } - - /** - * Sets a setting with the provided setting key and class as value. - * - * @param key The setting key - * @param clazz The setting class value - * @return The builder - */ - public Builder put(String key, Class clazz) { - map.put(key, clazz.getName()); - return this; - } - - /** - * Sets the setting with the provided setting key and the boolean value. - * - * @param setting The setting key - * @param value The boolean value - * @return The builder - */ - public Builder put(String setting, boolean value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the int value. - * - * @param setting The setting key - * @param value The int value - * @return The builder - */ - public Builder put(String setting, int value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the long value. - * - * @param setting The setting key - * @param value The long value - * @return The builder - */ - public Builder put(String setting, long value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the float value. - * - * @param setting The setting key - * @param value The float value - * @return The builder - */ - public Builder put(String setting, float value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and the double value. - * - * @param setting The setting key - * @param value The double value - * @return The builder - */ - public Builder put(String setting, double value) { - put(setting, String.valueOf(value)); - return this; - } - - /** - * Sets the setting with the provided setting key and an array of values. - * - * @param setting The setting key - * @param values The values - * @return The builder - */ - public Builder putArray(String setting, String... values) { - remove(setting); - int counter = 0; - while (true) { - String value = map.remove(setting + '.' + (counter++)); - if (value == null) { - break; - } - } - for (int i = 0; i < values.length; i++) { - put(setting + '.' + i, values[i]); - } - return this; - } - - /** - * Sets the setting with the provided setting key and an array of values. - * - * @param setting The setting key - * @param values The values - * @return The builder - */ - public Builder putArray(String setting, List values) { - remove(setting); - int counter = 0; - while (true) { - String value = map.remove(setting + '.' + (counter++)); - if (value == null) { - break; - } - } - for (int i = 0; i < values.size(); i++) { - put(setting + '.' + i, values.get(i)); - } - return this; - } - - /** - * Sets the setting group. - * @param settingPrefix setting prefix - * @param groupName group name - * @param settings settings - * @param values values - * @return a builder - * @throws SettingsException if setting fails - */ - public Builder put(String settingPrefix, String groupName, String[] settings, String[] values) - throws SettingsException { - if (settings.length != values.length) { - throw new SettingsException("The settings length must match the value length"); - } - for (int i = 0; i < settings.length; i++) { - if (values[i] == null) { - continue; - } - put(settingPrefix + "" + groupName + "." + settings[i], values[i]); - } - return this; - } - - /** - * Sets all the provided settings. - * @param settings settings - * @return builder - */ - public Builder put(Settings settings) { - map.putAll(settings.getAsMap()); - return this; - } - - /** - * Sets all the provided settings. - * - * @param settings settings - * @return a builder - */ - public Builder put(Map settings) { - map.putAll(settings); - return this; - } - - /** - * Loads settings from the actual string content that represents them using the - * {@link SettingsLoaderService#loaderFromString(String)}. - * - * @param source source - * @return builder - */ - public Builder loadFromString(String source) { - SettingsLoaderService settingsLoaderService = new SettingsLoaderService(); - SettingsLoader settingsLoader = settingsLoaderService.loaderFromString(source); - try { - Map loadedSettings = settingsLoader.load(source); - put(loadedSettings); - } catch (Exception e) { - throw new SettingsException("Failed to load settings from [" + source + "]", e); - } - return this; - } - - /** - * Loads settings from an URL. - * @param url url - * @return builder - */ - public Builder loadFromUrl(URL url) throws SettingsException { - try { - return loadFromStream(url.toExternalForm(), url.openStream()); - } catch (IOException e) { - throw new SettingsException("Failed to open stream for url [" + url.toExternalForm() + "]", e); - } - } - - /** - * Loads settings from a stream. - * @param resourceName resource name - * @param inputStream input stream - * @return builder - */ - public Builder loadFromStream(String resourceName, InputStream inputStream) throws SettingsException { - SettingsLoaderService settingsLoaderService = new SettingsLoaderService(); - SettingsLoader settingsLoader = settingsLoaderService.loaderFromResource(resourceName); - try { - Map loadedSettings = settingsLoader - .load(copyToString(new InputStreamReader(inputStream, StandardCharsets.UTF_8))); - put(loadedSettings); - } catch (Exception e) { - throw new SettingsException("Failed to load settings from [" + resourceName + "]", e); - } - return this; - } - - /** - * Load system properties to this settings. - * @return builder - */ - public Builder loadFromSystemProperties() { - for (Map.Entry entry : System.getProperties().entrySet()) { - put((String) entry.getKey(), (String) entry.getValue()); - } - return this; - } - - /** - * Load system environment to this settings. - * @return builder - */ - public Builder loadFromSystemEnvironment() { - for (Map.Entry entry : System.getenv().entrySet()) { - put(entry.getKey(), entry.getValue()); - } - return this; - } - /** - * Runs across all the settings set on this builder and replaces {@code ${...}} elements in the - * each setting value according to the following logic: - * - * First, tries to resolve it against a System property ({@link System#getProperty(String)}), next, - * tries and resolve it against an environment variable ({@link System#getenv(String)}), next, - * tries and resolve it against a date pattern to resolve the current date, - * and last, tries and replace it with another setting already set on this builder. - * @return builder - */ - public Builder replacePropertyPlaceholders() { - return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false), - placeholderName -> { - // system property - String value = System.getProperty(placeholderName); - if (value != null) { - return value; - } - // environment - value = System.getenv(placeholderName); - if (value != null) { - return value; - } - // current date - try { - return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now()); - } catch (IllegalArgumentException | DateTimeException e) { - return map.get(placeholderName); - } - } - ); - } - - public Builder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder, - PlaceholderResolver 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, path, initialDelay, period, timeUnit); - } - } - class DefaultSettingsRefresher implements Runnable { private final Path path; diff --git a/content-settings/src/main/java/org/xbib/content/settings/ContentSettingsBuilder.java b/content-settings/src/main/java/org/xbib/content/settings/ContentSettingsBuilder.java new file mode 100644 index 0000000..1951b66 --- /dev/null +++ b/content-settings/src/main/java/org/xbib/content/settings/ContentSettingsBuilder.java @@ -0,0 +1,363 @@ +package org.xbib.content.settings; + +import org.xbib.content.PlaceholderResolver; +import org.xbib.content.PropertyPlaceholder; +import org.xbib.content.Settings; +import org.xbib.content.SettingsBuilder; +import org.xbib.content.SettingsLoader; +import org.xbib.datastructures.tiny.TinyMap; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * + */ +public class ContentSettingsBuilder implements SettingsBuilder { + + private final Map map; + + private Path path; + + private long initialDelay; + + private long period; + + private TimeUnit timeUnit; + + public ContentSettingsBuilder() { + map = TinyMap.builder(); + } + + public Map map() { + return map; + } + + public String remove(String key) { + return map.remove(key); + } + + public String get(String key) { + return map.get(key); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + /** + * Sets a setting with the provided setting key and value. + * + * @param key The setting key + * @param value The setting value + * @return The builder + */ + public ContentSettingsBuilder put(String key, String value) { + map.put(key, value); + return this; + } + + /** + * Sets a setting with the provided setting key and class as value. + * + * @param key The setting key + * @param clazz The setting class value + * @return The builder + */ + public ContentSettingsBuilder put(String key, Class clazz) { + map.put(key, clazz.getName()); + return this; + } + + /** + * Sets the setting with the provided setting key and the boolean value. + * + * @param setting The setting key + * @param value The boolean value + * @return The builder + */ + public ContentSettingsBuilder put(String setting, boolean value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the int value. + * + * @param setting The setting key + * @param value The int value + * @return The builder + */ + public ContentSettingsBuilder put(String setting, int value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the long value. + * + * @param setting The setting key + * @param value The long value + * @return The builder + */ + public ContentSettingsBuilder put(String setting, long value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the float value. + * + * @param setting The setting key + * @param value The float value + * @return The builder + */ + public ContentSettingsBuilder put(String setting, float value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and the double value. + * + * @param setting The setting key + * @param value The double value + * @return The builder + */ + public ContentSettingsBuilder put(String setting, double value) { + put(setting, String.valueOf(value)); + return this; + } + + /** + * Sets the setting with the provided setting key and an array of values. + * + * @param setting The setting key + * @param values The values + * @return The builder + */ + public ContentSettingsBuilder putArray(String setting, String... values) { + remove(setting); + int counter = 0; + while (true) { + String value = map.remove(setting + '.' + (counter++)); + if (value == null) { + break; + } + } + for (int i = 0; i < values.length; i++) { + put(setting + '.' + i, values[i]); + } + return this; + } + + /** + * Sets the setting with the provided setting key and an array of values. + * + * @param setting The setting key + * @param values The values + * @return The builder + */ + public ContentSettingsBuilder putArray(String setting, List values) { + remove(setting); + int counter = 0; + while (true) { + String value = map.remove(setting + '.' + (counter++)); + if (value == null) { + break; + } + } + for (int i = 0; i < values.size(); i++) { + put(setting + '.' + i, values.get(i)); + } + return this; + } + + /** + * Sets the setting group. + * + * @param settingPrefix setting prefix + * @param groupName group name + * @param settings settings + * @param values values + * @return a builder + * @throws SettingsException if setting fails + */ + public ContentSettingsBuilder put(String settingPrefix, String groupName, String[] settings, String[] values) + throws SettingsException { + if (settings.length != values.length) { + throw new SettingsException("The settings length must match the value length"); + } + for (int i = 0; i < settings.length; i++) { + if (values[i] == null) { + continue; + } + put(settingPrefix + "" + groupName + "." + settings[i], values[i]); + } + return this; + } + + /** + * Sets all the provided settings. + * + * @param settings settings + * @return builder + */ + public ContentSettingsBuilder put(Settings settings) { + map.putAll(settings.getAsMap()); + return this; + } + + /** + * Sets all the provided settings. + * + * @param settings settings + * @return a builder + */ + public ContentSettingsBuilder put(Map settings) { + map.putAll(settings); + return this; + } + + /** + * Loads settings from the actual string content that represents them using the + * {@link SettingsLoaderService#loaderFromString(String)}. + * + * @param source source + * @return builder + */ + public ContentSettingsBuilder loadFromString(String source) { + SettingsLoaderService settingsLoaderService = new SettingsLoaderService(); + SettingsLoader settingsLoader = settingsLoaderService.loaderFromString(source); + try { + Map loadedSettings = settingsLoader.load(source); + put(loadedSettings); + } catch (Exception e) { + throw new SettingsException("Failed to load settings from [" + source + "]", e); + } + return this; + } + + /** + * Loads settings from an URL. + * + * @param url url + * @return builder + */ + public ContentSettingsBuilder loadFromUrl(URL url) throws SettingsException { + try { + return loadFromResource(url.toExternalForm(), url.openStream()); + } catch (IOException e) { + throw new SettingsException("Failed to open stream for url [" + url.toExternalForm() + "]", e); + } + } + + /** + * Loads settings from a stream. + * + * @param resourceName resource name + * @param inputStream input stream + * @return builder + */ + @Override + public ContentSettingsBuilder loadFromResource(String resourceName, InputStream inputStream) throws SettingsException { + SettingsLoaderService settingsLoaderService = new SettingsLoaderService(); + SettingsLoader settingsLoader = settingsLoaderService.loaderFromResource(resourceName); + try { + Map loadedSettings = settingsLoader + .load(ContentSettings.copyToString(new InputStreamReader(inputStream, StandardCharsets.UTF_8))); + put(loadedSettings); + } catch (Exception e) { + throw new SettingsException("Failed to load settings from [" + resourceName + "]", e); + } + return this; + } + + /** + * Load system properties to this settings. + * + * @return builder + */ + @Override + public ContentSettingsBuilder loadFromSystemProperties() { + for (Map.Entry entry : System.getProperties().entrySet()) { + put((String) entry.getKey(), (String) entry.getValue()); + } + return this; + } + + /** + * Load system environment to this settings. + * + * @return builder + */ + public ContentSettingsBuilder loadFromSystemEnvironment() { + for (Map.Entry entry : System.getenv().entrySet()) { + put(entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * Runs across all the settings set on this builder and replaces {@code ${...}} elements in the + * each setting value according to the following logic: + *

+ * First, tries to resolve it against a System property ({@link System#getProperty(String)}), next, + * tries and resolve it against an environment variable ({@link System#getenv(String)}), next, + * tries and resolve it against a date pattern to resolve the current date, + * and last, tries and replace it with another setting already set on this builder. + * + * @return builder + */ + public ContentSettingsBuilder replacePropertyPlaceholders() { + return replacePropertyPlaceholders(new PropertyPlaceholder("${", "}", false), + placeholderName -> { + // system property + String value = System.getProperty(placeholderName); + if (value != null) { + return value; + } + // environment + value = System.getenv(placeholderName); + if (value != null) { + return value; + } + // current date + try { + return DateTimeFormatter.ofPattern(placeholderName).format(LocalDate.now()); + } catch (IllegalArgumentException | DateTimeException e) { + return map.get(placeholderName); + } + } + ); + } + + public ContentSettingsBuilder replacePropertyPlaceholders(PropertyPlaceholder propertyPlaceholder, + PlaceholderResolver placeholderResolver) { + map.replaceAll((k, v) -> propertyPlaceholder.replacePlaceholders(v, placeholderResolver)); + return this; + } + + public ContentSettingsBuilder setRefresh(Path path, long initialDelay, long period, TimeUnit timeUnit) { + this.path = path; + this.initialDelay = initialDelay; + this.period = period; + this.timeUnit = timeUnit; + return this; + } + + public ContentSettings build() { + return new ContentSettings(map, path, initialDelay, period, timeUnit); + } +} diff --git a/content-core/src/main/java/org/xbib/content/properties/PropertiesSettingsLoader.java b/content-settings/src/main/java/org/xbib/content/settings/PropertiesSettingsLoader.java similarity index 98% rename from content-core/src/main/java/org/xbib/content/properties/PropertiesSettingsLoader.java rename to content-settings/src/main/java/org/xbib/content/settings/PropertiesSettingsLoader.java index a67e69a..367f40c 100644 --- a/content-core/src/main/java/org/xbib/content/properties/PropertiesSettingsLoader.java +++ b/content-settings/src/main/java/org/xbib/content/settings/PropertiesSettingsLoader.java @@ -1,4 +1,4 @@ -package org.xbib.content.properties; +package org.xbib.content.settings; import org.xbib.content.io.BytesReference; import org.xbib.content.SettingsLoader; @@ -39,17 +39,6 @@ public class PropertiesSettingsLoader implements SettingsLoader { } } - public Map load(BytesReference ref) throws IOException { - Properties props = new Properties(); - try (Reader reader = new InputStreamReader(ref.streamInput(), StandardCharsets.UTF_8)) { - props.load(reader); - Map result = new HashMap<>(); - for (Map.Entry entry : props.entrySet()) { - result.put((String) entry.getKey(), (String) entry.getValue()); - } - return result; - } - } @Override public Map load(Map source) throws IOException { @@ -66,4 +55,16 @@ public class PropertiesSettingsLoader implements SettingsLoader { public boolean canLoad(String source) { return true; } + + public Map load(BytesReference ref) throws IOException { + Properties props = new Properties(); + try (Reader reader = new InputStreamReader(ref.streamInput(), StandardCharsets.UTF_8)) { + props.load(reader); + Map result = new HashMap<>(); + for (Map.Entry entry : props.entrySet()) { + result.put((String) entry.getKey(), (String) entry.getValue()); + } + return result; + } + } } diff --git a/content-settings/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java b/content-settings/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java deleted file mode 100644 index 77ca815..0000000 --- a/content-settings/src/main/java/org/xbib/content/settings/PropertyPlaceholder.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.xbib.content.settings; - -import java.util.HashSet; -import java.util.Set; - -/** - * - */ -public class PropertyPlaceholder { - - private final String placeholderPrefix; - - private final String placeholderSuffix; - - private final boolean ignoreUnresolvablePlaceholders; - - /** - * Creates a new PropertyPlaceholderHelper that uses the supplied prefix and suffix. - * - * @param placeholderPrefix the prefix that denotes the start of a placeholder. - * @param placeholderSuffix the suffix that denotes the end of a placeholder. - * @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should be ignored - * (true) or cause an exception (false). - */ - public PropertyPlaceholder(String placeholderPrefix, String placeholderSuffix, - boolean ignoreUnresolvablePlaceholders) { - this.placeholderPrefix = placeholderPrefix; - this.placeholderSuffix = placeholderSuffix; - this.ignoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; - } - - - /** - * Replaces all placeholders of format ${name} with the value returned from the supplied {@link - * PlaceholderResolver}. - * - * @param value the value containing the placeholders to be replaced. - * @param placeholderResolver the PlaceholderResolver to use for replacement. - * @return the supplied value with placeholders replaced inline. - */ - public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) { - return parseStringValue(value, placeholderResolver, new HashSet()); - } - - protected String parseStringValue(String strVal, PlaceholderResolver placeholderResolver, - Set visitedPlaceholders) { - StringBuilder buf = new StringBuilder(strVal); - int startIndex = strVal.indexOf(this.placeholderPrefix); - while (startIndex != -1) { - int endIndex = findPlaceholderEndIndex(buf, startIndex); - if (endIndex != -1) { - String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex); - if (!visitedPlaceholders.add(placeholder)) { - throw new IllegalArgumentException( - "Circular placeholder reference '" + placeholder + "' in property definitions"); - } - // Recursive invocation, parsing placeholders contained in the placeholder key. - placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); - // Now obtain the value for the fully resolved key... - int defaultValueIdx = placeholder.indexOf(':'); - String defaultValue = null; - if (defaultValueIdx != -1) { - defaultValue = placeholder.substring(defaultValueIdx + 1); - placeholder = placeholder.substring(0, defaultValueIdx); - } - String propVal = placeholderResolver.resolvePlaceholder(placeholder); - if (propVal == null) { - propVal = defaultValue; - } - if (propVal != null) { - // Recursive invocation, parsing placeholders contained in the - // previously resolved placeholder value. - propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); - buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); - startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length()); - } else if (this.ignoreUnresolvablePlaceholders) { - // Proceed with unprocessed value. - startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length()); - } else { - throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'"); - } - visitedPlaceholders.remove(placeholder); - } else { - startIndex = -1; - } - } - return buf.toString(); - } - - private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { - int index = startIndex + this.placeholderPrefix.length(); - int withinNestedPlaceholder = 0; - while (index < buf.length()) { - if (substringMatch(buf, index, this.placeholderSuffix)) { - if (withinNestedPlaceholder > 0) { - withinNestedPlaceholder--; - index = index + this.placeholderPrefix.length() - 1; - } else { - return index; - } - } else if (substringMatch(buf, index, this.placeholderPrefix)) { - withinNestedPlaceholder++; - index = index + this.placeholderPrefix.length(); - } else { - index++; - } - } - return -1; - } - - private boolean substringMatch(CharSequence str, int index, CharSequence substring) { - for (int j = 0; j < substring.length(); j++) { - int i = index + j; - if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { - return false; - } - } - return true; - } -} diff --git a/content-settings/src/main/java/org/xbib/content/settings/SettingsException.java b/content-settings/src/main/java/org/xbib/content/settings/SettingsException.java deleted file mode 100644 index 7e75d59..0000000 --- a/content-settings/src/main/java/org/xbib/content/settings/SettingsException.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.xbib.content.settings; - -/** - * A generic failure to handle settings. - */ -public class SettingsException extends RuntimeException { - - private static final long serialVersionUID = -1833327708622505101L; - - public SettingsException(String message) { - super(message); - } - - public SettingsException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/content-settings/src/main/java/org/xbib/content/settings/SettingsLoaderService.java b/content-settings/src/main/java/org/xbib/content/settings/SettingsLoaderService.java deleted file mode 100644 index 1b12ff3..0000000 --- a/content-settings/src/main/java/org/xbib/content/settings/SettingsLoaderService.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.xbib.content.settings; - -import org.xbib.content.SettingsLoader; - -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.Set; - -/** - * A settings loader service for loading {@link SettingsLoader} implementations. - */ -public final class SettingsLoaderService { - - private final Map, SettingsLoader> settingsLoaderMap; - - public SettingsLoaderService() { - this.settingsLoaderMap = new HashMap<>(); - ServiceLoader serviceLoader = ServiceLoader.load(SettingsLoader.class); - for (SettingsLoader settingsLoader : serviceLoader) { - if (!settingsLoaderMap.containsKey(settingsLoader.suffixes())) { - settingsLoaderMap.put(settingsLoader.suffixes(), settingsLoader); - } - } - } - - /** - * Returns a {@link SettingsLoader} based on the resource name. - * @param resourceName the resource - * @return the settings loader - */ - public SettingsLoader loaderFromResource(String resourceName) { - for (Map.Entry, SettingsLoader> entry : settingsLoaderMap.entrySet()) { - Set suffixes = entry.getKey(); - for (String suffix : suffixes) { - if (resourceName.endsWith("." + suffix)) { - return entry.getValue(); - } - } - } - throw new UnsupportedOperationException(); - } - - /** - * Returns a {@link SettingsLoader} based on the actual source. - * @param source the source - * @return the settings loader - */ - public SettingsLoader loaderFromString(String source) { - for (SettingsLoader loader : settingsLoaderMap.values()) { - if (loader.canLoad(source)) { - return loader; - } - } - throw new UnsupportedOperationException(); - } -} diff --git a/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder b/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder new file mode 100644 index 0000000..9e0a5f8 --- /dev/null +++ b/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsBuilder @@ -0,0 +1 @@ +org.xbib.content.settings.ContentSettingsBuilder \ No newline at end of file diff --git a/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader b/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader new file mode 100644 index 0000000..2ccefbb --- /dev/null +++ b/content-settings/src/main/resources/META-INF/services/org.xbib.content.SettingsLoader @@ -0,0 +1 @@ +org.xbib.content.settings.PropertiesSettingsLoader \ No newline at end of file diff --git a/content-settings/src/test/java/org/xbib/content/settings/test/SettingsTest.java b/content-settings/src/test/java/org/xbib/content/settings/test/SettingsTest.java index 4878740..6a5d9c7 100644 --- a/content-settings/src/test/java/org/xbib/content/settings/test/SettingsTest.java +++ b/content-settings/src/test/java/org/xbib/content/settings/test/SettingsTest.java @@ -10,7 +10,7 @@ import org.xbib.content.io.BytesArray; import org.xbib.content.io.BytesReference; import org.xbib.content.json.JsonSettingsLoader; import org.xbib.content.json.JsonXContent; -import org.xbib.content.settings.Settings; +import org.xbib.content.Settings; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; @@ -31,8 +31,8 @@ public class SettingsTest { @Test public void testEmpty() { - Settings settings = Settings.EMPTY_SETTINGS; - assertTrue(settings.getAsMap().isEmpty()); + Settings settings = Settings.emptySettings(); + assertTrue(settings.isEmpty()); } @Test @@ -134,7 +134,7 @@ public class SettingsTest { @Test public void testPropertiesLoader() { Settings settings = Settings.settingsBuilder() - .loadFromStream(".properties", new ByteArrayInputStream("a.b=c".getBytes(StandardCharsets.UTF_8))) + .loadFromResource(".properties", new ByteArrayInputStream("a.b=c".getBytes(StandardCharsets.UTF_8))) .build(); assertEquals("{a.b=c}", settings.getAsMap().toString()); } diff --git a/content-yaml/src/test/java/YamlTest.java b/content-yaml/src/test/java/YamlTest.java deleted file mode 100644 index 430deed..0000000 --- a/content-yaml/src/test/java/YamlTest.java +++ /dev/null @@ -1,2 +0,0 @@ -public class YamlTest { -} diff --git a/gradle/quality/pmd.gradle b/gradle/quality/pmd.gradle index 5a2092c..1201b01 100644 --- a/gradle/quality/pmd.gradle +++ b/gradle/quality/pmd.gradle @@ -5,5 +5,5 @@ pmd { consoleOutput = false toolVersion = "6.24.0" rulePriority = 5 - ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"] + ruleSets = ["category/java/bestpractices.xml"] }