New data system.

This commit is contained in:
Brianna OKeefe 2024-03-21 17:08:38 -05:00
parent 8e644a4be9
commit fc232fa8b1
22 changed files with 1111 additions and 0 deletions

View File

@ -0,0 +1,6 @@
package com.craftaro.core.data;
public interface ComputedValue {
Object compute();
}

View File

@ -0,0 +1,40 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import java.sql.Connection;
import java.sql.SQLException;
public interface DatabaseConnector {
/**
* Checks if the connection to the database has been created
*
* @return true if the connection is created, otherwise false
*/
boolean isInitialized();
/**
* Closes all open connections to the database
*/
void closeConnection();
/**
* Executes a callback with a Connection passed and automatically closes it when finished
*
* @param callback The callback to execute once the connection is retrieved
*/
default void connect(ConnectionCallback callback) {
connect(true, callback);
}
void connect(boolean sqlThread, ConnectionCallback callback);
/**
* Wraps a connection in a callback which will automagically handle catching sql errors
*/
interface ConnectionCallback {
void accept(DSLContext ctx) throws SQLException;
}
}

View File

@ -0,0 +1,91 @@
package com.craftaro.core.data;
import com.craftaro.core.SongodaPlugin;
import com.craftaro.core.configuration.Config;
import com.craftaro.core.data.connector.H2Connector;
import com.craftaro.core.data.connector.MariaDBConnector;
import com.craftaro.core.data.connector.MySQLConnector;
import com.craftaro.core.data.connector.SQLiteConnector;
import com.craftaro.core.thread.MonitoredThread;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.io.File;
import java.util.concurrent.TimeUnit;
public class DatabaseManager {
private static DatabaseManager INSTANCE;
private final MonitoredThread thread;
private DatabaseConnector connector;
private final Config databaseConfig;
public DatabaseManager(SongodaPlugin plugin) {
INSTANCE = this;
thread = new MonitoredThread(plugin.getName().toLowerCase() + "-sql-thread", 15, TimeUnit.SECONDS);
databaseConfig = new Config(plugin, "database.yml");
if (!new File(plugin.getDataFolder(), "database.yml").exists())
plugin.saveResource("database.yml", false);
databaseConfig.load();
String type = databaseConfig.getString("type", "H2").toUpperCase();
String host = databaseConfig.getString("host", "localhost");
int port = databaseConfig.getInt("port", 3306);
String database = databaseConfig.getString("database", "plugin");
String username = databaseConfig.getString("username", "root");
String password = databaseConfig.getString("password", "");
int poolSize = databaseConfig.getInt("poolSize", 10);
boolean useSSL = databaseConfig.getBoolean("useSSL", false);
boolean autoReconnect = databaseConfig.getBoolean("autoReconnect", true);
String dataPath = plugin.getDataFolder().getPath().replaceAll("\\\\", "/") + "/";
String dbFile = "./" + dataPath + databaseConfig.getString("file", "data");
switch (DatabaseType.valueOf(type)) {
case H2:
connector = new H2Connector(dbFile, poolSize);
break;
case MYSQL:
connector = new MySQLConnector(host, port, database, username, password, useSSL, autoReconnect, poolSize);
break;
case SQLITE:
connector = new SQLiteConnector(dbFile, poolSize);
break;
case MARIADB:
connector = new MariaDBConnector(host, port, database, username, password, useSSL, autoReconnect, poolSize);
break;
default:
throw new IllegalArgumentException("Invalid database type: " + type);
}
}
public void execute(Runnable runnable) {
execute(runnable, false);
}
public void execute(Runnable runnable, boolean nonDisruptable) {
thread.execute(runnable, nonDisruptable);
}
public void load(String name, Runnable load) {
load.run();
System.out.println("Loaded " + name);
}
public DatabaseConnector getDatabaseConnector() {
return connector;
}
public Config getConfig() {
return databaseConfig;
}
public static DatabaseManager getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,26 @@
package com.craftaro.core.data;
import org.jooq.SQLDialect;
public enum DatabaseType {
MARIADB,
MYSQL,
H2,
SQLITE;
public SQLDialect getDialect() {
switch (this) {
case MARIADB:
return SQLDialect.MARIADB;
case MYSQL:
return SQLDialect.MYSQL;
case SQLITE:
return SQLDialect.SQLITE;
case H2:
return SQLDialect.H2;
default:
return SQLDialect.DEFAULT;
}
}
}

View File

@ -0,0 +1,19 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
public interface LoadsData {
default void loadData() {
DatabaseManager.getInstance().getDatabaseConnector().connect(false, ctx -> {
setupTables(ctx);
loadDataImpl(ctx);
});
}
void loadDataImpl(DSLContext ctx);
void setupTables(DSLContext ctx);
}

View File

@ -0,0 +1,46 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.impl.DSL;
import java.util.Collection;
public class SQLBase {
protected final DSLContext ctx;
public SQLBase(DSLContext ctx) {
this.ctx = ctx;
}
protected Object cleanValue(Object value) {
if (value instanceof ComputedValue) {
ComputedValue c = (ComputedValue) value;
value = c.compute();
}
if (value instanceof Collection) {
Collection<?> c = (Collection<?>) value;
if (c.isEmpty()) {
value = null;
}
}
if (value instanceof String) {
String s = (String) value;
if (s.trim().isEmpty()) {
value = null;
}
}
if (value instanceof Boolean) {
value = (Boolean) value ? 1 : 0;
}
return value;
}
protected Field getField(String field, Class<?> type) {
String fieldFinal = "`" + field + "`";
if (type == boolean.class)
return DSL.field(fieldFinal, int.class);
return type == null ? DSL.field(fieldFinal) : DSL.field(fieldFinal, type);
}
}

View File

@ -0,0 +1,50 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class SQLBatch implements SavesData {
private final List<SavesData> batch = new LinkedList<>();
public SQLBatch add(SavesData... data) {
batch.addAll(Arrays.asList(data));
return this;
}
public SQLBatch addAll(Collection<? extends SavesData> data) {
batch.addAll(data);
return this;
}
public List<SavesData> getBatch() {
return batch;
}
@Override
public void save(String... columns) {
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx -> {
for (SavesData data : batch)
data.saveImpl(ctx, columns);
});
}
@Override
public void saveImpl(DSLContext ctx, String... columns) {
for (SavesData data : batch)
data.saveImpl(ctx, columns);
}
@Override
public void deleteImpl(DSLContext ctx) {
for (SavesData data : batch)
data.deleteImpl(ctx);
}
}

