From 7ae532f082f322e69cfffafa6b625581bd33b41f Mon Sep 17 00:00:00 2001 From: Luck Date: Thu, 7 May 2020 03:46:22 +0100 Subject: [PATCH] Add UserManager/GroupManager searchAll method --- .../java/net/luckperms/api/LuckPerms.java | 9 + .../api/model/group/GroupManager.java | 16 ++ .../luckperms/api/model/user/UserManager.java | 16 ++ .../java/net/luckperms/api/node/HeldNode.java | 1 + .../api/node/matcher/NodeMatcher.java | 146 ++++++++++++++++ .../api/node/matcher/NodeMatcherFactory.java | 120 +++++++++++++ .../common/api/LuckPermsApiProvider.java | 7 + .../api/implementation/ApiGroupManager.java | 29 +++- .../implementation/ApiNodeMatcherFactory.java | 83 +++++++++ .../api/implementation/ApiUserManager.java | 29 +++- .../comparison/StandardComparison.java | 7 +- .../commands/group/GroupListMembers.java | 28 ++-- .../common/commands/misc/SearchCommand.java | 28 ++-- .../{node => }/model/InheritanceOrigin.java | 2 +- .../lucko/luckperms/common/model/NodeMap.java | 1 - ...mparator.java => NodeEntryComparator.java} | 14 +- .../node/matcher/ConstraintNodeMatcher.java | 60 +++++++ .../node/matcher/StandardNodeMatchers.java | 157 ++++++++++++++++++ .../luckperms/common/storage/Storage.java | 13 +- .../implementation/StorageImplementation.java | 9 +- .../file/CombinedConfigurateStorage.java | 25 ++- .../file/SeparatedConfigurateStorage.java | 25 ++- .../implementation/mongodb/MongoStorage.java | 25 ++- .../implementation/split/SplitStorage.java | 9 +- .../implementation/sql/SqlStorage.java | 29 ++-- .../misc/NodeEntry.java} | 26 +-- .../model/manager/SpongeGroupManager.java | 14 +- .../model/manager/SpongeUserManager.java | 14 +- 28 files changed, 807 insertions(+), 135 deletions(-) create mode 100644 api/src/main/java/net/luckperms/api/node/matcher/NodeMatcher.java create mode 100644 api/src/main/java/net/luckperms/api/node/matcher/NodeMatcherFactory.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiNodeMatcherFactory.java rename common/src/main/java/me/lucko/luckperms/common/{node => }/model/InheritanceOrigin.java (97%) rename common/src/main/java/me/lucko/luckperms/common/node/comparator/{HeldNodeComparator.java => NodeEntryComparator.java} (75%) create mode 100644 common/src/main/java/me/lucko/luckperms/common/node/matcher/ConstraintNodeMatcher.java create mode 100644 common/src/main/java/me/lucko/luckperms/common/node/matcher/StandardNodeMatchers.java rename common/src/main/java/me/lucko/luckperms/common/{node/model/HeldNodeImpl.java => storage/misc/NodeEntry.java} (77%) diff --git a/api/src/main/java/net/luckperms/api/LuckPerms.java b/api/src/main/java/net/luckperms/api/LuckPerms.java index 26d55d374..a230e3d55 100644 --- a/api/src/main/java/net/luckperms/api/LuckPerms.java +++ b/api/src/main/java/net/luckperms/api/LuckPerms.java @@ -39,6 +39,7 @@ import net.luckperms.api.model.group.GroupManager; import net.luckperms.api.model.user.User; import net.luckperms.api.model.user.UserManager; import net.luckperms.api.node.NodeBuilderRegistry; +import net.luckperms.api.node.matcher.NodeMatcherFactory; import net.luckperms.api.platform.Platform; import net.luckperms.api.platform.PluginMetadata; import net.luckperms.api.query.QueryOptionsRegistry; @@ -192,6 +193,14 @@ public interface LuckPerms { */ @NonNull MetaStackFactory getMetaStackFactory(); + /** + * Gets the {@link NodeMatcherFactory}. + * + * @return the node matcher factory + * @since 5.1 + */ + @NonNull NodeMatcherFactory getNodeMatcherFactory(); + /** * Schedules the execution of an update task, and returns an encapsulation * of the task as a {@link CompletableFuture}. diff --git a/api/src/main/java/net/luckperms/api/model/group/GroupManager.java b/api/src/main/java/net/luckperms/api/model/group/GroupManager.java index 6e0e244b6..a0b324804 100644 --- a/api/src/main/java/net/luckperms/api/model/group/GroupManager.java +++ b/api/src/main/java/net/luckperms/api/model/group/GroupManager.java @@ -26,11 +26,15 @@ package net.luckperms.api.model.group; import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.matcher.NodeMatcher; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -105,13 +109,25 @@ public interface GroupManager { */ @NonNull CompletableFuture loadAllGroups(); + /** + * Searches the {@link Group#data() normal node maps} of all known {@link Group}s for {@link Node} + * entries matching the given {@link NodeMatcher matcher}. + * + * @param matcher the matcher + * @return the entries which matched + * @since 5.1 + */ + @NonNull CompletableFuture>> searchAll(@NonNull NodeMatcher matcher); + /** * Searches for a list of groups with a given permission. * * @param permission the permission to search for * @return a list of held permissions, or null if the operation failed * @throws NullPointerException if the permission is null + * @deprecated use {@link #searchAll(NodeMatcher)} */ + @Deprecated @NonNull CompletableFuture>> getWithPermission(@NonNull String permission); /** diff --git a/api/src/main/java/net/luckperms/api/model/user/UserManager.java b/api/src/main/java/net/luckperms/api/model/user/UserManager.java index 667fbce31..bd5b7bb43 100644 --- a/api/src/main/java/net/luckperms/api/model/user/UserManager.java +++ b/api/src/main/java/net/luckperms/api/model/user/UserManager.java @@ -27,11 +27,15 @@ package net.luckperms.api.model.user; import net.luckperms.api.model.PlayerSaveResult; import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.matcher.NodeMatcher; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -131,13 +135,25 @@ public interface UserManager { */ @NonNull CompletableFuture> getUniqueUsers(); + /** + * Searches the {@link User#data() normal node maps} of all known {@link User}s for {@link Node} + * entries matching the given {@link NodeMatcher matcher}. + * + * @param matcher the matcher + * @return the entries which matched + * @since 5.1 + */ + @NonNull CompletableFuture>> searchAll(@NonNull NodeMatcher matcher); + /** * Searches for a list of users with a given permission. * * @param permission the permission to search for * @return a list of held permissions * @throws NullPointerException if the permission is null + * @deprecated use {@link #searchAll(NodeMatcher)} */ + @Deprecated @NonNull CompletableFuture>> getWithPermission(@NonNull String permission); /** diff --git a/api/src/main/java/net/luckperms/api/node/HeldNode.java b/api/src/main/java/net/luckperms/api/node/HeldNode.java index 8dcd260b8..fd5439d7f 100644 --- a/api/src/main/java/net/luckperms/api/node/HeldNode.java +++ b/api/src/main/java/net/luckperms/api/node/HeldNode.java @@ -34,6 +34,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; * * @param the identifier type of the holder */ +@Deprecated public interface HeldNode { /** diff --git a/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcher.java b/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcher.java new file mode 100644 index 000000000..e15491725 --- /dev/null +++ b/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcher.java @@ -0,0 +1,146 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * 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 net.luckperms.api.node.matcher; + +import net.luckperms.api.LuckPerms; +import net.luckperms.api.LuckPermsProvider; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeEqualityPredicate; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.MetaNode; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.function.Predicate; + +/** + * A predicate which matches certain {@link Node}s. + * + * @param the node type matched + * @since 5.1 + */ +public interface NodeMatcher extends Predicate { + + /** + * Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + * @param key the key + * @return the matcher + */ + static @NonNull NodeMatcher key(@NonNull String key) { + return LuckPermsProvider.get().getNodeMatcherFactory().key(key); + } + + /** + * Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + * @param node the node to use for the key + * @param the node type + * @return the matcher + */ + static @NonNull NodeMatcher key(@NonNull T node) { + return LuckPermsProvider.get().getNodeMatcherFactory().key(node); + } + + /** + * Gets a {@link NodeMatcher} which matches nodes with a {@link Node#getKey() key} starting + * with the given string. + * + * @param startingWith the string to match + * @return the matcher + */ + static @NonNull NodeMatcher keyStartsWith(@NonNull String startingWith) { + return LuckPermsProvider.get().getNodeMatcherFactory().keyStartsWith(startingWith); + } + + /** + * Gets a {@link NodeMatcher} which matches nodes which are + * {@link Node#equals(Node, NodeEqualityPredicate) equal to} the given {@code other} node + * according to the {@link NodeEqualityPredicate}. + * + * @param other the other node to test against + * @param equalityPredicate the equality predicate + * @param the node type + * @return the matcher + */ + static @NonNull NodeMatcher equals(@NonNull T other, @NonNull NodeEqualityPredicate equalityPredicate) { + return LuckPermsProvider.get().getNodeMatcherFactory().equals(other, equalityPredicate); + } + + /** + * Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same + * {@link MetaNode#getMetaKey() meta key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + * @param metaKey the meta key + * @return the matcher + */ + static @NonNull NodeMatcher metaKey(@NonNull String metaKey) { + return LuckPermsProvider.get().getNodeMatcherFactory().metaKey(metaKey); + } + + /** + * Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same + * {@link MetaNode#getMetaKey() meta key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + * @param metaNode the meta node to use for the meta key + * @return the matcher + */ + static @NonNull NodeMatcher metaKey(@NonNull MetaNode metaNode) { + return metaKey(metaNode.getMetaKey()); + } + + /** + * Gets a {@link NodeMatcher} which matches {@link Node}s with the same + * type as the given {@link NodeType}. + * + *

{@link NodeType#PERMISSION}, {@link NodeType#CHAT_META} and + * {@link NodeType#META_OR_CHAT_META} are not supported by this method.

+ * + * @param type the node type + * @param the node type + * @return the matcher + */ + static @NonNull NodeMatcher type(NodeType type) { + return LuckPermsProvider.get().getNodeMatcherFactory().type(type); + } + + /** + * Tests to see if the given {@link Node} matches. + * + * @param node the node to test + * @return true if the node matched + */ + @Override + boolean test(@NonNull Node node); +} diff --git a/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcherFactory.java b/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcherFactory.java new file mode 100644 index 000000000..ab7f44064 --- /dev/null +++ b/api/src/main/java/net/luckperms/api/node/matcher/NodeMatcherFactory.java @@ -0,0 +1,120 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * 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 net.luckperms.api.node.matcher; + +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeEqualityPredicate; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.MetaNode; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * A factory which creates {@link NodeMatcher}s. + * + * @since 5.1 + */ +public interface NodeMatcherFactory { + + /** + * Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + *

Prefer using the {@link NodeMatcher#key(String)} accessor.

+ * + * @param key the key + * @return the matcher + */ + @NonNull NodeMatcher key(@NonNull String key); + + /** + * Gets a {@link NodeMatcher} which matches nodes with the same {@link Node#getKey() key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + *

Prefer using the {@link NodeMatcher#key(Node)} accessor.

+ * + * @param node the node to use for the key + * @param the node type + * @return the matcher + */ + @NonNull NodeMatcher key(@NonNull T node); + + /** + * Gets a {@link NodeMatcher} which matches nodes with a {@link Node#getKey() key} starting + * with the given string. + * + *

Prefer using the {@link NodeMatcher#keyStartsWith(String)} accessor.

+ * + * @param startingWith the string to match + * @return the matcher + */ + @NonNull NodeMatcher keyStartsWith(@NonNull String startingWith); + + /** + * Gets a {@link NodeMatcher} which matches nodes which are + * {@link Node#equals(Node, NodeEqualityPredicate) equal to} the given {@code other} node + * according to the {@link NodeEqualityPredicate}. + * + *

Prefer using the {@link NodeMatcher#equals(Node, NodeEqualityPredicate)} accessor.

+ * + * @param other the other node to test against + * @param equalityPredicate the equality predicate + * @param the node type + * @return the matcher + */ + @NonNull NodeMatcher equals(@NonNull T other, @NonNull NodeEqualityPredicate equalityPredicate); + + /** + * Gets a {@link NodeMatcher} which matches {@link MetaNode}s with the same + * {@link MetaNode#getMetaKey() meta key}. + * + *

The {@link String#equalsIgnoreCase(String)} method is used to test key equality.

+ * + *

Prefer using the {@link NodeMatcher#metaKey(String)} accessor.

+ * + * @param metaKey the meta key + * @return the matcher + */ + @NonNull NodeMatcher metaKey(@NonNull String metaKey); + + /** + * Gets a {@link NodeMatcher} which matches {@link Node}s with the same + * type as the given {@link NodeType}. + * + *

{@link NodeType#PERMISSION}, {@link NodeType#CHAT_META} and + * {@link NodeType#META_OR_CHAT_META} are not supported by this method.

+ * + *

Prefer using the {@link NodeMatcher#type(NodeType)} accessor.

+ * + * @param type the node type + * @param the node type + * @return the matcher + */ + @NonNull NodeMatcher type(NodeType type); + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java index a54667494..a1211fd57 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java @@ -31,6 +31,7 @@ import me.lucko.luckperms.common.api.implementation.ApiGroupManager; import me.lucko.luckperms.common.api.implementation.ApiMessagingService; import me.lucko.luckperms.common.api.implementation.ApiMetaStackFactory; import me.lucko.luckperms.common.api.implementation.ApiNodeBuilderRegistry; +import me.lucko.luckperms.common.api.implementation.ApiNodeMatcherFactory; import me.lucko.luckperms.common.api.implementation.ApiPlatform; import me.lucko.luckperms.common.api.implementation.ApiQueryOptionsRegistry; import me.lucko.luckperms.common.api.implementation.ApiTrackManager; @@ -49,6 +50,7 @@ import net.luckperms.api.metastacking.MetaStackFactory; import net.luckperms.api.model.group.GroupManager; import net.luckperms.api.model.user.UserManager; import net.luckperms.api.node.NodeBuilderRegistry; +import net.luckperms.api.node.matcher.NodeMatcherFactory; import net.luckperms.api.platform.Platform; import net.luckperms.api.platform.PluginMetadata; import net.luckperms.api.query.QueryOptionsRegistry; @@ -163,4 +165,9 @@ public class LuckPermsApiProvider implements LuckPerms { return this.metaStackFactory; } + @Override + public @NonNull NodeMatcherFactory getNodeMatcherFactory() { + return ApiNodeMatcherFactory.INSTANCE; + } + } diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiGroupManager.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiGroupManager.java index 471f1fa1a..b22af3f00 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiGroupManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiGroupManager.java @@ -25,21 +25,28 @@ package me.lucko.luckperms.common.api.implementation; +import com.google.common.collect.ImmutableListMultimap; + import me.lucko.luckperms.common.api.ApiUtils; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.manager.group.GroupManager; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.ImmutableCollectors; import net.luckperms.api.event.cause.CreationCause; import net.luckperms.api.event.cause.DeletionCause; import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.matcher.NodeMatcher; import org.checkerframework.checker.nullness.qual.NonNull; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -89,10 +96,26 @@ public class ApiGroupManager extends ApiAbstractManager>> getWithPermission(@NonNull String permission) { Objects.requireNonNull(permission, "permission"); - return this.plugin.getStorage().getGroupsWithPermission(Constraint.of(StandardComparison.EQUAL, permission)); + return (CompletableFuture) this.plugin.getStorage().getUsersWithPermission(StandardNodeMatchers.key(permission)); + } + + @SuppressWarnings("unchecked") + @Override + public @NonNull CompletableFuture>> searchAll(@NonNull NodeMatcher matcher) { + Objects.requireNonNull(matcher, "matcher"); + ConstraintNodeMatcher constraint = (ConstraintNodeMatcher) matcher; + return this.plugin.getStorage().getGroupsWithPermission(constraint).thenApply(list -> { + ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); + for (NodeEntry row : list) { + builder.put(row.getHolder(), row.getNode()); + } + return builder.build().asMap(); + }); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiNodeMatcherFactory.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiNodeMatcherFactory.java new file mode 100644 index 000000000..5b92b13c9 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiNodeMatcherFactory.java @@ -0,0 +1,83 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * 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.common.api.implementation; + +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; + +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeEqualityPredicate; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.matcher.NodeMatcher; +import net.luckperms.api.node.matcher.NodeMatcherFactory; +import net.luckperms.api.node.types.MetaNode; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.Objects; + +public final class ApiNodeMatcherFactory implements NodeMatcherFactory { + public static final ApiNodeMatcherFactory INSTANCE = new ApiNodeMatcherFactory(); + + private ApiNodeMatcherFactory() { + + } + + @Override + public @NonNull NodeMatcher key(@NonNull String key) { + Objects.requireNonNull(key, "key"); + return StandardNodeMatchers.key(key); + } + + @Override + public @NonNull NodeMatcher key(@NonNull T node) { + return StandardNodeMatchers.key(node); + } + + @Override + public @NonNull NodeMatcher keyStartsWith(@NonNull String startingWith) { + Objects.requireNonNull(startingWith, "startingWith"); + return StandardNodeMatchers.keyStartsWith(startingWith); + } + + @Override + public @NonNull NodeMatcher equals(@NonNull T other, @NonNull NodeEqualityPredicate equalityPredicate) { + Objects.requireNonNull(other, "other"); + Objects.requireNonNull(equalityPredicate, "equalityPredicate"); + return StandardNodeMatchers.equals(other, equalityPredicate); + } + + @Override + public @NonNull NodeMatcher metaKey(@NonNull String metaKey) { + Objects.requireNonNull(metaKey, "metaKey"); + return StandardNodeMatchers.metaKey(metaKey); + } + + @Override + public @NonNull NodeMatcher type(NodeType type) { + Objects.requireNonNull(type, "type"); + return StandardNodeMatchers.type(type); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiUserManager.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiUserManager.java index cd43e6343..223c521c9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiUserManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiUserManager.java @@ -25,21 +25,28 @@ package me.lucko.luckperms.common.api.implementation; +import com.google.common.collect.ImmutableListMultimap; + import me.lucko.luckperms.common.api.ApiUtils; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.manager.user.UserManager; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.ImmutableCollectors; import net.luckperms.api.model.PlayerSaveResult; import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.matcher.NodeMatcher; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -98,10 +105,26 @@ public class ApiUserManager extends ApiAbstractManager>> getWithPermission(@NonNull String permission) { Objects.requireNonNull(permission, "permission"); - return this.plugin.getStorage().getUsersWithPermission(Constraint.of(StandardComparison.EQUAL, permission)); + return (CompletableFuture) this.plugin.getStorage().getUsersWithPermission(StandardNodeMatchers.key(permission)); + } + + @SuppressWarnings("unchecked") + @Override + public @NonNull CompletableFuture>> searchAll(@NonNull NodeMatcher matcher) { + Objects.requireNonNull(matcher, "matcher"); + ConstraintNodeMatcher constraint = (ConstraintNodeMatcher) matcher; + return this.plugin.getStorage().getUsersWithPermission(constraint).thenApply(list -> { + ImmutableListMultimap.Builder builder = ImmutableListMultimap.builder(); + for (NodeEntry row : list) { + builder.put(row.getHolder(), row.getNode()); + } + return builder.build().asMap(); + }); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java index 6aa19a302..f634caab0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java +++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java @@ -64,6 +64,9 @@ public enum StandardComparison implements Comparison { } }; + public static final String WILDCARD = "%"; + public static final String WILDCARD_ONE = "_"; + private final String symbol; private final String asSql; @@ -101,8 +104,8 @@ public enum StandardComparison implements Comparison { expression = expression.replace(".", "\\."); // convert from SQL LIKE syntax to regex - expression = expression.replace("_", "."); - expression = expression.replace("%", ".*"); + expression = expression.replace(WILDCARD_ONE, "."); + expression = expression.replace(WILDCARD, ".*"); return Pattern.compile(expression); } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java index 96130f006..4ffcbeff1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupListMembers.java @@ -27,8 +27,6 @@ package me.lucko.luckperms.common.commands.group; import com.google.common.collect.Maps; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; import me.lucko.luckperms.common.cache.LoadingMap; import me.lucko.luckperms.common.command.CommandResult; import me.lucko.luckperms.common.command.abstraction.ChildCommand; @@ -42,11 +40,14 @@ import me.lucko.luckperms.common.locale.command.CommandSpec; import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.HolderType; -import me.lucko.luckperms.common.node.comparator.HeldNodeComparator; +import me.lucko.luckperms.common.node.comparator.NodeEntryComparator; import me.lucko.luckperms.common.node.factory.NodeCommandFactory; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; import me.lucko.luckperms.common.node.types.Inheritance; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; @@ -56,7 +57,6 @@ import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import net.luckperms.api.node.types.InheritanceNode; @@ -80,16 +80,16 @@ public class GroupListMembers extends ChildCommand { return CommandResult.NO_PERMISSION; } - Constraint constraint = Constraint.of(StandardComparison.EQUAL, Inheritance.key(group.getName())); + ConstraintNodeMatcher matcher = StandardNodeMatchers.key(Inheritance.builder(group.getName()).build()); int page = ArgumentParser.parseIntOrElse(0, args, 1); Message.SEARCH_SEARCHING_MEMBERS.send(sender, group.getName()); - List> matchedUsers = plugin.getStorage().getUsersWithPermission(constraint).join().stream() + List> matchedUsers = plugin.getStorage().getUsersWithPermission(matcher).join().stream() .filter(n -> n.getNode().getValue()) .collect(Collectors.toList()); - List> matchedGroups = plugin.getStorage().getGroupsWithPermission(constraint).join().stream() + List> matchedGroups = plugin.getStorage().getGroupsWithPermission(matcher).join().stream() .filter(n -> n.getNode().getValue()) .collect(Collectors.toList()); @@ -124,28 +124,28 @@ public class GroupListMembers extends ChildCommand { return CommandResult.SUCCESS; } - private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page) { + private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page) { results = new ArrayList<>(results); - results.sort(HeldNodeComparator.normal()); + results.sort(NodeEntryComparator.normal()); int pageIndex = page - 1; - List>> pages = Iterators.divideIterable(results, 15); + List>> pages = Iterators.divideIterable(results, 15); if (pageIndex < 0 || pageIndex >= pages.size()) { page = 1; pageIndex = 0; } - List> content = pages.get(pageIndex); + List> content = pages.get(pageIndex); - List>> mappedContent = content.stream() + List>> mappedContent = content.stream() .map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp)) .collect(Collectors.toList()); // send header headerMessage.send(sender, page, pages.size(), results.size()); - for (Map.Entry> ent : mappedContent) { + for (Map.Entry> ent : mappedContent) { String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().getNode()) + MessageUtils.getAppendableNodeContextString(sender.getPlugin().getLocaleManager(), ent.getValue().getNode()); TextComponent message = TextUtils.fromLegacy(s, TextUtils.AMPERSAND_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue(), sender.getPlugin())).build(); sender.sendMessage(message); @@ -160,7 +160,7 @@ public class GroupListMembers extends ChildCommand { return " &8(&7expires in " + DurationFormatter.LONG.format(node.getExpiryDuration()) + "&8)"; } - private static Consumer> makeFancy(String holderName, HolderType holderType, String label, HeldNode perm, LuckPermsPlugin plugin) { + private static Consumer> makeFancy(String holderName, HolderType holderType, String label, NodeEntry perm, LuckPermsPlugin plugin) { HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( "&3> &b" + ((InheritanceNode) perm.getNode()).getGroupName(), " ", diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java index c69d6372e..a50864f4f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java @@ -43,10 +43,13 @@ import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.command.CommandSpec; import me.lucko.luckperms.common.locale.message.Message; import me.lucko.luckperms.common.model.HolderType; -import me.lucko.luckperms.common.node.comparator.HeldNodeComparator; +import me.lucko.luckperms.common.node.comparator.NodeEntryComparator; import me.lucko.luckperms.common.node.factory.NodeCommandFactory; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.sender.Sender; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.DurationFormatter; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.Predicates; @@ -56,7 +59,6 @@ import net.kyori.text.ComponentBuilder; import net.kyori.text.TextComponent; import net.kyori.text.event.ClickEvent; import net.kyori.text.event.HoverEvent; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import java.util.ArrayList; @@ -80,13 +82,13 @@ public class SearchCommand extends SingleCommand { args.add(0, "=="); } - Constraint query = Constraint.of(comparison, args.get(1)); + ConstraintNodeMatcher matcher = StandardNodeMatchers.of(Constraint.of(comparison, args.get(1))); int page = ArgumentParser.parseIntOrElse(2, args, 1); - Message.SEARCH_SEARCHING.send(sender, query); + Message.SEARCH_SEARCHING.send(sender, matcher); - List> matchedUsers = plugin.getStorage().getUsersWithPermission(query).join(); - List> matchedGroups = plugin.getStorage().getGroupsWithPermission(query).join(); + List> matchedUsers = plugin.getStorage().getUsersWithPermission(matcher).join(); + List> matchedGroups = plugin.getStorage().getGroupsWithPermission(matcher).join(); int users = matchedUsers.size(); int groups = matchedGroups.size(); @@ -126,28 +128,28 @@ public class SearchCommand extends SingleCommand { .complete(args); } - private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page, Comparison comparison) { + private static > void sendResult(Sender sender, List> results, Function lookupFunction, Message headerMessage, HolderType holderType, String label, int page, Comparison comparison) { results = new ArrayList<>(results); - results.sort(HeldNodeComparator.normal()); + results.sort(NodeEntryComparator.normal()); int pageIndex = page - 1; - List>> pages = Iterators.divideIterable(results, 15); + List>> pages = Iterators.divideIterable(results, 15); if (pageIndex < 0 || pageIndex >= pages.size()) { page = 1; pageIndex = 0; } - List> content = pages.get(pageIndex); + List> content = pages.get(pageIndex); - List>> mappedContent = content.stream() + List>> mappedContent = content.stream() .map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp)) .collect(Collectors.toList()); // send header headerMessage.send(sender, page, pages.size(), results.size()); - for (Map.Entry> ent : mappedContent) { + for (Map.Entry> ent : mappedContent) { // only show the permission in the results if the comparison isn't equals String permission = ""; if (comparison != StandardComparison.EQUAL) { @@ -168,7 +170,7 @@ public class SearchCommand extends SingleCommand { return " &8(&7expires in " + DurationFormatter.LONG.format(node.getExpiryDuration()) + "&8)"; } - private static Consumer> makeFancy(String holderName, HolderType holderType, String label, HeldNode perm, LuckPermsPlugin plugin) { + private static Consumer> makeFancy(String holderName, HolderType holderType, String label, NodeEntry perm, LuckPermsPlugin plugin) { HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline( "&3> " + (perm.getNode().getValue() ? "&a" : "&c") + perm.getNode().getKey(), " ", diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/InheritanceOrigin.java b/common/src/main/java/me/lucko/luckperms/common/model/InheritanceOrigin.java similarity index 97% rename from common/src/main/java/me/lucko/luckperms/common/node/model/InheritanceOrigin.java rename to common/src/main/java/me/lucko/luckperms/common/model/InheritanceOrigin.java index 1ca48c11d..d9acea639 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/InheritanceOrigin.java +++ b/common/src/main/java/me/lucko/luckperms/common/model/InheritanceOrigin.java @@ -23,7 +23,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.node.model; +package me.lucko.luckperms.common.model; import net.luckperms.api.model.PermissionHolder; import net.luckperms.api.node.metadata.types.InheritanceOriginMetadata; diff --git a/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java b/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java index 2e82b8ba4..d1102d55f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java +++ b/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java @@ -34,7 +34,6 @@ import me.lucko.luckperms.common.cache.Cache; import me.lucko.luckperms.common.context.ContextSetComparator; import me.lucko.luckperms.common.node.comparator.NodeComparator; import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator; -import me.lucko.luckperms.common.node.model.InheritanceOrigin; import me.lucko.luckperms.common.query.QueryOptionsImpl; import net.luckperms.api.context.ContextSet; diff --git a/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeEntryComparator.java similarity index 75% rename from common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java rename to common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeEntryComparator.java index ea350a884..1165d098d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/comparator/HeldNodeComparator.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/comparator/NodeEntryComparator.java @@ -25,22 +25,22 @@ package me.lucko.luckperms.common.node.comparator; -import net.luckperms.api.node.HeldNode; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import java.util.Comparator; -public class HeldNodeComparator> implements Comparator> { +public class NodeEntryComparator> implements Comparator> { - public static > Comparator> normal() { - return new HeldNodeComparator<>(); + public static > Comparator> normal() { + return new NodeEntryComparator<>(); } - public static > Comparator> reverse() { - return HeldNodeComparator.normal().reversed(); + public static > Comparator> reverse() { + return NodeEntryComparator.normal().reversed(); } @Override - public int compare(HeldNode o1, HeldNode o2) { + public int compare(NodeEntry o1, NodeEntry o2) { int i = NodeWithContextComparator.normal().compare(o1.getNode(), o2.getNode()); if (i != 0) { return i; diff --git a/common/src/main/java/me/lucko/luckperms/common/node/matcher/ConstraintNodeMatcher.java b/common/src/main/java/me/lucko/luckperms/common/node/matcher/ConstraintNodeMatcher.java new file mode 100644 index 000000000..6602706b5 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/node/matcher/ConstraintNodeMatcher.java @@ -0,0 +1,60 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * 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.common.node.matcher; + +import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; + +import net.luckperms.api.node.Node; +import net.luckperms.api.node.matcher.NodeMatcher; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Abstract implementation of {@link NodeMatcher} backed by a {@link Constraint}. + */ +public abstract class ConstraintNodeMatcher implements NodeMatcher { + private final Constraint constraint; + + protected ConstraintNodeMatcher(Constraint constraint) { + this.constraint = constraint; + } + + public Constraint getConstraint() { + return this.constraint; + } + + public abstract @Nullable T filterConstraintMatch(@NonNull Node node); + + public @Nullable T match(Node node) { + return getConstraint().eval(node.getKey()) ? filterConstraintMatch(node) : null; + } + + @Override + public boolean test(@NonNull Node node) { + return match(node) != null; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/node/matcher/StandardNodeMatchers.java b/common/src/main/java/me/lucko/luckperms/common/node/matcher/StandardNodeMatchers.java new file mode 100644 index 000000000..3a0a0d48e --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/node/matcher/StandardNodeMatchers.java @@ -0,0 +1,157 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * 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.common.node.matcher; + +import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; +import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; +import me.lucko.luckperms.common.node.AbstractNode; +import me.lucko.luckperms.common.node.types.DisplayName; +import me.lucko.luckperms.common.node.types.Inheritance; +import me.lucko.luckperms.common.node.types.Meta; +import me.lucko.luckperms.common.node.types.Prefix; +import me.lucko.luckperms.common.node.types.RegexPermission; +import me.lucko.luckperms.common.node.types.Suffix; +import me.lucko.luckperms.common.node.types.Weight; + +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeEqualityPredicate; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.MetaNode; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class StandardNodeMatchers { + private StandardNodeMatchers() {} + + public static ConstraintNodeMatcher of(Constraint constraint) { + return new Generic(constraint); + } + + public static ConstraintNodeMatcher key(String key) { + return new Generic(Constraint.of(StandardComparison.EQUAL, key)); + } + + public static ConstraintNodeMatcher key(T node) { + return new NodeEquals<>(node, NodeEqualityPredicate.ONLY_KEY); + } + + public static ConstraintNodeMatcher keyStartsWith(String startsWith) { + return new Generic(Constraint.of(StandardComparison.SIMILAR, startsWith + StandardComparison.WILDCARD)); + } + + public static ConstraintNodeMatcher equals(T other, NodeEqualityPredicate equalityPredicate) { + return new NodeEquals<>(other, equalityPredicate); + } + + public static ConstraintNodeMatcher metaKey(String metaKey) { + return new MetaKeyEquals(metaKey); + } + + public static ConstraintNodeMatcher type(NodeType type) { + return new TypeEquals<>(type); + } + + private static class Generic extends ConstraintNodeMatcher { + Generic(Constraint constraint) { + super(constraint); + } + + @Nullable + @Override + public Node filterConstraintMatch(@NonNull Node node) { + return node; + } + } + + private static final class NodeEquals extends ConstraintNodeMatcher { + private final T node; + private final NodeEqualityPredicate equalityPredicate; + + NodeEquals(T node, NodeEqualityPredicate equalityPredicate) { + super(Constraint.of(StandardComparison.EQUAL, node.getKey())); + this.node = node; + this.equalityPredicate = equalityPredicate; + } + + @SuppressWarnings("unchecked") + @Override + public @Nullable T filterConstraintMatch(@NonNull Node node) { + if (this.equalityPredicate == NodeEqualityPredicate.ONLY_KEY || this.node.equals(node, this.equalityPredicate)) { + return (T) node; + } + return null; + } + } + + private static final class MetaKeyEquals extends ConstraintNodeMatcher { + MetaKeyEquals(String metaKey) { + super(Constraint.of(StandardComparison.SIMILAR, Meta.key(metaKey, StandardComparison.WILDCARD))); + } + + @Nullable + @Override + public MetaNode filterConstraintMatch(@NonNull Node node) { + return NodeType.META.tryCast(node).orElse(null); + } + } + + private static final class TypeEquals extends ConstraintNodeMatcher { + private final NodeType type; + + protected TypeEquals(NodeType type) { + super(getConstraintForType(type)); + this.type = type; + } + + @Nullable + @Override + public T filterConstraintMatch(@NonNull Node node) { + return this.type.tryCast(node).orElse(null); + } + + private static Constraint getConstraintForType(NodeType type) { + if (type == NodeType.REGEX_PERMISSION) { + return Constraint.of(StandardComparison.SIMILAR, RegexPermission.key(StandardComparison.WILDCARD)); + } else if (type == NodeType.INHERITANCE) { + return Constraint.of(StandardComparison.SIMILAR, Inheritance.key(StandardComparison.WILDCARD)); + } else if (type == NodeType.PREFIX) { + return Constraint.of(StandardComparison.SIMILAR, Prefix.NODE_MARKER + StandardComparison.WILDCARD + AbstractNode.NODE_SEPARATOR + StandardComparison.WILDCARD); + } else if (type == NodeType.SUFFIX) { + return Constraint.of(StandardComparison.SIMILAR, Suffix.NODE_MARKER + StandardComparison.WILDCARD + AbstractNode.NODE_SEPARATOR + StandardComparison.WILDCARD); + } else if (type == NodeType.META) { + return Constraint.of(StandardComparison.SIMILAR, Meta.key(StandardComparison.WILDCARD, StandardComparison.WILDCARD)); + } else if (type == NodeType.WEIGHT) { + return Constraint.of(StandardComparison.SIMILAR, Weight.NODE_MARKER + StandardComparison.WILDCARD); + } else if (type == NodeType.DISPLAY_NAME) { + return Constraint.of(StandardComparison.SIMILAR, DisplayName.key(StandardComparison.WILDCARD)); + } + + throw new IllegalArgumentException("Unable to create a NodeMatcher for NodeType " + type.name()); + } + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java index d14c3e2d9..5ee595189 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java @@ -29,20 +29,21 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.implementation.StorageImplementation; import me.lucko.luckperms.common.storage.implementation.split.SplitStorage; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.Throwing; import net.luckperms.api.actionlog.Action; import net.luckperms.api.event.cause.CreationCause; import net.luckperms.api.event.cause.DeletionCause; import net.luckperms.api.model.PlayerSaveResult; -import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; import java.util.Collection; import java.util.Collections; @@ -161,9 +162,9 @@ public class Storage { return makeFuture(this.implementation::getUniqueUsers); } - public CompletableFuture>> getUsersWithPermission(Constraint constraint) { + public CompletableFuture>> getUsersWithPermission(ConstraintNodeMatcher constraint) { return makeFuture(() -> { - List> result = this.implementation.getUsersWithPermission(constraint); + List> result = this.implementation.getUsersWithPermission(constraint); result.removeIf(entry -> entry.getNode().hasExpired()); return ImmutableList.copyOf(result); }); @@ -207,9 +208,9 @@ public class Storage { }); } - public CompletableFuture>> getGroupsWithPermission(Constraint constraint) { + public CompletableFuture>> getGroupsWithPermission(ConstraintNodeMatcher constraint) { return makeFuture(() -> { - List> result = this.implementation.getGroupsWithPermission(constraint); + List> result = this.implementation.getGroupsWithPermission(constraint); result.removeIf(entry -> entry.getNode().hasExpired()); return ImmutableList.copyOf(result); }); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/StorageImplementation.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/StorageImplementation.java index d8c15b696..d3ea7fc51 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/StorageImplementation.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/StorageImplementation.java @@ -27,15 +27,16 @@ package me.lucko.luckperms.common.storage.implementation; import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import net.luckperms.api.actionlog.Action; import net.luckperms.api.model.PlayerSaveResult; -import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; import org.checkerframework.checker.nullness.qual.Nullable; @@ -71,7 +72,7 @@ public interface StorageImplementation { Set getUniqueUsers() throws Exception; - List> getUsersWithPermission(Constraint constraint) throws Exception; + List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws Exception; Group createAndLoadGroup(String name) throws Exception; @@ -83,7 +84,7 @@ public interface StorageImplementation { void deleteGroup(Group group) throws Exception; - List> getGroupsWithPermission(Constraint constraint) throws Exception; + List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws Exception; Track createAndLoadTrack(String name) throws Exception; diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/CombinedConfigurateStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/CombinedConfigurateStorage.java index b901620fa..4802fe83e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/CombinedConfigurateStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/CombinedConfigurateStorage.java @@ -26,14 +26,13 @@ package me.lucko.luckperms.common.storage.implementation.file; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.node.model.HeldNodeImpl; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.implementation.file.loader.ConfigurateLoader; import me.lucko.luckperms.common.storage.implementation.file.watcher.FileWatcher; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.Iterators; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import ninja.leaping.configurate.ConfigurationNode; @@ -262,8 +261,8 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage { } @Override - public List> getUsersWithPermission(Constraint constraint) throws Exception { - List> held = new ArrayList<>(); + public List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); this.usersLoader.apply(false, true, root -> { for (Map.Entry entry : root.getChildrenMap().entrySet()) { try { @@ -272,10 +271,10 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage { Set nodes = readNodes(object); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } catch (Exception e) { e.printStackTrace(); @@ -302,8 +301,8 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage { } @Override - public List> getGroupsWithPermission(Constraint constraint) throws Exception { - List> held = new ArrayList<>(); + public List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); this.groupsLoader.apply(false, true, root -> { for (Map.Entry entry : root.getChildrenMap().entrySet()) { try { @@ -312,10 +311,10 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage { Set nodes = readNodes(object); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } catch (Exception e) { e.printStackTrace(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/SeparatedConfigurateStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/SeparatedConfigurateStorage.java index c1f9dc8ca..73d28efc1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/SeparatedConfigurateStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/SeparatedConfigurateStorage.java @@ -26,17 +26,16 @@ package me.lucko.luckperms.common.storage.implementation.file; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.model.User; -import me.lucko.luckperms.common.node.model.HeldNodeImpl; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.implementation.file.loader.ConfigurateLoader; import me.lucko.luckperms.common.storage.implementation.file.watcher.FileWatcher; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.MoreFiles; import me.lucko.luckperms.common.util.Uuids; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import ninja.leaping.configurate.ConfigurationNode; @@ -255,8 +254,8 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage { } @Override - public List> getUsersWithPermission(Constraint constraint) throws Exception { - List> held = new ArrayList<>(); + public List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); try (Stream stream = Files.list(getDirectory(StorageLocation.USER))) { stream.filter(getFileTypeFilter()) .forEach(file -> { @@ -267,10 +266,10 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage { UUID holder = UUID.fromString(fileName.substring(0, fileName.length() - this.fileExtension.length())); Set nodes = readNodes(object); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } catch (Exception e) { throw reportException(file.getFileName().toString(), e); @@ -298,8 +297,8 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage { } @Override - public List> getGroupsWithPermission(Constraint constraint) throws Exception { - List> held = new ArrayList<>(); + public List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); try (Stream stream = Files.list(getDirectory(StorageLocation.GROUP))) { stream.filter(getFileTypeFilter()) .forEach(file -> { @@ -310,10 +309,10 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage { String holder = fileName.substring(0, fileName.length() - this.fileExtension.length()); Set nodes = readNodes(object); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } catch (Exception e) { throw reportException(file.getFileName().toString(), e); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java index fe73c3af4..67354164a 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java @@ -40,16 +40,16 @@ import com.mongodb.client.model.ReplaceOptions; import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.actionlog.LoggedAction; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.context.contextset.MutableContextSetImpl; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.manager.group.GroupManager; import me.lucko.luckperms.common.node.factory.NodeBuilders; -import me.lucko.luckperms.common.node.model.HeldNodeImpl; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.implementation.StorageImplementation; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.storage.misc.PlayerSaveResultImpl; import me.lucko.luckperms.common.storage.misc.StorageCredentials; import me.lucko.luckperms.common.util.Iterators; @@ -61,7 +61,6 @@ import net.luckperms.api.context.DefaultContextKeys; import net.luckperms.api.context.MutableContextSet; import net.luckperms.api.model.PlayerSaveResult; import net.luckperms.api.model.data.DataType; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import net.luckperms.api.node.NodeBuilder; @@ -361,8 +360,8 @@ public class MongoStorage implements StorageImplementation { } @Override - public List> getUsersWithPermission(Constraint constraint) { - List> held = new ArrayList<>(); + public List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); MongoCollection c = this.database.getCollection(this.prefix + "users"); try (MongoCursor cursor = c.find().iterator()) { while (cursor.hasNext()) { @@ -371,10 +370,10 @@ public class MongoStorage implements StorageImplementation { Set nodes = new HashSet<>(nodesFromDoc(d)); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } } @@ -471,8 +470,8 @@ public class MongoStorage implements StorageImplementation { } @Override - public List> getGroupsWithPermission(Constraint constraint) { - List> held = new ArrayList<>(); + public List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws Exception { + List> held = new ArrayList<>(); MongoCollection c = this.database.getCollection(this.prefix + "groups"); try (MongoCursor cursor = c.find().iterator()) { while (cursor.hasNext()) { @@ -481,10 +480,10 @@ public class MongoStorage implements StorageImplementation { Set nodes = new HashSet<>(nodesFromDoc(d)); for (Node e : nodes) { - if (!constraint.eval(e.getKey())) { - continue; + N match = constraint.match(e); + if (match != null) { + held.add(NodeEntry.of(holder, match)); } - held.add(HeldNodeImpl.of(holder, e)); } } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/split/SplitStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/split/SplitStorage.java index 30a1f74a5..986c1b398 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/split/SplitStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/split/SplitStorage.java @@ -29,17 +29,18 @@ import com.google.common.collect.ImmutableMap; import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.StorageType; import me.lucko.luckperms.common.storage.implementation.StorageImplementation; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import net.luckperms.api.actionlog.Action; import net.luckperms.api.model.PlayerSaveResult; -import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; import java.util.LinkedHashMap; import java.util.List; @@ -153,7 +154,7 @@ public class SplitStorage implements StorageImplementation { } @Override - public List> getUsersWithPermission(Constraint constraint) throws Exception { + public List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws Exception { return implFor(SplitStorageType.USER).getUsersWithPermission(constraint); } @@ -183,7 +184,7 @@ public class SplitStorage implements StorageImplementation { } @Override - public List> getGroupsWithPermission(Constraint constraint) throws Exception { + public List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws Exception { return implFor(SplitStorageType.GROUP).getGroupsWithPermission(constraint); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java index 802bd81e3..ddf92031e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java @@ -32,16 +32,16 @@ import me.lucko.luckperms.common.actionlog.Log; import me.lucko.luckperms.common.actionlog.LoggedAction; import me.lucko.luckperms.common.bulkupdate.BulkUpdate; import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; import me.lucko.luckperms.common.context.ContextSetJsonSerializer; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.manager.group.GroupManager; -import me.lucko.luckperms.common.node.model.HeldNodeImpl; +import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.storage.implementation.StorageImplementation; import me.lucko.luckperms.common.storage.implementation.sql.connection.ConnectionFactory; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.storage.misc.PlayerSaveResultImpl; import me.lucko.luckperms.common.util.Iterators; import me.lucko.luckperms.common.util.gson.GsonProvider; @@ -49,7 +49,6 @@ import me.lucko.luckperms.common.util.gson.GsonProvider; import net.luckperms.api.actionlog.Action; import net.luckperms.api.model.PlayerSaveResult; import net.luckperms.api.model.data.DataType; -import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import java.io.IOException; @@ -363,18 +362,22 @@ public class SqlStorage implements StorageImplementation { } @Override - public List> getUsersWithPermission(Constraint constraint) throws SQLException { + public List> getUsersWithPermission(ConstraintNodeMatcher constraint) throws SQLException { PreparedStatementBuilder builder = new PreparedStatementBuilder().append(USER_PERMISSIONS_SELECT_PERMISSION); - constraint.appendSql(builder, "permission"); + constraint.getConstraint().appendSql(builder, "permission"); - List> held = new ArrayList<>(); + List> held = new ArrayList<>(); try (Connection c = this.connectionFactory.getConnection()) { try (PreparedStatement ps = builder.build(c, this.statementProcessor)) { try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { UUID holder = UUID.fromString(rs.getString("uuid")); Node node = readNode(rs).toNode(); - held.add(HeldNodeImpl.of(holder, node)); + + N match = constraint.filterConstraintMatch(node); + if (match != null) { + held.add(NodeEntry.of(holder, match)); + } } } } @@ -490,18 +493,22 @@ public class SqlStorage implements StorageImplementation { } @Override - public List> getGroupsWithPermission(Constraint constraint) throws SQLException { + public List> getGroupsWithPermission(ConstraintNodeMatcher constraint) throws SQLException { PreparedStatementBuilder builder = new PreparedStatementBuilder().append(GROUP_PERMISSIONS_SELECT_PERMISSION); - constraint.appendSql(builder, "permission"); + constraint.getConstraint().appendSql(builder, "permission"); - List> held = new ArrayList<>(); + List> held = new ArrayList<>(); try (Connection c = this.connectionFactory.getConnection()) { try (PreparedStatement ps = builder.build(c, this.statementProcessor)) { try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { String holder = rs.getString("name"); Node node = readNode(rs).toNode(); - held.add(HeldNodeImpl.of(holder, node)); + + N match = constraint.filterConstraintMatch(node); + if (match != null) { + held.add(NodeEntry.of(holder, match)); + } } } } diff --git a/common/src/main/java/me/lucko/luckperms/common/node/model/HeldNodeImpl.java b/common/src/main/java/me/lucko/luckperms/common/storage/misc/NodeEntry.java similarity index 77% rename from common/src/main/java/me/lucko/luckperms/common/node/model/HeldNodeImpl.java rename to common/src/main/java/me/lucko/luckperms/common/storage/misc/NodeEntry.java index a8870c1f1..07eb19977 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/model/HeldNodeImpl.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/misc/NodeEntry.java @@ -23,42 +23,42 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.node.model; +package me.lucko.luckperms.common.storage.misc; import net.luckperms.api.node.HeldNode; import net.luckperms.api.node.Node; import org.checkerframework.checker.nullness.qual.NonNull; -public final class HeldNodeImpl> implements HeldNode { +public final class NodeEntry, N extends Node> implements HeldNode { - public static > HeldNodeImpl of(T holder, Node node) { - return new HeldNodeImpl<>(holder, node); + public static , N extends Node> NodeEntry of(H holder, N node) { + return new NodeEntry<>(holder, node); } - private final T holder; - private final Node node; + private final H holder; + private final N node; - private HeldNodeImpl(T holder, Node node) { + private NodeEntry(H holder, N node) { this.holder = holder; this.node = node; } @Override - public @NonNull Node getNode() { - return this.node; + public @NonNull H getHolder() { + return this.holder; } @Override - public @NonNull T getHolder() { - return this.holder; + public @NonNull N getNode() { + return this.node; } @Override public boolean equals(Object o) { if (o == this) return true; - if (!(o instanceof HeldNodeImpl)) return false; - final HeldNodeImpl other = (HeldNodeImpl) o; + if (!(o instanceof NodeEntry)) return false; + final NodeEntry other = (NodeEntry) o; return this.getHolder().equals(other.getHolder()) && this.getNode().equals(other.getNode()); } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeGroupManager.java b/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeGroupManager.java index 642f1559a..68f92b852 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeGroupManager.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeGroupManager.java @@ -32,11 +32,11 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl; import me.lucko.luckperms.common.model.manager.group.AbstractGroupManager; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; import me.lucko.luckperms.common.storage.misc.DataConstraints; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.ImmutableCollectors; import me.lucko.luckperms.sponge.LPSpongePlugin; import me.lucko.luckperms.sponge.model.SpongeGroup; @@ -48,7 +48,7 @@ import me.lucko.luckperms.sponge.service.model.LPSubjectReference; import net.luckperms.api.context.ImmutableContextSet; import net.luckperms.api.event.cause.CreationCause; -import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; import net.luckperms.api.util.Tristate; import org.spongepowered.api.service.permission.PermissionService; @@ -193,8 +193,8 @@ public class SpongeGroupManager extends AbstractGroupManager implem return CompletableFuture.supplyAsync(() -> { ImmutableMap.Builder builder = ImmutableMap.builder(); - List> lookup = this.plugin.getStorage().getGroupsWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).join(); - for (HeldNode holder : lookup) { + List> lookup = this.plugin.getStorage().getGroupsWithPermission(StandardNodeMatchers.key(permission)).join(); + for (NodeEntry holder : lookup) { if (holder.getNode().getContexts().equals(ImmutableContextSetImpl.EMPTY)) { builder.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder()), holder.getNode().getValue()); } @@ -209,8 +209,8 @@ public class SpongeGroupManager extends AbstractGroupManager implem return CompletableFuture.supplyAsync(() -> { ImmutableMap.Builder builder = ImmutableMap.builder(); - List> lookup = this.plugin.getStorage().getGroupsWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).join(); - for (HeldNode holder : lookup) { + List> lookup = this.plugin.getStorage().getGroupsWithPermission(StandardNodeMatchers.key(permission)).join(); + for (NodeEntry holder : lookup) { if (holder.getNode().getContexts().equals(contexts)) { builder.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder()), holder.getNode().getValue()); } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeUserManager.java b/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeUserManager.java index b1058804f..3eb3c23bd 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeUserManager.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/model/manager/SpongeUserManager.java @@ -32,11 +32,11 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; -import me.lucko.luckperms.common.bulkupdate.comparison.Constraint; -import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison; import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl; import me.lucko.luckperms.common.model.manager.user.AbstractUserManager; import me.lucko.luckperms.common.model.manager.user.UserHousekeeper; +import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers; +import me.lucko.luckperms.common.storage.misc.NodeEntry; import me.lucko.luckperms.common.util.ImmutableCollectors; import me.lucko.luckperms.common.util.Uuids; import me.lucko.luckperms.sponge.LPSpongePlugin; @@ -48,7 +48,7 @@ import me.lucko.luckperms.sponge.service.model.LPSubjectCollection; import me.lucko.luckperms.sponge.service.model.LPSubjectReference; import net.luckperms.api.context.ImmutableContextSet; -import net.luckperms.api.node.HeldNode; +import net.luckperms.api.node.Node; import net.luckperms.api.util.Tristate; import org.spongepowered.api.service.permission.PermissionService; @@ -212,8 +212,8 @@ public class SpongeUserManager extends AbstractUserManager implement return CompletableFuture.supplyAsync(() -> { ImmutableMap.Builder builder = ImmutableMap.builder(); - List> lookup = this.plugin.getStorage().getUsersWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).join(); - for (HeldNode holder : lookup) { + List> lookup = this.plugin.getStorage().getUsersWithPermission(StandardNodeMatchers.key(permission)).join(); + for (NodeEntry holder : lookup) { if (holder.getNode().getContexts().equals(ImmutableContextSetImpl.EMPTY)) { builder.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder().toString()), holder.getNode().getValue()); } @@ -228,8 +228,8 @@ public class SpongeUserManager extends AbstractUserManager implement return CompletableFuture.supplyAsync(() -> { ImmutableMap.Builder builder = ImmutableMap.builder(); - List> lookup = this.plugin.getStorage().getUsersWithPermission(Constraint.of(StandardComparison.EQUAL, permission)).join(); - for (HeldNode holder : lookup) { + List> lookup = this.plugin.getStorage().getUsersWithPermission(StandardNodeMatchers.key(permission)).join(); + for (NodeEntry holder : lookup) { if (holder.getNode().getContexts().equals(contexts)) { builder.put(getService().getReferenceFactory().obtain(getIdentifier(), holder.getHolder().toString()), holder.getNode().getValue()); }