Refactor PermissionHolder & Sponge subjects

This commit is contained in:
Luck
2016-10-02 15:05:53 +01:00
Unverified
parent 18e126b781
commit 1b3b50c113
15 changed files with 875 additions and 904 deletions
@@ -39,7 +39,7 @@ import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
/**
* Provides a link between {@link PermissionHolder} and {@link me.lucko.luckperms.core.PermissionHolder}
*/
@SuppressWarnings({"unused", "deprecation"})
@SuppressWarnings("unused")
@AllArgsConstructor
public class PermissionHolderLink implements PermissionHolder {
@@ -58,12 +58,12 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Set<Node> getEnduringPermissions() {
return Collections.unmodifiableSet(master.getNodes());
return master.getNodes();
}
@Override
public Set<Node> getTransientPermissions() {
return Collections.unmodifiableSet(master.getTransientNodes());
return master.getTransientNodes();
}
@Override
@@ -233,22 +233,36 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, world, excludedGroups, possibleNodes);
Map<String, String> context = new HashMap<>();
if (server != null && !server.equals("")) {
context.put("server", server);
}
if (world != null && !world.equals("")) {
context.put("world", world);
}
return master.exportNodes(new Contexts(context, true, true, true, true, true), Collections.emptyList(), false);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return master.getLocalPermissions(server, world, excludedGroups);
Map<String, String> context = new HashMap<>();
if (server != null && !server.equals("")) {
context.put("server", server);
}
if (world != null && !world.equals("")) {
context.put("world", world);
}
return master.exportNodes(new Contexts(context, true, true, true, true, true), Collections.emptyList(), false);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, excludedGroups, possibleNodes);
return getLocalPermissions(server, null, excludedGroups, possibleNodes);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return master.getLocalPermissions(server, excludedGroups);
return getLocalPermissions(server, null, excludedGroups, null);
}
@Override
@@ -27,6 +27,8 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import java.util.HashSet;
@@ -55,6 +57,7 @@ public class GroupBulkChange extends SubCommand<Group> {
}
Set<Node> toAdd = new HashSet<>();
Set<Node> toRemove = new HashSet<>();
if (!type.equals("world") && !type.equals("server")) {
Message.BULK_CHANGE_TYPE_ERROR.send(sender);
@@ -70,7 +73,7 @@ public class GroupBulkChange extends SubCommand<Group> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setWorld(to).build());
}
} else {
@@ -81,12 +84,23 @@ public class GroupBulkChange extends SubCommand<Group> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setServer(to).build());
}
}
group.getNodes().addAll(toAdd);
toRemove.forEach(n -> {
try {
group.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
toAdd.forEach(n -> {
try {
group.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
});
save(group, sender, plugin);
Message.BULK_CHANGE_SUCCESS.send(sender, toAdd.size());
return CommandResult.SUCCESS;
@@ -27,6 +27,8 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.users.User;
import java.util.HashSet;
@@ -55,6 +57,7 @@ public class UserBulkChange extends SubCommand<User> {
}
Set<Node> toAdd = new HashSet<>();
Set<Node> toRemove = new HashSet<>();
if (!type.equals("world") && !type.equals("server")) {
Message.BULK_CHANGE_TYPE_ERROR.send(sender);
@@ -75,7 +78,7 @@ public class UserBulkChange extends SubCommand<User> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setWorld(to).build());
}
} else {
@@ -91,12 +94,23 @@ public class UserBulkChange extends SubCommand<User> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setServer(to).build());
}
}
user.getNodes().addAll(toAdd);
toRemove.forEach(n -> {
try {
user.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
toAdd.forEach(n -> {
try {
user.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
});
save(user, sender, plugin);
Message.BULK_CHANGE_SUCCESS.send(sender, toAdd.size());
return CommandResult.SUCCESS;
@@ -27,6 +27,8 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.users.User;
@@ -70,6 +72,7 @@ public class BulkEditGroup extends SubCommand<Datastore> {
}
Set<Node> toAdd = new HashSet<>();
Set<Node> toRemove = new HashSet<>();
Iterator<Node> iterator = user.getNodes().iterator();
if (type.equals("world")) {
while (iterator.hasNext()) {
@@ -92,7 +95,7 @@ public class BulkEditGroup extends SubCommand<Datastore> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setWorld(to).build());
}
} else {
@@ -116,12 +119,23 @@ public class BulkEditGroup extends SubCommand<Datastore> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setServer(to).build());
}
}
user.getNodes().addAll(toAdd);
toRemove.forEach(n -> {
try {
user.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
toAdd.forEach(n -> {
try {
user.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
});
plugin.getUserManager().cleanup(user);
plugin.getDatastore().saveUser(user);
}
@@ -27,6 +27,8 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.storage.Datastore;
import me.lucko.luckperms.users.User;
@@ -69,6 +71,7 @@ public class BulkEditPermission extends SubCommand<Datastore> {
}
Set<Node> toAdd = new HashSet<>();
Set<Node> toRemove = new HashSet<>();
Iterator<Node> iterator = user.getNodes().iterator();
if (type.equals("world")) {
while (iterator.hasNext()) {
@@ -87,7 +90,7 @@ public class BulkEditPermission extends SubCommand<Datastore> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setWorld(to).build());
}
} else {
@@ -107,12 +110,23 @@ public class BulkEditPermission extends SubCommand<Datastore> {
continue;
}
iterator.remove();
toRemove.add(element);
toAdd.add(me.lucko.luckperms.core.Node.builderFromExisting(element).setServer(to).build());
}
}
user.getNodes().addAll(toAdd);
toRemove.forEach(n -> {
try {
user.unsetPermission(n);
} catch (ObjectLacksException ignored) {}
});
toAdd.forEach(n -> {
try {
user.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {}
});
plugin.getUserManager().cleanup(user);
plugin.getDatastore().saveUser(user);
}
@@ -22,6 +22,8 @@
package me.lucko.luckperms.core;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@@ -37,11 +39,13 @@ import me.lucko.luckperms.contexts.Contexts;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Cache;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
@@ -64,46 +68,138 @@ public abstract class PermissionHolder {
@Getter(AccessLevel.PROTECTED)
private final LuckPermsPlugin plugin;
/**
* The user/group's permissions
*/
@Getter
private Set<Node> nodes = ConcurrentHashMap.newKeySet();
private final Set<Node> nodes = new HashSet<>();
private final Set<Node> transientNodes = new HashSet<>();
/**
* The user/group's transient permissions
*/
@Getter
private Set<Node> transientNodes = ConcurrentHashMap.newKeySet();
private Cache<SortedSet<LocalizedNode>> cache = new Cache<>();
private Cache<SortedSet<LocalizedNode>> mergedCache = new Cache<>();
private Cache<ImmutableSet<Node>> enduringCache = new Cache<>();
private Cache<ImmutableSet<Node>> transientCache = new Cache<>();
@Getter
private final Lock ioLock = new ReentrantLock();
private void invalidateCache(boolean enduring) {
if (enduring) {
enduringCache.invalidate();
} else {
transientCache.invalidate();
}
cache.invalidate();
mergedCache.invalidate();
}
public Set<Node> getNodes() {
synchronized (nodes) {
return enduringCache.get(() -> ImmutableSet.copyOf(nodes));
}
}
public Set<Node> getTransientNodes() {
synchronized (transientNodes) {
return transientCache.get(() -> ImmutableSet.copyOf(transientNodes));
}
}
public void setNodes(Set<Node> nodes) {
synchronized (this.nodes) {
if (!this.nodes.equals(nodes)) {
invalidateCache(true);
}
this.nodes.clear();
this.nodes.addAll(nodes);
}
auditTemporaryPermissions();
}
public void setTransientNodes(Set<Node> nodes) {
synchronized (this.transientNodes) {
if (!this.transientNodes.equals(nodes)) {
invalidateCache(false);
}
this.transientNodes.clear();
this.transientNodes.addAll(nodes);
}
auditTemporaryPermissions();
}
@Deprecated
public void setNodes(Map<String, Boolean> nodes) {
synchronized (this.nodes) {
if (!this.nodes.equals(nodes)) {
invalidateCache(true);
}
this.nodes.clear();
this.nodes.addAll(nodes.entrySet().stream()
.map(e -> me.lucko.luckperms.core.Node.fromSerialisedNode(e.getKey(), e.getValue()))
.collect(Collectors.toList()));
}
auditTemporaryPermissions();
}
public void addNodeUnchecked(Node node) {
synchronized (nodes) {
nodes.add(node);
invalidateCache(true);
}
}
/**
* Returns a Set of nodes in priority order
* Clear all of the holders permission nodes
*/
public void clearNodes() {
synchronized (nodes) {
nodes.clear();
invalidateCache(true);
}
}
public void clearTransientNodes() {
synchronized (transientNodes) {
transientNodes.clear();
invalidateCache(false);
}
}
/**
* Combines and returns this holders nodes in a priority order.
* @return the holders transient and permanent nodes
*/
public SortedSet<LocalizedNode> getPermissions(boolean mergeTemp) {
// Returns no duplicate nodes. as in, nodes with the same value.
Supplier<SortedSet<LocalizedNode>> supplier = () -> {
TreeSet<LocalizedNode> combined = new TreeSet<>(PriorityComparator.reverse());
TreeSet<LocalizedNode> combined = new TreeSet<>(PriorityComparator.reverse());
nodes.stream().map(n -> LocalizedNode.of(n, getObjectName())).forEach(combined::add);
transientNodes.stream().map(n -> LocalizedNode.of(n, getObjectName())).forEach(combined::add);
getNodes().stream()
.map(n -> LocalizedNode.of(n, getObjectName()))
.forEach(combined::add);
TreeSet<LocalizedNode> permissions = new TreeSet<>(PriorityComparator.reverse());
getTransientNodes().stream()
.map(n -> LocalizedNode.of(n, getObjectName()))
.forEach(combined::add);
combined:
for (LocalizedNode node : combined) {
for (LocalizedNode other : permissions) {
if (mergeTemp ? node.getNode().equalsIgnoringValueOrTemp(other.getNode()) : node.getNode().almostEquals(other.getNode())) {
continue combined;
TreeSet<LocalizedNode> permissions = new TreeSet<>(PriorityComparator.reverse());
combined:
for (LocalizedNode node : combined) {
for (LocalizedNode other : permissions) {
if (mergeTemp ? node.getNode().equalsIgnoringValueOrTemp(other.getNode()) : node.getNode().almostEquals(other.getNode())) {
continue combined;
}
}
permissions.add(node);
}
permissions.add(node);
}
return permissions;
};
return permissions;
return mergeTemp ? mergedCache.get(supplier) : cache.get(supplier);
}
/**
@@ -111,33 +207,44 @@ public abstract class PermissionHolder {
* @return true if permissions had expired and were removed
*/
public boolean auditTemporaryPermissions() {
final boolean[] work = {false};
boolean work = false;
final PermissionHolder instance = this;
nodes.removeIf(node -> {
if (node.hasExpired()) {
work[0] = true;
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(instance), node));
return true;
synchronized (nodes) {
boolean w = nodes.removeIf(node -> {
if (node.hasExpired()) {
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(instance), node));
return true;
}
return false;
});
if (w) {
invalidateCache(true);
work = true;
}
return false;
});
}
transientNodes.removeIf(node -> {
if (node.hasExpired()) {
work[0] = true;
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(instance), node));
return true;
synchronized (transientNodes) {
boolean w = transientNodes.removeIf(node -> {
if (node.hasExpired()) {
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(instance), node));
return true;
}
return false;
});
if (w) {
invalidateCache(false);
work = true;
}
return false;
});
}
return work[0];
return work;
}
/**
* Gets all of the nodes that this holder has and inherits
* Resolves inherited nodes and returns them
* @param excludedGroups a list of groups to exclude
* @param context context to decide if groups should be applied
* @return a set of nodes
*/
public SortedSet<LocalizedNode> getAllNodes(List<String> excludedGroups, Contexts context) {
@@ -197,7 +304,6 @@ public abstract class PermissionHolder {
* @return a map of permissions
*/
public Set<LocalizedNode> getAllNodesFiltered(Contexts context) {
Set<LocalizedNode> perms = ConcurrentHashMap.newKeySet();
SortedSet<LocalizedNode> allNodes;
if (context.isApplyGroups()) {
@@ -212,24 +318,19 @@ public abstract class PermissionHolder {
contexts.remove("server");
contexts.remove("world");
allNodes.removeIf(node ->
!node.shouldApplyOnServer(server, context.isIncludeGlobal(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyOnWorld(world, context.isIncludeGlobalWorld(), plugin.getConfiguration().isApplyingRegex()) ||
!node.shouldApplyWithContext(contexts, false)
);
Set<LocalizedNode> perms = ConcurrentHashMap.newKeySet();
all:
for (LocalizedNode ln : allNodes) {
Node node = ln.getNode();
if (!node.shouldApplyOnServer(server, context.isIncludeGlobal(), plugin.getConfiguration().isApplyingRegex())) {
continue;
}
if (!node.shouldApplyOnWorld(world, context.isIncludeGlobalWorld(), plugin.getConfiguration().isApplyingRegex())) {
continue;
}
if (!node.shouldApplyWithContext(contexts, false)) {
continue;
}
// Force higher priority nodes to override
for (LocalizedNode alreadyIn : perms) {
if (node.getPermission().equals(alreadyIn.getNode().getPermission())) {
if (ln.getNode().getPermission().equals(alreadyIn.getNode().getPermission())) {
continue all;
}
}
@@ -278,43 +379,7 @@ public abstract class PermissionHolder {
}
}
return Collections.unmodifiableMap(perms);
}
public void setNodes(Set<Node> nodes) {
this.nodes.clear();
this.nodes.addAll(nodes);
auditTemporaryPermissions();
}
public void setTransiestNodes(Set<Node> nodes) {
this.transientNodes.clear();
this.transientNodes.addAll(nodes);
auditTemporaryPermissions();
}
public static Map<String, Boolean> exportToLegacy(Set<Node> nodes) {
Map<String, Boolean> m = new HashMap<>();
for (Node node : nodes) {
m.put(node.toSerializedNode(), node.getValue());
}
return Collections.unmodifiableMap(m);
}
// Convenience method
private static Node.Builder buildNode(String permission) {
return new me.lucko.luckperms.core.Node.Builder(permission);
}
@Deprecated
public void setNodes(Map<String, Boolean> nodes) {
this.nodes.clear();
this.nodes.addAll(nodes.entrySet().stream()
.map(e -> me.lucko.luckperms.core.Node.fromSerialisedNode(e.getKey(), e.getValue()))
.collect(Collectors.toList()));
auditTemporaryPermissions();
return ImmutableMap.copyOf(perms);
}
/**
@@ -324,7 +389,7 @@ public abstract class PermissionHolder {
* @return a tristate
*/
public Tristate hasPermission(Node node, boolean t) {
for (Node n : t ? transientNodes : nodes) {
for (Node n : t ? getTransientNodes() : getNodes()) {
if (n.almostEquals(node)) {
return n.getTristate();
}
@@ -419,7 +484,11 @@ public abstract class PermissionHolder {
throw new ObjectAlreadyHasException();
}
nodes.add(node);
synchronized (nodes) {
nodes.add(node);
invalidateCache(true);
}
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
}
@@ -433,7 +502,11 @@ public abstract class PermissionHolder {
throw new ObjectAlreadyHasException();
}
transientNodes.add(node);
synchronized (transientNodes) {
transientNodes.add(node);
invalidateCache(false);
}
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
}
@@ -471,7 +544,10 @@ public abstract class PermissionHolder {
throw new ObjectLacksException();
}
nodes.removeIf(e -> e.almostEquals(node));
synchronized (nodes) {
nodes.removeIf(e -> e.almostEquals(node));
invalidateCache(true);
}
if (node.isGroupNode()) {
plugin.getApiProvider().fireEventAsync(new GroupRemoveEvent(new PermissionHolderLink(this),
@@ -491,7 +567,10 @@ public abstract class PermissionHolder {
throw new ObjectLacksException();
}
transientNodes.removeIf(e -> e.almostEquals(node));
synchronized (transientNodes) {
transientNodes.removeIf(e -> e.almostEquals(node));
invalidateCache(false);
}
if (node.isGroupNode()) {
plugin.getApiProvider().fireEventAsync(new GroupRemoveEvent(new PermissionHolderLink(this),
@@ -578,43 +657,15 @@ public abstract class PermissionHolder {
.collect(Collectors.toList());
}
/*
* Don't use these methods, only here for compat reasons
*/
@Deprecated
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
Map<String, String> context = new HashMap<>();
if (server != null && !server.equals("")) {
context.put("server", server);
public static Map<String, Boolean> exportToLegacy(Set<Node> nodes) {
ImmutableMap.Builder<String, Boolean> m = ImmutableMap.builder();
for (Node node : nodes) {
m.put(node.toSerializedNode(), node.getValue());
}
if (world != null && !world.equals("")) {
context.put("world", world);
}
return exportNodes(new Contexts(context, plugin.getConfiguration().isIncludingGlobalPerms(), true, true, true, true), Collections.emptyList(), false);
return m.build();
}
@Deprecated
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
Map<String, String> context = new HashMap<>();
if (server != null && !server.equals("")) {
context.put("server", server);
}
if (world != null && !world.equals("")) {
context.put("world", world);
}
return exportNodes(new Contexts(context, plugin.getConfiguration().isIncludingGlobalPerms(), true, true, true, true), Collections.emptyList(), false);
}
@SuppressWarnings("deprecation")
@Deprecated
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return getLocalPermissions(server, null, excludedGroups, possibleNodes);
}
@SuppressWarnings("deprecation")
@Deprecated
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return getLocalPermissions(server, null, excludedGroups, null);
private static Node.Builder buildNode(String permission) {
return new me.lucko.luckperms.core.Node.Builder(permission);
}
}
@@ -248,11 +248,4 @@ public class Group extends PermissionHolder implements Identifiable<String> {
public void unsetInheritGroup(Group group, String server, String world, boolean temporary) throws ObjectLacksException {
unsetPermission("group." + group.getName(), server, world, temporary);
}
/**
* Clear all of the groups permission nodes
*/
public void clearNodes() {
getNodes().clear();
}
}
@@ -79,6 +79,7 @@ public class JSONDatastore extends FlatfileDatastore {
public boolean loadUser(UUID uuid, String username) {
User user = plugin.getUserManager().getOrMake(UserIdentifier.of(uuid, username));
user.getIoLock().lock();
plugin.getLog().info("#loadUser for: " + user.getName());
try {
return call(() -> {
File userFile = new File(usersDir, uuid.toString() + ".json");
@@ -96,7 +97,7 @@ public class JSONDatastore extends FlatfileDatastore {
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
user.getNodes().add(Node.fromSerialisedNode(node, b));
user.addNodeUnchecked(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
@@ -139,6 +140,7 @@ public class JSONDatastore extends FlatfileDatastore {
}
}, false);
} finally {
plugin.getLog().info("#loadUser finished for: " + user.getName());
user.getIoLock().unlock();
}
}
@@ -146,6 +148,7 @@ public class JSONDatastore extends FlatfileDatastore {
@Override
public boolean saveUser(User user) {
user.getIoLock().lock();
plugin.getLog().info("#saveUser for: " + user.getName());
try {
return call(() -> {
File userFile = new File(usersDir, user.getUuid().toString() + ".json");
@@ -173,6 +176,7 @@ public class JSONDatastore extends FlatfileDatastore {
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
plugin.getLog().info("entry: " + e.toString());
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
@@ -181,6 +185,7 @@ public class JSONDatastore extends FlatfileDatastore {
});
}, false);
} finally {
plugin.getLog().info("#saveUser ended for: " + user.getName());
user.getIoLock().unlock();
}
}
@@ -257,7 +262,7 @@ public class JSONDatastore extends FlatfileDatastore {
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.getNodes().add(Node.fromSerialisedNode(node, b));
group.addNodeUnchecked(Node.fromSerialisedNode(node, b));
}
reader.endObject();
@@ -307,7 +312,7 @@ public class JSONDatastore extends FlatfileDatastore {
while (reader.hasNext()) {
String node = reader.nextName();
boolean b = reader.nextBoolean();
group.getNodes().add(Node.fromSerialisedNode(node, b));
group.addNodeUnchecked(Node.fromSerialisedNode(node, b));
}
reader.endObject();
reader.endObject();
@@ -92,7 +92,7 @@ public class YAMLDatastore extends FlatfileDatastore {
user.setPrimaryGroup((String) values.get("primary-group"));
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
user.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
user.addNodeUnchecked(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false);
@@ -214,7 +214,7 @@ public class YAMLDatastore extends FlatfileDatastore {
return doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
group.addNodeUnchecked(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
return true;
});
@@ -247,7 +247,7 @@ public class YAMLDatastore extends FlatfileDatastore {
return groupFile.exists() && doRead(groupFile, values -> {
Map<String, Boolean> perms = (Map<String, Boolean>) values.get("perms");
for (Map.Entry<String, Boolean> e : perms.entrySet()) {
group.getNodes().add(Node.fromSerialisedNode(e.getKey(), e.getValue()));
group.addNodeUnchecked(Node.fromSerialisedNode(e.getKey(), e.getValue()));
}
return true;
});
@@ -249,8 +249,9 @@ public abstract class User extends PermissionHolder implements Identifiable<User
/**
* Clear all of the users permission nodes
*/
@Override
public void clearNodes() {
getNodes().clear();
super.clearNodes();
getPlugin().getUserManager().giveDefaultIfNeeded(this, false);
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.utils;
import java.util.function.Supplier;
public class Cache<T> {
private T t = null;
public T get(Supplier<T> supplier) {
synchronized (this) {
if (t == null) {
t = supplier.get();
}
return t;
}
}
public void invalidate() {
synchronized (this) {
t = null;
}
}
}