mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2024-09-19 20:25:51 +00:00
feat(sql): Support sql based configuration provider.
This commit is contained in:
parent
aa50345329
commit
374f646f9e
@ -137,39 +137,43 @@ interface ConfigurationReader {
|
||||
return getWrapper().get(path, def, String.class);
|
||||
}
|
||||
|
||||
default <V> @NotNull List<V> getList(@NotNull String path, @NotNull ConfigValueParser<Object, V> parser) {
|
||||
return parseList(getWrapper().getList(path), parser);
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<String> getStringList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.castToString());
|
||||
return getList(path, ConfigValueParser.castToString());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Integer> getIntegerList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.intValue());
|
||||
return getList(path, ConfigValueParser.intValue());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Long> getLongList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.longValue());
|
||||
return getList(path, ConfigValueParser.longValue());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Double> getDoubleList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.doubleValue());
|
||||
return getList(path, ConfigValueParser.doubleValue());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Float> getFloatList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.floatValue());
|
||||
return getList(path, ConfigValueParser.floatValue());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Byte> getByteList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.byteValue());
|
||||
return getList(path, ConfigValueParser.byteValue());
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
default @NotNull List<Character> getCharList(@NotNull String path) {
|
||||
return parseList(getWrapper().getList(path), ConfigValueParser.castObject(Character.class));
|
||||
return getList(path, ConfigValueParser.castObject(Character.class));
|
||||
}
|
||||
|
||||
@Unmodifiable
|
||||
|
@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
@ -37,6 +38,16 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
|
||||
}
|
||||
|
||||
public void initializeConfig() {
|
||||
onReload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JSONConfigWrapper getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() {
|
||||
LinkedHashMap<?, ?> map = null;
|
||||
|
||||
try (FileInputStream is = new FileInputStream(file)) {
|
||||
@ -50,17 +61,6 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
|
||||
this.configuration = new JSONConfigWrapper(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull JSONConfigWrapper getConfiguration() {
|
||||
return this.configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() throws Exception {
|
||||
super.reload();
|
||||
initializeConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigurationComments getComments() {
|
||||
return null;
|
||||
@ -68,7 +68,7 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
|
||||
|
||||
@Override
|
||||
public void save() throws Exception {
|
||||
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
|
||||
try (Writer writer = new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8)) {
|
||||
gson.toJson(configuration.data, writer);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
<log4j.version>2.22.0</log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
|
||||
@ -28,6 +28,54 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easysql-beecp</artifactId>
|
||||
<version>0.4.7</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>2.1.210</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -1,8 +1,26 @@
|
||||
package cc.carm.lib.configuration;
|
||||
|
||||
import cc.carm.lib.configuration.sql.SQLConfigProvider;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class EasyConfiguration {
|
||||
|
||||
private EasyConfiguration() {
|
||||
}
|
||||
|
||||
public static SQLConfigProvider from(@NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
|
||||
SQLConfigProvider provider = new SQLConfigProvider(sqlManager, tableName, namespace);
|
||||
try {
|
||||
provider.initializeConfig();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static SQLConfigProvider from(@NotNull SQLManager sqlManager, @NotNull String tableName) {
|
||||
return from(sqlManager, tableName, "base");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,36 +3,184 @@ package cc.carm.lib.configuration.sql;
|
||||
import cc.carm.lib.configuration.core.ConfigInitializer;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationComments;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.api.SQLQuery;
|
||||
import cc.carm.lib.easysql.api.SQLTable;
|
||||
import cc.carm.lib.easysql.api.enums.IndexType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SQLConfigProvider extends ConfigurationProvider<SQLSectionWrapper> {
|
||||
import java.sql.ResultSet;
|
||||
import java.util.*;
|
||||
|
||||
public class SQLConfigProvider extends ConfigurationProvider<SQLConfigWrapper> {
|
||||
|
||||
@Override
|
||||
public @NotNull SQLSectionWrapper getConfiguration() {
|
||||
return null;
|
||||
public static Gson GSON = new GsonBuilder().serializeNulls().disableHtmlEscaping().setPrettyPrinting().create();
|
||||
|
||||
protected final @NotNull SQLManager sqlManager;
|
||||
protected final @NotNull SQLTable table;
|
||||
protected final @NotNull String namespace;
|
||||
|
||||
protected ConfigInitializer<SQLConfigProvider> initializer;
|
||||
protected ConfigurationComments comments = new ConfigurationComments();
|
||||
protected SQLConfigWrapper rootConfiguration;
|
||||
|
||||
protected final @NotNull Set<String> updated = new HashSet<>();
|
||||
|
||||
public SQLConfigProvider(@NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
|
||||
this.sqlManager = sqlManager;
|
||||
this.table = SQLTable.of(tableName, builder -> {
|
||||
|
||||
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
|
||||
builder.addColumn("path", "VARCHAR(96) NOT NULL");
|
||||
|
||||
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
|
||||
builder.addColumn("value", "TEXT");
|
||||
|
||||
builder.addColumn("inline_comment", "TEXT");
|
||||
builder.addColumn("header_comments", "MEDIUMTEXT");
|
||||
|
||||
builder.addColumn("create_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
|
||||
builder.setIndex(
|
||||
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
|
||||
"namespace", "path"
|
||||
);
|
||||
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
||||
});
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws Exception {
|
||||
public @NotNull SQLConfigWrapper getConfiguration() {
|
||||
return rootConfiguration;
|
||||
}
|
||||
|
||||
public void initializeConfig() throws Exception {
|
||||
this.table.create(this.sqlManager);
|
||||
this.initializer = new ConfigInitializer<>(this);
|
||||
onReload();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() throws Exception {
|
||||
this.comments = new ConfigurationComments();
|
||||
LinkedHashMap<String, Object> values = new LinkedHashMap<>();
|
||||
|
||||
try (SQLQuery query = this.table.createQuery()
|
||||
.addCondition("namespace", namespace)
|
||||
.build().execute()) {
|
||||
ResultSet rs = query.getResultSet();
|
||||
while (rs.next()) {
|
||||
String path = rs.getString("path");
|
||||
int type = rs.getInt("type");
|
||||
try {
|
||||
SQLValueResolver<?> resolver = SQLValueTypes.get(type);
|
||||
if (resolver == null) throw new IllegalStateException("No resolver for type #" + type);
|
||||
String value = rs.getString("value");
|
||||
values.put(path, resolver.resolve(value));
|
||||
|
||||
loadInlineComment(path, rs.getString("inline_comment"));
|
||||
loadHeaderComment(path, rs.getString("header_comments"));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.rootConfiguration = new SQLConfigWrapper(this, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigurationComments getComments() {
|
||||
return null;
|
||||
public void save() throws Exception {
|
||||
if (this.updated.isEmpty()) return;
|
||||
|
||||
Date date = new Date();
|
||||
List<Object[]> values = new ArrayList<>();
|
||||
List<String> deletes = new ArrayList<>();
|
||||
|
||||
for (String path : this.updated) {
|
||||
Object value = this.rootConfiguration.get(path);
|
||||
if (value == null) {
|
||||
deletes.add(path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value instanceof SQLConfigWrapper) {
|
||||
value = getSourceMap(((SQLConfigWrapper) value).getSource());
|
||||
}
|
||||
|
||||
SQLValueResolver<?> type = SQLValueTypes.get(value.getClass());
|
||||
if (type != null) {
|
||||
values.add(new Object[]{
|
||||
this.namespace, path, date,
|
||||
type.getID(), type.serializeObject(value),
|
||||
getComments().getInlineComment(path),
|
||||
GSON.toJson(getComments().getHeaderComment(path))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.updated.clear();
|
||||
|
||||
this.table.createReplaceBatch()
|
||||
.setColumnNames("namespace", "path", "update_time", "type", "value", "inline_comment", "header_comments")
|
||||
.setAllParams(values)
|
||||
.execute();
|
||||
|
||||
for (String path : deletes) {
|
||||
this.table.createDelete()
|
||||
.addCondition("namespace", this.namespace)
|
||||
.addCondition("path", path)
|
||||
.build().execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigurationComments getComments() {
|
||||
return this.comments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigInitializer<? extends ConfigurationProvider<SQLSectionWrapper>> getInitializer() {
|
||||
return null;
|
||||
public @NotNull ConfigInitializer<? extends ConfigurationProvider<SQLConfigWrapper>> getInitializer() {
|
||||
return this.initializer;
|
||||
}
|
||||
|
||||
|
||||
protected void loadInlineComment(String path, String comment) {
|
||||
if (comment == null) return;
|
||||
comment = comment.trim();
|
||||
if (comment.isEmpty()) return;
|
||||
|
||||
this.comments.setInlineComment(path, comment);
|
||||
}
|
||||
|
||||
protected void loadHeaderComment(String path, String commentJson) {
|
||||
if (commentJson == null) return;
|
||||
commentJson = commentJson.trim();
|
||||
if (commentJson.isEmpty()) return;
|
||||
|
||||
List<String> headerComments = GSON.fromJson(commentJson, new TypeToken<List<String>>() {
|
||||
}.getType());
|
||||
if (headerComments == null || headerComments.isEmpty()) return;
|
||||
|
||||
this.comments.setHeaderComments(path, headerComments);
|
||||
}
|
||||
|
||||
protected static Map<String, Object> getSourceMap(Map<String, Object> map) {
|
||||
Map<String, Object> source = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
if (entry.getValue() instanceof SQLConfigWrapper) {
|
||||
source.put(entry.getKey(), getSourceMap(((SQLConfigWrapper) entry.getValue()).getSource()));
|
||||
} else {
|
||||
source.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,122 @@
|
||||
package cc.carm.lib.configuration.sql;
|
||||
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* For SQL configs, that primary path will be directly mapped to the value.
|
||||
*
|
||||
* @author CarmJos
|
||||
*/
|
||||
public class SQLConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
|
||||
|
||||
private static final char SEPARATOR = '.';
|
||||
protected final @NotNull SQLConfigProvider provider;
|
||||
protected final @NotNull Map<String, Object> data;
|
||||
|
||||
SQLConfigWrapper(@NotNull SQLConfigProvider provider, @NotNull Map<?, ?> map) {
|
||||
this.provider = provider;
|
||||
this.data = new LinkedHashMap<>();
|
||||
|
||||
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||
String key = (entry.getKey() == null) ? "null" : entry.getKey().toString();
|
||||
|
||||
if (entry.getValue() instanceof Map) {
|
||||
this.data.put(key, new SQLConfigWrapper(provider, (Map<?, ?>) entry.getValue()));
|
||||
} else {
|
||||
this.data.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> getSource() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<String> getKeys(boolean deep) {
|
||||
return getValues(deep).keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||
// Deep is not supported for SQL configs.
|
||||
return new LinkedHashMap<>(this.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@NotNull String path, @Nullable Object value) {
|
||||
if (value instanceof Map) {
|
||||
value = new SQLConfigWrapper(this.provider, (Map<?, ?>) value);
|
||||
}
|
||||
|
||||
SQLConfigWrapper section = getSectionFor(path);
|
||||
if (section == this) {
|
||||
if (value == null) {
|
||||
this.data.remove(path);
|
||||
} else {
|
||||
this.data.put(path, value);
|
||||
}
|
||||
} else {
|
||||
section.set(getChild(path), value);
|
||||
}
|
||||
|
||||
this.provider.updated.add(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String path) {
|
||||
return get(path) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object get(@NotNull String path) {
|
||||
SQLConfigWrapper section = getSectionFor(path);
|
||||
return section == this ? data.get(path) : section.get(getChild(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isList(@NotNull String path) {
|
||||
return get(path) instanceof List<?>;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<?> getList(@NotNull String path) {
|
||||
Object val = get(path);
|
||||
return (val instanceof List<?>) ? (List<?>) val : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurationSection(@NotNull String path) {
|
||||
return get(path) instanceof SQLConfigWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SQLConfigWrapper getConfigurationSection(@NotNull String path) {
|
||||
Object val = get(path);
|
||||
return (val instanceof SQLConfigWrapper) ? (SQLConfigWrapper) val : null;
|
||||
}
|
||||
|
||||
private SQLConfigWrapper getSectionFor(String path) {
|
||||
int index = path.indexOf(SEPARATOR);
|
||||
if (index == -1) return this;
|
||||
|
||||
String root = path.substring(0, index);
|
||||
Object section = this.data.computeIfAbsent(root, k -> new SQLConfigWrapper(this.provider, new LinkedHashMap<>()));
|
||||
|
||||
return (SQLConfigWrapper) section;
|
||||
}
|
||||
|
||||
private String getChild(String path) {
|
||||
int index = path.indexOf(SEPARATOR);
|
||||
return (index == -1) ? path : path.substring(index + 1);
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package cc.carm.lib.configuration.sql;
|
||||
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class SQLSectionWrapper implements ConfigurationWrapper<Map<String, Object>> {
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<String> getKeys(boolean deep) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@NotNull String path, @Nullable Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object get(@NotNull String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isList(@NotNull String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<?> getList(@NotNull String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurationSection(@NotNull String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable SQLSectionWrapper getConfigurationSection(@NotNull String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package cc.carm.lib.configuration.sql;
|
||||
|
||||
public class SQLValueParser {
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package cc.carm.lib.configuration.sql;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SQLValueResolver<T> {
|
||||
|
||||
public static <V> SQLValueResolver<V> of(int id, @NotNull Class<V> clazz,
|
||||
@NotNull ConfigDataFunction<String, V> resolver) {
|
||||
return of(id, clazz, resolver, String::valueOf);
|
||||
}
|
||||
|
||||
public static <V> SQLValueResolver<V> of(int id, @NotNull Class<V> clazz,
|
||||
@NotNull ConfigDataFunction<String, V> resolver,
|
||||
@NotNull Function<V, String> serializer) {
|
||||
return new SQLValueResolver<>(id, clazz, resolver, serializer);
|
||||
}
|
||||
|
||||
protected final int id;
|
||||
protected final @NotNull Class<T> clazz;
|
||||
protected final @NotNull ConfigDataFunction<String, T> resolver;
|
||||
protected final @NotNull Function<T, String> serializer;
|
||||
|
||||
protected SQLValueResolver(int id, @NotNull Class<T> clazz,
|
||||
@NotNull ConfigDataFunction<String, T> resolver,
|
||||
@NotNull Function<T, String> serializer) {
|
||||
this.id = id;
|
||||
this.clazz = clazz;
|
||||
this.resolver = resolver;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @NotNull Class<T> getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public boolean isTypeOf(@NotNull Class<?> clazz) {
|
||||
return this.clazz.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public @NotNull T resolve(String data) throws Exception {
|
||||
return resolver.parse(data);
|
||||
}
|
||||
|
||||
public @Nullable String serialize(T value) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
public @Nullable String serializeObject(Object value) {
|
||||
return isTypeOf(value.getClass()) ? serialize(clazz.cast(value)) : null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package cc.carm.lib.configuration.sql;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
interface SQLValueTypes {
|
||||
|
||||
SQLValueResolver<String> STRING = SQLValueResolver.of(0, String.class, ConfigDataFunction.identity());
|
||||
SQLValueResolver<Byte> BYTE = SQLValueResolver.of(1, Byte.class, Byte::parseByte);
|
||||
SQLValueResolver<Short> SHORT = SQLValueResolver.of(2, Short.class, Short::parseShort);
|
||||
SQLValueResolver<Integer> INTEGER = SQLValueResolver.of(3, Integer.class, Integer::parseInt);
|
||||
SQLValueResolver<Long> LONG = SQLValueResolver.of(4, Long.class, Long::parseLong);
|
||||
SQLValueResolver<Float> FLOAT = SQLValueResolver.of(5, Float.class, Float::parseFloat);
|
||||
SQLValueResolver<Double> DOUBLE = SQLValueResolver.of(6, Double.class, Double::parseDouble);
|
||||
SQLValueResolver<Boolean> BOOLEAN = SQLValueResolver.of(7, Boolean.class, Boolean::parseBoolean);
|
||||
SQLValueResolver<Character> CHAR = SQLValueResolver.of(8, Character.class, s -> s.charAt(0));
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
SQLValueResolver<List> LIST = SQLValueResolver.of(10, List.class,
|
||||
array -> SQLConfigProvider.GSON.fromJson(array, List.class),
|
||||
list -> SQLConfigProvider.GSON.toJson(list)
|
||||
);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
SQLValueResolver<Map> SECTION = SQLValueResolver.of(20, Map.class,
|
||||
section -> SQLConfigProvider.GSON.fromJson(section, LinkedHashMap.class),
|
||||
section -> SQLConfigProvider.GSON.toJson(section)
|
||||
);
|
||||
|
||||
static @NotNull SQLValueResolver<?>[] values() {
|
||||
return new SQLValueResolver<?>[]{
|
||||
STRING, BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, BOOLEAN, CHAR, LIST, SECTION
|
||||
};
|
||||
}
|
||||
|
||||
static SQLValueResolver<?> valueOf(int index) {
|
||||
return values()[index];
|
||||
}
|
||||
|
||||
static @Nullable SQLValueResolver<?> get(int id) {
|
||||
return Arrays.stream(values()).filter(v -> v.id == id).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
static @Nullable SQLValueResolver<?> get(Class<?> typeClazz) {
|
||||
return Arrays.stream(values()).filter(v -> v.isTypeOf(typeClazz)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
40
impl/sql/src/test/java/config/SQLConfigTest.java
Normal file
40
impl/sql/src/test/java/config/SQLConfigTest.java
Normal file
@ -0,0 +1,40 @@
|
||||
package config;
|
||||
|
||||
import cc.carm.lib.configuration.EasyConfiguration;
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.sql.SQLConfigProvider;
|
||||
import cc.carm.lib.easysql.EasySQL;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.beecp.BeeDataSourceConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SQLConfigTest {
|
||||
|
||||
@Test
|
||||
public void onTest() {
|
||||
// test();
|
||||
}
|
||||
|
||||
|
||||
public void test() {
|
||||
BeeDataSourceConfig config = new BeeDataSourceConfig();
|
||||
config.setDriverClassName("org.h2.Driver");
|
||||
config.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MySQL;");
|
||||
SQLManager manager = EasySQL.createManager(config);
|
||||
manager.setDebugMode(true);
|
||||
|
||||
SQLConfigProvider provider = EasyConfiguration.from(manager, "conf_test", "TESTING");
|
||||
|
||||
ConfigurationTest.testDemo(provider);
|
||||
ConfigurationTest.testInner(provider);
|
||||
|
||||
System.out.println("----------------------------------------------------");
|
||||
provider.getConfiguration().getValues(true).forEach((k, v) -> System.out.println(k + ": " + v));
|
||||
System.out.println("----------------------------------------------------");
|
||||
provider.getConfiguration().getValues(false).forEach((k, v) -> System.out.println(k + ": " + v));
|
||||
System.out.println("----------------------------------------------------");
|
||||
|
||||
ConfigurationTest.save(provider);
|
||||
}
|
||||
|
||||
}
|
19
impl/sql/src/test/resources/log4j2.xml
Normal file
19
impl/sql/src/test/resources/log4j2.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN" packages="config.SQLConfigTest">
|
||||
<Appenders>
|
||||
<console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n"/>
|
||||
</console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Root level="info">
|
||||
<filters>
|
||||
<MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/>
|
||||
<RegexFilter regex=".*\$\{[^}]*\}.*" onMatch="DENY" onMismatch="NEUTRAL"/>
|
||||
</filters>
|
||||
<AppenderRef ref="File"/>
|
||||
<appender-ref ref="Console"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
|
@ -1,7 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS conf
|
||||
(
|
||||
`namespace` VARCHAR(255) NOT NULL, # 命名空间
|
||||
`path` VARCHAR(255) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念)
|
||||
`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||
`inline_comments` TEXT, # 行内注释
|
||||
|
@ -41,6 +41,7 @@
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bspfsystems</groupId>
|
||||
<artifactId>yamlconfiguration</artifactId>
|
||||
|
Loading…
Reference in New Issue
Block a user