diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/WorldCalculator.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/WorldCalculator.java index fb025432..1ad58a80 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/WorldCalculator.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/WorldCalculator.java @@ -71,11 +71,11 @@ public class WorldCalculator extends ContextCalculator implements Listen private String getWorld(Player player) { UUID internal = plugin.getUuidCache().getUUID(player.getUniqueId()); - if (!worldCache.containsKey(internal)) { + String world = worldCache.get(internal); + if (world == null) { return null; } - String world = worldCache.get(internal); return plugin.getConfiguration().getWorldRewrites().getOrDefault(world, world); } diff --git a/common/src/main/java/me/lucko/luckperms/common/calculators/RegexProcessor.java b/common/src/main/java/me/lucko/luckperms/common/calculators/RegexProcessor.java index d5ad4ecb..aa21c5f7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/calculators/RegexProcessor.java +++ b/common/src/main/java/me/lucko/luckperms/common/calculators/RegexProcessor.java @@ -39,15 +39,17 @@ public class RegexProcessor implements PermissionProcessor { @Override public Tristate hasPermission(String permission) { for (Map.Entry e : map.entrySet()) { - if (e.getKey().toLowerCase().startsWith("r=")) { - Pattern p = Patterns.compile(e.getKey().substring(2)); - if (p == null) { - continue; - } + if (!e.getKey().startsWith("r=") && !e.getKey().startsWith("R=")) { + continue; + } - if (p.matcher(permission).matches()) { - return Tristate.fromBoolean(e.getValue()); - } + Pattern p = Patterns.compile(e.getKey().substring(2)); + if (p == null) { + continue; + } + + if (p.matcher(permission).matches()) { + return Tristate.fromBoolean(e.getValue()); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/constants/Patterns.java b/common/src/main/java/me/lucko/luckperms/common/constants/Patterns.java index fa9edb93..95c7e88d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/constants/Patterns.java +++ b/common/src/main/java/me/lucko/luckperms/common/constants/Patterns.java @@ -22,16 +22,30 @@ package me.lucko.luckperms.common.constants; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import lombok.experimental.UtilityClass; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; @UtilityClass public class Patterns { - private static final Map CACHE = new ConcurrentHashMap<>(); + private static final LoadingCache CACHE = CacheBuilder.newBuilder() + .build(new CacheLoader() { + @Override + public Pattern load(String s) throws Exception { + return Pattern.compile(s); + } + + @Override + public ListenableFuture reload(String s, Pattern pattern) { + return Futures.immediateFuture(pattern); + } + }); public static final Pattern COMMAND_SEPARATOR = Pattern.compile(" (?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)"); public static final Pattern NON_ALPHA_NUMERIC = Pattern.compile("[\\/\\$\\.\\- ]"); @@ -42,14 +56,8 @@ public class Patterns { public static Pattern compile(String regex) { try { - return CACHE.computeIfAbsent(regex, s -> { - try { - return Pattern.compile(regex); - } catch (PatternSyntaxException e) { - return null; - } - }); - } catch (NullPointerException e) { + return CACHE.get(regex); + } catch (ExecutionException e) { return null; } } diff --git a/common/src/main/java/me/lucko/luckperms/common/users/User.java b/common/src/main/java/me/lucko/luckperms/common/users/User.java index 55b88d77..51397101 100644 --- a/common/src/main/java/me/lucko/luckperms/common/users/User.java +++ b/common/src/main/java/me/lucko/luckperms/common/users/User.java @@ -112,10 +112,7 @@ public class User extends PermissionHolder implements Identifiable the class this manager is "managing" */ public abstract class AbstractManager> implements Function { - private final Map objects = new HashMap<>(); + + private final LoadingCache objects = CacheBuilder.newBuilder() + .removalListener((RemovalListener) removal -> preUnload(removal.getValue())) + .build(new CacheLoader() { + @Override + public T load(I i) { + return apply(i); + } + + @Override + public ListenableFuture reload(I i, T t) { + return Futures.immediateFuture(t); // Never needs to be refreshed. + } + }); public final Map getAll() { - Map map; - synchronized (objects) { - map = ImmutableMap.copyOf(objects); - } - return map; + return ImmutableMap.copyOf(objects.asMap()); } /** @@ -50,9 +64,7 @@ public abstract class AbstractManager> implements F * @return a {@link T} object if the object is loaded or makes and returns a new object */ public final T getOrMake(I id) { - synchronized (objects) { - return objects.computeIfAbsent(id, this); - } + return objects.getUnchecked(id); } /** @@ -61,9 +73,7 @@ public abstract class AbstractManager> implements F * @return a {@link T} object if the object is loaded, returns null if the object is not loaded */ public final T get(I id) { - synchronized (objects) { - return objects.get(id); - } + return objects.asMap().get(id); } /** @@ -72,9 +82,7 @@ public abstract class AbstractManager> implements F * @return true if the object is loaded */ public final boolean isLoaded(I id) { - synchronized (objects) { - return objects.containsKey(id); - } + return objects.asMap().containsKey(id); } /** @@ -83,12 +91,7 @@ public abstract class AbstractManager> implements F */ public final void unload(T t) { if (t != null) { - synchronized (objects) { - objects.computeIfPresent(t.getId(), (i, t1) -> { - preUnload(t1); - return null; - }); - } + objects.invalidate(t); } } @@ -100,10 +103,7 @@ public abstract class AbstractManager> implements F * Unloads all objects from the manager */ public final void unloadAll() { - synchronized (objects) { - objects.values().forEach(this::preUnload); - objects.clear(); - } + objects.invalidateAll(); } }