View File

@ -0,0 +1,24 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
public class SQLDelete extends SQLBase {
private SQLDelete(DSLContext ctx) {
super(ctx);
}
public static SQLDelete create(DSLContext ctx) {
return new SQLDelete(ctx);
}
public void delete(String table, String id, Object value) {
new SQLExecutable(ctx, ctx.delete(DSL.table(table)).where(DSL.field(id).eq(value))).execute();
}
public void delete(String table, String id, Object value, String id2, Object value2) {
new SQLExecutable(ctx, ctx.delete(DSL.table(table)).where(DSL.field(id).eq(value))
.and(DSL.field(id2).eq(value2))).execute();
}
}

View File

@ -0,0 +1,40 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Query;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.ResultQuery;
import org.jooq.SelectSelectStep;
import org.jooq.UpdateReturningStep;
import java.util.List;
import java.util.stream.Stream;
public class SQLExecutable extends SQLBase {
protected Query query;
public SQLExecutable(DSLContext ctx, Query query) {
super(ctx);
this.query = query;
}
public int execute() {
return query.execute();
}
public Stream<SQLResult.StoredRecord> get() {
if (query instanceof ResultQuery) {
ResultQuery<?> resultQuery = (ResultQuery<?>) query;
Result<?> result = resultQuery.getResult();
return result.stream().map(SQLResult::new).map(SQLResult::getResults).flatMap(List::stream);
} else {
throw new IllegalStateException("Query is not an instance of ResultQuery");
}
}
public interface SQLResultI {
void forEach(SQLResult.StoredRecord result);
}
}

View File

