diff --git a/src/main/java/com/Acrobot/ChestShop/ChestShop.java b/src/main/java/com/Acrobot/ChestShop/ChestShop.java index 8c8be0b..9929b27 100644 --- a/src/main/java/com/Acrobot/ChestShop/ChestShop.java +++ b/src/main/java/com/Acrobot/ChestShop/ChestShop.java @@ -7,17 +7,14 @@ import com.Acrobot.ChestShop.Commands.Toggle; import com.Acrobot.ChestShop.Commands.Version; import com.Acrobot.ChestShop.Configuration.Messages; import com.Acrobot.ChestShop.Configuration.Properties; -import com.Acrobot.ChestShop.DB.Generator; -import com.Acrobot.ChestShop.DB.Queue; -import com.Acrobot.ChestShop.DB.Transaction; -import com.Acrobot.ChestShop.Database.Account; -import com.Acrobot.ChestShop.Database.ConnectionManager; +import com.Acrobot.ChestShop.Database.Migrations; import com.Acrobot.ChestShop.Listeners.Block.BlockPlace; import com.Acrobot.ChestShop.Listeners.Block.Break.ChestBreak; import com.Acrobot.ChestShop.Listeners.Block.Break.SignBreak; import com.Acrobot.ChestShop.Listeners.Block.SignCreate; import com.Acrobot.ChestShop.Listeners.Economy.ServerAccountCorrector; import com.Acrobot.ChestShop.Listeners.Economy.TaxModule; +import com.Acrobot.ChestShop.Listeners.GarbageTextListener; import com.Acrobot.ChestShop.Listeners.Item.ItemMoveListener; import com.Acrobot.ChestShop.Listeners.ItemInfoListener; import com.Acrobot.ChestShop.Listeners.Modules.DiscountModule; @@ -39,12 +36,6 @@ import com.Acrobot.ChestShop.Metadata.ItemDatabase; import com.Acrobot.ChestShop.Signs.RestrictedSign; import com.Acrobot.ChestShop.UUIDs.NameManager; import com.Acrobot.ChestShop.Updater.Updater; -import com.avaje.ebean.EbeanServer; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.jdbc.JdbcConnectionSource; -import com.j256.ormlite.support.ConnectionSource; -import com.lennardf1989.bukkitex.Database; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Marker; @@ -55,7 +46,6 @@ import org.apache.logging.log4j.core.filter.AbstractFilter; import org.apache.logging.log4j.message.Message; import org.bukkit.Bukkit; import org.bukkit.Server; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Event; import org.bukkit.event.Listener; @@ -65,8 +55,6 @@ import org.mcstats.Metrics; import java.io.File; import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.logging.FileHandler; import java.util.logging.Logger; @@ -82,19 +70,20 @@ public class ChestShop extends JavaPlugin { private static PluginDescriptionFile description; private static File dataFolder; - private static EbeanServer database; private static ItemDatabase itemDatabase; private static Logger logger; private FileHandler handler; - public void onEnable() { - plugin = this; - logger = getLogger(); + public ChestShop() { dataFolder = getDataFolder(); + logger = getLogger(); description = getDescription(); server = getServer(); + plugin = this; + } + public void onEnable() { Configuration.pairFileAndClass(loadFile("config.yml"), Properties.class); Configuration.pairFileAndClass(loadFile("local.yml"), Messages.class); @@ -109,15 +98,6 @@ public class ChestShop extends JavaPlugin { registerEvents(); - if (Properties.LOG_TO_DATABASE || Properties.GENERATE_STATISTICS_PAGE) { - setupDB(); - } - - if (Properties.GENERATE_STATISTICS_PAGE) { - File htmlFolder = new File(Properties.STATISTICS_PAGE_PATH); - scheduleTask(new Generator(htmlFolder), 300L, Properties.STATISTICS_PAGE_GENERATION_INTERVAL * 20L); - } - if (Properties.LOG_TO_FILE) { File log = loadFile("ChestShop.log"); @@ -181,14 +161,13 @@ public class ChestShop extends JavaPlugin { }); } - private final int CURRENT_DATABASE_VERSION = 2; private void handleMigrations() { File versionFile = loadFile("version"); YamlConfiguration previousVersion = YamlConfiguration.loadConfiguration(versionFile); if (previousVersion.get("version") == null) { - previousVersion.set("version", CURRENT_DATABASE_VERSION); + previousVersion.set("version", Migrations.CURRENT_DATABASE_VERSION); try { previousVersion.save(versionFile); @@ -198,32 +177,16 @@ public class ChestShop extends JavaPlugin { } int lastVersion = previousVersion.getInt("version"); + int newVersion = Migrations.migrate(lastVersion); - if (CURRENT_DATABASE_VERSION != lastVersion) { - logger.info("Updating database..."); - } + if (lastVersion != newVersion) { + previousVersion.set("version", newVersion); - switch (lastVersion) { - case 1: - try { - File databaseFile = ChestShop.loadFile("users.db"); - String uri = ConnectionManager.getURI(databaseFile); - ConnectionSource connection = new JdbcConnectionSource(uri); - - Dao accounts = DaoManager.createDao(connection, Account.class); - - accounts.executeRaw("ALTER TABLE `accounts` ADD COLUMN lastSeenName VARCHAR"); - - previousVersion.set("version", 2); - previousVersion.save(versionFile); - } catch (SQLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - case CURRENT_DATABASE_VERSION: - default: - //do nothing + try { + previousVersion.save(versionFile); + } catch (IOException e) { + e.printStackTrace(); + } } } @@ -296,6 +259,7 @@ public class ChestShop extends JavaPlugin { registerEvent(new PlayerTeleport()); registerEvent(new ItemInfoListener()); + registerEvent(new GarbageTextListener()); registerEvent(new RestrictedSign()); @@ -394,40 +358,6 @@ public class ChestShop extends JavaPlugin { new Updater(this, PROJECT_BUKKITDEV_ID, this.getFile(), Updater.UpdateType.DEFAULT, true); } - ///////////////////// DATABASE STUFF //////////////////////////////// - private void setupDB() { - loadFile(new File("ebean.properties")); - - Database DB; - - DB = new Database(this) { - protected java.util.List> getDatabaseClasses() { - List> list = new ArrayList>(); - list.add(Transaction.class); - return list; - } - }; - - FileConfiguration config = YamlConfiguration.loadConfiguration(new File("bukkit.yml")); - - DB.initializeDatabase( - config.getString("database.driver"), - config.getString("database.url"), - config.getString("database.username"), - config.getString("database.password"), - config.getString("database.isolation") - ); - - database = DB.getDatabase(); - - scheduleTask(new Queue(), 200L, 200L); - } - - @Override - public EbeanServer getDatabase() { - return database; - } - /////////////////////////////////////////////////////////////////////////////// public static ItemDatabase getItemDatabase() { @@ -454,10 +384,6 @@ public class ChestShop extends JavaPlugin { return description.getName(); } - public static EbeanServer getDB() { - return database; - } - public static List getDependencies() { return description.getSoftDepend(); } diff --git a/src/main/java/com/Acrobot/ChestShop/DB/Generator.java b/src/main/java/com/Acrobot/ChestShop/DB/Generator.java deleted file mode 100644 index ec5949b..0000000 --- a/src/main/java/com/Acrobot/ChestShop/DB/Generator.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.Acrobot.ChestShop.DB; - -import com.Acrobot.Breeze.Utils.StringUtil; -import com.Acrobot.ChestShop.ChestShop; -import com.avaje.ebean.ExpressionList; -import org.bukkit.Material; - -import javax.persistence.PersistenceException; -import java.io.*; -import java.util.List; - -/** - * @author Acrobot - */ -public class Generator implements Runnable { - private final File pagePath; - - private static String header; - private static String row; - private static String footer; - - private static BufferedWriter buf; - - - public Generator(File pagePath) { - this.pagePath = pagePath; - } - - public void run() { - header = fileToString("header"); - row = fileToString("row"); - footer = fileToString("footer"); - - if (row.isEmpty()) { - ChestShop.getBukkitLogger().severe("You lack the necessary HTML files in your plugins/ChestShop/HTML folder!"); - return; - } - - generateStats(); - } - - private void fileStart() throws IOException { - FileWriter fw = new FileWriter(pagePath); - fw.write(header); - fw.close(); - } - - private void fileEnd(long generationTime) throws IOException { - FileWriter fw = new FileWriter(pagePath, true); - fw.write(footer.replace("%time", String.valueOf(generationTime))); - fw.close(); - } - - private static String fileToString(String fileName) { - try { - File htmlFolder = new File(ChestShop.getFolder(), "HTML"); - File fileToRead = new File(htmlFolder, fileName + ".html"); - - FileReader rd = new FileReader(fileToRead); - char[] buf = new char[(int) fileToRead.length()]; - rd.read(buf); - return new String(buf); - } catch (Exception e) { - return ""; - } - } - - private static double generateItemTotal(Material item, boolean bought, boolean sold) { - List list; - ExpressionList checkIf = ChestShop.getDB().find(Transaction.class).where(); - - if (bought || sold) { - list = checkIf.eq("buy", bought ? 1 : 0).eq("itemID", item.getId()).findList(); - } else { - list = checkIf.eq("itemID", item.getId()).findList(); - } - - return countTransactionAmount(list); - } - - private static double countTransactionAmount(List list) { - double amount = 0; - - for (Transaction transaction : list) { - amount += transaction.getAmount(); - } - - return amount; - } - - private static double generateTotalBought(Material item) { - return generateItemTotal(item, true, false); - } - - private static double generateTotalSold(Material item) { - return generateItemTotal(item, false, true); - } - - private static double generateItemTotal(Material item) { - return generateItemTotal(item, false, false); - } - - private static float generateAveragePrice(Material item) { - float price = 0; - List prices = ChestShop.getDB().find(Transaction.class).where().eq("itemID", item.getId()).eq("buy", true).findList(); - - for (Transaction t : prices) { - price += t.getAveragePricePerItem(); - } - - float toReturn = price / prices.size(); - return (!Float.isNaN(toReturn) ? toReturn : 0); - } - - private static float generateAverageBuyPrice(Material item) { - return generateAveragePrice(item); - } - - private static void generateItemStats(Material material) throws IOException { - double total = generateItemTotal(material); - - if (total == 0) return; - - double bought = generateTotalBought(material); - double sold = generateTotalSold(material); - - String matName = StringUtil.capitalizeFirstLetter(material.name(), '_'); - - int maxStackSize = material.getMaxStackSize(); - - float buyPrice = generateAverageBuyPrice(material); - - buf.write(row.replace("%material", matName) - .replace("%total", String.valueOf(total)) - .replace("%bought", String.valueOf(bought)) - .replace("%sold", String.valueOf(sold)) - .replace("%maxStackSize", String.valueOf(maxStackSize)) - .replace("%pricePerStack", String.valueOf((buyPrice * maxStackSize))) - .replace("%pricePerItem", String.valueOf(buyPrice))); - } - - private void generateStats() { - try { - File parentFolder = pagePath.getParentFile(); - if (!parentFolder.exists()) { - parentFolder.mkdir(); - } - - fileStart(); - - buf = new BufferedWriter(new FileWriter(pagePath, true)); - - long genTime = System.currentTimeMillis(); - for (Material m : Material.values()) { - generateItemStats(m); - } - - buf.close(); - - long generationTime = (System.currentTimeMillis() - genTime) / 1000; - - fileEnd(generationTime); - } catch (Exception e) { - ChestShop.getBukkitLogger().severe("Couldn't generate statistics page!"); - - if (!(e instanceof PersistenceException)) { - e.printStackTrace(); - } - } - } -} diff --git a/src/main/java/com/Acrobot/ChestShop/DB/Queue.java b/src/main/java/com/Acrobot/ChestShop/DB/Queue.java deleted file mode 100644 index 07a100b..0000000 --- a/src/main/java/com/Acrobot/ChestShop/DB/Queue.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.Acrobot.ChestShop.DB; - -import com.Acrobot.ChestShop.ChestShop; -import com.Acrobot.ChestShop.Configuration.Properties; - -import javax.persistence.OptimisticLockException; -import java.util.List; -import java.util.concurrent.ConcurrentLinkedQueue; - -/** - * @author Acrobot - */ -public class Queue implements Runnable { - private static final ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); - - public static void addToQueue(Transaction t) { - queue.add(t); - } - - public synchronized void run() { - if (Properties.RECORD_TIME_TO_LIVE != -1) - deleteOld(); - - ChestShop.getDB().save(queue); - queue.clear(); - } - - public synchronized static boolean deleteOld() { - try { - ChestShop.getDB().delete(getOld()); - return true; - } catch (OptimisticLockException ex) { - return false; - } - } - - public static List getOld() throws OptimisticLockException { - return ChestShop - .getDB() - .find(Transaction.class) - .where() - .lt("sec", (System.currentTimeMillis() / 1000L) - Properties.RECORD_TIME_TO_LIVE) - .findList(); - } -} diff --git a/src/main/java/com/Acrobot/ChestShop/DB/Transaction.java b/src/main/java/com/Acrobot/ChestShop/DB/Transaction.java deleted file mode 100644 index 346e3a7..0000000 --- a/src/main/java/com/Acrobot/ChestShop/DB/Transaction.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.Acrobot.ChestShop.DB; - -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -/** - * @author Acrobot - */ -@Entity() -@Table(name = "cs_transactions") -public class Transaction { - - @Id - private int id; - - private boolean buy; - private String shopOwner; - private String shopUser; - private int itemID; - private int itemDurability; - private int amount; - private float price; - private long sec; - - public Transaction() { - } - - public float getAveragePricePerItem() { - return price / amount; - } - - public int getId() { - return id; - } - - public boolean isBuy() { - return buy; - } - - public String getShopOwner() { - return shopOwner; - } - - public String getShopUser() { - return shopUser; - } - - public int getItemID() { - return itemID; - } - - public int getItemDurability() { - return itemDurability; - } - - public int getAmount() { - return amount; - } - - public float getPrice() { - return price; - } - - public long getSec() { - return sec; - } - - public void setId(int id) { - this.id = id; - } - - public void setBuy(boolean buy) { - this.buy = buy; - } - - public void setShopOwner(String shopOwner) { - this.shopOwner = shopOwner; - } - - public void setShopUser(String shopUser) { - this.shopUser = shopUser; - } - - public void setItemID(int itemID) { - this.itemID = itemID; - } - - public void setItemDurability(int itemDurability) { - this.itemDurability = itemDurability; - } - - public void setAmount(int amount) { - this.amount = amount; - } - - public void setPrice(float price) { - this.price = price; - } - - public void setSec(long sec) { - this.sec = sec; - } -} diff --git a/src/main/java/com/Acrobot/ChestShop/Listeners/Block/Break/SignBreak.java b/src/main/java/com/Acrobot/ChestShop/Listeners/Block/Break/SignBreak.java index 8fd71f7..bf02bcd 100644 --- a/src/main/java/com/Acrobot/ChestShop/Listeners/Block/Break/SignBreak.java +++ b/src/main/java/com/Acrobot/ChestShop/Listeners/Block/Break/SignBreak.java @@ -25,10 +25,7 @@ import org.bukkit.material.PistonBaseMaterial; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import static com.Acrobot.Breeze.Utils.BlockUtil.getAttachedBlock; import static com.Acrobot.Breeze.Utils.BlockUtil.isSign; @@ -174,7 +171,7 @@ public class SignBreak implements Listener { } if (isSign(block)) { - return Arrays.asList((Sign) block.getState()); + return Collections.singletonList((Sign) block.getState()); } else { List attachedSigns = new LinkedList(); diff --git a/src/main/java/com/lennardf1989/bukkitex/Database.java b/src/main/java/com/lennardf1989/bukkitex/Database.java deleted file mode 100644 index 9f13c11..0000000 --- a/src/main/java/com/lennardf1989/bukkitex/Database.java +++ /dev/null @@ -1,389 +0,0 @@ -package com.lennardf1989.bukkitex; - -import com.avaje.ebean.EbeanServer; -import com.avaje.ebean.EbeanServerFactory; -import com.avaje.ebean.config.DataSourceConfig; -import com.avaje.ebean.config.ServerConfig; -import com.avaje.ebean.config.dbplatform.SQLitePlatform; -import com.avaje.ebeaninternal.api.SpiEbeanServer; -import com.avaje.ebeaninternal.server.ddl.DdlGenerator; -import com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.BufferedReader; -import java.io.StringReader; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -public abstract class Database { - private JavaPlugin javaPlugin; - private ClassLoader classLoader; - private Level loggerLevel; - private boolean usingSQLite; - private ServerConfig serverConfig; - private EbeanServer ebeanServer; - - /** - * Create an instance of Database - * - * @param javaPlugin Plugin instancing this database - */ - public Database(JavaPlugin javaPlugin) { - //Store the JavaPlugin - this.javaPlugin = javaPlugin; - - //Try to get the ClassLoader of the plugin using Reflection - try { - //Find the "getClassLoader" method and make it "public" instead of "protected" - Method method = JavaPlugin.class.getDeclaredMethod("getClassLoader"); - method.setAccessible(true); - - //Store the ClassLoader - this.classLoader = (ClassLoader) method.invoke(javaPlugin); - } catch (Exception ex) { - throw new RuntimeException("Failed to retrieve the ClassLoader of the plugin using Reflection", ex); - } - } - - /** - * Initialize the database using the passed arguments - * - * @param driver Database-driver to use. For example: org.sqlite.JDBC - * @param url Location of the database. For example: jdbc:sqlite:{DIR}{NAME}.db - * @param username Username required to access the database - * @param password Password belonging to the username, may be empty - * @param isolation Isolation type. For example: SERIALIZABLE, also see TransactionIsolation - */ - public void initializeDatabase(String driver, String url, String username, String password, String isolation) { - //Logging needs to be set back to the original level, no matter what happens - try { - //Disable all logging - disableDatabaseLogging(false); - - //Prepare the database - prepareDatabase(driver, url, username, password, isolation); - - //Load the database - loadDatabase(); - - //Create all tables - installDatabase(false); - } catch (Exception ex) { - throw new RuntimeException("An exception has occured while initializing the database", ex); - } finally { - //Enable all logging - enableDatabaseLogging(false); - } - } - - private void prepareDatabase(String driver, String url, String username, String password, String isolation) { - //Setup the data source - DataSourceConfig ds = new DataSourceConfig(); - ds.setDriver(driver); - ds.setUrl(replaceDatabaseString(url)); - ds.setUsername(username); - ds.setPassword(password); - ds.setIsolationLevel(TransactionIsolation.getLevel(isolation)); - - //Setup the server configuration - ServerConfig sc = new ServerConfig(); - sc.setDefaultServer(false); - sc.setRegister(false); - sc.setName(ds.getUrl().replaceAll("[^a-zA-Z0-9]", "")); - - //Get all persistent classes - List> classes = getDatabaseClasses(); - - //Do a sanity check first - if (classes.isEmpty()) { - //Exception: There is no use in continuing to load this database - throw new RuntimeException("Database has been enabled, but no classes are registered to it"); - } - - //Register them with the EbeanServer - sc.setClasses(classes); - - //Check if the SQLite JDBC supplied with Bukkit is being used - if (ds.getDriver().equalsIgnoreCase("org.sqlite.JDBC")) { - //Remember the database is a SQLite-database - usingSQLite = true; - - //Modify the platform, as SQLite has no AUTO_INCREMENT field - sc.setDatabasePlatform(new SQLitePlatform()); - sc.getDatabasePlatform().getDbDdlSyntax().setIdentity(""); - } - - prepareDatabaseAdditionalConfig(ds, sc); - - //Finally the data source - sc.setDataSourceConfig(ds); - - //Store the ServerConfig - serverConfig = sc; - } - - private void loadDatabase() { - //Declare a few local variables for later use - ClassLoader currentClassLoader = null; - Field cacheField = null; - boolean cacheValue = true; - - try { - //Store the current ClassLoader, so it can be reverted later - currentClassLoader = Thread.currentThread().getContextClassLoader(); - - //Set the ClassLoader to Plugin ClassLoader - Thread.currentThread().setContextClassLoader(classLoader); - - //Get a reference to the private static "defaultUseCaches"-field in URLConnection - cacheField = URLConnection.class.getDeclaredField("defaultUseCaches"); - - //Make it accessible, store the default value and set it to false - cacheField.setAccessible(true); - cacheValue = cacheField.getBoolean(null); - cacheField.setBoolean(null, false); - - //Setup Ebean based on the configuration - ebeanServer = EbeanServerFactory.create(serverConfig); - } catch (Exception ex) { - throw new RuntimeException("Failed to create a new instance of the EbeanServer", ex); - } finally { - //Revert the ClassLoader back to its original value - if (currentClassLoader != null) { - Thread.currentThread().setContextClassLoader(currentClassLoader); - } - - //Revert the "defaultUseCaches"-field in URLConnection back to its original value - try { - if (cacheField != null) { - cacheField.setBoolean(null, cacheValue); - } - } catch (Exception e) { - System.out.println("Failed to revert the \"defaultUseCaches\"-field back to its original value, URLConnection-caching remains disabled."); - } - } - } - - private void installDatabase(boolean rebuild) { - //Check if the database already (partially) exists - boolean databaseExists = false; - - List> classes = getDatabaseClasses(); - for (Class aClass : classes) { - try { - //Do a simple query which only throws an exception if the table does not exist - ebeanServer.find(aClass).findRowCount(); - - //Query passed without throwing an exception, a database therefore already exists - databaseExists = true; - break; - } catch (Exception ex) { - //Do nothing - } - } - - //Check if the database has to be created or rebuilt - if (!rebuild && databaseExists) { - return; - } - - //Create a DDL generator - SpiEbeanServer serv = (SpiEbeanServer) ebeanServer; - DdlGenerator gen = serv.getDdlGenerator(); - - //Fire "before drop" event - try { - beforeDropDatabase(); - } catch (Exception ex) { - //If the database exists, dropping has to be canceled to prevent data-loss - if (databaseExists) { - throw new RuntimeException("An unexpected exception occured", ex); - } - } - - //Generate a DropDDL-script - gen.runScript(true, gen.generateDropDdl()); - - //If SQLite is being used, the database has to reloaded to release all resources - if (usingSQLite) { - loadDatabase(); - } - - //Generate a CreateDDL-script - if (usingSQLite) { - //If SQLite is being used, the CreateDLL-script has to be validated and potentially fixed to be valid - gen.runScript(false, validateCreateDDLSqlite(gen.generateCreateDdl())); - } else { - gen.runScript(false, gen.generateCreateDdl()); - } - - //Fire "after create" event - try { - afterCreateDatabase(); - } catch (Exception ex) { - throw new RuntimeException("An unexpected exception occured", ex); - } - } - - private String replaceDatabaseString(String input) { - input = input.replaceAll("\\{DIR\\}", javaPlugin.getDataFolder().getPath().replaceAll("\\\\", "/") + '/'); - input = input.replaceAll("\\{NAME\\}", javaPlugin.getDescription().getName().replaceAll("[^\\w_-]", "")); - - return input; - } - - private static String validateCreateDDLSqlite(String oldScript) { - try { - //Create a BufferedReader out of the potentially invalid script - BufferedReader scriptReader = new BufferedReader(new StringReader(oldScript)); - - //Create an array to store all the lines - List scriptLines = new ArrayList(); - - //Create some additional variables for keeping track of tables - HashMap foundTables = new HashMap(); - String currentTable = null; - int tableOffset = 0; - - //Loop through all lines - String currentLine; - while ((currentLine = scriptReader.readLine()) != null) { - //Trim the current line to remove trailing spaces - currentLine = currentLine.trim(); - - //Add the current line to the rest of the lines - scriptLines.add(currentLine.trim()); - - //Check if the current line is of any use - if (currentLine.startsWith("create table")) { - //Found a table, so get its name and remember the line it has been encountered on - currentTable = currentLine.split(" ", 4)[2]; - foundTables.put(currentLine.split(" ", 3)[2], scriptLines.size() - 1); - } else if (!currentLine.isEmpty() && currentLine.charAt(0) == ';' && currentTable != null && !currentTable.isEmpty()) { - //Found the end of a table definition, so update the entry - int index = scriptLines.size() - 1; - foundTables.put(currentTable, index); - - //Remove the last ")" from the previous line - String previousLine = scriptLines.get(index - 1); - previousLine = previousLine.substring(0, previousLine.length() - 1); - scriptLines.set(index - 1, previousLine); - - //Change ";" to ");" on the current line - scriptLines.set(index, ");"); - - //Reset the table-tracker - currentTable = null; - } else if (currentLine.startsWith("alter table")) { - //Found a potentially unsupported action - String[] alterTableLine = currentLine.split(" ", 4); - - if (alterTableLine[3].startsWith("add constraint")) { - //Found an unsupported action: ALTER TABLE using ADD CONSTRAINT - String[] addConstraintLine = alterTableLine[3].split(" ", 4); - - //Check if this line can be fixed somehow - if (addConstraintLine[3].startsWith("foreign key")) { - //Calculate the index of last line of the current table - int tableLastLine = foundTables.get(alterTableLine[2]) + tableOffset; - - //Add a "," to the previous line - scriptLines.set(tableLastLine - 1, scriptLines.get(tableLastLine - 1) + ','); - - //Add the constraint as a new line - Remove the ";" on the end - String constraintLine = String.format("%s %s %s", addConstraintLine[1], addConstraintLine[2], addConstraintLine[3]); - scriptLines.add(tableLastLine, constraintLine.substring(0, constraintLine.length() - 1)); - - //Remove this line and raise the table offset because a line has been inserted - scriptLines.remove(scriptLines.size() - 1); - tableOffset++; - } else { - //Exception: This line cannot be fixed but is known the be unsupported by SQLite - throw new RuntimeException("Unsupported action encountered: ALTER TABLE using ADD CONSTRAINT with " + addConstraintLine[3]); - } - } - } - } - - //Turn all the lines back into a single string - StringBuilder newScript = new StringBuilder(5); - for (String newLine : scriptLines) { - newScript.append(newLine).append('\n'); - } - - //Print the new script - System.out.println(newScript); - - //Return the fixed script - return newScript.toString(); - } catch (Exception ex) { - //Exception: Failed to fix the DDL or something just went plain wrong - throw new RuntimeException("Failed to validate the CreateDDL-script for SQLite", ex); - } - } - - private void disableDatabaseLogging(boolean logging) { - //If logging is allowed, nothing has to be changed - if (logging) { - return; - } - - //Retrieve the level of the root logger - loggerLevel = Logger.getLogger("").getLevel(); - - //Set the level of the root logger to OFF - Logger.getLogger("").setLevel(Level.OFF); - } - - private void enableDatabaseLogging(boolean logging) { - //If logging is allowed, nothing has to be changed - if (logging) { - return; - } - - //Set the level of the root logger back to the original value - Logger.getLogger("").setLevel(loggerLevel); - } - - /** - * Get a list of classes which should be registered with the EbeanServer - * - * @return List List of classes which should be registered with the EbeanServer - */ - protected List> getDatabaseClasses() { - return new ArrayList>(); - } - - /** - * Method called before the loaded database is being dropped - */ - protected void beforeDropDatabase() {} - - /** - * Method called after the loaded database has been created - */ - protected void afterCreateDatabase() {} - - /** - * Method called near the end of prepareDatabase, before the dataSourceConfig is attached to the serverConfig. - * - * @param dataSourceConfig - * @param serverConfig - */ - protected void prepareDatabaseAdditionalConfig(DataSourceConfig dataSourceConfig, ServerConfig serverConfig) {} - - /** - * Get the instance of the EbeanServer - * - * @return EbeanServer Instance of the EbeanServer - */ - public EbeanServer getDatabase() { - return ebeanServer; - } -}