Add data migration framework

This commit is contained in:
GeorgH93 2018-07-25 22:35:15 +02:00
parent 8b883ec2e3
commit b59e2bd368
No known key found for this signature in database
GPG Key ID: D1630D37F9E4B3C8
7 changed files with 324 additions and 0 deletions

View File

@ -74,6 +74,7 @@ public CommandManager(Minepacks plugin)
registerSubCommand(new ReloadCommand(plugin));
registerSubCommand(new UpdateCommand(plugin));
registerSubCommand(new BackupCommand(plugin));
registerSubCommand(new MigrateCommand(plugin));
registerSubCommand(new HelpCommand(plugin, commands));
}

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Command;
import at.pcgamingfreaks.Command.HelpData;
import at.pcgamingfreaks.Minepacks.Bukkit.API.MinepacksCommand;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration.MigrationManager;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MigrateCommand extends MinepacksCommand
{
public MigrateCommand(Minepacks plugin)
{
super(plugin, "migrate", plugin.getLanguage().getTranslated("Commands.Description.Migrate"), "backpack.migrate", plugin.getLanguage().getCommandAliases("migrate"));
}
@Override
public void execute(final @NotNull CommandSender sender, final @NotNull String mainCommandAlias, final @NotNull String alias, final @NotNull String[] args)
{
if(args.length >= 1)
{
switch(args[0].toLowerCase())
{
case "db": case "database": case "storage": migrateDb(sender, args); break;
}
}
else
{
sender.sendMessage("/" + mainCommandAlias + ' ' + alias + "database");
}
}
private void migrateDb(final @NotNull CommandSender sender, final @NotNull String[] args)
{
if(args.length >= 2)
{
if(args.length >= 3 && args[2].equalsIgnoreCase("start"))
{
MigrationManager migrationManager = new MigrationManager((Minepacks) getMinepacksPlugin());
migrationManager.migrateDB(args[1], result -> {
sender.sendMessage("Minepacks database migration result: " + result.getType().name());
sender.sendMessage(result.getMessage());
});
}
else
{
sender.sendMessage("This process will convert your storage type from " + ((Minepacks) getMinepacksPlugin()).getDatabase().getClass().getName() + " to " + args[1]);
sender.sendMessage("Your old data will not be deleted and you can switch back any time in the \"config.yml\" file.");
if(args[1].equalsIgnoreCase("mysql"))
{
sender.sendMessage("Please make sure that you have set the config options \"Host\", \"Database\", \"User\" and \"Password\" to the correct values.");
}
sender.sendMessage("To start the migration please confirm with: /backpack migrate " + args[0] + ' ' + args[1] + " start");
}
}
else
{
sender.sendMessage("/backpacks migrate " + args[0] + " <mysql/sqlite/files/shared>");
}
}
@Override
public List<String> tabComplete(final @NotNull CommandSender sender, final @NotNull String mainCommandAlias, final @NotNull String alias, final @NotNull String[] args)
{
return null;
}
@Override
public List<HelpData> getHelp(final @NotNull CommandSender requester)
{
return null;
}
}

View File

@ -28,6 +28,7 @@
import org.bukkit.GameMode;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.FileNotFoundException;
import java.util.*;
public class Config extends Configuration
@ -72,6 +73,19 @@ public String getDatabaseType()
return getConfig().getString("Database.Type", "sqlite");
}
public void setDatabaseType(String type)
{
getConfig().set("Database.Type", type);
try
{
save();
}
catch(FileNotFoundException e)
{
e.printStackTrace();
}
}
public String getSQLHost()
{
return getConfig().getString("Database.SQL.Host", "localhost");

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class Migration
{
protected final Minepacks plugin;
protected final Database oldDb;
protected Migration(@NotNull Minepacks plugin, @NotNull Database oldDb)
{
this.plugin = plugin;
this.oldDb = oldDb;
}
public abstract @Nullable MigrationResult migrate() throws Exception;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
public interface MigrationCallback
{
void onResult(MigrationResult result);
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import at.pcgamingfreaks.ConsoleColor;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
import at.pcgamingfreaks.Reflection;
import org.bukkit.event.HandlerList;
public class MigrationManager
{
private final Minepacks plugin;
public MigrationManager(final Minepacks plugin)
{
this.plugin = plugin;
}
public void migrateDB(final String targetDatabaseType, final MigrationCallback callback)
{
final Migration migration = getMigrationPerformer(targetDatabaseType);
if(migration == null)
{
callback.onResult(new MigrationResult("There is no need to migrate the database.", MigrationResult.MigrationResultType.NOT_NEEDED));
return;
}
final Database db = plugin.getDatabase();
//region Disable the plugin except for the database
try
{
plugin.getLogger().info("Unloading plugin for migration");
Reflection.setValue(plugin, "database", null); // Hack to prevent the unload of the database
Reflection.getMethod(Minepacks.class, "unload").invoke(plugin); // Unload plugin
HandlerList.unregisterAll(db); // Disable events for database
}
catch(Exception e)
{
plugin.getLogger().warning(ConsoleColor.RED + "Failed to unload plugin! Please restart your server!" + ConsoleColor.RESET);
e.printStackTrace();
callback.onResult(new MigrationResult("Failed to unload plugin! Please restart your server!", MigrationResult.MigrationResultType.ERROR));
return;
}
//endregion
//region Migrate data
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
MigrationResult migrationResult = null;
try
{
plugin.getLogger().info("Start migrating data to new database");
migrationResult = migration.migrate();
plugin.getConfiguration().setDatabaseType(targetDatabaseType);
}
catch(Exception e)
{
plugin.getLogger().warning(ConsoleColor.RED + "There was a problem migrating from " + plugin.getDatabase().getClass().getName() + " to " + targetDatabaseType + ConsoleColor.RESET);
e.printStackTrace();
callback.onResult(new MigrationResult("There was a problem migrating from " + plugin.getDatabase().getClass().getName() + " to " + targetDatabaseType + ". Please check the console for details.", MigrationResult.MigrationResultType.ERROR));
}
//region Start the plugin again
final MigrationResult migrationResultFinal = migrationResult;
plugin.getServer().getScheduler().runTask(plugin, () -> {
db.close();
// No need to reload the config
try
{
plugin.getLogger().info("Migration is done, loading the plugin again.");
Reflection.getMethod(Minepacks.class, "load").invoke(plugin); // load the plugin again
plugin.getLogger().info(ConsoleColor.GREEN + "Plugin loaded successful and is ready to use again." + ConsoleColor.RESET);
if(migrationResultFinal != null) callback.onResult(migrationResultFinal);
}
catch(Exception e)
{
plugin.getLogger().warning(ConsoleColor.RED + "Failed to start plugin again!" + ConsoleColor.RESET);
e.printStackTrace();
}
});
//endregion
});
//endregion
}
public Migration getMigrationPerformer(final String targetDatabaseType)
{
return null;
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class MigrationResult
{
public enum MigrationResultType { SUCCESS, ERROR, NOT_NEEDED }
private final String message;
private final MigrationResultType type;
public MigrationResult(@NonNls String message, @NotNull MigrationResultType type) {
this.message = message;
this.type = type;
}
public @NotNull MigrationResultType getType()
{
return type;
}
public @NonNls String getMessage()
{
return message;
}
@Override
public String toString()
{
return getType().name() + ": " + getMessage();
}
}