@ -0,0 +1,96 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.InsertOnDuplicateSetMoreStep;
import org.jooq.InsertOnDuplicateSetStep;
import org.jooq.InsertValuesStepN;
import org.jooq.impl.DSL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class SQLInsert extends SQLBase {
private String table;
private final Map<String, Object> fields = new LinkedHashMap<>();
private boolean voidedKey = false;
private InsertValuesStepN currentStep;
public SQLInsert(DSLContext ctx) {
super(ctx);
}
public static SQLInsert create(DSLContext ctx) {
return new SQLInsert(ctx);
}
public SQLInsert insertInto(String table) {
this.table = table;
return this;
}
public SQLInsert withField(String field, Object value, boolean voidKey) {
if (voidKey)
voidedKey = true;
return voidKey ? this : withField(field, value);
}
public SQLInsert withField(String field, Object value) {
if (field.equalsIgnoreCase("desc"))
field = "`desc`";
fields.put(field.toLowerCase(), value);
return this;
}
// For some reason this must be used before we submit. So I'm going to apply the values here.
public SQLExecutable onDuplicateKeyUpdate(String... columns) {
currentStep = ctx.insertInto(DSL.table(table), fields.keySet().stream().map(DSL::field).toArray(Field[]::new));
currentStep = currentStep.values(fields.values().stream().map(this::cleanValue).toArray());
if (voidedKey)
return new SQLExecutable(ctx, currentStep);
SQLOnDupeUpdate sqlOnDupeUpdate = new SQLOnDupeUpdate(ctx, currentStep, columns);
for (String column : (columns.length > 0 ? new HashSet<>(Arrays.asList(columns)) : fields.keySet()))
sqlOnDupeUpdate.set(column.replace("`", ""), fields.get(column.toLowerCase()));
return sqlOnDupeUpdate;
}
public static class SQLOnDupeUpdate extends SQLExecutable {
private InsertOnDuplicateSetStep currentStep;
private final List<String> columnsToUpdate = new ArrayList<>();
public SQLOnDupeUpdate(DSLContext ctx, InsertValuesStepN currentStep, String... columns) {
super(ctx, null);
this.currentStep = currentStep.onDuplicateKeyUpdate();
columnsToUpdate.addAll(Arrays.asList(columns));
}
public SQLOnDupeUpdate set(String field, Object value) {
if (!columnsToUpdate.isEmpty() && !columnsToUpdate.contains(field))
return this;
value = cleanValue(value);
Field fieldName = getField(field, value == null ? null : value.getClass());
if (currentStep != null) {
this.query = value == null ? this.currentStep.setNull(fieldName)
: this.currentStep.set(fieldName, value);
currentStep = null;
} else {
this.query = value == null ? ((InsertOnDuplicateSetMoreStep) this.query).setNull(fieldName)
: ((InsertOnDuplicateSetMoreStep) this.query).set(fieldName, value);
}
return this;
}
}
}

View File

@ -0,0 +1,63 @@
package com.craftaro.core.data;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.Result;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class SQLResult {
private final List<StoredRecord> results = new LinkedList<>();
public SQLResult(Result<?> result) {
for (Record record : result) {
Map<String, StoredData> map = new java.util.HashMap<>();
for (Field<?> field : record.fields()) {
String fieldName = field.getName();
Object value = record.get(fieldName);
map.put(fieldName, new StoredData(value));
}
results.add(new StoredRecord(map));
}
}
public SQLResult(Record record) {
Map<String, StoredData> map = new java.util.HashMap<>();
for (Field<?> field : record.fields()) {
String fieldName = field.getName();
Object value = record.get(fieldName);
map.put(fieldName, new StoredData(value));
}
results.add(new StoredRecord(map));
}
public List<StoredRecord> getResults() {
return results;
}
public interface SQLResultI {
void forEach(StoredRecord result);
}
public static class StoredRecord {
private final Map<String, StoredData> record;
public StoredRecord(Map<String, StoredData> record) {
this.record = record;
}
public StoredData get(String key) {
return record.get(key);
}
public boolean has(String key) {
return record.containsKey(key) && record.get(key).asString() != null;
}
public boolean isNull(String key) {
return record.containsKey(key) && record.get(key).isNull();
}
}
}

View File

