diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/AbstractDhRepo.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/AbstractDhRepo.java index b932b9561..9a17f7d69 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/AbstractDhRepo.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/AbstractDhRepo.java @@ -19,18 +19,19 @@ package com.seibel.distanthorizons.core.sql; +import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; +import com.seibel.distanthorizons.core.util.ResourceUtil; +import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.junit.Assert; -import java.io.*; -import java.net.URL; +import java.io.IOException; +import java.net.URISyntaxException; import java.sql.*; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Scanner; -import java.util.stream.Collectors; +import java.util.*; /** + * Handles interfacing with SQL databases. * * @param DTO stands for "Data Table Object" */ @@ -38,6 +39,8 @@ public abstract class AbstractDhRepo { public static final int TIMEOUT_SECONDS = 30; + private static final Logger LOGGER = DhLoggerBuilder.getLogger(); + private final Connection connection; public final String databaseType; @@ -47,7 +50,9 @@ public abstract class AbstractDhRepo + //=============// // constructor // + //=============// public AbstractDhRepo(String databaseType, String databaseLocation, Class dtoClass) throws SQLException { @@ -61,46 +66,30 @@ public abstract class AbstractDhRepo } private void runFirstTimeSetup() { - // get all sql scripts - ArrayList sqlScriptNames = new ArrayList<>(); + // get the resource scripts + ArrayList sqlScripts; try { - Enumeration resources = Thread.currentThread().getContextClassLoader().getResources("sqlScripts"); // package/name/with/slashes/instead/dots - while (resources.hasMoreElements()) - { - URL url = resources.nextElement(); - - String fileName = new Scanner((InputStream) url.getContent()).useDelimiter("\\A").next(); - fileName = fileName.trim(); - - if (fileName.endsWith(".sql")) - { - sqlScriptNames.add(fileName); - } - } + sqlScripts = ResourceUtil.getFilesInFolder("sqlScripts", ".sql"); } - catch (IOException e) + catch (URISyntaxException | IOException e) { - + throw new RuntimeException(e); } // attempt to run them - for (String scriptName : sqlScriptNames) + for (ResourceUtil.ResourceFile file : sqlScripts) { - InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("sqlScripts/"+scriptName); - if (inputStream != null) - { - String script = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n")); - System.out.println("Running script: "+scriptName); - - this.queryNoResult(script); - } + LOGGER.info("Running automatic SQL script: ["+file.name +"]"); + this.queryNoResult(file.content); } } + //===============// // high level DB // + //===============// public TDTO get(TDTO dto) { return this.getByPrimaryKey(dto.getPrimaryKeyString()); } public TDTO getByPrimaryKey(String primaryKey) @@ -137,8 +126,9 @@ public abstract class AbstractDhRepo public void delete(TDTO dto) { this.queryNoResult(this.createDeleteSql(dto)); } - + //==============// // low level DB // + //==============// public void queryNoResult(String sql) { this.query(sql, false); } public ResultSet query(String sql) { return this.query(sql, true); } @@ -199,7 +189,9 @@ public abstract class AbstractDhRepo - // abstract // + //==================// + // abstract methods // + //==================// public abstract String getTableName(); diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/FileUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/FileUtil.java index 26ab91db4..5434afbb3 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/util/FileUtil.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/FileUtil.java @@ -23,6 +23,10 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder; import org.apache.logging.log4j.Logger; import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; public class FileUtil { @@ -72,5 +76,11 @@ public class FileUtil return corruptedFile; } + /** Returns the content of the given file as a string. */ + public static String readFile(File file, Charset encoding) throws IOException + { + byte[] encoded = Files.readAllBytes(file.toPath()); + return new String(encoded, encoding); + } } diff --git a/core/src/main/java/com/seibel/distanthorizons/core/util/ResourceUtil.java b/core/src/main/java/com/seibel/distanthorizons/core/util/ResourceUtil.java new file mode 100644 index 000000000..275708dfd --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/util/ResourceUtil.java @@ -0,0 +1,115 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.util; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public class ResourceUtil +{ + /** + * Returns all files in the "resources" folders. getFilesInFolder(String directoryName, String fileExtension) throws URISyntaxException, IOException + { + ArrayList resourceFiles = new ArrayList<>(); + + URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName); + if (url != null) + { + if (url.getProtocol().equals("file")) + { + File rootFile = Paths.get(url.toURI()).toFile(); + File[] files = rootFile.listFiles(); + if (files != null) + { + for (File file : files) + { + if (file.getName().endsWith(fileExtension)) + { + String content = FileUtil.readFile(file, Charset.defaultCharset()); + ResourceFile resourceFile = new ResourceFile(file.getName(), content); + resourceFiles.add(resourceFile); + } + } + } + } + else if (url.getProtocol().equals("jar")) + { + String dirname = directoryName + "/"; + String path = url.getPath(); + String jarPath = path.substring(5, path.indexOf("!")); + try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) + { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) + { + JarEntry entry = entries.nextElement(); + String fileName = entry.getName(); + if (fileName.startsWith(dirname) && !dirname.equals(fileName)) + { + if (fileName.endsWith(fileExtension)) + { + URL resource = Thread.currentThread().getContextClassLoader().getResource(fileName); + File file = new File(resource.getFile()); + String content = FileUtil.readFile(file, Charset.defaultCharset()); + + ResourceFile resourceFile = new ResourceFile(file.getName(), content); + resourceFiles.add(resourceFile); + } + } + } + } + } + } + + return resourceFiles; + } + + + + //==============// + // helper class // + //==============// + + public static class ResourceFile + { + public final String name; + public final String content; + + public ResourceFile(String name, String content) + { + this.name = name; + this.content = content; + } + } + +} diff --git a/core/src/main/resources/sqlScripts/0010-sqlite-createInitialTables.sql b/core/src/main/resources/sqlScripts/0010-sqlite-createInitialTables.sql new file mode 100644 index 000000000..dac04a703 --- /dev/null +++ b/core/src/main/resources/sqlScripts/0010-sqlite-createInitialTables.sql @@ -0,0 +1,9 @@ + +-- TODO should track ran scripts +CREATE TABLE IF NOT EXISTS DhFullData( + DhSectionPos TEXT NOT NULL PRIMARY KEY + + ,Data BLOB NULL + + --,CreatedDateTime DATETIME NOT NULL default CURRENT_TIMESTAMP -- in UTC +); diff --git a/core/src/main/resources/sqlScripts/0011-sqlite-createInitialTables.sql b/core/src/main/resources/sqlScripts/0011-sqlite-createInitialTables.sql new file mode 100644 index 000000000..ab76adbe2 --- /dev/null +++ b/core/src/main/resources/sqlScripts/0011-sqlite-createInitialTables.sql @@ -0,0 +1,9 @@ + +-- TODO should track ran scripts +CREATE TABLE IF NOT EXISTS DhRenderData( + DhSectionPos TEXT NOT NULL PRIMARY KEY + + ,Data BLOB NULL + + --,CreatedDateTime DATETIME NOT NULL default CURRENT_TIMESTAMP -- in UTC +);