mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-12-25 02:27:42 +01:00
Re-implemented region data migration.
This commit is contained in:
parent
06df4585c2
commit
768532cb8b
@ -19,11 +19,17 @@
|
||||
|
||||
package com.sk89q.worldguard.bukkit;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.sk89q.commandbook.CommandBook;
|
||||
import com.sk89q.commandbook.GodComponent;
|
||||
import com.sk89q.util.yaml.YAMLFormat;
|
||||
import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.DirectoryYamlDriver;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.DriverType;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.SQLDriver;
|
||||
import com.sk89q.worldguard.util.sql.DataSourceConfig;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@ -90,11 +96,8 @@ public class ConfigurationManager {
|
||||
/**
|
||||
* Region Storage Configuration method, and config values
|
||||
*/
|
||||
public boolean useSqlDatabase = false;
|
||||
public String sqlDsn;
|
||||
public String sqlUsername;
|
||||
public String sqlPassword;
|
||||
public String sqlTablePrefix;
|
||||
public RegionStoreDriver selectedRegionStoreDriver;
|
||||
public Map<DriverType, RegionStoreDriver> regionStoreDriverMap;
|
||||
|
||||
/**
|
||||
* Construct the object.
|
||||
@ -167,12 +170,25 @@ public void load() {
|
||||
}
|
||||
}
|
||||
|
||||
useSqlDatabase = config.getBoolean("regions.sql.use", false);
|
||||
// ====================================================================
|
||||
// Region store drivers
|
||||
// ====================================================================
|
||||
|
||||
sqlDsn = config.getString("regions.sql.dsn", "jdbc:mysql://localhost/worldguard");
|
||||
sqlUsername = config.getString("regions.sql.username", "worldguard");
|
||||
sqlPassword = config.getString("regions.sql.password", "worldguard");
|
||||
sqlTablePrefix = config.getString("regions.sql.table-prefix", "");
|
||||
boolean useSqlDatabase = config.getBoolean("regions.sql.use", false);
|
||||
String sqlDsn = config.getString("regions.sql.dsn", "jdbc:mysql://localhost/worldguard");
|
||||
String sqlUsername = config.getString("regions.sql.username", "worldguard");
|
||||
String sqlPassword = config.getString("regions.sql.password", "worldguard");
|
||||
String sqlTablePrefix = config.getString("regions.sql.table-prefix", "");
|
||||
|
||||
DataSourceConfig dataSourceConfig = new DataSourceConfig(sqlDsn, sqlUsername, sqlPassword, sqlTablePrefix);
|
||||
SQLDriver sqlDriver = new SQLDriver(dataSourceConfig);
|
||||
DirectoryYamlDriver yamlDriver = new DirectoryYamlDriver(getWorldsDataFolder(), "regions.yml");
|
||||
|
||||
this.regionStoreDriverMap = ImmutableMap.<DriverType, RegionStoreDriver>builder()
|
||||
.put(DriverType.MYSQL, sqlDriver)
|
||||
.put(DriverType.YAML, yamlDriver)
|
||||
.build();
|
||||
this.selectedRegionStoreDriver = useSqlDatabase ? sqlDriver : yamlDriver;
|
||||
|
||||
// Load configurations for each world
|
||||
for (World world : plugin.getServer().getWorlds()) {
|
||||
|
@ -20,7 +20,12 @@
|
||||
package com.sk89q.worldguard.bukkit;
|
||||
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldguard.protection.managers.ManagerContainer;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.managers.migration.Migration;
|
||||
import com.sk89q.worldguard.protection.managers.migration.MigrationException;
|
||||
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
@ -35,6 +40,8 @@
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -51,6 +58,8 @@
|
||||
*/
|
||||
public class RegionContainer {
|
||||
|
||||
private static final Logger log = Logger.getLogger(RegionContainer.class.getCanonicalName());
|
||||
|
||||
/**
|
||||
* Invalidation frequency in ticks.
|
||||
*/
|
||||
@ -58,8 +67,8 @@ public class RegionContainer {
|
||||
|
||||
private final Object lock = new Object();
|
||||
private final WorldGuardPlugin plugin;
|
||||
private final ManagerContainer container;
|
||||
private final QueryCache cache = new QueryCache();
|
||||
private ManagerContainer container;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -68,16 +77,17 @@ public class RegionContainer {
|
||||
*/
|
||||
RegionContainer(WorldGuardPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
ConfigurationManager config = plugin.getGlobalStateManager();
|
||||
container = new ManagerContainer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the region container.
|
||||
*/
|
||||
void initialize() {
|
||||
container.initialize();
|
||||
ConfigurationManager config = plugin.getGlobalStateManager();
|
||||
container = new ManagerContainer(config.selectedRegionStoreDriver);
|
||||
|
||||
// Migrate to UUIDs
|
||||
autoMigrate();
|
||||
|
||||
loadWorlds();
|
||||
|
||||
@ -128,6 +138,15 @@ void unload() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the region store driver.
|
||||
*
|
||||
* @return the driver
|
||||
*/
|
||||
public RegionStoreDriver getDriver() {
|
||||
return container.getDriver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try loading the region managers for all currently loaded worlds.
|
||||
*/
|
||||
@ -229,4 +248,49 @@ public RegionQuery createQuery() {
|
||||
return new RegionQuery(plugin, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a migration and block any loading of region data during
|
||||
* the migration.
|
||||
*
|
||||
* @param migration the migration
|
||||
* @throws MigrationException thrown by the migration on error
|
||||
*/
|
||||
public void migrate(Migration migration) throws MigrationException {
|
||||
checkNotNull(migration);
|
||||
|
||||
synchronized (lock) {
|
||||
try {
|
||||
log.info("Unloading and saving region data that is currently loaded...");
|
||||
unload();
|
||||
migration.migrate();
|
||||
} finally {
|
||||
log.info("Loading region data for loaded worlds...");
|
||||
loadWorlds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute auto-migration.
|
||||
*/
|
||||
private void autoMigrate() {
|
||||
ConfigurationManager config = plugin.getGlobalStateManager();
|
||||
|
||||
if (config.migrateRegionsToUuid) {
|
||||
RegionStoreDriver driver = getDriver();
|
||||
UUIDMigration migrator = new UUIDMigration(driver, plugin.getProfileService());
|
||||
migrator.setKeepUnresolvedNames(config.keepUnresolvedNames);
|
||||
try {
|
||||
migrate(migrator);
|
||||
|
||||
log.info("Regions saved after UUID migration! This won't happen again unless " +
|
||||
"you change the relevant configuration option in WorldGuard's config.");
|
||||
|
||||
config.disableUuidMigration();
|
||||
} catch (MigrationException e) {
|
||||
log.log(Level.WARNING, "Failed to execute the migration", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,11 +30,6 @@
|
||||
import com.sk89q.minecraft.util.commands.MissingNestedCommandException;
|
||||
import com.sk89q.minecraft.util.commands.SimpleInjector;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
import com.sk89q.worldguard.bukkit.listener.RegionFlagsListener;
|
||||
import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors;
|
||||
import com.sk89q.worldguard.util.task.SimpleSupervisor;
|
||||
import com.sk89q.worldguard.util.task.Supervisor;
|
||||
import com.sk89q.worldguard.util.task.Task;
|
||||
import com.sk89q.squirrelid.cache.HashMapCache;
|
||||
import com.sk89q.squirrelid.cache.ProfileCache;
|
||||
import com.sk89q.squirrelid.cache.SQLiteCache;
|
||||
@ -55,6 +50,7 @@
|
||||
import com.sk89q.worldguard.bukkit.listener.DebuggingListener;
|
||||
import com.sk89q.worldguard.bukkit.listener.EventAbstractionListener;
|
||||
import com.sk89q.worldguard.bukkit.listener.FlagStateManager;
|
||||
import com.sk89q.worldguard.bukkit.listener.RegionFlagsListener;
|
||||
import com.sk89q.worldguard.bukkit.listener.RegionProtectionListener;
|
||||
import com.sk89q.worldguard.bukkit.listener.WorldGuardBlockListener;
|
||||
import com.sk89q.worldguard.bukkit.listener.WorldGuardCommandBookListener;
|
||||
@ -68,9 +64,11 @@
|
||||
import com.sk89q.worldguard.protection.GlobalRegionManager;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.util.UnresolvedNamesException;
|
||||
import com.sk89q.worldguard.protection.util.migrator.MigrationException;
|
||||
import com.sk89q.worldguard.protection.util.migrator.UUIDMigrator;
|
||||
import com.sk89q.worldguard.util.FatalConfigurationLoadingException;
|
||||
import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors;
|
||||
import com.sk89q.worldguard.util.task.SimpleSupervisor;
|
||||
import com.sk89q.worldguard.util.task.Supervisor;
|
||||
import com.sk89q.worldguard.util.task.Task;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
@ -188,11 +186,6 @@ public void run() {
|
||||
try {
|
||||
// Load the configuration
|
||||
configuration.load();
|
||||
|
||||
getLogger().info("Loading region data...");
|
||||
regionContainer.initialize();
|
||||
|
||||
migrateRegionUniqueIds(); // Migrate to UUIDs
|
||||
} catch (FatalConfigurationLoadingException e) {
|
||||
getLogger().log(Level.WARNING, "Encountered fatal error while loading configuration", e);
|
||||
getServer().shutdown();
|
||||
@ -208,6 +201,9 @@ public void run() {
|
||||
"******************************************************\n");
|
||||
}
|
||||
|
||||
getLogger().info("Loading region data...");
|
||||
regionContainer.initialize();
|
||||
|
||||
flagStateManager = new FlagStateManager(this);
|
||||
|
||||
if (configuration.useRegionsScheduler) {
|
||||
@ -289,35 +285,6 @@ public void onDisable() {
|
||||
this.getServer().getScheduler().cancelTasks(this);
|
||||
}
|
||||
|
||||
private void migrateRegionUniqueIds() {
|
||||
try {
|
||||
if (configuration.migrateRegionsToUuid) {
|
||||
UUIDMigrator migrator = new UUIDMigrator(profileService, getLogger());
|
||||
migrator.readConfiguration(configuration);
|
||||
List<RegionManager> managers = globalRegionManager.getLoaded();
|
||||
|
||||
// Try migration
|
||||
if (migrator.migrate(managers)) {
|
||||
getLogger().info("Now saving regions... this may take a while.");
|
||||
|
||||
for (RegionManager manager : managers) {
|
||||
manager.save();
|
||||
}
|
||||
|
||||
getLogger().info(
|
||||
"Regions saved after UUID migration! This won't happen again unless " +
|
||||
"you change the relevant configuration option in WorldGuard's config.");
|
||||
|
||||
configuration.disableUuidMigration();
|
||||
}
|
||||
}
|
||||
} catch (MigrationException e) {
|
||||
getLogger().log(Level.WARNING, "Failed to migrate regions to use UUIDs instead of player names", e);
|
||||
} catch (IOException e) {
|
||||
getLogger().log(Level.WARNING, "Failed to save region data", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
try {
|
||||
|
@ -28,6 +28,8 @@
|
||||
import com.sk89q.worldedit.Location;
|
||||
import com.sk89q.worldedit.bukkit.BukkitUtil;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
||||
import com.sk89q.worldguard.bukkit.RegionContainer;
|
||||
import com.sk89q.worldguard.bukkit.WorldConfiguration;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.bukkit.commands.AsyncCommandHelper;
|
||||
@ -49,17 +51,20 @@
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.managers.RemovalStrategy;
|
||||
import com.sk89q.worldguard.protection.managers.migration.DriverMigration;
|
||||
import com.sk89q.worldguard.protection.managers.migration.MigrationException;
|
||||
import com.sk89q.worldguard.protection.managers.migration.UUIDMigration;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.DriverType;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
|
||||
import com.sk89q.worldguard.protection.util.migrator.MigrationException;
|
||||
import com.sk89q.worldguard.protection.util.migrator.UUIDMigrator;
|
||||
import com.sk89q.worldguard.util.Enums;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@ -808,60 +813,74 @@ public void save(CommandContext args, final CommandSender sender) throws Command
|
||||
* @throws CommandException any error
|
||||
*/
|
||||
@Command(aliases = {"migratedb"}, usage = "<from> <to>",
|
||||
desc = "Migrate from one Protection Database to another.", min = 2, max = 2)
|
||||
flags = "y",
|
||||
desc = "Migrate from one Protection Database to another.", min = 2, max = 2)
|
||||
public void migrateDB(CommandContext args, CommandSender sender) throws CommandException {
|
||||
// Check permissions
|
||||
if (!getPermissionModel(sender).mayMigrateRegionStore()) {
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
|
||||
/*
|
||||
String from = args.getString(0).toLowerCase().trim();
|
||||
String to = args.getString(1).toLowerCase().trim();
|
||||
DriverType from = Enums.findFuzzyByValue(DriverType.class, args.getString(0));
|
||||
DriverType to = Enums.findFuzzyByValue(DriverType.class, args.getString(1));
|
||||
|
||||
if (from == null) {
|
||||
throw new CommandException("The value of 'from' is not a recognized type of region data database.");
|
||||
}
|
||||
|
||||
if (to == null) {
|
||||
throw new CommandException("The value of 'to' is not a recognized type of region region data database.");
|
||||
}
|
||||
|
||||
if (from.equals(to)) {
|
||||
throw new CommandException("Will not migrate with common source and target.");
|
||||
throw new CommandException("It is not possible to migrate between the same types of region data databases.");
|
||||
}
|
||||
|
||||
Map<MigratorKey, Class<? extends AbstractDatabaseMigrator>> migrators =
|
||||
AbstractDatabaseMigrator.getMigrators();
|
||||
MigratorKey key = new MigratorKey(from,to);
|
||||
|
||||
if (!migrators.containsKey(key)) {
|
||||
throw new CommandException("No migrator found for that combination and direction.");
|
||||
}
|
||||
|
||||
long lastRequest = 10000000;
|
||||
if (this.migrateDBRequestDate != null) {
|
||||
lastRequest = new Date().getTime() - this.migrateDBRequestDate.getTime();
|
||||
}
|
||||
if (this.migrateDBRequest == null || lastRequest > 60000) {
|
||||
this.migrateDBRequest = key;
|
||||
this.migrateDBRequestDate = new Date();
|
||||
|
||||
if (!args.hasFlag('y')) {
|
||||
throw new CommandException("This command is potentially dangerous.\n" +
|
||||
"Please ensure you have made a backup of your data, and then re-enter the command exactly to procede.");
|
||||
"Please ensure you have made a backup of your data, and then re-enter the command with -y tacked on at the end to proceed.");
|
||||
}
|
||||
|
||||
Class<? extends AbstractDatabaseMigrator> cls = migrators.get(key);
|
||||
ConfigurationManager config = plugin.getGlobalStateManager();
|
||||
RegionStoreDriver fromDriver = config.regionStoreDriverMap.get(from);
|
||||
RegionStoreDriver toDriver = config.regionStoreDriverMap.get(to);
|
||||
|
||||
if (fromDriver == null) {
|
||||
throw new CommandException("The driver specified as 'from' does not seem to be supported in your version of WorldGuard.");
|
||||
}
|
||||
|
||||
if (toDriver == null) {
|
||||
throw new CommandException("The driver specified as 'to' does not seem to be supported in your version of WorldGuard.");
|
||||
}
|
||||
|
||||
DriverMigration migration = new DriverMigration(fromDriver, toDriver);
|
||||
|
||||
LoggerToChatHandler handler = null;
|
||||
Logger minecraftLogger = null;
|
||||
|
||||
if (sender instanceof Player) {
|
||||
handler = new LoggerToChatHandler(sender);
|
||||
handler.setLevel(Level.ALL);
|
||||
minecraftLogger = Logger.getLogger("com.sk89q.worldguard");
|
||||
minecraftLogger.addHandler(handler);
|
||||
}
|
||||
|
||||
try {
|
||||
AbstractDatabaseMigrator migrator = cls.getConstructor(WorldGuardPlugin.class).newInstance(plugin);
|
||||
|
||||
migrator.migrate();
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
} catch (SecurityException ignore) {
|
||||
} catch (InstantiationException ignore) {
|
||||
} catch (IllegalAccessException ignore) {
|
||||
} catch (InvocationTargetException ignore) {
|
||||
} catch (NoSuchMethodException ignore) {
|
||||
RegionContainer container = plugin.getRegionContainer();
|
||||
sender.sendMessage(ChatColor.YELLOW + "Now performing migration... this may take a while.");
|
||||
container.migrate(migration);
|
||||
sender.sendMessage(ChatColor.YELLOW +
|
||||
"Migration complete! This only migrated the data. If you already changed your settings to use " +
|
||||
"the target driver, then WorldGuard is now using the new data. If not, you have to adjust your " +
|
||||
"configuration to use the new driver and then restart your server.");
|
||||
} catch (MigrationException e) {
|
||||
throw new CommandException("Error migrating database: " + e.getMessage());
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to migrate", e);
|
||||
throw new CommandException("Error encountered while migrating: " + e.getMessage());
|
||||
} finally {
|
||||
if (minecraftLogger != null) {
|
||||
minecraftLogger.removeHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.YELLOW + "Regions have been migrated successfully.\n" +
|
||||
"If you wish to use the destination format as your new backend, please update your config and reload WorldGuard.");
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -885,30 +904,19 @@ public void migrateUuid(CommandContext args, CommandSender sender) throws Comman
|
||||
if (sender instanceof Player) {
|
||||
handler = new LoggerToChatHandler(sender);
|
||||
handler.setLevel(Level.ALL);
|
||||
minecraftLogger = Logger.getLogger("Minecraft");
|
||||
minecraftLogger = Logger.getLogger("com.sk89q.worldguard");
|
||||
minecraftLogger.addHandler(handler);
|
||||
}
|
||||
|
||||
try {
|
||||
UUIDMigrator migrator = new UUIDMigrator(plugin.getProfileService(), plugin.getLogger());
|
||||
migrator.readConfiguration(plugin.getGlobalStateManager());
|
||||
List<RegionManager> managers = plugin.getRegionContainer().getLoaded();
|
||||
|
||||
// Try migration
|
||||
if (migrator.migrate(managers)) {
|
||||
sender.sendMessage(ChatColor.YELLOW + "Now saving regions... this may take a while.");
|
||||
|
||||
for (RegionManager manager : managers) {
|
||||
manager.save();
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.YELLOW + "Migration complete!");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + "There were no names to migrate.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to save", e);
|
||||
throw new CommandException("Error encountered while saving: " + e.getMessage());
|
||||
ConfigurationManager config = plugin.getGlobalStateManager();
|
||||
RegionContainer container = plugin.getRegionContainer();
|
||||
RegionStoreDriver driver = container.getDriver();
|
||||
UUIDMigration migration = new UUIDMigration(driver, plugin.getProfileService());
|
||||
migration.setKeepUnresolvedNames(config.keepUnresolvedNames);
|
||||
sender.sendMessage(ChatColor.YELLOW + "Now performing migration... this may take a while.");
|
||||
container.migrate(migration);
|
||||
sender.sendMessage(ChatColor.YELLOW + "Migration complete!");
|
||||
} catch (MigrationException e) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to migrate", e);
|
||||
throw new CommandException("Error encountered while migrating: " + e.getMessage());
|
||||
|
@ -17,15 +17,13 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.bukkit;
|
||||
package com.sk89q.worldguard.protection.managers;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.managers.index.ChunkHashTable;
|
||||
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
|
||||
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
|
||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.DriverType;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import com.sk89q.worldguard.util.Normal;
|
||||
|
||||
@ -33,7 +31,6 @@
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
@ -48,43 +45,35 @@
|
||||
/**
|
||||
* Manages different {@link RegionManager}s for different worlds or dimensions.
|
||||
*/
|
||||
class ManagerContainer {
|
||||
public class ManagerContainer {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ManagerContainer.class.getCanonicalName());
|
||||
private static final int SAVE_INTERVAL = 1000 * 30;
|
||||
|
||||
private final ConfigurationManager config;
|
||||
private final ConcurrentMap<Normal, RegionManager> mapping = new ConcurrentHashMap<Normal, RegionManager>();
|
||||
private final Object lock = new Object();
|
||||
private final EnumMap<DriverType, RegionStoreDriver> drivers = new EnumMap<DriverType, RegionStoreDriver>(DriverType.class);
|
||||
private RegionStoreDriver defaultDriver;
|
||||
private final RegionStoreDriver driver;
|
||||
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
|
||||
private final Timer timer = new Timer();
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param config the configuration
|
||||
* @param driver the region store driver
|
||||
*/
|
||||
ManagerContainer(ConfigurationManager config) {
|
||||
checkNotNull(config);
|
||||
this.config = config;
|
||||
public ManagerContainer(RegionStoreDriver driver) {
|
||||
checkNotNull(driver);
|
||||
this.driver = driver;
|
||||
timer.schedule(new BackgroundSaver(), SAVE_INTERVAL, SAVE_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create drivers from the configuration.
|
||||
* Get the region store driver.
|
||||
*
|
||||
* @return the driver
|
||||
*/
|
||||
public void initialize() {
|
||||
for (DriverType type : DriverType.values()) {
|
||||
drivers.put(type, type.create(config));
|
||||
}
|
||||
|
||||
if (config.useSqlDatabase) {
|
||||
defaultDriver = drivers.get(DriverType.SQL);
|
||||
} else {
|
||||
defaultDriver = drivers.get(DriverType.YAML);
|
||||
}
|
||||
public RegionStoreDriver getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +114,7 @@ public RegionManager load(String name) {
|
||||
* @throws IOException thrown if loading fals
|
||||
*/
|
||||
private RegionManager createAndLoad(String name) throws IOException {
|
||||
RegionStore store = defaultDriver.get(name);
|
||||
RegionStore store = driver.get(name);
|
||||
RegionManager manager = new RegionManager(store, indexFactory);
|
||||
manager.load(); // Try loading, although it may fail
|
||||
return manager;
|
||||
@ -168,7 +157,7 @@ public void unloadAll() {
|
||||
String name = entry.getKey().toString();
|
||||
RegionManager manager = entry.getValue();
|
||||
try {
|
||||
manager.save();
|
||||
manager.saveChanges();
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to save the region data for '" + name + "' while unloading the data for all worlds", e);
|
||||
}
|
||||
@ -212,7 +201,9 @@ public void run() {
|
||||
String name = entry.getKey().toString();
|
||||
RegionManager manager = entry.getValue();
|
||||
try {
|
||||
manager.saveChanges();
|
||||
if (manager.saveChanges()) {
|
||||
log.info("Region data changes made in '" + name + "' have been background saved");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.log(Level.WARNING, "Failed to save the region data for '" + name + "' during a periodical save", e);
|
||||
} catch (Exception e) {
|
@ -81,7 +81,11 @@ public RegionManager(RegionStore store, Supplier<? extends ConcurrentRegionIndex
|
||||
* @throws IOException thrown when loading fails
|
||||
*/
|
||||
public void load() throws IOException {
|
||||
setRegions(store.loadAll());
|
||||
Set<ProtectedRegion> regions = store.loadAll();
|
||||
for (ProtectedRegion region : regions) {
|
||||
region.setDirty(false);
|
||||
}
|
||||
setRegions(regions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,9 +104,10 @@ public void save() throws IOException {
|
||||
*
|
||||
* <p>This method does nothing if there are no changes.</p>
|
||||
*
|
||||
* @return true if there were changes to be saved
|
||||
* @throws IOException thrown on save error
|
||||
*/
|
||||
public void saveChanges() throws IOException {
|
||||
public boolean saveChanges() throws IOException {
|
||||
RegionDifference diff = index.getAndClearDifference();
|
||||
|
||||
if (diff.containsChanges()) {
|
||||
@ -111,6 +116,9 @@ public void saveChanges() throws IOException {
|
||||
} catch (DifferenceSaveException e) {
|
||||
save(); // Partial save is not supported
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.managers.migration;
|
||||
|
||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An abstract implementation of a migrator that gets all the worlds in
|
||||
* a driver and calls a override-able {@code migrate()} method for
|
||||
* each store.
|
||||
*/
|
||||
abstract class AbstractMigration implements Migration {
|
||||
|
||||
private static final Logger log = Logger.getLogger(AbstractMigration.class.getCanonicalName());
|
||||
private final RegionStoreDriver driver;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param driver the storage driver
|
||||
*/
|
||||
public AbstractMigration(RegionStoreDriver driver) {
|
||||
checkNotNull(driver);
|
||||
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void migrate() throws MigrationException {
|
||||
try {
|
||||
for (RegionStore store : driver.getAll()) {
|
||||
try {
|
||||
migrate(store);
|
||||
} catch (MigrationException e) {
|
||||
log.log(Level.WARNING, "Migration of one world (" + store.getName() + ") failed with an error", e);
|
||||
}
|
||||
}
|
||||
|
||||
postMigration();
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("Migration failed because the process of getting a list of all the worlds to migrate failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called for all the worlds in the driver.
|
||||
*
|
||||
* @param store the region store
|
||||
* @throws MigrationException on migration error
|
||||
*/
|
||||
protected abstract void migrate(RegionStore store)throws MigrationException;
|
||||
|
||||
/**
|
||||
* Called after migration has successfully completed.
|
||||
*/
|
||||
protected abstract void postMigration();
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.managers.migration;
|
||||
|
||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Handles migration from one region store driver to another.
|
||||
*/
|
||||
public class DriverMigration extends AbstractMigration {
|
||||
|
||||
private static final Logger log = Logger.getLogger(DriverMigration.class.getCanonicalName());
|
||||
private final RegionStoreDriver target;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param driver the source storage driver
|
||||
* @param target the target storage driver
|
||||
*/
|
||||
public DriverMigration(RegionStoreDriver driver, RegionStoreDriver target) {
|
||||
super(driver);
|
||||
checkNotNull(target);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void migrate(RegionStore store) throws MigrationException {
|
||||
Set<ProtectedRegion> regions;
|
||||
|
||||
log.info("Loading the regions for '" + store.getName() + "' with the old driver...");
|
||||
|
||||
try {
|
||||
regions = store.loadAll();
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
|
||||
}
|
||||
|
||||
write(store.getName(), regions);
|
||||
}
|
||||
|
||||
private void write(String name, Set<ProtectedRegion> regions) throws MigrationException {
|
||||
log.info("Saving the data for '" + name + "' with the new driver...");
|
||||
|
||||
RegionStore store;
|
||||
|
||||
try {
|
||||
store = target.get(name);
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("The driver to migrate to can't store region data for the world '" + name + "'", e);
|
||||
}
|
||||
|
||||
try {
|
||||
store.saveAll(regions);
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("Failed to save region data for '" + store.getName() + "' to the new driver", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postMigration() {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.managers.migration;
|
||||
|
||||
/**
|
||||
* An object that migrates region data.
|
||||
*/
|
||||
public interface Migration {
|
||||
|
||||
/**
|
||||
* Execute the migration.
|
||||
*
|
||||
* @throws MigrationException thrown if the migration fails
|
||||
*/
|
||||
void migrate() throws MigrationException;
|
||||
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.util.migrator;
|
||||
package com.sk89q.worldguard.protection.managers.migration;
|
||||
|
||||
/**
|
||||
* Thrown when a migration fails.
|
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.managers.migration;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.sk89q.squirrelid.Profile;
|
||||
import com.sk89q.squirrelid.resolver.ProfileService;
|
||||
import com.sk89q.worldguard.domains.DefaultDomain;
|
||||
import com.sk89q.worldguard.domains.PlayerDomain;
|
||||
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
|
||||
import com.sk89q.worldguard.protection.managers.storage.driver.RegionStoreDriver;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Migrates names to UUIDs for all the worlds in a region store.
|
||||
*/
|
||||
public class UUIDMigration extends AbstractMigration {
|
||||
|
||||
private static final Logger log = Logger.getLogger(UUIDMigration.class.getCanonicalName());
|
||||
private static final int LOG_DELAY = 5000;
|
||||
|
||||
private final Timer timer = new Timer();
|
||||
private final ProfileService profileService;
|
||||
private final ConcurrentMap<String, UUID> resolvedNames = new ConcurrentHashMap<String, UUID>();
|
||||
private final Set<String> unresolvedNames = new HashSet<String>();
|
||||
private boolean keepUnresolvedNames = true;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param driver the storage driver
|
||||
* @param profileService the profile service
|
||||
*/
|
||||
public UUIDMigration(RegionStoreDriver driver, ProfileService profileService) {
|
||||
super(driver);
|
||||
checkNotNull(profileService);
|
||||
this.profileService = profileService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void migrate(RegionStore store) throws MigrationException {
|
||||
log.log(Level.INFO, "Migrating regions in '" + store.getName() + "' to convert names -> UUIDs...");
|
||||
|
||||
Set<ProtectedRegion> regions;
|
||||
|
||||
try {
|
||||
regions = store.loadAll();
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
|
||||
}
|
||||
|
||||
migrate(regions);
|
||||
|
||||
try {
|
||||
store.saveAll(regions);
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("Failed to save region data after migration of the world '" + store.getName() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean migrate(Collection<ProtectedRegion> regions) throws MigrationException {
|
||||
// Name scan pass
|
||||
Set<String> names = getNames(regions);
|
||||
|
||||
if (!names.isEmpty()) {
|
||||
// This task logs the progress of conversion (% converted...)
|
||||
// periodically
|
||||
TimerTask task = new ResolvedNamesTimerTask();
|
||||
|
||||
try {
|
||||
timer.schedule(task, LOG_DELAY, LOG_DELAY);
|
||||
|
||||
log.log(Level.INFO, "Resolving " + names.size() + " name(s) into UUIDs... this may take a while.");
|
||||
|
||||
// Don't lookup names that we already looked up for previous
|
||||
// worlds -- note: all names are lowercase in these collections
|
||||
Set<String> lookupNames = new HashSet<String>(names);
|
||||
lookupNames.removeAll(resolvedNames.keySet());
|
||||
|
||||
// Ask Mojang for names
|
||||
profileService.findAllByName(lookupNames, new Predicate<Profile>() {
|
||||
@Override
|
||||
public boolean apply(Profile profile) {
|
||||
resolvedNames.put(profile.getName().toLowerCase(), profile.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("The name -> UUID service failed", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new MigrationException("The migration was interrupted");
|
||||
} finally {
|
||||
// Stop showing the % converted messages
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
// Name -> UUID in all regions
|
||||
log.log(Level.INFO, "UUIDs resolved... now migrating all regions to UUIDs where possible...");
|
||||
convert(regions);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postMigration() {
|
||||
if (!unresolvedNames.isEmpty()) {
|
||||
if (keepUnresolvedNames) {
|
||||
log.log(Level.WARNING,
|
||||
"Some member and owner names do not seem to exist or own Minecraft so they " +
|
||||
"could not be converted into UUIDs. They have been left as names, but the conversion can " +
|
||||
"be re-run with 'keep-names-that-lack-uuids' set to false in the configuration in " +
|
||||
"order to remove these names. Leaving the names means that someone can register with one of " +
|
||||
"these names in the future and become that player.");
|
||||
} else {
|
||||
log.log(Level.WARNING,
|
||||
"Some member and owner names do not seem to exist or own Minecraft so they " +
|
||||
"could not be converted into UUIDs. These names have been removed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab all the player names from all the regions in the given collection.
|
||||
*
|
||||
* @param regions a collection of regions
|
||||
* @return a set of names
|
||||
*/
|
||||
private static Set<String> getNames(Collection<ProtectedRegion> regions) {
|
||||
Set<String> names = new HashSet<String>();
|
||||
for (ProtectedRegion region : regions) {
|
||||
// Names are already lower case
|
||||
names.addAll(region.getOwners().getPlayers());
|
||||
names.addAll(region.getMembers().getPlayers());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all the names to UUIDs.
|
||||
*
|
||||
* @param regions a collection of regions
|
||||
*/
|
||||
private void convert(Collection<ProtectedRegion> regions) {
|
||||
for (ProtectedRegion region : regions) {
|
||||
convert(region.getOwners());
|
||||
convert(region.getMembers());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert all the names to UUIDs.
|
||||
*
|
||||
* @param domain the domain
|
||||
*/
|
||||
private void convert(DefaultDomain domain) {
|
||||
PlayerDomain playerDomain = new PlayerDomain();
|
||||
for (UUID uuid : domain.getUniqueIds()) {
|
||||
playerDomain.addPlayer(uuid);
|
||||
}
|
||||
|
||||
for (String name : domain.getPlayers()) {
|
||||
UUID uuid = resolvedNames.get(name.toLowerCase());
|
||||
if (uuid != null) {
|
||||
playerDomain.addPlayer(uuid);
|
||||
} else {
|
||||
if (keepUnresolvedNames) {
|
||||
playerDomain.addPlayer(name);
|
||||
}
|
||||
unresolvedNames.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
domain.setPlayerDomain(playerDomain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether names that have no UUID equivalent (i.e. name that is not
|
||||
* owned) should be kept as names and not removed.
|
||||
*
|
||||
* @return true to keep names
|
||||
*/
|
||||
public boolean getKeepUnresolvedNames() {
|
||||
return keepUnresolvedNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether names that have no UUID equivalent (i.e. name that is not
|
||||
* owned) should be kept as names and not removed.
|
||||
*
|
||||
* @param keepUnresolvedNames true to keep names
|
||||
*/
|
||||
public void setKeepUnresolvedNames(boolean keepUnresolvedNames) {
|
||||
this.keepUnresolvedNames = keepUnresolvedNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* A task to periodically say how many names have been resolved.
|
||||
*/
|
||||
private class ResolvedNamesTimerTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
log.info("UUIDs have been found for " + resolvedNames.size() + " name(s)...");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -34,6 +34,11 @@ public class MemoryRegionStore implements RegionStore {
|
||||
|
||||
private Set<ProtectedRegion> regions = Collections.emptySet();
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MEMORY";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtectedRegion> loadAll() throws IOException {
|
||||
return regions;
|
||||
|
@ -30,6 +30,11 @@
|
||||
*/
|
||||
public interface RegionStore {
|
||||
|
||||
/**
|
||||
* Get a displayable name for this store.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Load all regions from storage and place them into the passed map.
|
||||
*
|
||||
|
@ -81,23 +81,23 @@ public RegionStore get(String id) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
return new YamlFileStore(file);
|
||||
return new YamlFileStore(id, file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> fetchAllExisting() {
|
||||
List<String> names = new ArrayList<String>();
|
||||
public List<RegionStore> getAll() throws IOException {
|
||||
List<RegionStore> stores = new ArrayList<RegionStore>();
|
||||
|
||||
File files[] = rootDir.listFiles();
|
||||
if (files != null) {
|
||||
for (File dir : files) {
|
||||
if (dir.isDirectory() && new File(dir, "regions.yml").isFile()) {
|
||||
names.add(dir.getName());
|
||||
stores.add(new YamlFileStore(dir.getName(), getPath(dir.getName())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
return stores;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,34 +19,12 @@
|
||||
|
||||
package com.sk89q.worldguard.protection.managers.storage.driver;
|
||||
|
||||
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
||||
import com.sk89q.worldguard.util.sql.DataSourceConfig;
|
||||
|
||||
/**
|
||||
* An enumeration of supported drivers.
|
||||
*/
|
||||
public enum DriverType {
|
||||
|
||||
YAML {
|
||||
@Override
|
||||
public RegionStoreDriver create(ConfigurationManager config) {
|
||||
return new DirectoryYamlDriver(config.getWorldsDataFolder(), "regions.yml");
|
||||
}
|
||||
},
|
||||
SQL {
|
||||
@Override
|
||||
public RegionStoreDriver create(ConfigurationManager config) {
|
||||
DataSourceConfig dataSourceConfig = new DataSourceConfig(config.sqlDsn, config.sqlUsername, config.sqlPassword, config.sqlTablePrefix);
|
||||
return new SQLDriver(dataSourceConfig);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a driver instance from a configuration.
|
||||
*
|
||||
* @param config a configuration
|
||||
* @return a driver
|
||||
*/
|
||||
public abstract RegionStoreDriver create(ConfigurationManager config);
|
||||
YAML,
|
||||
MYSQL
|
||||
|
||||
}
|
||||
|
@ -44,6 +44,6 @@ public interface RegionStoreDriver {
|
||||
* @return a list of names
|
||||
* @throws IOException thrown if the fetch operation fails
|
||||
*/
|
||||
List<String> fetchAllExisting() throws IOException;
|
||||
List<RegionStore> getAll() throws IOException;
|
||||
|
||||
}
|
||||
|
@ -80,17 +80,17 @@ public RegionStore get(String name) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> fetchAllExisting() throws IOException {
|
||||
public List<RegionStore> getAll() throws IOException {
|
||||
Closer closer = Closer.create();
|
||||
try {
|
||||
List<String> names = new ArrayList<String>();
|
||||
List<RegionStore> stores = new ArrayList<RegionStore>();
|
||||
Connection connection = closer.register(getConnectionPool().getConnection());
|
||||
Statement stmt = connection.createStatement();
|
||||
ResultSet rs = closer.register(stmt.executeQuery("SELECT name FROM world"));
|
||||
while (rs.next()) {
|
||||
names.add(rs.getString(1));
|
||||
stores.add(get(rs.getString(1)));
|
||||
}
|
||||
return names;
|
||||
return stores;
|
||||
} catch (SQLException e) {
|
||||
throw new IOException("Failed to fetch list of worlds", e);
|
||||
} finally {
|
||||
|
@ -78,6 +78,7 @@ public class YamlFileStore implements RegionStore {
|
||||
"# REMEMBER TO KEEP PERIODICAL BACKUPS.\r\n" +
|
||||
"#";
|
||||
|
||||
private final String name;
|
||||
private final File file;
|
||||
|
||||
static {
|
||||
@ -91,11 +92,14 @@ public class YamlFileStore implements RegionStore {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param name the name of this store
|
||||
* @param file the file
|
||||
* @throws IOException thrown if the file cannot be written to
|
||||
*/
|
||||
public YamlFileStore(File file) throws IOException {
|
||||
public YamlFileStore(String name, File file) throws IOException {
|
||||
checkNotNull(name);
|
||||
checkNotNull(file);
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
if (!file.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
@ -103,6 +107,11 @@ public YamlFileStore(File file) throws IOException {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ProtectedRegion> loadAll() throws IOException {
|
||||
Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
|
||||
|
@ -60,6 +60,7 @@ public class SQLRegionStore implements RegionStore {
|
||||
|
||||
private static final Logger log = Logger.getLogger(SQLRegionStore.class.getCanonicalName());
|
||||
|
||||
private final String name;
|
||||
private final BoneCP connectionPool;
|
||||
private final DataSourceConfig config;
|
||||
private final int worldId;
|
||||
@ -67,6 +68,7 @@ public class SQLRegionStore implements RegionStore {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param name the name of this store
|
||||
* @param config a configuration object that configures a {@link Connection}
|
||||
* @param connectionPool a connection pool
|
||||
* @param worldName the name of the world to store regions by
|
||||
@ -77,6 +79,7 @@ public SQLRegionStore(DataSourceConfig config, BoneCP connectionPool, String wor
|
||||
checkNotNull(connectionPool);
|
||||
checkNotNull(worldName);
|
||||
|
||||
this.name = worldName;
|
||||
this.config = config;
|
||||
this.connectionPool = connectionPool;
|
||||
|
||||
@ -95,6 +98,11 @@ public SQLRegionStore(DataSourceConfig config, BoneCP connectionPool, String wor
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to migrate the tables to the latest version.
|
||||
*
|
||||
|
@ -1,176 +0,0 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.protection.util.migrator;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.sk89q.squirrelid.Profile;
|
||||
import com.sk89q.squirrelid.resolver.ProfileService;
|
||||
import com.sk89q.worldguard.bukkit.ConfigurationManager;
|
||||
import com.sk89q.worldguard.domains.DefaultDomain;
|
||||
import com.sk89q.worldguard.domains.PlayerDomain;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class UUIDMigrator {
|
||||
|
||||
private static final int LOG_DELAY = 5000;
|
||||
|
||||
private final Timer timer = new Timer();
|
||||
private final ProfileService profileService;
|
||||
private final Logger logger;
|
||||
private final ConcurrentMap<String, UUID> resolvedNames = new ConcurrentHashMap<String, UUID>();
|
||||
private final Set<String> unresolvedNames = new HashSet<String>();
|
||||
private boolean keepUnresolvedNames = true;
|
||||
|
||||
public UUIDMigrator(ProfileService profileService, Logger logger) {
|
||||
checkNotNull(profileService);
|
||||
checkNotNull(logger);
|
||||
|
||||
this.profileService = profileService;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public boolean migrate(Collection<RegionManager> managers) throws MigrationException {
|
||||
Set<String> names = new HashSet<String>();
|
||||
|
||||
// Name scan pass
|
||||
logger.log(Level.INFO, "UUID migrator: Gathering names to convert...");
|
||||
for (RegionManager manager : managers) {
|
||||
scanForNames(manager, names);
|
||||
}
|
||||
|
||||
if (names.isEmpty()) {
|
||||
logger.log(Level.INFO, "UUID migrator: No names to convert!");
|
||||
return false;
|
||||
}
|
||||
|
||||
TimerTask resolvedTask = new ResolvedNamesTimerTask();
|
||||
try {
|
||||
timer.schedule(resolvedTask, LOG_DELAY, LOG_DELAY);
|
||||
logger.log(Level.INFO, "UUID migrator: Resolving " + names.size() + " name(s) into UUIDs... this may take a while.");
|
||||
profileService.findAllByName(names, new Predicate<Profile>() {
|
||||
@Override
|
||||
public boolean apply(Profile profile) {
|
||||
resolvedNames.put(profile.getName().toLowerCase(), profile.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new MigrationException("The name -> UUID service failed", e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new MigrationException("The migration was interrupted");
|
||||
} finally {
|
||||
resolvedTask.cancel();
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "UUID migrator: UUIDs resolved... now migrating all regions to UUIDs where possible...");
|
||||
for (RegionManager manager : managers) {
|
||||
convertToUniqueIds(manager);
|
||||
}
|
||||
|
||||
if (!unresolvedNames.isEmpty()) {
|
||||
if (keepUnresolvedNames) {
|
||||
logger.log(Level.WARNING,
|
||||
"UUID migrator: Some member and owner names do not seem to exist or own Minecraft so they " +
|
||||
"could not be converted into UUIDs. They have been left as names, but the conversion can " +
|
||||
"be re-run with 'keep-names-that-lack-uuids' set to false in the configuration in " +
|
||||
"order to remove these names. Leaving the names means that someone can register with one of " +
|
||||
"these names in the future and become that player.");
|
||||
} else {
|
||||
logger.log(Level.WARNING,
|
||||
"UUID migrator: Some member and owner names do not seem to exist or own Minecraft so they " +
|
||||
"could not be converted into UUIDs. These names have been removed.");
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "UUID migrator: Migration finished!");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void scanForNames(RegionManager manager, Set<String> target) {
|
||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||
target.addAll(region.getOwners().getPlayers());
|
||||
target.addAll(region.getMembers().getPlayers());
|
||||
}
|
||||
}
|
||||
|
||||
private void convertToUniqueIds(RegionManager manager) {
|
||||
for (ProtectedRegion region : manager.getRegions().values()) {
|
||||
convertToUniqueIds(region.getOwners());
|
||||
convertToUniqueIds(region.getMembers());
|
||||
}
|
||||
}
|
||||
|
||||
private void convertToUniqueIds(DefaultDomain domain) {
|
||||
PlayerDomain playerDomain = new PlayerDomain();
|
||||
for (UUID uuid : domain.getUniqueIds()) {
|
||||
playerDomain.addPlayer(uuid);
|
||||
}
|
||||
|
||||
for (String name : domain.getPlayers()) {
|
||||
UUID uuid = resolvedNames.get(name.toLowerCase());
|
||||
if (uuid != null) {
|
||||
playerDomain.addPlayer(uuid);
|
||||
} else {
|
||||
if (keepUnresolvedNames) {
|
||||
playerDomain.addPlayer(name);
|
||||
}
|
||||
unresolvedNames.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
domain.setPlayerDomain(playerDomain);
|
||||
}
|
||||
|
||||
public boolean isKeepUnresolvedNames() {
|
||||
return keepUnresolvedNames;
|
||||
}
|
||||
|
||||
public void setKeepUnresolvedNames(boolean keepUnresolvedNames) {
|
||||
this.keepUnresolvedNames = keepUnresolvedNames;
|
||||
}
|
||||
|
||||
public void readConfiguration(ConfigurationManager config) {
|
||||
setKeepUnresolvedNames(config.keepUnresolvedNames);
|
||||
}
|
||||
|
||||
private class ResolvedNamesTimerTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
logger.info("UUID migrator: UUIDs have been found for " + resolvedNames.size() + " name(s)...");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
80
src/main/java/com/sk89q/worldguard/util/Enums.java
Normal file
80
src/main/java/com/sk89q/worldguard/util/Enums.java
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* WorldGuard, a suite of tools for Minecraft
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldGuard team and contributors
|
||||
*
|
||||
* 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, 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 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldguard.util;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Helper methods for enums.
|
||||
*/
|
||||
public final class Enums {
|
||||
|
||||
private Enums() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given enum for a value that is equal to the one of the
|
||||
* given values, searching in an ascending manner.
|
||||
*
|
||||
* @param enumType the enum type
|
||||
* @param values the list of values
|
||||
* @param <T> the type of enum
|
||||
* @return the found value or null
|
||||
*/
|
||||
@Nullable
|
||||
public static <T extends Enum<T>> T findByValue(Class<T> enumType, String... values) {
|
||||
checkNotNull(enumType);
|
||||
checkNotNull(values);
|
||||
for (String val : values) {
|
||||
try {
|
||||
return Enum.valueOf(enumType, val);
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given enum for a value that is equal to the one of the
|
||||
* given values, searching in an ascending manner.
|
||||
*
|
||||
* <p>Some fuzzy matching of the provided values may be performed.</p>
|
||||
*
|
||||
* @param enumType the enum type
|
||||
* @param values the list of values
|
||||
* @param <T> the type of enum
|
||||
* @return the found value or null
|
||||
*/
|
||||
@Nullable
|
||||
public static <T extends Enum<T>> T findFuzzyByValue(Class<T> enumType, String... values) {
|
||||
checkNotNull(enumType);
|
||||
checkNotNull(values);
|
||||
for (String test : values) {
|
||||
for (T value : enumType.getEnumConstants()) {
|
||||
if (value.name().equalsIgnoreCase(test)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user