@ -0,0 +1,57 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Result;
import org.jooq.Select;
import org.jooq.SelectSelectStep;
import org.jooq.SelectWhereStep;
import org.jooq.impl.DSL;
public class SQLSelect extends SQLBase {
private Select<?> currentStep;
public SQLSelect(DSLContext ctx) {
super(ctx);
this.currentStep = ctx.select();
}
public static SQLSelect create(DSLContext ctx) {
return new SQLSelect(ctx);
}
public SQLSelect select(String... fields) {
if (fields.length > 0) {
currentStep = ctx.select(DSL.field(fields[0]));
for (int i = 1; i < fields.length; i++) {
currentStep = ((SelectSelectStep<?>)currentStep).select(DSL.field(fields[i]));
}
} else {
currentStep = ctx.select();
}
return this;
}
public SQLSelect from(String table) {
currentStep = ((SelectSelectStep<?>)currentStep).from(DSL.table(table));
return this;
}
public void from(String table, SQLResult.SQLResultI result) {
Result<?> resultData = ((SelectSelectStep<?>)currentStep).from(DSL.table(table)).fetch();
SQLResult rs = new SQLResult(resultData);
for (SQLResult.StoredRecord record : rs.getResults()) {
result.forEach(record);
}
}
public SQLWhere where(String id, Object value) {
currentStep = ((SelectWhereStep<?>)currentStep).where(DSL.field(id).eq(value));
return new SQLWhere(ctx, currentStep);
}
public SQLWhere whereBetween(String id, Object value1, Object value2) {
currentStep = ((SelectWhereStep<?>)currentStep).where(DSL.field(id).between(value1, value2));
return new SQLWhere(ctx, currentStep);
}
}

View File

@ -0,0 +1,47 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.UpdateSetMoreStep;
import org.jooq.UpdateSetStep;
import org.jooq.impl.DSL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SQLUpdate extends SQLBase {
private final List<String> columnsToUpdate = new ArrayList<>();
private UpdateSetStep currentStep;
private SQLUpdate(DSLContext ctx, String... columns) {
super(ctx);
columnsToUpdate.addAll(Arrays.asList(columns));
}
public static SQLUpdate create(DSLContext ctx, String... columns) {
return new SQLUpdate(ctx, columns);
}
public SQLUpdate update(String table) {
this.currentStep = ctx.update(DSL.table(table));
return this;
}
public SQLUpdate set(String field, Object value) {
if (!columnsToUpdate.isEmpty() && !columnsToUpdate.contains(field))
return this;
value = cleanValue(value);
Field fieldName = getField(field, value == null ? null : value.getClass());
this.currentStep = value == null ? this.currentStep.setNull(fieldName) : this.currentStep.set(fieldName, value);
return this;
}
public SQLWhere where(String id, Object value) {
return new SQLWhere(ctx, ((UpdateSetMoreStep) this.currentStep).where(DSL.field(id).eq(value)));
}
}

View File

@ -0,0 +1,23 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Query;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
public class SQLWhere extends SQLExecutable {
public SQLWhere(DSLContext ctx, Query query) {
super(ctx, query);
}
public SQLWhere and(String id, Object value) {
query = ((UpdateConditionStep) query).and(DSL.field(id).eq(value));
return this;
}
public SQLWhere or(String id, Object value) {
query = ((UpdateConditionStep) query).or(DSL.field(id).eq(value));
return this;
}
}

View File

