Handle region data load / save failure more gracefully.

Also remove use of BoneCP and reorganize the classes.
This commit is contained in:
sk89q 2014-08-22 02:08:37 -07:00
parent 3045dc0293
commit 4d4e1c6c26
47 changed files with 1355 additions and 901 deletions

14
pom.xml
View File

@ -149,15 +149,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.jolbox</groupId>
<artifactId>bonecp</artifactId>
<version>0.8.0.RELEASE</version>
<scope>compile</scope>
<type>jar</type>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -398,16 +389,11 @@
<includes>
<include>net.sf.opencsv:opencsv</include>
<include>org.khelekore:prtree</include>
<include>com.jolbox:bonecp</include>
<include>org.flywaydb:flyway-core</include>
<include>com.sk89q:squirrelid</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>com.jolbox.bonecp</pattern>
<shadedPattern>com.sk89q.worldguard.internal.bonecp</shadedPattern>
</relocation>
<relocation>
<pattern>org.flywaydb</pattern>
<shadedPattern>com.sk89q.worldguard.internal.flywaydb</shadedPattern>

View File

@ -25,10 +25,10 @@
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.protection.managers.storage.file.DirectoryYamlDriver;
import com.sk89q.worldguard.protection.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.sql.SQLDriver;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import org.bukkit.World;
import org.bukkit.entity.Player;
@ -99,8 +99,8 @@ public class ConfigurationManager {
/**
* Region Storage Configuration method, and config values
*/
public RegionStoreDriver selectedRegionStoreDriver;
public Map<DriverType, RegionStoreDriver> regionStoreDriverMap;
public RegionDriver selectedRegionStoreDriver;
public Map<DriverType, RegionDriver> regionStoreDriverMap;
/**
* Construct the object.
@ -187,7 +187,7 @@ public void load() {
SQLDriver sqlDriver = new SQLDriver(dataSourceConfig);
DirectoryYamlDriver yamlDriver = new DirectoryYamlDriver(getWorldsDataFolder(), "regions.yml");
this.regionStoreDriverMap = ImmutableMap.<DriverType, RegionStoreDriver>builder()
this.regionStoreDriverMap = ImmutableMap.<DriverType, RegionDriver>builder()
.put(DriverType.MYSQL, sqlDriver)
.put(DriverType.YAML, yamlDriver)
.build();

View File

@ -20,6 +20,7 @@
package com.sk89q.worldguard.bukkit;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.managers.RegionManager;
import org.bukkit.Location;
import org.bukkit.World;
@ -30,7 +31,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Keeps a cache of {@link ApplicableRegionSet}s. The contents of the cache
* Keeps a cache of {@link RegionResultSet}s. The contents of the cache
* must be externally invalidated occasionally (and frequently).
*
* <p>This class is fully concurrent.</p>

View File

@ -20,12 +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.RegionContainerImpl;
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 com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
@ -69,7 +69,7 @@ public class RegionContainer {
private final Object lock = new Object();
private final WorldGuardPlugin plugin;
private final QueryCache cache = new QueryCache();
private ManagerContainer container;
private RegionContainerImpl container;
/**
* Create a new instance.
@ -85,7 +85,7 @@ public class RegionContainer {
*/
void initialize() {
ConfigurationManager config = plugin.getGlobalStateManager();
container = new ManagerContainer(config.selectedRegionStoreDriver);
container = new RegionContainerImpl(config.selectedRegionStoreDriver);
// Migrate to UUIDs
autoMigrate();
@ -144,7 +144,7 @@ void unload() {
*
* @return the driver
*/
public RegionStoreDriver getDriver() {
public RegionDriver getDriver() {
return container.getDriver();
}
@ -287,7 +287,7 @@ private void autoMigrate() {
ConfigurationManager config = plugin.getGlobalStateManager();
if (config.migrateRegionsToUuid) {
RegionStoreDriver driver = getDriver();
RegionDriver driver = getDriver();
UUIDMigration migrator = new UUIDMigration(driver, plugin.getProfileService());
migrator.setKeepUnresolvedNames(config.keepUnresolvedNames);
try {

View File

@ -21,7 +21,10 @@
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.FailedLoadRegionSet;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.PermissiveRegionSet;
import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
@ -70,7 +73,7 @@ public class RegionQuery {
/**
* Query for regions containing the given location.
*
* <p>An instance of {@link ApplicableRegionSet} will always be returned,
* <p>An instance of {@link RegionResultSet} will always be returned,
* even if regions are disabled or region data failed to load. An
* appropriate "virtual" set will be returned in such a case
* (for example, if regions are disabled, the returned set
@ -86,14 +89,14 @@ public ApplicableRegionSet getApplicableRegions(Location location) {
WorldConfiguration worldConfig = config.get(world);
if (!worldConfig.useRegions) {
return ApplicableRegionSet.getEmpty();
return PermissiveRegionSet.getInstance();
}
RegionManager manager = globalManager.get(location.getWorld());
if (manager != null) {
return cache.queryContains(manager, location);
} else {
return ApplicableRegionSet.getEmpty();
return FailedLoadRegionSet.getInstance();
}
}
@ -109,7 +112,7 @@ public ApplicableRegionSet getApplicableRegions(Location location) {
* @param player the player
* @param flags zero or more flags
* @return true if permission is granted
* @see ApplicableRegionSet#testBuild(RegionAssociable, StateFlag...)
* @see RegionResultSet#testBuild(RegionAssociable, StateFlag...)
*/
public boolean testBuild(Location location, Player player, StateFlag... flags) {
checkNotNull(location);
@ -137,7 +140,7 @@ public boolean testBuild(Location location, Player player, StateFlag... flags) {
* @param subject the subject
* @param flags zero or more flags
* @return true if permission is granted
* @see ApplicableRegionSet#testBuild(RegionAssociable, StateFlag...)
* @see RegionResultSet#testBuild(RegionAssociable, StateFlag...)
*/
public boolean testBuild(Location location, RegionAssociable subject, StateFlag... flags) {
checkNotNull(location);
@ -165,7 +168,7 @@ public boolean testBuild(Location location, RegionAssociable subject, StateFlag.
* @param player an optional player, which would be used to determine the region group to apply
* @param flag the flag
* @return true if the result was {@code ALLOW}
* @see ApplicableRegionSet#queryValue(RegionAssociable, Flag)
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
*/
public boolean testState(Location location, @Nullable Player player, StateFlag... flag) {
return StateFlag.test(queryState(location, player, flag));
@ -186,7 +189,7 @@ public boolean testState(Location location, @Nullable Player player, StateFlag..
* @param player an optional player, which would be used to determine the region groups that apply
* @param flags a list of flags to check
* @return a state
* @see ApplicableRegionSet#queryState(RegionAssociable, StateFlag...)
* @see RegionResultSet#queryState(RegionAssociable, StateFlag...)
*/
@Nullable
public State queryState(Location location, @Nullable Player player, StateFlag... flags) {
@ -216,7 +219,7 @@ public State queryState(Location location, @Nullable Player player, StateFlag...
* @param player an optional player, which would be used to determine the region group to apply
* @param flag the flag
* @return a value, which could be {@code null}
* @see ApplicableRegionSet#queryValue(RegionAssociable, Flag)
* @see RegionResultSet#queryValue(RegionAssociable, Flag)
*/
@Nullable
public <V> V queryValue(Location location, @Nullable Player player, Flag<V> flag) {
@ -239,7 +242,7 @@ public <V> V queryValue(Location location, @Nullable Player player, Flag<V> flag
* @param player an optional player, which would be used to determine the region group to apply
* @param flag the flag
* @return a collection of values
* @see ApplicableRegionSet#queryAllValues(RegionAssociable, Flag)
* @see RegionResultSet#queryAllValues(RegionAssociable, Flag)
*/
public <V> Collection<V> queryAllValues(Location location, @Nullable Player player, Flag<V> flag) {
LocalPlayer localPlayer = player != null ? plugin.wrapPlayer(player) : null;

View File

@ -63,6 +63,7 @@
import com.sk89q.worldguard.bukkit.listener.WorldGuardWorldListener;
import com.sk89q.worldguard.protection.GlobalRegionManager;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.util.UnresolvedNamesException;
import com.sk89q.worldguard.util.FatalConfigurationLoadingException;
import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors;
@ -320,6 +321,9 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String
public String convertThrowable(@Nullable Throwable throwable) {
if (throwable instanceof NumberFormatException) {
return "Number expected, string received instead.";
} else if (throwable instanceof StorageException) {
log.log(Level.WARNING, "Error loading/saving regions", throwable);
return "Region data could not be loaded/saved: " + throwable.getMessage();
} else if (throwable instanceof RejectedExecutionException) {
return "There are currently too many tasks queued to add yours. Use /wg running to list queued and running tasks.";
} else if (throwable instanceof CancellationException) {

View File

@ -151,9 +151,9 @@ public void listRunningTasks(CommandContext args, CommandSender sender) throws C
Collections.sort(tasks, new TaskStateComparator());
StringBuilder builder = new StringBuilder();
builder.append(ChatColor.GRAY);
builder.append("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
builder.append("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
builder.append(" Running tasks ");
builder.append("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
builder.append("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
builder.append("\n").append(ChatColor.GRAY).append("Note: Some 'running' tasks may be waiting to be start.");
for (Task task : tasks) {
builder.append("\n");

View File

@ -54,8 +54,8 @@
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.managers.storage.DriverType;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion.CircularInheritanceException;
import com.sk89q.worldguard.util.Enums;
@ -864,8 +864,8 @@ public void migrateDB(CommandContext args, CommandSender sender) throws CommandE
}
ConfigurationManager config = plugin.getGlobalStateManager();
RegionStoreDriver fromDriver = config.regionStoreDriverMap.get(from);
RegionStoreDriver toDriver = config.regionStoreDriverMap.get(to);
RegionDriver fromDriver = config.regionStoreDriverMap.get(from);
RegionDriver 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.");
@ -933,7 +933,7 @@ public void migrateUuid(CommandContext args, CommandSender sender) throws Comman
try {
ConfigurationManager config = plugin.getGlobalStateManager();
RegionContainer container = plugin.getRegionContainer();
RegionStoreDriver driver = container.getDriver();
RegionDriver 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.");

View File

@ -20,8 +20,8 @@
package com.sk89q.worldguard.bukkit.commands.task;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
@ -42,7 +42,7 @@ public RegionManagerReloader(RegionManager... manager) {
}
@Override
public Collection<RegionManager> call() throws IOException {
public Collection<RegionManager> call() throws StorageException {
for (RegionManager manager : managers) {
manager.load();
}

View File

@ -20,8 +20,8 @@
package com.sk89q.worldguard.bukkit.commands.task;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Callable;
@ -42,7 +42,7 @@ public RegionManagerSaver(RegionManager... manager) {
}
@Override
public Collection<RegionManager> call() throws IOException {
public Collection<RegionManager> call() throws StorageException {
for (RegionManager manager : managers) {
manager.save();
}

View File

@ -0,0 +1,111 @@
/*
* 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;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.flags.StateFlag.test;
public abstract class AbstractRegionSet implements ApplicableRegionSet {
@Override
@Deprecated
public boolean canBuild(LocalPlayer player) {
checkNotNull(player);
return test(queryState(player, DefaultFlag.BUILD));
}
@Override
@Deprecated
public boolean canConstruct(LocalPlayer player) {
checkNotNull(player);
final RegionGroup flag = getFlag(DefaultFlag.CONSTRUCT, player);
return RegionGroupFlag.isMember(this, flag, player);
}
@Override
public boolean testState(@Nullable RegionAssociable subject, StateFlag... flags) {
return test(queryState(subject, flags));
}
@Nullable
@Override
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
State value = null;
for (StateFlag flag : flags) {
value = StateFlag.combine(value, queryValue(subject, flag));
if (value == State.DENY) {
break;
}
}
return value;
}
@Override
@Deprecated
public boolean allows(StateFlag flag) {
checkNotNull(flag);
if (flag == DefaultFlag.BUILD) {
throw new IllegalArgumentException("Can't use build flag with allows()");
}
return test(queryState(null, flag));
}
@Override
@Deprecated
public boolean allows(StateFlag flag, @Nullable LocalPlayer player) {
checkNotNull(flag);
if (flag == DefaultFlag.BUILD) {
throw new IllegalArgumentException("Can't use build flag with allows()");
}
return test(queryState(player, flag));
}
@Override
@Deprecated
@Nullable
public <T extends Flag<V>, V> V getFlag(T flag, @Nullable LocalPlayer groupPlayer) {
return queryValue(groupPlayer, flag);
}
@Override
@Deprecated
@Nullable
public <T extends Flag<V>, V> V getFlag(T flag) {
return getFlag(flag, null);
}
}

View File

@ -20,11 +20,11 @@
package com.sk89q.worldguard.protection;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.bukkit.RegionQuery;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.RegionGroup;
import com.sk89q.worldguard.protection.flags.RegionGroupFlag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.managers.RegionManager;
@ -32,15 +32,8 @@
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.flags.StateFlag.test;
/**
* Represents the effective set of flags, owners, and members for a given
* spatial query.
@ -48,45 +41,25 @@
* <p>An instance of this can be created using the spatial query methods
* available on {@link RegionManager}.</p>
*/
public class ApplicableRegionSet implements Iterable<ProtectedRegion> {
public interface ApplicableRegionSet extends Iterable<ProtectedRegion> {
/**
* A static instance of an empty set.
*/
private static final ApplicableRegionSet EMPTY = new ApplicableRegionSet(Collections.<ProtectedRegion>emptyList(), null);
private final List<ProtectedRegion> applicable;
private final FlagValueCalculator flagValueCalculator;
@Nullable
private Set<ProtectedRegion> regionSet;
/**
* Construct the object.
* Return whether this region set is a virtual set. A virtual set
* does not contain real results.
*
* <p>A sorted set will be created to include the collection of regions.</p>
* <p>A virtual result may be returned if region data failed to load or
* there was some special exception (i.e. the region bypass permission).
* </p>
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
* <p>Be sure to check the value of this flag if an instance of this
* interface is being retrieved from {@link RegionQuery} as it may
* return an instance of {@link PermissiveRegionSet} or
* {@link FailedLoadRegionSet}, among other possibilities.</p>
*
* @return true if loaded
* @see FailedLoadRegionSet
*/
public ApplicableRegionSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion) {
this(applicable, globalRegion, false);
}
/**
* Construct the object.
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
* @param sorted true if the list is already sorted
*/
private ApplicableRegionSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
checkNotNull(applicable);
if (!sorted) {
Collections.sort(applicable);
}
this.applicable = applicable;
this.flagValueCalculator = new FlagValueCalculator(applicable, globalRegion);
}
boolean isVirtual();
/**
* Tests whether the {@link DefaultFlag#BUILD} flag or membership
@ -102,10 +75,7 @@ private ApplicableRegionSet(List<ProtectedRegion> applicable, @Nullable Protecte
* @deprecated use {@link #testBuild(RegionAssociable, StateFlag...)}
*/
@Deprecated
public boolean canBuild(LocalPlayer player) {
checkNotNull(player);
return test(flagValueCalculator.queryState(player, DefaultFlag.BUILD));
}
boolean canBuild(LocalPlayer player);
/**
* Test whether the given flags evaluate to {@code ALLOW}, implicitly also
@ -120,10 +90,7 @@ public boolean canBuild(LocalPlayer player) {
* @return true if permission is granted
* @see #queryState(RegionAssociable, StateFlag...)
*/
public boolean testBuild(RegionAssociable subject, StateFlag... flags) {
checkNotNull(subject);
return test(flagValueCalculator.queryState(subject, DefaultFlag.BUILD, flags));
}
boolean testBuild(RegionAssociable subject, StateFlag... flags);
/**
* Test whether the (effective) value for a list of state flags equals
@ -140,9 +107,7 @@ public boolean testBuild(RegionAssociable subject, StateFlag... flags) {
* @return true if the result was {@code ALLOW}
* @see #queryState(RegionAssociable, StateFlag...)
*/
public boolean testState(@Nullable RegionAssociable subject, StateFlag... flags) {
return test(flagValueCalculator.queryState(subject, flags));
}
boolean testState(@Nullable RegionAssociable subject, StateFlag... flags);
/**
* Get the (effective) value for a list of state flags. The rules of
@ -160,9 +125,7 @@ public boolean testState(@Nullable RegionAssociable subject, StateFlag... flags)
* @return a state
*/
@Nullable
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
return flagValueCalculator.queryState(subject, flags);
}
State queryState(@Nullable RegionAssociable subject, StateFlag... flags);
/**
* Get the effective value for a flag. If there are multiple values
@ -187,9 +150,7 @@ public State queryState(@Nullable RegionAssociable subject, StateFlag... flags)
* @return a value, which could be {@code null}
*/
@Nullable
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryValue(subject, flag);
}
<V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Get the effective values for a flag, returning a collection of all
@ -206,9 +167,7 @@ public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
* @param flag the flag
* @return a collection of values
*/
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryAllValues(subject, flag);
}
<V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag);
/**
* Test whether the construct flag evaluates true for the given player.
@ -219,11 +178,7 @@ public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag
* needed because flags now support groups assigned to them.
*/
@Deprecated
public boolean canConstruct(LocalPlayer player) {
checkNotNull(player);
final RegionGroup flag = getFlag(DefaultFlag.CONSTRUCT, player);
return RegionGroupFlag.isMember(this, flag, player);
}
boolean canConstruct(LocalPlayer player);
/**
* Gets the state of a state flag. This cannot be used for the build flag.
@ -234,19 +189,11 @@ public boolean canConstruct(LocalPlayer player) {
* @deprecated use {@link #queryState(RegionAssociable, StateFlag...)} instead
*/
@Deprecated
public boolean allows(StateFlag flag) {
checkNotNull(flag);
boolean allows(StateFlag flag);
if (flag == DefaultFlag.BUILD) {
throw new IllegalArgumentException("Can't use build flag with allows()");
}
return test(flagValueCalculator.queryState(null, flag));
}
/**
* Gets the state of a state flag. This cannot be used for the build flag.
*
*
* @param flag flag to check
* @param player player (used by some flags)
* @return whether the state is allows for it
@ -254,51 +201,23 @@ public boolean allows(StateFlag flag) {
* @deprecated use {@link #queryState(RegionAssociable, StateFlag...)} instead
*/
@Deprecated
public boolean allows(StateFlag flag, @Nullable LocalPlayer player) {
checkNotNull(flag);
boolean allows(StateFlag flag, @Nullable LocalPlayer player);
if (flag == DefaultFlag.BUILD) {
throw new IllegalArgumentException("Can't use build flag with allows()");
}
return test(flagValueCalculator.queryState(player, flag));
}
/**
* Test whether a player is an owner of all regions in this set.
*
*
* @param player the player
* @return whether the player is an owner of all regions
*/
public boolean isOwnerOfAll(LocalPlayer player) {
checkNotNull(player);
boolean isOwnerOfAll(LocalPlayer player);
for (ProtectedRegion region : applicable) {
if (!region.isOwner(player)) {
return false;
}
}
return true;
}
/**
* Test whether a player is an owner or member of all regions in this set.
*
*
* @param player the player
* @return whether the player is a member of all regions
*/
public boolean isMemberOfAll(LocalPlayer player) {
checkNotNull(player);
for (ProtectedRegion region : applicable) {
if (!region.isMember(player)) {
return false;
}
}
return true;
}
boolean isMemberOfAll(LocalPlayer player);
/**
* Gets the value of a flag. Do not use this for state flags
@ -311,14 +230,12 @@ public boolean isMemberOfAll(LocalPlayer player) {
*/
@Deprecated
@Nullable
public <T extends Flag<V>, V> V getFlag(T flag) {
return getFlag(flag, null);
}
<T extends Flag<V>, V> V getFlag(T flag);
/**
* Gets the value of a flag. Do not use this for state flags
* (use {@link #allows(StateFlag, LocalPlayer)} for that).
*
*
* @param flag flag to check
* @param groupPlayer player to check {@link RegionGroup}s against
* @return value of the flag, which may be null
@ -328,54 +245,20 @@ public <T extends Flag<V>, V> V getFlag(T flag) {
*/
@Deprecated
@Nullable
public <T extends Flag<V>, V> V getFlag(T flag, @Nullable LocalPlayer groupPlayer) {
return flagValueCalculator.queryValue(groupPlayer, flag);
}
<T extends Flag<V>, V> V getFlag(T flag, @Nullable LocalPlayer groupPlayer);
/**
* Get the number of regions that are included.
*
*
* @return the number of contained regions
*/
public int size() {
return applicable.size();
}
int size();
/**
* Get an immutable set of regions that are included in this set.
*
* @return a set of regions
*/
public Set<ProtectedRegion> getRegions() {
if (regionSet != null) {
return regionSet;
}
regionSet = Collections.unmodifiableSet(new HashSet<ProtectedRegion>(applicable));
return regionSet;
}
@Override
public Iterator<ProtectedRegion> iterator() {
return applicable.iterator();
}
/**
* Return an instance that contains no regions and has no global region.
*/
public static ApplicableRegionSet getEmpty() {
return EMPTY;
}
/**
* Create a new instance using a list of regions that is known to
* already be sorted by priority descending.
*
* @param regions a list of regions
* @param globalRegion a global region
* @return
*/
public static ApplicableRegionSet fromSortedList(List<ProtectedRegion> regions, @Nullable ProtectedRegion globalRegion) {
return new ApplicableRegionSet(regions, globalRegion, true);
}
Set<ProtectedRegion> getRegions();
}

View File

@ -0,0 +1,107 @@
/*
* 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;
import com.google.common.collect.Iterators;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
/**
* A region set that is to be used when region data has failed. Operations
* are blocked.
*/
public class FailedLoadRegionSet extends AbstractRegionSet {
private static final FailedLoadRegionSet INSTANCE = new FailedLoadRegionSet();
private FailedLoadRegionSet() {
}
@Override
public boolean isVirtual() {
return true;
}
@Override
public boolean testBuild(RegionAssociable subject, StateFlag... flags) {
return false;
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
if (flag instanceof StateFlag) {
return ((StateFlag) flag).getDefault() ? (V) State.DENY : (V) State.ALLOW; // Inverse default
} else {
return null;
}
}
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return Collections.emptySet();
}
@Override
public boolean isOwnerOfAll(LocalPlayer player) {
return false;
}
@Override
public boolean isMemberOfAll(LocalPlayer player) {
return false;
}
@Override
public int size() {
return 0;
}
@Override
public Set<ProtectedRegion> getRegions() {
return Collections.emptySet();
}
@Override
public Iterator<ProtectedRegion> iterator() {
return Iterators.emptyIterator();
}
/**
* Get an instance.
*
* @return an instance
*/
public static FailedLoadRegionSet getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,107 @@
/*
* 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;
import com.google.common.collect.Iterators;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
/**
* A virtual region result set that is highly permissive, considering everyone
* a member. Returned flag values are default values (when available).
*/
public class PermissiveRegionSet extends AbstractRegionSet {
private static final PermissiveRegionSet INSTANCE = new PermissiveRegionSet();
private PermissiveRegionSet() {
}
@Override
public boolean isVirtual() {
return true;
}
@Override
public boolean testBuild(RegionAssociable subject, StateFlag... flags) {
return true;
}
@SuppressWarnings("unchecked")
@Nullable
@Override
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
if (flag instanceof StateFlag) {
return ((StateFlag) flag).getDefault() ? (V) State.ALLOW : null;
} else {
return null;
}
}
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return Collections.emptySet();
}
@Override
public boolean isOwnerOfAll(LocalPlayer player) {
return true;
}
@Override
public boolean isMemberOfAll(LocalPlayer player) {
return true;
}
@Override
public int size() {
return 0;
}
@Override
public Set<ProtectedRegion> getRegions() {
return Collections.emptySet();
}
@Override
public Iterator<ProtectedRegion> iterator() {
return Iterators.emptyIterator();
}
/**
* Get an instance.
*
* @return an instance
*/
public static PermissiveRegionSet getInstance() {
return INSTANCE;
}
}

View File

@ -0,0 +1,164 @@
/*
* 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;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.association.RegionAssociable;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.flags.StateFlag;
import com.sk89q.worldguard.protection.flags.StateFlag.State;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldguard.protection.flags.StateFlag.test;
/**
* An implementation that calculates flags using a list of regions.
*/
public class RegionResultSet extends AbstractRegionSet {
private final List<ProtectedRegion> applicable;
private final FlagValueCalculator flagValueCalculator;
@Nullable
private Set<ProtectedRegion> regionSet;
/**
* Construct the object.
*
* <p>A sorted set will be created to include the collection of regions.</p>
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
*/
public RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion) {
this(applicable, globalRegion, false);
}
/**
* Construct the object.
*
* @param applicable the regions contained in this set
* @param globalRegion the global region, set aside for special handling.
* @param sorted true if the list is already sorted
*/
private RegionResultSet(List<ProtectedRegion> applicable, @Nullable ProtectedRegion globalRegion, boolean sorted) {
checkNotNull(applicable);
if (!sorted) {
Collections.sort(applicable);
}
this.applicable = applicable;
this.flagValueCalculator = new FlagValueCalculator(applicable, globalRegion);
}
@Override
public boolean isVirtual() {
return false;
}
@Override
public boolean testBuild(RegionAssociable subject, StateFlag... flags) {
checkNotNull(subject);
return test(flagValueCalculator.queryState(subject, DefaultFlag.BUILD, flags));
}
@Override
@Nullable
public State queryState(@Nullable RegionAssociable subject, StateFlag... flags) {
return flagValueCalculator.queryState(subject, flags);
}
@Override
@Nullable
public <V> V queryValue(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryValue(subject, flag);
}
@Override
public <V> Collection<V> queryAllValues(@Nullable RegionAssociable subject, Flag<V> flag) {
return flagValueCalculator.queryAllValues(subject, flag);
}
@Override
public boolean isOwnerOfAll(LocalPlayer player) {
checkNotNull(player);
for (ProtectedRegion region : applicable) {
if (!region.isOwner(player)) {
return false;
}
}
return true;
}
@Override
public boolean isMemberOfAll(LocalPlayer player) {
checkNotNull(player);
for (ProtectedRegion region : applicable) {
if (!region.isMember(player)) {
return false;
}
}
return true;
}
@Override
public int size() {
return applicable.size();
}
@Override
public Set<ProtectedRegion> getRegions() {
if (regionSet != null) {
return regionSet;
}
regionSet = Collections.unmodifiableSet(new HashSet<ProtectedRegion>(applicable));
return regionSet;
}
@Override
public Iterator<ProtectedRegion> iterator() {
return applicable.iterator();
}
/**
* Create a new instance using a list of regions that is known to
* already be sorted by priority descending.
*
* @param regions a list of regions
* @param globalRegion a global region
* @return an instance
*/
public static RegionResultSet fromSortedList(List<ProtectedRegion> regions, @Nullable ProtectedRegion globalRegion) {
return new RegionResultSet(regions, globalRegion, true);
}
}

View File

@ -23,15 +23,16 @@
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.RegionStoreDriver;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -47,18 +48,22 @@
/**
* Manages different {@link RegionManager}s for different worlds or dimensions.
*
* <p>This is an internal class. Do not use it.</p>
*/
public class ManagerContainer {
public class RegionContainerImpl {
private static final Logger log = Logger.getLogger(ManagerContainer.class.getCanonicalName());
private static final Logger log = Logger.getLogger(RegionContainerImpl.class.getCanonicalName());
private static final int LOAD_ATTEMPT_INTERVAL = 1000 * 30;
private static final int SAVE_INTERVAL = 1000 * 30;
private final ConcurrentMap<Normal, RegionManager> mapping = new ConcurrentHashMap<Normal, RegionManager>();
private final Object lock = new Object();
private final RegionStoreDriver driver;
private final RegionDriver driver;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory = new ChunkHashTable.Factory(new PriorityRTreeIndex.Factory());
private final Timer timer = new Timer();
private final Set<Normal> failingLoads = new HashSet<Normal>();
private final Set<RegionManager> failingSaves = Collections.synchronizedSet(
Collections.newSetFromMap(new WeakHashMap<RegionManager, Boolean>()));
@ -67,9 +72,10 @@ public class ManagerContainer {
*
* @param driver the region store driver
*/
public ManagerContainer(RegionStoreDriver driver) {
public RegionContainerImpl(RegionDriver driver) {
checkNotNull(driver);
this.driver = driver;
timer.schedule(new BackgroundLoader(), LOAD_ATTEMPT_INTERVAL, LOAD_ATTEMPT_INTERVAL);
timer.schedule(new BackgroundSaver(), SAVE_INTERVAL, SAVE_INTERVAL);
}
@ -78,7 +84,7 @@ public ManagerContainer(RegionStoreDriver driver) {
*
* @return the driver
*/
public RegionStoreDriver getDriver() {
public RegionDriver getDriver() {
return driver;
}
@ -103,9 +109,11 @@ public RegionManager load(String name) {
try {
manager = createAndLoad(name);
mapping.put(normal, manager);
failingLoads.remove(normal);
return manager;
} catch (IOException e) {
log.log(Level.WARNING, "Failed to load the region data for '" + name + "'", e);
} catch (StorageException e) {
log.log(Level.WARNING, "Failed to load the region data for '" + name + "' (periodic attempts will be made to load the data until success)", e);
failingLoads.add(normal);
return null;
}
}
@ -117,10 +125,10 @@ public RegionManager load(String name) {
*
* @param name the name of the world
* @return a region manager
* @throws IOException thrown if loading fals
* @throws StorageException thrown if loading fals
*/
private RegionManager createAndLoad(String name) throws IOException {
RegionStore store = driver.get(name);
private RegionManager createAndLoad(String name) throws StorageException {
RegionDatabase store = driver.get(name);
RegionManager manager = new RegionManager(store, indexFactory);
manager.load(); // Try loading, although it may fail
return manager;
@ -144,12 +152,15 @@ public void unload(String name) {
if (manager != null) {
try {
manager.save();
} catch (IOException e) {
} catch (StorageException e) {
log.log(Level.WARNING, "Failed to save the region data for '" + name + "'", e);
}
mapping.remove(normal);
failingSaves.remove(manager);
}
failingLoads.remove(normal);
}
}
@ -164,12 +175,14 @@ public void unloadAll() {
RegionManager manager = entry.getValue();
try {
manager.saveChanges();
} catch (IOException e) {
} catch (StorageException e) {
log.log(Level.WARNING, "Failed to save the region data for '" + name + "' while unloading the data for all worlds", e);
}
}
mapping.clear();
failingLoads.clear();
failingSaves.clear();
}
}
@ -220,7 +233,7 @@ public void run() {
log.info("Region data changes made in '" + name + "' have been background saved");
}
failingSaves.remove(manager);
} catch (IOException e) {
} catch (StorageException e) {
failingSaves.add(manager);
log.log(Level.WARNING, "Failed to save the region data for '" + name + "' during a periodical save", e);
} catch (Exception e) {
@ -232,4 +245,33 @@ public void run() {
}
}
/**
* A task to re-try loading region data that has not yet been
* successfully loaded.
*/
private class BackgroundLoader extends TimerTask {
@Override
public void run() {
synchronized (lock) {
if (!failingLoads.isEmpty()) {
log.info("Attempting to load region data that has previously failed to load...");
Iterator<Normal> it = failingLoads.iterator();
while (it.hasNext()) {
Normal normal = it.next();
try {
RegionManager manager = createAndLoad(normal.toString());
mapping.put(normal, manager);
it.remove();
log.info("Successfully loaded region data for '" + normal.toString() + "'");
} catch (StorageException e) {
log.log(Level.WARNING, "Region data is still failing to load, at least for the world named '" + normal.toString() + "'", e);
break;
}
}
}
}
}
}
}

View File

@ -25,16 +25,17 @@
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldguard.LocalPlayer;
import com.sk89q.worldguard.protection.ApplicableRegionSet;
import com.sk89q.worldguard.protection.RegionResultSet;
import com.sk89q.worldguard.protection.managers.index.ConcurrentRegionIndex;
import com.sk89q.worldguard.protection.managers.index.RegionIndex;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.util.RegionCollectionConsumer;
import com.sk89q.worldguard.util.Normal;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -48,9 +49,12 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A region manager holds the regions for a world.
*/
public final class RegionManager {
private final RegionStore store;
private final RegionDatabase store;
private final Supplier<? extends ConcurrentRegionIndex> indexFactory;
private ConcurrentRegionIndex index;
@ -60,7 +64,7 @@ public final class RegionManager {
* @param store the region store
* @param indexFactory the factory for creating new instances of the index
*/
public RegionManager(RegionStore store, Supplier<? extends ConcurrentRegionIndex> indexFactory) {
public RegionManager(RegionDatabase store, Supplier<? extends ConcurrentRegionIndex> indexFactory) {
checkNotNull(store);
checkNotNull(indexFactory);
@ -85,9 +89,9 @@ public String getName() {
* prevent the creation or modification of regions in the index while
* a new collection of regions is loaded from storage.</p>
*
* @throws IOException thrown when loading fails
* @throws StorageException thrown when loading fails
*/
public void load() throws IOException {
public void load() throws StorageException {
Set<ProtectedRegion> regions = store.loadAll();
for (ProtectedRegion region : regions) {
region.setDirty(false);
@ -98,9 +102,9 @@ public void load() throws IOException {
/**
* Save a snapshot of all the regions as it is right now to storage.
*
* @throws IOException
* @throws StorageException thrown on save error
*/
public void save() throws IOException {
public void save() throws StorageException {
store.saveAll(new HashSet<ProtectedRegion>(getValuesCopy()));
}
@ -112,9 +116,9 @@ 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
* @throws StorageException thrown on save error
*/
public boolean saveChanges() throws IOException {
public boolean saveChanges() throws StorageException {
RegionDifference diff = index.getAndClearDifference();
boolean successful = false;
@ -314,7 +318,7 @@ public ApplicableRegionSet getApplicableRegions(Vector position) {
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
index.applyContaining(position, new RegionCollectionConsumer(regions, true));
return new ApplicableRegionSet(regions, index.get("__global__"));
return new RegionResultSet(regions, index.get("__global__"));
}
/**
@ -329,7 +333,7 @@ public ApplicableRegionSet getApplicableRegions(ProtectedRegion region) {
List<ProtectedRegion> regions = new ArrayList<ProtectedRegion>();
index.applyIntersecting(region, new RegionCollectionConsumer(regions, true));
return new ApplicableRegionSet(regions, index.get("__global__"));
return new RegionResultSet(regions, index.get("__global__"));
}
/**

View File

@ -19,10 +19,10 @@
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.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -36,14 +36,14 @@
abstract class AbstractMigration implements Migration {
private static final Logger log = Logger.getLogger(AbstractMigration.class.getCanonicalName());
private final RegionStoreDriver driver;
private final RegionDriver driver;
/**
* Create a new instance.
*
* @param driver the storage driver
*/
public AbstractMigration(RegionStoreDriver driver) {
public AbstractMigration(RegionDriver driver) {
checkNotNull(driver);
this.driver = driver;
@ -52,7 +52,7 @@ public AbstractMigration(RegionStoreDriver driver) {
@Override
public final void migrate() throws MigrationException {
try {
for (RegionStore store : driver.getAll()) {
for (RegionDatabase store : driver.getAll()) {
try {
migrate(store);
} catch (MigrationException e) {
@ -61,7 +61,7 @@ public final void migrate() throws MigrationException {
}
postMigration();
} catch (IOException e) {
} catch (StorageException e) {
throw new MigrationException("Migration failed because the process of getting a list of all the worlds to migrate failed", e);
}
}
@ -72,7 +72,7 @@ public final void migrate() throws MigrationException {
* @param store the region store
* @throws MigrationException on migration error
*/
protected abstract void migrate(RegionStore store)throws MigrationException;
protected abstract void migrate(RegionDatabase store)throws MigrationException;
/**
* Called after migration has successfully completed.

View File

@ -19,11 +19,11 @@
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.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.Set;
import java.util.logging.Logger;
@ -35,7 +35,7 @@
public class DriverMigration extends AbstractMigration {
private static final Logger log = Logger.getLogger(DriverMigration.class.getCanonicalName());
private final RegionStoreDriver target;
private final RegionDriver target;
/**
* Create a new instance.
@ -43,21 +43,21 @@ public class DriverMigration extends AbstractMigration {
* @param driver the source storage driver
* @param target the target storage driver
*/
public DriverMigration(RegionStoreDriver driver, RegionStoreDriver target) {
public DriverMigration(RegionDriver driver, RegionDriver target) {
super(driver);
checkNotNull(target);
this.target = target;
}
@Override
protected void migrate(RegionStore store) throws MigrationException {
protected void migrate(RegionDatabase 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) {
} catch (StorageException e) {
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
}
@ -67,17 +67,11 @@ protected void migrate(RegionStore store) throws MigrationException {
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);
}
RegionDatabase store = target.get(name);
try {
store.saveAll(regions);
} catch (IOException e) {
} catch (StorageException e) {
throw new MigrationException("Failed to save region data for '" + store.getName() + "' to the new driver", e);
}
}

View File

@ -24,8 +24,9 @@
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.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
@ -62,21 +63,21 @@ public class UUIDMigration extends AbstractMigration {
* @param driver the storage driver
* @param profileService the profile service
*/
public UUIDMigration(RegionStoreDriver driver, ProfileService profileService) {
public UUIDMigration(RegionDriver driver, ProfileService profileService) {
super(driver);
checkNotNull(profileService);
this.profileService = profileService;
}
@Override
protected void migrate(RegionStore store) throws MigrationException {
protected void migrate(RegionDatabase 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) {
} catch (StorageException e) {
throw new MigrationException("Failed to load region data for the world '" + store.getName() + "'", e);
}
@ -84,7 +85,7 @@ protected void migrate(RegionStore store) throws MigrationException {
try {
store.saveAll(regions);
} catch (IOException e) {
} catch (StorageException e) {
throw new MigrationException("Failed to save region data after migration of the world '" + store.getName() + "'", e);
}
}

View File

@ -22,7 +22,7 @@
/**
* Thrown when a partial save is not supported.
*/
public class DifferenceSaveException extends RegionStoreException {
public class DifferenceSaveException extends StorageException {
public DifferenceSaveException() {
}

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.driver;
package com.sk89q.worldguard.protection.managers.storage;
/**
* An enumeration of supported drivers.

View File

@ -22,15 +22,17 @@
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* A memory store that saves the memory to a temporary variable.
* A region database that saves the memory to an in-memory {@link HashSet}.
*
* <p>This implementation is thread-safe. Difference saves
* are not supported.</p>
*/
public class MemoryRegionStore implements RegionStore {
public class MemoryRegionDatabase implements RegionDatabase {
private Set<ProtectedRegion> regions = Collections.emptySet();
@ -40,17 +42,17 @@ public String getName() {
}
@Override
public Set<ProtectedRegion> loadAll() throws IOException {
public Set<ProtectedRegion> loadAll() {
return regions;
}
@Override
public void saveAll(Set<ProtectedRegion> regions) throws IOException {
public void saveAll(Set<ProtectedRegion> regions) {
this.regions = Collections.unmodifiableSet(new HashSet<ProtectedRegion>(regions));
}
@Override
public void saveChanges(RegionDifference difference) throws DifferenceSaveException, IOException {
public void saveChanges(RegionDifference difference) throws DifferenceSaveException {
throw new DifferenceSaveException();
}

View File

@ -22,13 +22,18 @@
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import java.io.IOException;
import java.util.Set;
/**
* An object that persists region data to a persistent store.
* A region database stores a set of regions for a single world.
*
* <p>If there are multiple worlds, then there should be one region database
* per world. To manage multiple region databases, consider using an
* implementation of a {@link RegionDriver}.</p>
*
* @see RegionDriver
*/
public interface RegionStore {
public interface RegionDatabase {
/**
* Get a displayable name for this store.
@ -48,18 +53,18 @@ public interface RegionStore {
* {@code get()} and {@code put()} calls in order to maximize performance.
* </p>
*
* @return a setf loaded regions
* @throws IOException thrown on read error
* @return a set of loaded regions
* @throws StorageException thrown on read error
*/
Set<ProtectedRegion> loadAll() throws IOException;
Set<ProtectedRegion> loadAll() throws StorageException;
/**
* Replace all the data in the store with the given collection of regions.
*
* @param regions a set of regions
* @throws IOException thrown on write error
* @throws StorageException thrown on write error
*/
void saveAll(Set<ProtectedRegion> regions) throws IOException;
void saveAll(Set<ProtectedRegion> regions) throws StorageException;
/**
* Perform a partial save that only commits changes, rather than the
@ -67,8 +72,8 @@ public interface RegionStore {
*
* @param difference the difference
* @throws DifferenceSaveException thrown if partial saves are not supported
* @throws IOException thrown on write error
* @throws StorageException thrown on write error
*/
void saveChanges(RegionDifference difference) throws DifferenceSaveException, IOException;
void saveChanges(RegionDifference difference) throws DifferenceSaveException, StorageException;
}

View File

@ -31,13 +31,16 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Utility methods for region stores.
* This class provides utility methods that may be helpful in the
* implementation of region databases.
*
* @see RegionDatabase
*/
public final class RegionStoreUtils {
public final class RegionDatabaseUtils {
private static final Logger log = Logger.getLogger(RegionStoreUtils.class.getCanonicalName());
private static final Logger log = Logger.getLogger(RegionDatabaseUtils.class.getCanonicalName());
private RegionStoreUtils() {
private RegionDatabaseUtils() {
}
/**
@ -59,14 +62,14 @@ public static void trySetFlagMap(ProtectedRegion region, Map<String, Object> fla
Object o = flagData.get(flag.getName());
if (o != null) {
RegionStoreUtils.trySetFlag(region, flag, o);
RegionDatabaseUtils.trySetFlag(region, flag, o);
}
// Set group
if (flag.getRegionGroupFlag() != null) {
Object o2 = flagData.get(flag.getRegionGroupFlag().getName());
if (o2 != null) {
RegionStoreUtils.trySetFlag(region, flag.getRegionGroupFlag(), o2);
RegionDatabaseUtils.trySetFlag(region, flag.getRegionGroupFlag(), o2);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.storage;
import java.util.List;
/**
* A driver manages {@link RegionDatabase}s for several worlds. An instance
* can return instances of a database for any given world.
*
* @see RegionDatabase
*/
public interface RegionDriver {
/**
* Get a region database for a world.
*
* <p>The given name should be a unique name for the world. Due to
* legacy reasons, there are no stipulations on the case sensitivity
* of the name. Historically, however, if the driver is a file-based
* driver, case-sensitivity will vary on whether the underlying
* filesystem is case-sensitive.</p>
*
* <p>This method should return quickly.</p>
*
* @param name the name of the world, which may be case sensitive
* @return the world
*/
RegionDatabase get(String name);
/**
* Fetch all the region databases that have been stored using this driver.
* Essentially, return a region database for all worlds that have had
* regions saved for it in the past.
*
* <p>As this may require a query to be performed, this method may block
* for a prolonged period of time.</p>
*
* @return a list of databases
* @throws StorageException thrown if the fetch operation fails
*/
List<RegionDatabase> getAll() throws StorageException;
}

View File

@ -22,20 +22,20 @@
/**
* Exceptions related to region stores inherit from this exception.
*/
public class RegionStoreException extends Exception {
public class StorageException extends Exception {
public RegionStoreException() {
public StorageException() {
}
public RegionStoreException(String message) {
public StorageException(String message) {
super(message);
}
public RegionStoreException(String message, Throwable cause) {
public StorageException(String message, Throwable cause) {
super(message, cause);
}
public RegionStoreException(Throwable cause) {
public StorageException(Throwable cause) {
super(cause);
}

View File

@ -1,49 +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.managers.storage.driver;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import java.io.IOException;
import java.util.List;
/**
* A driver is able to create new {@code RegionStore}s for named worlds.
*/
public interface RegionStoreDriver {
/**
* Get a region store for the named world.
*
* @param name the name
* @return the world
* @throws IOException thrown if the region store can't be created due to an I/O error
*/
RegionStore get(String name) throws IOException;
/**
* Fetch the names of all worlds that are stored with this driver.
*
* @return a list of names
* @throws IOException thrown if the fetch operation fails
*/
List<RegionStore> getAll() throws IOException;
}

View File

@ -1,101 +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.managers.storage.driver;
import com.jolbox.bonecp.BoneCP;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import com.sk89q.worldguard.protection.managers.storage.sql.SQLRegionStore;
import com.sk89q.worldguard.util.io.Closer;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores regions using {@link SQLRegionStore}.
*/
public class SQLDriver implements RegionStoreDriver {
private final DataSourceConfig config;
private final Object lock = new Object();
private BoneCP connectionPool;
/**
* Create a new instance.
*
* @param config a configuration
*/
public SQLDriver(DataSourceConfig config) {
checkNotNull(config);
this.config = config;
}
/**
* Get an instance of the connection pool.
*
* @return the connection pool
* @throws SQLException occurs when the connection pool can't be created
*/
protected BoneCP getConnectionPool() throws SQLException {
synchronized (lock) {
if (connectionPool == null) {
connectionPool = new BoneCP(config.createBoneCPConfig());
}
return connectionPool;
}
}
@Override
public RegionStore get(String name) throws IOException {
try {
return new SQLRegionStore(config, getConnectionPool(), name);
} catch (SQLException e) {
throw new IOException("Failed to get a connection pool for storing regions (are the SQL details correct? is the SQL server online?)");
}
}
@Override
public List<RegionStore> getAll() throws IOException {
Closer closer = Closer.create();
try {
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()) {
stores.add(get(rs.getString(1)));
}
return stores;
} catch (SQLException e) {
throw new IOException("Failed to fetch list of worlds", e);
} finally {
closer.close();
}
}
}

View File

@ -17,10 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.protection.managers.storage.driver;
package com.sk89q.worldguard.protection.managers.storage.file;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import com.sk89q.worldguard.protection.managers.storage.file.YamlFileStore;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import java.io.File;
import java.io.IOException;
@ -31,9 +32,9 @@
/**
* Stores region data in a {root_dir}/{id}/{filename} pattern on disk
* using {@link YamlFileStore}.
* using {@link YamlRegionFile}.
*/
public class DirectoryYamlDriver implements RegionStoreDriver {
public class DirectoryYamlDriver implements RegionDriver {
private final File rootDir;
private final String filename;
@ -70,29 +71,23 @@ private File getPath(String id) {
}
@Override
public RegionStore get(String id) throws IOException {
public RegionDatabase get(String id) {
checkNotNull(id);
File file = getPath(id);
File parentDir = file.getParentFile();
if (!parentDir.exists()) {
if (!parentDir.mkdirs()) {
throw new IOException("Failed to create the parent directory (" + parentDir.getAbsolutePath() + ") to store the regions file in");
}
}
return new YamlFileStore(id, file);
return new YamlRegionFile(id, file);
}
@Override
public List<RegionStore> getAll() throws IOException {
List<RegionStore> stores = new ArrayList<RegionStore>();
public List<RegionDatabase> getAll() throws StorageException {
List<RegionDatabase> stores = new ArrayList<RegionDatabase>();
File files[] = rootDir.listFiles();
if (files != null) {
for (File dir : files) {
if (dir.isDirectory() && new File(dir, "regions.yml").isFile()) {
stores.add(new YamlFileStore(dir.getName(), getPath(dir.getName())));
stores.add(new YamlRegionFile(dir.getName(), getPath(dir.getName())));
}
}
}

View File

@ -29,8 +29,9 @@
import com.sk89q.worldguard.protection.flags.Flag;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import com.sk89q.worldguard.protection.managers.storage.RegionStoreUtils;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
@ -61,9 +62,9 @@
/**
* A store that persists regions in a YAML-encoded file.
*/
public class YamlFileStore implements RegionStore {
public class YamlRegionFile implements RegionDatabase {
private static final Logger log = Logger.getLogger(YamlFileStore.class.getCanonicalName());
private static final Logger log = Logger.getLogger(YamlRegionFile.class.getCanonicalName());
private static final Yaml ERROR_DUMP_YAML;
private static final String FILE_HEADER = "#\r\n" +
@ -94,17 +95,12 @@ public class YamlFileStore implements RegionStore {
*
* @param name the name of this store
* @param file the file
* @throws IOException thrown if the file cannot be written to
*/
public YamlFileStore(String name, File file) throws IOException {
public YamlRegionFile(String name, File file) {
checkNotNull(name);
checkNotNull(file);
this.name = name;
this.file = file;
if (!file.exists()) {
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
}
}
@Override
@ -113,7 +109,7 @@ public String getName() {
}
@Override
public Set<ProtectedRegion> loadAll() throws IOException {
public Set<ProtectedRegion> loadAll() throws StorageException {
Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
YAMLProcessor config = createYamlProcessor(file);
@ -121,6 +117,8 @@ public Set<ProtectedRegion> loadAll() throws IOException {
config.load();
} catch (FileNotFoundException e) {
return new HashSet<ProtectedRegion>(loaded.values());
} catch (IOException e) {
throw new StorageException("Failed to load region data from '" + file + "'", e);
}
Map<String, YAMLNode> regionData = config.getNodes("regions");
@ -183,13 +181,13 @@ public Set<ProtectedRegion> loadAll() throws IOException {
}
// Relink parents
RegionStoreUtils.relinkParents(loaded, parentSets);
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<ProtectedRegion>(loaded.values());
}
@Override
public void saveAll(Set<ProtectedRegion> regions) throws IOException {
public void saveAll(Set<ProtectedRegion> regions) throws StorageException {
checkNotNull(regions);
File tempFile = new File(file.getParentFile(), file.getName() + ".tmp");
@ -248,7 +246,7 @@ public void saveAll(Set<ProtectedRegion> regions) throws IOException {
//noinspection ResultOfMethodCallIgnored
file.delete();
if (!tempFile.renameTo(file)) {
throw new IOException("Failed to rename temporary regions file to " + file.getAbsolutePath());
throw new StorageException("Failed to rename temporary regions file to " + file.getAbsolutePath());
}
}
@ -297,7 +295,7 @@ private Map<String, Object> getFlagData(ProtectedRegion region) {
private void setFlags(ProtectedRegion region, YAMLNode flagsData) {
if (flagsData != null) {
RegionStoreUtils.trySetFlagMap(region, flagsData.getMap());
RegionDatabaseUtils.trySetFlagMap(region, flagsData.getMap());
}
}

View File

@ -27,7 +27,7 @@
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.domains.DefaultDomain;
import com.sk89q.worldguard.protection.managers.storage.RegionStoreUtils;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabaseUtils;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
@ -62,9 +62,9 @@ class DataLoader {
private final Map<String, ProtectedRegion> loaded = new HashMap<String, ProtectedRegion>();
private final Map<ProtectedRegion, String> parentSets = new HashMap<ProtectedRegion, String>();
private final Yaml yaml = SQLRegionStore.createYaml();
private final Yaml yaml = SQLRegionDatabase.createYaml();
DataLoader(SQLRegionStore regionStore, Connection conn) throws SQLException {
DataLoader(SQLRegionDatabase regionStore, Connection conn) throws SQLException {
checkNotNull(regionStore);
this.conn = conn;
@ -81,7 +81,7 @@ public Set<ProtectedRegion> load() throws SQLException {
loadDomainUsers();
loadDomainGroups();
RegionStoreUtils.relinkParents(loaded, parentSets);
RegionDatabaseUtils.relinkParents(loaded, parentSets);
return new HashSet<ProtectedRegion>(loaded.values());
}
@ -238,7 +238,7 @@ private void loadFlags() throws SQLException {
for (Map.Entry<String, Map<String, Object>> entry : data.rowMap().entrySet()) {
ProtectedRegion region = loaded.get(entry.getKey());
if (region != null) {
RegionStoreUtils.trySetFlagMap(region, entry.getValue());
RegionDatabaseUtils.trySetFlagMap(region, entry.getValue());
} else {
throw new RuntimeException("An unexpected error occurred (loaded.get() returned null)");
}

View File

@ -43,7 +43,7 @@ class DataUpdater {
final int worldId;
final DomainTableCache domainTableCache;
DataUpdater(SQLRegionStore regionStore, Connection conn) throws SQLException {
DataUpdater(SQLRegionDatabase regionStore, Connection conn) throws SQLException {
checkNotNull(regionStore);
this.conn = conn;

View File

@ -86,7 +86,7 @@ private void insertRegionTypes() throws SQLException {
for (ProtectedRegion region : partition) {
stmt.setString(1, region.getId());
stmt.setInt(2, worldId);
stmt.setString(3, SQLRegionStore.getRegionTypeName(region));
stmt.setString(3, SQLRegionDatabase.getRegionTypeName(region));
stmt.setInt(4, region.getPriority());
stmt.addBatch();
}

View File

@ -54,7 +54,7 @@ class RegionUpdater {
private final Set<UUID> userUuids = new HashSet<UUID>();
private final Set<String> groupNames = new HashSet<String>();
private final Yaml yaml = SQLRegionStore.createYaml();
private final Yaml yaml = SQLRegionDatabase.createYaml();
private final List<ProtectedRegion> typesToUpdate = new ArrayList<ProtectedRegion>();
private final List<ProtectedRegion> parentsToSet = new ArrayList<ProtectedRegion>();
@ -308,7 +308,7 @@ private void updateRegionTypes() throws SQLException {
for (List<ProtectedRegion> partition : Lists.partition(typesToUpdate, StatementBatch.MAX_BATCH_SIZE)) {
for (ProtectedRegion region : partition) {
stmt.setString(1, SQLRegionStore.getRegionTypeName(region));
stmt.setString(1, SQLRegionDatabase.getRegionTypeName(region));
stmt.setInt(2, region.getPriority());
stmt.setString(3, region.getId());
stmt.addBatch();

View File

@ -0,0 +1,257 @@
/*
* 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.storage.sql;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.RegionDriver;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.util.io.Closer;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationVersion;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores regions using a JDBC connection with support for SQL.
*
* <p>Note, however, that this implementation <strong>only supports MySQL.
* </strong></p>
*/
public class SQLDriver implements RegionDriver {
private static final Logger log = Logger.getLogger(SQLDriver.class.getCanonicalName());
private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool();
private static final int CONNECTION_TIMEOUT = 6000;
private final DataSourceConfig config;
private boolean initialized = false;
/**
* Create a new instance.
*
* @param config a configuration
*/
public SQLDriver(DataSourceConfig config) {
checkNotNull(config);
this.config = config;
}
@Override
public RegionDatabase get(String name) {
return new SQLRegionDatabase(this, name);
}
@Override
public List<RegionDatabase> getAll() throws StorageException {
Closer closer = Closer.create();
try {
List<RegionDatabase> stores = new ArrayList<RegionDatabase>();
Connection connection = closer.register(getConnection());
Statement stmt = connection.createStatement();
ResultSet rs = closer.register(stmt.executeQuery("SELECT name FROM world"));
while (rs.next()) {
stores.add(get(rs.getString(1)));
}
return stores;
} catch (SQLException e) {
throw new StorageException("Failed to fetch list of worlds", e);
} finally {
closer.closeQuietly();
}
}
/**
* Perform initialization if it hasn't been (successfully) performed yet.
*
* @throws StorageException thrown on error
*/
synchronized void initialize() throws StorageException {
if (!initialized) {
try {
migrate();
} catch (SQLException e) {
throw new StorageException("Failed to migrate database tables", e);
}
initialized = true;
}
}
/**
* Attempt to migrate the tables to the latest version.
*
* @throws StorageException thrown if migration fails
* @throws SQLException thrown on SQL error
*/
private void migrate() throws SQLException, StorageException {
Closer closer = Closer.create();
Connection conn = closer.register(getConnection());
try {
// Check some tables
boolean tablesExist;
boolean isRecent;
boolean isBeforeMigrations;
boolean hasMigrations;
try {
tablesExist = tryQuery(conn, "SELECT * FROM " + config.getTablePrefix() + "region_cuboid LIMIT 1");
isRecent = tryQuery(conn, "SELECT world_id FROM " + config.getTablePrefix() + "region_cuboid LIMIT 1");
isBeforeMigrations = !tryQuery(conn, "SELECT uuid FROM " + config.getTablePrefix() + "user LIMIT 1");
hasMigrations = tryQuery(conn, "SELECT * FROM " + config.getTablePrefix() + "migrations LIMIT 1");
} finally {
closer.closeQuietly();
}
// We don't bother with migrating really old tables
if (tablesExist && !isRecent) {
throw new StorageException(
"Sorry, your tables are too old for the region SQL auto-migration system. " +
"Please run region_manual_update_20110325.sql on your database, which comes " +
"with WorldGuard or can be found in http://github.com/sk89q/worldguard");
}
// Our placeholders
Map<String, String> placeHolders = new HashMap<String, String>();
placeHolders.put("tablePrefix", config.getTablePrefix());
Flyway flyway = new Flyway();
// The SQL support predates the usage of Flyway, so let's do some
// checks and issue messages appropriately
if (!hasMigrations) {
flyway.setInitOnMigrate(true);
if (tablesExist) {
// Detect if this is before migrations
if (isBeforeMigrations) {
flyway.setInitVersion(MigrationVersion.fromVersion("1"));
}
log.log(Level.INFO, "The SQL region tables exist but the migrations table seems to not exist yet. Creating the migrations table...");
} else {
// By default, if Flyway sees any tables at all in the schema, it
// will assume that we are up to date, so we have to manually
// check ourselves and then ask Flyway to start from the beginning
// if our test table doesn't exist
flyway.setInitVersion(MigrationVersion.fromVersion("0"));
log.log(Level.INFO, "SQL region tables do not exist: creating...");
}
}
flyway.setClassLoader(getClass().getClassLoader());
flyway.setLocations("migrations/region/" + getMigrationFolderName());
flyway.setDataSource(config.getDsn(), config.getUsername(), config.getPassword());
flyway.setTable(config.getTablePrefix() + "migrations");
flyway.setPlaceholders(placeHolders);
flyway.setValidateOnMigrate(false);
flyway.migrate();
} catch (FlywayException e) {
throw new StorageException("Failed to migrate tables", e);
} finally {
closer.closeQuietly();
}
}
/**
* Get the name of the folder in migrations/region containing the migration files.
*
* @return the migration folder name
*/
public String getMigrationFolderName() {
return "mysql";
}
/**
* Try to execute a query and return true if it did not fail.
*
* @param conn the connection to run the query on
* @param sql the SQL query
* @return true if the query did not end in error
*/
private boolean tryQuery(Connection conn, String sql) {
Closer closer = Closer.create();
try {
Statement statement = closer.register(conn.createStatement());
statement.executeQuery(sql);
return true;
} catch (SQLException ex) {
return false;
} finally {
closer.closeQuietly();
}
}
/**
* Get the database configuration.
*
* @return the database configuration
*/
DataSourceConfig getConfig() {
return config;
}
/**
* Create a new connection.
*
* @return the connection
* @throws SQLException raised if the connection cannot be instantiated
*/
Connection getConnection() throws SQLException {
Future<Connection> future = EXECUTOR.submit(new Callable<Connection>() {
@Override
public Connection call() throws Exception {
return config.getConnection();
}
});
try {
return future.get(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new SQLException("Failed to get a SQL connection because the operation was interrupted", e);
} catch (ExecutionException e) {
throw new SQLException("Failed to get a SQL connection due to an error", e);
} catch (TimeoutException e) {
future.cancel(true);
throw new SQLException("Failed to get a SQL connection within the time limit");
}
}
}

View File

@ -0,0 +1,276 @@
/*
* 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.storage.sql;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionDatabase;
import com.sk89q.worldguard.protection.managers.storage.StorageException;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.io.Closer;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.representer.Representer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores region data into a SQL database in a highly normalized fashion.
*/
class SQLRegionDatabase implements RegionDatabase {
private final String worldName;
private final DataSourceConfig config;
private final SQLDriver driver;
private int worldId;
private boolean initialized = false;
/**
* Create a new instance.
*
* @param driver the driver instance
* @param worldName the name of the world to store regions by
*/
SQLRegionDatabase(SQLDriver driver, String worldName) {
checkNotNull(driver);
checkNotNull(worldName);
this.config = driver.getConfig();
this.worldName = worldName;
this.driver = driver;
}
@Override
public String getName() {
return worldName;
}
/**
* Initialize the database if it hasn't been yet initialized.
*
* @throws StorageException thrown if initialization fails
*/
private synchronized void initialize() throws StorageException {
if (!initialized) {
driver.initialize();
try {
worldId = chooseWorldId(worldName);
} catch (SQLException e) {
throw new StorageException("Failed to choose the ID for this world", e);
}
initialized = true;
}
}
/**
* Get the ID for this world from the database or pick a new one if
* an entry does not exist yet.
*
* @param worldName the world name
* @return a world ID
* @throws SQLException on a database access error
*/
private int chooseWorldId(String worldName) throws SQLException {
Closer closer = Closer.create();
try {
Connection conn = closer.register(getConnection());
PreparedStatement stmt = closer.register(conn.prepareStatement(
"SELECT id FROM " + config.getTablePrefix() + "world WHERE name = ? LIMIT 0, 1"));
stmt.setString(1, worldName);
ResultSet worldResult = closer.register(stmt.executeQuery());
if (worldResult.next()) {
return worldResult.getInt("id");
} else {
PreparedStatement stmt2 = closer.register(conn.prepareStatement(
"INSERT INTO " + config.getTablePrefix() + "world (id, name) VALUES (null, ?)",
Statement.RETURN_GENERATED_KEYS));
stmt2.setString(1, worldName);
stmt2.execute();
ResultSet generatedKeys = stmt2.getGeneratedKeys();
if (generatedKeys.next()) {
return generatedKeys.getInt(1);
} else {
throw new SQLException("Expected result, got none");
}
}
} finally {
closer.closeQuietly();
}
}
/**
* Return a new database connection.
*
* @return a connection
* @throws SQLException thrown if the connection could not be created
*/
private Connection getConnection() throws SQLException {
return driver.getConnection();
}
/**
* Get the data source config.
*
* @return the data source config
*/
public DataSourceConfig getDataSourceConfig() {
return config;
}
/**
* Get the world ID.
*
* @return the world ID
*/
public int getWorldId() {
return worldId;
}
/**
* Get the identifier string for a region's type.
*
* @param region the region
* @return the ID of the region type
*/
static String getRegionTypeName(ProtectedRegion region) {
if (region instanceof ProtectedCuboidRegion) {
return "cuboid";
} else if (region instanceof ProtectedPolygonalRegion) {
return "poly2d"; // Differs from getTypeName() on ProtectedRegion
} else if (region instanceof GlobalProtectedRegion) {
return "global";
} else {
throw new IllegalArgumentException("Unexpected region type: " + region.getClass().getName());
}
}
/**
* Create a YAML dumper / parser.
*
* @return a YAML dumper / parser
*/
static Yaml createYaml() {
DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setDefaultFlowStyle(FlowStyle.FLOW);
Representer representer = new Representer();
representer.setDefaultFlowStyle(FlowStyle.FLOW);
// We have to use this in order to properly save non-string values
return new Yaml(new SafeConstructor(), new Representer(), options);
}
@Override
public Set<ProtectedRegion> loadAll() throws StorageException {
initialize();
Closer closer = Closer.create();
DataLoader loader;
try {
try {
loader = new DataLoader(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new StorageException("Failed to get a connection to the database", e);
}
try {
return loader.load();
} catch (SQLException e) {
throw new StorageException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
@Override
public void saveAll(Set<ProtectedRegion> regions) throws StorageException {
checkNotNull(regions);
initialize();
Closer closer = Closer.create();
DataUpdater updater;
try {
try {
updater = new DataUpdater(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new StorageException("Failed to get a connection to the database", e);
}
try {
updater.saveAll(regions);
} catch (SQLException e) {
throw new StorageException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
@Override
public void saveChanges(RegionDifference difference) throws DifferenceSaveException, StorageException {
checkNotNull(difference);
initialize();
Closer closer = Closer.create();
DataUpdater updater;
try {
try {
updater = new DataUpdater(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new StorageException("Failed to get a connection to the database", e);
}
try {
updater.saveChanges(difference.getChanged(), difference.getRemoved());
} catch (SQLException e) {
throw new StorageException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
}

View File

@ -1,399 +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.managers.storage.sql;
import com.jolbox.bonecp.BoneCP;
import com.jolbox.bonecp.BoneCPConfig;
import com.sk89q.worldguard.protection.managers.RegionDifference;
import com.sk89q.worldguard.protection.managers.storage.DifferenceSaveException;
import com.sk89q.worldguard.protection.managers.storage.RegionStore;
import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.util.io.Closer;
import com.sk89q.worldguard.util.sql.DataSourceConfig;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationVersion;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import org.yaml.snakeyaml.representer.Representer;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Stores region data into a SQL database in a highly normalized fashion.
*/
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;
/**
* Create a new instance.
*
* @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
* @throws IOException thrown on error
*/
public SQLRegionStore(DataSourceConfig config, BoneCP connectionPool, String worldName) throws IOException {
checkNotNull(config);
checkNotNull(connectionPool);
checkNotNull(worldName);
this.name = worldName;
this.config = config;
this.connectionPool = connectionPool;
try {
migrate();
} catch (FlywayException e) {
throw new IOException("Failed to migrate tables", e);
} catch (SQLException e) {
throw new IOException("Failed to migrate tables", e);
}
try {
worldId = chooseWorldId(worldName);
} catch (SQLException e) {
throw new IOException("Failed to choose the ID for this world", e);
}
}
@Override
public String getName() {
return name;
}
/**
* Attempt to migrate the tables to the latest version.
*
* @throws SQLException thrown on SQL errors
*/
private void migrate() throws SQLException {
Closer closer = Closer.create();
Connection conn = closer.register(getConnection());
try {
// Check some tables
boolean tablesExist;
boolean isRecent;
boolean isBeforeMigrations;
boolean hasMigrations;
try {
tablesExist = tryQuery(conn, "SELECT * FROM " + config.getTablePrefix() + "region_cuboid LIMIT 1");
isRecent = tryQuery(conn, "SELECT world_id FROM " + config.getTablePrefix() + "region_cuboid LIMIT 1");
isBeforeMigrations = !tryQuery(conn, "SELECT uuid FROM " + config.getTablePrefix() + "user LIMIT 1");
hasMigrations = tryQuery(conn, "SELECT * FROM " + config.getTablePrefix() + "migrations LIMIT 1");
} finally {
closer.closeQuietly();
}
// We don't bother with migrating really old tables
if (tablesExist && !isRecent) {
throw new SQLException(
"Sorry, your tables are too old for the region SQL auto-migration system. " +
"Please run region_manual_update_20110325.sql on your database, which comes " +
"with WorldGuard or can be found in http://github.com/sk89q/worldguard");
}
// Our placeholders
Map<String, String> placeHolders = new HashMap<String, String>();
placeHolders.put("tablePrefix", config.getTablePrefix());
BoneCPConfig boneConfig = connectionPool.getConfig();
Flyway flyway = new Flyway();
// The SQL support predates the usage of Flyway, so let's do some
// checks and issue messages appropriately
if (!hasMigrations) {
flyway.setInitOnMigrate(true);
if (tablesExist) {
// Detect if this is before migrations
if (isBeforeMigrations) {
flyway.setInitVersion(MigrationVersion.fromVersion("1"));
}
log.log(Level.INFO, "The SQL region tables exist but the migrations table seems to not exist yet. Creating the migrations table...");
} else {
// By default, if Flyway sees any tables at all in the schema, it
// will assume that we are up to date, so we have to manually
// check ourselves and then ask Flyway to start from the beginning
// if our test table doesn't exist
flyway.setInitVersion(MigrationVersion.fromVersion("0"));
log.log(Level.INFO, "SQL region tables do not exist: creating...");
}
}
flyway.setClassLoader(getClass().getClassLoader());
flyway.setLocations("migrations/region/" + getMigrationFolderName());
flyway.setDataSource(boneConfig.getJdbcUrl(), boneConfig.getUser(), boneConfig.getPassword());
flyway.setTable(config.getTablePrefix() + "migrations");
flyway.setPlaceholders(placeHolders);
flyway.setValidateOnMigrate(false);
flyway.migrate();
} finally {
closer.closeQuietly();
}
}
/**
* Get the ID for this world from the database or pick a new one if
* an entry does not exist yet.
*
* @param worldName the world name
* @return a world ID
* @throws SQLException on a database access error
*/
private int chooseWorldId(String worldName) throws SQLException {
Closer closer = Closer.create();
try {
Connection conn = closer.register(getConnection());
PreparedStatement stmt = closer.register(conn.prepareStatement(
"SELECT id FROM " + config.getTablePrefix() + "world WHERE name = ? LIMIT 0, 1"));
stmt.setString(1, worldName);
ResultSet worldResult = closer.register(stmt.executeQuery());
if (worldResult.next()) {
return worldResult.getInt("id");
} else {
PreparedStatement stmt2 = closer.register(conn.prepareStatement(
"INSERT INTO " + config.getTablePrefix() + "world (id, name) VALUES (null, ?)",
Statement.RETURN_GENERATED_KEYS));
stmt2.setString(1, worldName);
stmt2.execute();
ResultSet generatedKeys = stmt2.getGeneratedKeys();
if (generatedKeys.next()) {
return generatedKeys.getInt(1);
} else {
throw new SQLException("Expected result, got none");
}
}
} finally {
closer.closeQuietly();
}
}
/**
* Return a new database connection.
*
* @return a connection
* @throws SQLException thrown if the connection could not be created
*/
private Connection getConnection() throws SQLException {
Future<Connection> future = connectionPool.getAsyncConnection();
try {
return future.get(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
future.cancel(true);
throw new SQLException("Failed to get connection -- interrupted");
} catch (ExecutionException e) {
future.cancel(true);
throw new SQLException("Failed to get connection; an error occurred", e);
} catch (TimeoutException e) {
future.cancel(true);
throw new SQLException("Failed to get connection; took too long to get a valid SQL connection (is the database server down?)");
}
}
/**
* Get the data source config.
*
* @return the data source config
*/
public DataSourceConfig getDataSourceConfig() {
return config;
}
/**
* Get the world ID.
*
* @return the world ID
*/
public int getWorldId() {
return worldId;
}
/**
* Try to execute a query and return true if it did not fail.
*
* @param conn the connection to run the query on
* @param sql the SQL query
* @return true if the query did not end in error
*/
private boolean tryQuery(Connection conn, String sql) {
Closer closer = Closer.create();
try {
Statement statement = closer.register(conn.createStatement());
statement.executeQuery(sql);
return true;
} catch (SQLException ex) {
return false;
} finally {
closer.closeQuietly();
}
}
/**
* Get the identifier string for a region's type.
*
* @param region the region
* @return the ID of the region type
*/
static String getRegionTypeName(ProtectedRegion region) {
if (region instanceof ProtectedCuboidRegion) {
return "cuboid";
} else if (region instanceof ProtectedPolygonalRegion) {
return "poly2d"; // Differs from getTypeName() on ProtectedRegion
} else if (region instanceof GlobalProtectedRegion) {
return "global";
} else {
throw new IllegalArgumentException("Unexpected region type: " + region.getClass().getName());
}
}
/**
* Create a YAML dumper / parser.
*
* @return a YAML dumper / parser
*/
static Yaml createYaml() {
DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setDefaultFlowStyle(FlowStyle.FLOW);
Representer representer = new Representer();
representer.setDefaultFlowStyle(FlowStyle.FLOW);
// We have to use this in order to properly save non-string values
return new Yaml(new SafeConstructor(), new Representer(), options);
}
/**
* Get the name of the folder in migrations/region containing the migration files.
*
* @return the migration folder name
*/
public String getMigrationFolderName() {
return "mysql";
}
@Override
public Set<ProtectedRegion> loadAll() throws IOException {
Closer closer = Closer.create();
DataLoader loader;
try {
try {
loader = new DataLoader(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new IOException("Failed to get a connection to the database", e);
}
try {
return loader.load();
} catch (SQLException e) {
throw new IOException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
@Override
public void saveAll(Set<ProtectedRegion> regions) throws IOException {
checkNotNull(regions);
Closer closer = Closer.create();
DataUpdater updater;
try {
try {
updater = new DataUpdater(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new IOException("Failed to get a connection to the database", e);
}
try {
updater.saveAll(regions);
} catch (SQLException e) {
throw new IOException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
@Override
public void saveChanges(RegionDifference difference) throws DifferenceSaveException, IOException {
checkNotNull(difference);
Closer closer = Closer.create();
DataUpdater updater;
try {
try {
updater = new DataUpdater(this, closer.register(getConnection()));
} catch (SQLException e) {
throw new IOException("Failed to get a connection to the database", e);
}
try {
updater.saveChanges(difference.getChanged(), difference.getRemoved());
} catch (SQLException e) {
throw new IOException("Failed to save the region data to the database", e);
}
} finally {
closer.closeQuietly();
}
}
}

View File

@ -19,7 +19,9 @@
package com.sk89q.worldguard.util.sql;
import com.jolbox.bonecp.BoneCPConfig;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static com.google.common.base.Preconditions.checkNotNull;
@ -130,16 +132,13 @@ public DataSourceConfig setTablePrefix(String tablePrefix) {
}
/**
* Create a new BoneCP configuration object.
* Create a new connection.
*
* @return a new configuration object
* @return the new connection
* @throws SQLException raised if the connection cannot be instantiated
*/
public BoneCPConfig createBoneCPConfig() {
BoneCPConfig config = new BoneCPConfig();
config.setJdbcUrl(dsn);
config.setUsername(username);
config.setPassword(password);
return config;
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(dsn, username, password);
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.HashMapIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class HashMapIndexPriorityTest extends RegionPriorityTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.HashMapIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class HashMapIndexRegionOverlapTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.HashMapIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class HashMapIndexTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new HashMapIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new HashMapIndex.Factory());
}
}

View File

@ -78,11 +78,11 @@ public ProtectedRegion add(int priority, ProtectedRegion parent)
}
public ApplicableRegionSet getApplicableSetInWilderness() {
return new ApplicableRegionSet(Collections.<ProtectedRegion>emptyList(), global);
return new RegionResultSet(Collections.<ProtectedRegion>emptyList(), global);
}
public ApplicableRegionSet getApplicableSet() {
return new ApplicableRegionSet(regions, global);
return new RegionResultSet(regions, global);
}
public FlagValueCalculator getFlagCalculator() {

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class PriorityRTreeIndexTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class PriorityRTreeRegionEntryExitTest extends RegionEntryExitTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class PriorityRTreeRegionOverlapTest extends RegionOverlapTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
}
}

View File

@ -21,13 +21,13 @@
import com.sk89q.worldguard.protection.managers.index.PriorityRTreeIndex;
import com.sk89q.worldguard.protection.managers.RegionManager;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionStore;
import com.sk89q.worldguard.protection.managers.storage.MemoryRegionDatabase;
public class PriorityRTreeRegionPriorityTest extends RegionPriorityTest {
@Override
protected RegionManager createRegionManager() throws Exception {
return new RegionManager(new MemoryRegionStore(), new PriorityRTreeIndex.Factory());
return new RegionManager(new MemoryRegionDatabase(), new PriorityRTreeIndex.Factory());
}
}