@ -0,0 +1,40 @@
package com.craftaro.core.data;
import org.jooq.DSLContext;
import org.jooq.Record1;
import org.jooq.Result;
import org.jooq.impl.DSL;
public interface SavesData {
default void save(String... columns) {
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx ->
saveImpl(ctx, columns));
}
default void save(Runnable callback, String... columns) {
DatabaseManager.getInstance().getDatabaseConnector().connect(ctx -> {
saveImpl(ctx, columns);
callback.run();
});
}
default void delete() {
DatabaseManager.getInstance().getDatabaseConnector().connect(this::deleteImpl);
}
void saveImpl(DSLContext ctx, String... columns);
void deleteImpl(DSLContext ctx);
default int lastInsertedId(String table, DSLContext ctx) {
try {
Result<Record1<Object>> results = ctx.select(DSL.field("id")).from(DSL.table(table)).orderBy(DSL.field("id").desc()).fetch();
Record1<Object> result = results.get(0);
return result != null ? result.get(DSL.field("id"), Integer.class) : -1;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}

View File

@ -0,0 +1,75 @@
package com.craftaro.core.data;
import com.craftaro.core.utils.ItemSerializer;
import org.bukkit.inventory.ItemStack;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
public class StoredData {
private Object object;
public StoredData(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
public String asString() {
if (object == null) return null;
return object.toString();
}
public int asInt() {
if (object == null) return 0;
return Integer.parseInt(asString());
}
public double asDouble() {
return Double.parseDouble(asString());
}
public long asLong() {
String string = asString();
if (string == null) return 0;
return Long.parseLong(string);
}
public Instant asInstant() {
return Instant.ofEpochMilli(asLong());
}
public boolean asBoolean() {
if (object instanceof Integer)
return (int) object == 1;
return Boolean.parseBoolean(asString());
}
public void swap(Object object) {
this.object = object;
}
public boolean isNull() {
return object == null;
}
// get longblob
public byte[] asBytes() {
return (byte[]) object;
}
public UUID asUniqueID() {
return UUID.fromString(asString());
}
public ItemStack asItemStack() {
return ItemSerializer.deserializeItem(asBytes());
}
}

View File

@ -0,0 +1,59 @@
package com.craftaro.core.data.connector;
import com.craftaro.core.data.DatabaseConnector;
import com.craftaro.core.data.DatabaseManager;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jooq.DSLContext;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.sql.Connection;
public class H2Connector implements DatabaseConnector {
private HikariDataSource hikari;
private boolean initializedSuccessfully;
public H2Connector(String databaseFile, int poolSize) {
System.out.println("Connecting to H2 database: " + databaseFile);
HikariConfig config = new HikariConfig();
config.setDriverClassName("com;craftaro;third_party;org;h2;Driver".replace(";", "."));
config.setJdbcUrl("jdbc:h2:" + databaseFile + ";AUTO_RECONNECT=TRUE;MODE=MySQL;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE");
config.setMaximumPoolSize(poolSize);
try {
this.hikari = new HikariDataSource(config);
this.initializedSuccessfully = true;
} catch (Exception ex) {
this.initializedSuccessfully = false;
}
}
@Override
public boolean isInitialized() {
return this.initializedSuccessfully;
}
@Override
public void closeConnection() {
this.hikari.close();
}
@Override
public void connect(boolean sqlThread, ConnectionCallback callback) {
Runnable runnable = () -> {
try (Connection connection = this.hikari.getConnection()) {
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
} catch (Exception ex) {
System.out.println("An error occurred executing an H2 query: " + ex.getMessage());
ex.printStackTrace();
}
};
if (sqlThread)
DatabaseManager.getInstance().execute(runnable);
else
runnable.run();
}
}

View File

@ -0,0 +1,59 @@
package com.craftaro.core.data.connector;
import com.craftaro.core.data.DatabaseConnector;
import com.craftaro.core.data.DatabaseManager;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.sql.Connection;
public class MariaDBConnector implements DatabaseConnector {
private HikariDataSource hikari;
private boolean initializedSuccessfully;
public MariaDBConnector(String hostname, int port, String database, String username, String password, boolean useSSL, boolean autoReconnect, int poolSize) {
System.out.println("Connecting to MariaDB: " + hostname + ":" + port);
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mariadb://" + hostname + ":" + port + "/" + database);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(poolSize);
config.addDataSourceProperty("useSSL", useSSL);
config.addDataSourceProperty("autoReconnect", autoReconnect);
try {
this.hikari = new HikariDataSource(config);
this.initializedSuccessfully = true;
} catch (Exception ex) {
this.initializedSuccessfully = false;
}
}
@Override
public boolean isInitialized() {
return this.initializedSuccessfully;
}
@Override
public void closeConnection() {
this.hikari.close();
}
@Override
public void connect(boolean sqlThread, ConnectionCallback callback) {
Runnable runnable = () -> {
try (Connection connection = this.hikari.getConnection()) {
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
} catch (Exception ex) {
System.out.println("An error occurred executing a MariaDB query: " + ex.getMessage());
ex.printStackTrace();
}
};
if (sqlThread) DatabaseManager.getInstance().execute(runnable);
else runnable.run();
}
}

View File

@ -0,0 +1,61 @@
package com.craftaro.core.data.connector;
import com.craftaro.core.data.DatabaseConnector;
import com.craftaro.core.data.DatabaseManager;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.sql.Connection;
public class MySQLConnector implements DatabaseConnector {
private HikariDataSource hikari;
private boolean initializedSuccessfully;
public MySQLConnector(String hostname, int port, String database, String username, String password, boolean useSSL, boolean autoReconnect, int poolSize) {
System.out.println("Connecting to " + hostname + " : " + port);
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL + "&autoReconnect=" + autoReconnect);
config.setUsername(username);
config.setPassword(password);
config.setMaximumPoolSize(poolSize);
try {
this.hikari = new HikariDataSource(config);
this.initializedSuccessfully = true;
} catch (Exception ex) {
this.initializedSuccessfully = false;
}
}
@Override
public boolean isInitialized() {
return this.initializedSuccessfully;
}
@Override
public void closeConnection() {
this.hikari.close();
}
@Override
public void connect(boolean sqlThread, ConnectionCallback callback) {
Runnable runnable = () -> {
try (Connection connection = this.hikari.getConnection()) {
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
} catch (Exception ex) {
System.out.println("An error occurred executing a MySQL query: " + ex.getMessage());
ex.printStackTrace();
}
};
if (sqlThread)
DatabaseManager.getInstance().execute(runnable);
else
runnable.run();
}
}

View File

@ -0,0 +1,57 @@
package com.craftaro.core.data.connector;
import com.craftaro.core.data.DatabaseConnector;
import com.craftaro.core.data.DatabaseManager;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import java.sql.Connection;
public class SQLiteConnector implements DatabaseConnector {
private HikariDataSource hikari;
private boolean initializedSuccessfully;
public SQLiteConnector(String databaseFile, int poolSize) {
System.out.println("Connecting to SQLite database: " + databaseFile);
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:sqlite:" + databaseFile);
config.setMaximumPoolSize(poolSize);
try {
this.hikari = new HikariDataSource(config);
this.initializedSuccessfully = true;
} catch (Exception ex) {
this.initializedSuccessfully = false;
}
}
@Override
public boolean isInitialized() {
return this.initializedSuccessfully;
}
@Override
public void closeConnection() {
this.hikari.close();
}
@Override
public void connect(boolean sqlThread, ConnectionCallback callback) {
Runnable runnable = () -> {
try (Connection connection = this.hikari.getConnection()) {
callback.accept(DSL.using(connection, SQLDialect.MYSQL));
} catch (Exception ex) {
System.out.println("An error occurred executing a SQLite query: " + ex.getMessage());
ex.printStackTrace();
}
};
if (sqlThread)
DatabaseManager.getInstance().execute(runnable);
else
runnable.run();
}
}

View File

@ -0,0 +1,66 @@
package com.craftaro.core.data.lazy;
import java.util.function.Supplier;
public class Lazy<T> {
private Supplier<T> supplier = null;
private T value = null;
public synchronized T get() {
if (value == null && supplier != null) {
value = supplier.get();
supplier = null;
}
return value;
}
public synchronized T getOrDefault(T def) {
T value = get();
return value == null ? def : value;
}
public synchronized Lazy<T> reset() {
value = null;
return this;
}
public synchronized Lazy<T> set(T value) {
this.value = value;
return this;
}
public Lazy<T> set(Supplier<T> supplier) {
this.supplier = supplier;
return this;
}
public synchronized boolean isLoaded() {
return supplier != null;
}
@Override
public String toString() {
return get().toString();
}
@Override
public boolean equals(Object obj) {
if (obj == get()) {
return true;
}
if (obj == null) {
return false;
}
if (obj instanceof Lazy) {
Lazy<?> other = (Lazy<?>) obj;
return get().equals(other.get());
}
return get().equals(obj);
}
@Override
public int hashCode() {
return get().hashCode();
}
}

View File

@ -0,0 +1,66 @@
package com.craftaro.core.data.lazy;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
public class LazyList<T> {
private final List<T> list;
private List<Lazy<T>> lazyList;
public LazyList(List list) {
this.list = list == null ? new LinkedList<>() : list;
this.lazyList = new LinkedList<>();
}
public List<T> getList() {
loadList();
return list;
}
public Set<T> getSet() {
loadList();
return new HashSet<>(list);
}
public void add(Supplier<T> supplier) {
if (lazyList == null)
list.add(supplier.get());
else if (supplier != null)
lazyList.add(new Lazy<T>().set(supplier));
}
public void add(T items) {
list.add(items);
}
public void addAll(List<T> items) {
list.addAll(items);
}
public void addAll(Supplier<T>... suppliers) {
for (Supplier<T> supplier : suppliers)
add(supplier);
}
private void loadList() {
if (lazyList == null) return;
for (Lazy<T> lazy : lazyList)
list.add(lazy.get());
lazyList = null;
}
public void clear() {
list.clear();
lazyList.clear();
}
public boolean isEmpty() {
if (lazyList != null)
return lazyList.isEmpty();
return list.isEmpty();
}
}