Big API refactor

- removed a bunch of ugly / badly designed methods and APIs
- refactored 'Contexts' --> 'QueryOptions'
- Removed the FullySatisfiedContexts hack and replaced it with a sane API
- Made PermissionHolder (in the API) less ugly and horrible
- removed lots of deprecated / duplicated API functionality
and much more...
This commit is contained in:
Luck 2019-05-20 22:39:46 +01:00
parent 8f8c916be3
commit 3474c66c1c
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
415 changed files with 9033 additions and 10669 deletions

View File

@ -1,7 +1,6 @@
project.version = '4.4'
project.version = '5.0'
dependencies {
compileOnly 'com.google.guava:guava:19.0'
compileOnly 'org.checkerframework:checker-qual:2.5.5'
}
@ -14,7 +13,6 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
options.encoding = 'UTF-8'
options.charSet = 'UTF-8'
options.links(
'https://google.github.io/guava/releases/21.0/api/docs/',
'https://docs.oracle.com/javase/8/docs/api/'
)
options.addStringOption('Xdoclint:none', '-quiet')

View File

@ -1,126 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* Represents a type of chat meta
*
* @since 3.2
*/
public enum ChatMetaType {
/**
* Represents a prefix
*/
PREFIX("prefix") {
@Override
public boolean matches(@NonNull Node node) {
return Objects.requireNonNull(node, "node").isPrefix();
}
@Override
public Map.@NonNull Entry<Integer, String> getEntry(@NonNull Node node) {
return Objects.requireNonNull(node, "node").getPrefix();
}
},
/**
* Represents a suffix
*/
SUFFIX("suffix") {
@Override
public boolean matches(@NonNull Node node) {
return Objects.requireNonNull(node, "node").isSuffix();
}
@Override
public Map.@NonNull Entry<Integer, String> getEntry(@NonNull Node node) {
return Objects.requireNonNull(node, "node").getSuffix();
}
};
private final String str;
ChatMetaType(String str) {
this.str = str;
}
/**
* Returns if the passed node matches the type
*
* @param node the node to test
* @return true if the node has the same type
*/
public abstract boolean matches(@NonNull Node node);
/**
* Returns if the passed node should be ignored when searching for meta of this type
*
* @param node the node to test
* @return true if the node does not share the same type
*/
public boolean shouldIgnore(@NonNull Node node) {
return !matches(node);
}
/**
* Maps the corresponding entry from the given node
*
* @param node the node to retrieve the entry from
* @return the entry
* @throws IllegalStateException if the node does not share the same type
*/
public abstract Map.@NonNull Entry<Integer, String> getEntry(@NonNull Node node);
@Override
public String toString() {
return this.str;
}
/**
* Parses a ChatMetaType from the given node.
*
* @param node the node
* @return the parsed chat meta type
* @since 3.4
*/
public static @NonNull Optional<ChatMetaType> ofNode(@NonNull Node node) {
if (node.isPrefix()) {
return Optional.of(PREFIX);
} else if (node.isSuffix()) {
return Optional.of(SUFFIX);
} else {
return Optional.empty();
}
}
}

View File

@ -1,357 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.Set;
/**
* Encapsulates the {@link ContextSet contexts} and {@link LookupSetting settings} for
* a permission or meta lookup.
*
* <p>This class is immutable.</p>
*
* @since 2.11
*/
public class Contexts {
/**
* The context key used to denote the subjects server
*/
public static final String SERVER_KEY = "server";
/**
* The context key used to denote the subjects world
*/
public static final String WORLD_KEY = "world";
/**
* The default {@link LookupSetting}s as a flag.
*/
private static final byte DEFAULT_SETTINGS_FLAG = LookupSetting.createFlag(
LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER,
LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD,
LookupSetting.RESOLVE_INHERITANCE,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER,
LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD
);
/**
* A 'global' or default contexts instance.
*
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*/
private static final Contexts GLOBAL = new Contexts(ImmutableContextSet.empty(), DEFAULT_SETTINGS_FLAG);
/**
* Gets the {@link FullySatisfiedContexts} instance.
*
* @return a context that will satisfy all contextual requirements.
*/
public static @NonNull Contexts allowAll() {
return FullySatisfiedContexts.getInstance();
}
/**
* Returns a 'global' or default contexts instance.
*
* <p>Formed of an empty {@link ContextSet} and all inclusion and
* inheritance {@link LookupSetting}s applied.</p>
*
* @return the global contexts
* @since 3.3
*/
public static @NonNull Contexts global() {
return GLOBAL;
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @return a new instance
*/
public static @NonNull Contexts of(@NonNull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
Objects.requireNonNull(contextSet, "contextSet");
byte settingsFlag = LookupSetting.createFlag(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
);
if (contextSet.isEmpty() && DEFAULT_SETTINGS_FLAG == settingsFlag) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), settingsFlag);
}
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param settings the settings
* @return a new instance
*/
public static Contexts of(@NonNull ContextSet contextSet, @NonNull Set<LookupSetting> settings) {
Objects.requireNonNull(contextSet, "contextSet");
Objects.requireNonNull(settings, "settings");
byte settingsFlag = LookupSetting.createFlag(settings);
if (contextSet.isEmpty() && DEFAULT_SETTINGS_FLAG == settingsFlag) {
return GLOBAL;
}
return new Contexts(contextSet.makeImmutable(), settingsFlag);
}
/**
* The contexts that apply for this lookup
*/
private final ImmutableContextSet contextSet;
/**
* The settings for this lookup
*/
private final byte settingsFlag;
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
private final int hashCode;
/**
* Creates a new {@link Contexts} instance.
*
* @param contextSet the context set
* @param includeNodesSetWithoutServer the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}
* @param includeNodesSetWithoutWorld the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}
* @param resolveInheritance the value of {@link LookupSetting#RESOLVE_INHERITANCE}
* @param applyParentsWithoutServer the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}
* @param applyParentsWithoutWorld the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}
* @param isOp the value of {@link LookupSetting#IS_OP}
* @deprecated in favour of {@link #of(ContextSet, boolean, boolean, boolean, boolean, boolean, boolean)}
*/
@Deprecated
public Contexts(@NonNull ContextSet contextSet, boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
this.contextSet = Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
this.settingsFlag = LookupSetting.createFlag(
includeNodesSetWithoutServer,
includeNodesSetWithoutWorld,
resolveInheritance,
applyParentsWithoutServer,
applyParentsWithoutWorld,
isOp
);
this.hashCode = calculateHashCode();
}
protected Contexts(@NonNull ImmutableContextSet contextSet, byte settingsFlag) {
this.contextSet = contextSet;
this.settingsFlag = settingsFlag;
this.hashCode = calculateHashCode();
}
/**
* Gets the {@link ContextSet set of context pairs} for this {@link Contexts} instance.
*
* @return an immutable context from this instance
* @since 2.13
*/
public @NonNull ContextSet getContexts() {
return this.contextSet;
}
/**
* Gets the set of {@link LookupSetting}s for this {@link Contexts} instance.
*
* @return the settings
* @since 4.2
*/
public @NonNull Set<LookupSetting> getSettings() {
return LookupSetting.createSetFromFlag(this.settingsFlag);
}
/**
* Creates a copy of this {@link Contexts} instance, but with the
* {@link ContextSet set of context pairs} replaced by the given set.
*
* @param contextSet the context set
* @return a new contexts instance representing the new settings
* @since 4.4
*/
public @NonNull Contexts setContexts(@NonNull ContextSet contextSet) {
ImmutableContextSet cs = Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
if (this.contextSet.equals(cs)) {
return this;
}
return new Contexts(cs, this.settingsFlag);
}
/**
* Creates a copy of this {@link Contexts} instance, but with the
* {@link LookupSetting}s replaced by the given settings.
*
* @param settings the lookup settings
* @return a new contexts instance representing the new settings
* @since 4.4
*/
public @NonNull Contexts setSettings(@NonNull Set<LookupSetting> settings) {
Objects.requireNonNull(settings, "settings");
byte settingsFlag = LookupSetting.createFlag(settings);
if (this.settingsFlag == settingsFlag) {
return this;
}
if (DEFAULT_SETTINGS_FLAG == settingsFlag && this.contextSet.isEmpty()) {
return GLOBAL;
}
return new Contexts(this.contextSet, settingsFlag);
}
/**
* Gets if the given {@link LookupSetting} is set.
*
* @param setting the setting
* @return the value
* @since 4.2
*/
public boolean hasSetting(@NonNull LookupSetting setting) {
return LookupSetting.isSet(this.settingsFlag, setting);
}
/**
* Gets the value of {@link LookupSetting#IS_OP}.
*
* @return the value
* @see LookupSetting#IS_OP
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isOp() {
return hasSetting(LookupSetting.IS_OP);
}
/**
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER}.
*
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobal() {
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER);
}
/**
* Gets the value of {@link LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD}.
*
* @return the value
* @see LookupSetting#INCLUDE_NODES_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isIncludeGlobalWorld() {
return hasSetting(LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD);
}
/**
* Gets the value of {@link LookupSetting#RESOLVE_INHERITANCE}.
*
* @return the value
* @see LookupSetting#RESOLVE_INHERITANCE
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGroups() {
return hasSetting(LookupSetting.RESOLVE_INHERITANCE);
}
/**
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER}.
*
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_SERVER
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalGroups() {
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER);
}
/**
* Gets the value of {@link LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD}.
*
* @return the value
* @see LookupSetting#APPLY_PARENTS_SET_WITHOUT_WORLD
* @deprecated in favour of {@link #hasSetting(LookupSetting)}
*/
@Deprecated
public boolean isApplyGlobalWorldGroups() {
return hasSetting(LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD);
}
@Override
public @NonNull String toString() {
return "Contexts(contextSet=" + this.contextSet + ", settings=" + LookupSetting.createSetFromFlag(this.settingsFlag) + ")";
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (o == allowAll()) return false;
if (!(o instanceof Contexts)) return false;
final Contexts that = (Contexts) o;
return this.contextSet.equals(that.contextSet) && this.settingsFlag == that.settingsFlag;
}
private int calculateHashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.contextSet.hashCode();
result = result * PRIME + this.settingsFlag;
return result;
}
@Override
public int hashCode() {
return this.hashCode;
}
}

View File

@ -1,79 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.caching.MetaContexts;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A special instance of {@link Contexts}, which when passed to:
*
* <p></p>
* <ul>
* <li>{@link CachedData#getPermissionData(Contexts)}</li>
* <li>{@link CachedData#getMetaData(Contexts)}</li>
* <li>{@link CachedData#getMetaData(MetaContexts)}</li>
* </ul>
*
* <p>... will always satisfy all contextual requirements.</p>
*
* <p>This effectively allows you to do lookups which ignore context.</p>
*
* @since 3.3
*/
public final class FullySatisfiedContexts extends Contexts {
// singleton
private static final FullySatisfiedContexts INSTANCE = new FullySatisfiedContexts();
public static @NonNull Contexts getInstance() {
return INSTANCE;
}
private FullySatisfiedContexts() {
super(ImmutableContextSet.empty(), LookupSetting.createFlag(Contexts.global().getSettings()));
}
@Override
public @NonNull String toString() {
return "FullySatisfiedContexts()";
}
@Override
public boolean equals(Object o) {
// this class is a singleton, so we can use object comparison to check equality.
return o == this;
}
@Override
public int hashCode() {
// just use the system hashcode - we need to override the hashcode impl in super
return System.identityHashCode(this);
}
}

View File

@ -1,117 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Map;
/**
* Wrapper around parts of the LuckPerms configuration file
*/
public interface LPConfiguration {
/**
* Gets the name of this server
*
* @return the name of this server
*/
@NonNull String getServer();
/**
* Gets if the users on this server will have their global permissions applied
*
* @return if the users on this server will have their global permissions applied
*/
boolean getIncludeGlobalPerms();
/**
* Gets if the users on this server will have their global world permissions applied
*
* @return if the users on this server will have their global world permissions applied
* @since 2.9
*/
boolean getIncludeGlobalWorldPerms();
/**
* Gets if the platform is applying global groups
*
* @return true if the platform is applying global groups
* @since 2.9
*/
boolean getApplyGlobalGroups();
/**
* Gets if the platform is applying global world groups
*
* @return true if the platform is applying global world groups
* @since 2.9
*/
boolean getApplyGlobalWorldGroups();
/**
* Gets the storage method string from the configuration
*
* @return the storage method string from the configuration
*/
@NonNull String getStorageMethod();
/**
* Gets true if split storage is enabled
*
* @return true if split storage is enabled
* @since 2.7
*/
boolean getSplitStorage();
/**
* Gets a map of split storage options
*
* @return a map of split storage options, where the key is the storage section, and the value is the storage
* method. For example: key = user, value = json
* @since 2.7
*/
@NonNull Map<String, String> getSplitStorageOptions();
@NonNull Unsafe unsafe();
interface Unsafe {
/**
* Gets an Object from the config.
*
* <p>This method is nested under {@link Unsafe} because the keys
* and return types may change between versions without warning.</p>
*
* @param key the key, as defined as a field name in
* the "ConfigKeys" class.
* @return the corresponding object, if one is present
* @throws IllegalArgumentException if the key isn't known
*/
@NonNull Object getObject(String key);
}
}

View File

@ -1,124 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import java.util.EnumSet;
import java.util.Set;
/**
* The various lookup setting flags for {@link Contexts}.
*
* @since 4.2
*/
public enum LookupSetting {
/**
* If the target subject is OP
*/
IS_OP,
/**
* If global or non-server-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific nodes should be applied
*/
INCLUDE_NODES_SET_WITHOUT_WORLD,
/**
* If parent groups should be resolved
*/
RESOLVE_INHERITANCE,
/**
* If global or non-server-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_SERVER,
/**
* If global or non-world-specific group memberships should be applied
*/
APPLY_PARENTS_SET_WITHOUT_WORLD;
/* bitwise utility methods */
static boolean isSet(byte b, LookupSetting setting) {
return ((b >> setting.ordinal()) & 1) == 1;
}
static byte createFlag(LookupSetting... settings) {
byte b = 0;
for (LookupSetting setting : settings) {
b |= (1 << setting.ordinal());
}
return b;
}
static byte createFlag(Set<LookupSetting> settings) {
byte b = 0;
for (LookupSetting setting : settings) {
b |= (1 << setting.ordinal());
}
return b;
}
static Set<LookupSetting> createSetFromFlag(byte b) {
EnumSet<LookupSetting> settings = EnumSet.noneOf(LookupSetting.class);
for (LookupSetting setting : LookupSetting.values()) {
if (((b >> setting.ordinal()) & 1) == 1) {
settings.add(setting);
}
}
return settings;
}
static byte createFlag(boolean includeNodesSetWithoutServer, boolean includeNodesSetWithoutWorld, boolean resolveInheritance, boolean applyParentsWithoutServer, boolean applyParentsWithoutWorld, boolean isOp) {
byte b = 0;
if (includeNodesSetWithoutServer) {
b |= (1 << LookupSetting.INCLUDE_NODES_SET_WITHOUT_SERVER.ordinal());
}
if (includeNodesSetWithoutWorld) {
b |= (1 << LookupSetting.INCLUDE_NODES_SET_WITHOUT_WORLD.ordinal());
}
if (resolveInheritance) {
b |= (1 << LookupSetting.RESOLVE_INHERITANCE.ordinal());
}
if (applyParentsWithoutServer) {
b |= (1 << LookupSetting.APPLY_PARENTS_SET_WITHOUT_SERVER.ordinal());
}
if (applyParentsWithoutWorld) {
b |= (1 << LookupSetting.APPLY_PARENTS_SET_WITHOUT_WORLD.ordinal());
}
if (isOp) {
b |= (1 << LookupSetting.IS_OP.ordinal());
}
return b;
}
}

View File

@ -0,0 +1,217 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import me.lucko.luckperms.api.actionlog.ActionLogger;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.messaging.MessagingService;
import me.lucko.luckperms.api.messenger.MessengerProvider;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.api.metastacking.MetaStackElement;
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.api.model.group.Group;
import me.lucko.luckperms.api.model.group.GroupManager;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.model.user.UserManager;
import me.lucko.luckperms.api.node.NodeBuilderRegistry;
import me.lucko.luckperms.api.platform.Platform;
import me.lucko.luckperms.api.platform.PluginMetadata;
import me.lucko.luckperms.api.track.Track;
import me.lucko.luckperms.api.track.TrackManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
/**
* The LuckPerms API.
*
* <p>The API allows other plugins on the server to read and modify LuckPerms
* data, change behaviour of the plugin, listen to certain events, and integrate
* LuckPerms into other plugins and systems.</p>
*
* <p>This interface represents the base of the API package. All functions are
* accessed via this interface.</p>
*
* <p>To start using the API, you need to obtain an instance of this interface.
* These are registered by the LuckPerms plugin to the platforms Services
* Manager. This is the preferred method for obtaining an instance.</p>
*
* <p>For ease of use, and for platforms without a Service Manager, an instance
* can also be obtained from the static singleton accessor in
* {@link LuckPermsProvider}.</p>
*/
public interface LuckPerms {
/**
* Gets the name of this server.
*
* <p>This is defined in the LuckPerms configuration file, and is used for
* server specific permission handling.</p>
*
* <p>The default server name is "global".</p>
*
* @return the server name
*/
@NonNull String getServerName();
/**
* Gets the {@link UserManager}, responsible for managing
* {@link User} instances.
*
* <p>This manager can be used to retrieve instances of {@link User} by uuid
* or name, or query all loaded users.</p>
*
* @return the user manager
*/
@NonNull UserManager getUserManager();
/**
* Gets the {@link GroupManager}, responsible for managing
* {@link Group} instances.
*
* <p>This manager can be used to retrieve instances of {@link Group} by
* name, or query all loaded groups.</p>
*
* @return the group manager
*/
@NonNull GroupManager getGroupManager();
/**
* Gets the {@link TrackManager}, responsible for managing
* {@link Track} instances.
*
* <p>This manager can be used to retrieve instances of {@link Track} by
* name, or query all loaded tracks.</p>
*
* @return the track manager
*/
@NonNull TrackManager getTrackManager();
/**
* Gets the {@link Platform}, which represents the server platform the
* plugin is running on.
*
* @return the platform
*/
@NonNull Platform getPlatform();
/**
* Gets the {@link PluginMetadata}, responsible for providing metadata about
* the LuckPerms plugin currently running.
*
* @return the plugin metadata
*/
@NonNull PluginMetadata getPluginMetadata();
/**
* Gets the {@link EventBus}, used for subscribing to internal LuckPerms
* events.
*
* @return the event bus
*/
@NonNull EventBus getEventBus();
/**
* Gets the {@link MessagingService}, used to dispatch updates throughout a
* network of servers running the plugin.
*
* <p>Not all instances of LuckPerms will have a messaging service setup and
* configured.</p>
*
* @return the messaging service instance, if present.
*/
@NonNull Optional<MessagingService> getMessagingService();
/**
* Gets the {@link ActionLogger}, responsible for saving and broadcasting
* defined actions occurring on the platform.
*
* @return the action logger
*/
@NonNull ActionLogger getActionLogger();
/**
* Gets the {@link ContextManager}, responsible for managing
* {@link ContextCalculator}s, and calculating applicable contexts.</p>
*
* @return the context manager
*/
@NonNull ContextManager getContextManager();
/**
* Gets the {@link NodeBuilderRegistry}.
*
* @return the node builder registry
*/
@NonNull NodeBuilderRegistry getNodeBuilderRegistry();
/**
* Gets the {@link MetaStackFactory}.
*
* <p>The metastack factory provides methods for retrieving
* {@link MetaStackElement}s and constructing
* {@link MetaStackDefinition}s.</p>
*
* @return the meta stack factory
*/
@NonNull MetaStackFactory getMetaStackFactory();
/**
* Schedules the execution of an update task, and returns an encapsulation
* of the task as a {@link CompletableFuture}.
*
* <p>The exact actions performed in an update task remains an
* implementation detail of the plugin, however, as a minimum, it is
* expected to perform a full reload of user, group and track data, and
* ensure that any changes are fully applied and propagated.</p>
*
* @return a future
*/
@NonNull CompletableFuture<Void> runUpdateTask();
/**
* Registers a {@link MessengerProvider} for use by the platform.
*
* <p>Note that the mere action of registering a provider doesn't
* necessarily mean that it will be used.</p>
*
* @param messengerProvider the messenger provider.
*/
void registerMessengerProvider(@NonNull MessengerProvider messengerProvider);
/**
* Gets a {@link Collection} of all known permission strings.
*
* @return a collection of the known permissions
*/
@NonNull Collection<String> getKnownPermissions();
}

View File

@ -1,473 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import me.lucko.luckperms.LuckPerms;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextCalculator;
import me.lucko.luckperms.api.context.ContextManager;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.event.EventBus;
import me.lucko.luckperms.api.manager.CachedDataManager;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.TrackManager;
import me.lucko.luckperms.api.manager.UserManager;
import me.lucko.luckperms.api.messenger.MessengerProvider;
import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.api.platform.PlatformInfo;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* The LuckPerms API.
*
* <p>This interface is the base of the entire API package. All API functions
* are accessed via this interface.</p>
*
* <p>An instance can be obtained via {@link LuckPerms#getApi()}, or the platforms
* Services Manager.</p>
*/
public interface LuckPermsApi {
/**
* Gets information about the platform LuckPerms is running on.
*
* @return the platform info
* @since 4.0
*/
@NonNull PlatformInfo getPlatformInfo();
/**
* Gets the {@link UserManager}, responsible for managing
* {@link User} instances.
*
* <p>This manager can be used to retrieve instances of {@link User} by uuid
* or name, or query all loaded users.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save users.</p>
*
* @return the user manager
* @since 4.0
*/
@NonNull UserManager getUserManager();
/**
* Gets the {@link GroupManager}, responsible for managing
* {@link Group} instances.
*
* <p>This manager can be used to retrieve instances of {@link Group} by
* name, or query all loaded groups.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete groups.</p>
*
* @return the group manager
* @since 4.0
*/
@NonNull GroupManager getGroupManager();
/**
* Gets the {@link TrackManager}, responsible for managing
* {@link Track} instances.
*
* <p>This manager can be used to retrieve instances of {@link Track} by
* name, or query all loaded tracks.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete tracks.</p>
*
* @return the track manager
* @since 4.0
*/
@NonNull TrackManager getTrackManager();
/**
* Gets the {@link CachedDataManager}, responsible for managing
* {@link CachedData} instances.
*
* @return the cached data manager
* @since 4.5
*/
@NonNull CachedDataManager getCachedDataManager();
/**
* Schedules the execution of an update task, and returns an encapsulation
* of the task as a {@link CompletableFuture}.
*
* <p>The exact actions performed in an update task remains an
* implementation detail of the plugin, however, as a minimum, it is
* expected to perform a full reload of user, group and track data, and
* ensure that any changes are fully applied and propagated.</p>
*
* @return a future
* @since 4.0
*/
@NonNull CompletableFuture<Void> runUpdateTask();
/**
* Gets the {@link EventBus}, used for subscribing to internal LuckPerms
* events.
*
* @return the event bus
* @since 3.0
*/
@NonNull EventBus getEventBus();
/**
* Gets a representation of the plugins configuration
*
* @return the configuration
*/
@NonNull LPConfiguration getConfiguration();
/**
* Gets the {@link MessagingService}, if present.
*
* <p>The MessagingService is used to dispatch updates throughout a network
* of servers running the plugin.</p>
*
* <p>Not all instances of LuckPerms will have a messaging service setup and
* configured, but it is recommended that all users of the API account for
* and make use of this.</p>
*
* @return the messaging service instance, if present.
*/
@NonNull Optional<MessagingService> getMessagingService();
/**
* Registers a {@link MessengerProvider} for use by the platform.
*
* <p>Note that the mere action of registering a provider doesn't
* necessarily mean that it will be used.</p>
*
* @param messengerProvider the messenger provider.
* @since 4.1
*/
void registerMessengerProvider(@NonNull MessengerProvider messengerProvider);
/**
* Gets the {@link ActionLogger}.
*
* <p>The action logger is responsible for saving and broadcasting defined
* actions occurring on the platform.</p>
*
* @return the action logger
* @since 4.1
*/
@NonNull ActionLogger getActionLogger();
/**
* Gets the {@link ContextManager}.
*
* <p>The context manager manages {@link ContextCalculator}s, and calculates
* applicable contexts for a given type.</p>
*
* @return the context manager
* @since 4.0
*/
@NonNull ContextManager getContextManager();
/**
* Gets a {@link Collection} of all known permission strings.
*
* @return a collection of the known permissions
* @since 4.4
*/
@NonNull Collection<String> getKnownPermissions();
/**
* Gets the {@link NodeFactory}.
*
* <p>The node factory provides methods for building {@link Node} instances.</p>
*
* @return the node factory
*/
@NonNull NodeFactory getNodeFactory();
/**
* Gets the {@link MetaStackFactory}.
*
* <p>The metastack factory provides methods for retrieving
* {@link me.lucko.luckperms.api.metastacking.MetaStackElement}s and constructing
* {@link me.lucko.luckperms.api.metastacking.MetaStackDefinition}s.</p>
*
* @return the meta stack factory
* @since 3.2
*/
@NonNull MetaStackFactory getMetaStackFactory();
/*
* The following methods are provided only for convenience, and offer no
* additional functionality.
*
* They are implemented as "default" methods, using the manager and factory
* instances provided by the methods above.
*/
/**
* Gets a wrapped user object from the user storage
*
* @param uuid the uuid of the user to get
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the uuid is null
*/
default @Nullable User getUser(@NonNull UUID uuid) {
return getUserManager().getUser(uuid);
}
/**
* Gets a wrapped user object from the user storage.
*
* @param uuid the uuid of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the uuid is null
*/
default @NonNull Optional<User> getUserSafe(@NonNull UUID uuid) {
return getUserManager().getUserOpt(uuid);
}
/**
* Gets a wrapped user object from the user storage
*
* @param name the username of the user to get
* @return a {@link User} object, if one matching the uuid is loaded, or null if not
* @throws NullPointerException if the name is null
*/
default @Nullable User getUser(@NonNull String name) {
return getUserManager().getUser(name);
}
/**
* Gets a wrapped user object from the user storage.
*
* @param name the username of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the name is null
*/
default @NonNull Optional<User> getUserSafe(@NonNull String name) {
return getUserManager().getUserOpt(name);
}
/**
* Gets a set of all loaded users.
*
* @return a {@link Set} of {@link User} objects
*/
default @NonNull Set<User> getUsers() {
return getUserManager().getLoadedUsers();
}
/**
* Check if a user is loaded in memory
*
* @param uuid the uuid to check for
* @return true if the user is loaded
* @throws NullPointerException if the uuid is null
*/
default boolean isUserLoaded(@NonNull UUID uuid) {
return getUserManager().isLoaded(uuid);
}
/**
* Unload a user from the internal storage, if they're not currently online.
*
* @param user the user to unload
* @throws NullPointerException if the user is null
*/
default void cleanupUser(@NonNull User user) {
getUserManager().cleanupUser(user);
}
/**
* Gets a wrapped group object from the group storage
*
* @param name the name of the group to get
* @return a {@link Group} object, if one matching the name exists, or null if not
* @throws NullPointerException if the name is null
*/
default @Nullable Group getGroup(@NonNull String name) {
return getGroupManager().getGroup(name);
}
/**
* Gets a wrapped group object from the group storage.
*
* <p>This method does not return null, unlike {@link #getGroup}</p>
*
* @param name the name of the group to get
* @return an optional {@link Group} object
* @throws NullPointerException if the name is null
*/
default @NonNull Optional<Group> getGroupSafe(@NonNull String name) {
return getGroupManager().getGroupOpt(name);
}
/**
* Gets a set of all loaded groups.
*
* @return a {@link Set} of {@link Group} objects
*/
default @NonNull Set<Group> getGroups() {
return getGroupManager().getLoadedGroups();
}
/**
* Check if a group is loaded in memory
*
* @param name the name to check for
* @return true if the group is loaded
* @throws NullPointerException if the name is null
*/
default boolean isGroupLoaded(@NonNull String name) {
return getGroupManager().isLoaded(name);
}
/**
* Gets a wrapped track object from the track storage
*
* @param name the name of the track to get
* @return a {@link Track} object, if one matching the name exists, or null
* if not
* @throws NullPointerException if the name is null
*/
default @Nullable Track getTrack(@NonNull String name) {
return getTrackManager().getTrack(name);
}
/**
* Gets a wrapped track object from the track storage.
*
* <p>This method does not return null, unlike {@link #getTrack}</p>
*
* @param name the name of the track to get
* @return an optional {@link Track} object
* @throws NullPointerException if the name is null
*/
default @NonNull Optional<Track> getTrackSafe(@NonNull String name) {
return getTrackManager().getTrackOpt(name);
}
/**
* Gets a set of all loaded tracks.
*
* @return a {@link Set} of {@link Track} objects
*/
default @NonNull Set<Track> getTracks() {
return getTrackManager().getLoadedTracks();
}
/**
* Check if a track is loaded in memory
*
* @param name the name to check for
* @return true if the track is loaded
* @throws NullPointerException if the name is null
*/
default boolean isTrackLoaded(@NonNull String name) {
return getTrackManager().isLoaded(name);
}
/**
* Returns a new LogEntry Builder instance
*
* @return a new builder
* @since 4.0
*/
default LogEntry.@NonNull Builder newLogEntryBuilder() {
return getActionLogger().newEntryBuilder();
}
/**
* Returns a permission builder instance
*
* @param permission the main permission node to build
* @return a {@link Node.Builder} instance
* @throws IllegalArgumentException if the permission is invalid
* @throws NullPointerException if the permission is null
* @since 2.6
*/
default Node.@NonNull Builder buildNode(@NonNull String permission) throws IllegalArgumentException {
return getNodeFactory().newBuilder(permission);
}
/**
* Register a custom context calculator to the server
*
* @param calculator the context calculator to register. The type MUST be the player class of the platform.
* @throws ClassCastException if the type is not the player class of the platform.
*/
default void registerContextCalculator(@NonNull ContextCalculator<?> calculator) {
getContextManager().registerCalculator(calculator);
}
/**
* Gets a calculated context instance for the user using the rules of the platform.
*
* <p> These values are calculated using the options in the configuration, and the provided calculators.
*
* @param user the user to get contexts for
* @return an optional containing contexts. Will return empty if the user is not online.
*/
default @NonNull Optional<Contexts> getContextForUser(@NonNull User user) {
return getContextManager().lookupApplicableContexts(user);
}
/**
* Gets set of contexts applicable to a player using the platforms {@link ContextCalculator}s.
*
* @param player the player to calculate for. Must be the player instance for the platform.
* @return a set of contexts.
* @since 2.17
*/
default @NonNull ContextSet getContextForPlayer(@NonNull Object player) {
return getContextManager().getApplicableContext(player);
}
/**
* Gets a Contexts instance for the player using the platforms {@link ContextCalculator}s.
*
* @param player the player to calculate for. Must be the player instance for the platform.
* @return a set of contexts.
* @since 3.3
*/
default @NonNull Contexts getContextsForPlayer(@NonNull Object player) {
return getContextManager().getApplicableContexts(player);
}
}

View File

@ -23,25 +23,21 @@
* SOFTWARE.
*/
package me.lucko.luckperms;
import me.lucko.luckperms.api.LuckPermsApi;
package me.lucko.luckperms.api;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Optional;
/**
* Provides static access to the {@link LuckPermsApi}.
* Provides static access to the {@link LuckPerms} service.
*
* <p>Ideally, the ServiceManager for the platform should be used to obtain an instance,
* however, this provider can be used if you need static access.</p>
* <p>Ideally, the ServiceManager for the platform should be used to obtain an
* instance, however, this provider can be used if you need static access.</p>
*/
public final class LuckPerms {
private static LuckPermsApi instance = null;
public final class LuckPermsProvider {
private static LuckPerms instance = null;
/**
* Gets an instance of the {@link LuckPermsApi},
* Gets an instance of the {@link LuckPerms} service,
* throwing {@link IllegalStateException} if an instance is not yet loaded.
*
* <p>Will never return null.</p>
@ -49,43 +45,22 @@ public final class LuckPerms {
* @return an api instance
* @throws IllegalStateException if the api is not loaded
*/
public static @NonNull LuckPermsApi getApi() {
public static @NonNull LuckPerms get() {
if (instance == null) {
throw new IllegalStateException("API is not loaded.");
throw new IllegalStateException("The LuckPerms API is not loaded.");
}
return instance;
}
/**
* Gets an instance of {@link LuckPermsApi}, if it is loaded.
*
* <p>Unlike {@link LuckPerms#getApi}, this method will not throw an
* {@link IllegalStateException} if an instance is not yet loaded, rather return
* an empty {@link Optional}.
*
* @return an optional api instance
*/
public static @NonNull Optional<LuckPermsApi> getApiSafe() {
return Optional.ofNullable(instance);
static void register(LuckPerms instance) {
LuckPermsProvider.instance = instance;
}
/**
* Registers an instance of the {@link LuckPermsApi} with this provider.
*
* @param instance the instance
*/
static void registerProvider(LuckPermsApi instance) {
LuckPerms.instance = instance;
static void unregister() {
LuckPermsProvider.instance = null;
}
/**
* Removes the current instance from this provider.
*/
static void unregisterProvider() {
LuckPerms.instance = null;
}
private LuckPerms() {
private LuckPermsProvider() {
throw new UnsupportedOperationException("This class cannot be instantiated.");
}

View File

@ -1,74 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
/**
* Represents the result to a "mutation" on an object.
*
* @since 4.2
*/
public interface MutateResult {
/**
* Instance of {@link MutateResult} which always reports success.
*/
MutateResult GENERIC_SUCCESS = () -> true;
/**
* Instance of {@link MutateResult} which always reports failure.
*/
MutateResult GENERIC_FAILURE = () -> false;
/**
* Gets if the operation which produced this result completed successfully.
*
* @return if the result indicates a success
*/
boolean wasSuccess();
/**
* Gets if the operation which produced this result failed.
*
* @return if the result indicates a failure
*/
default boolean wasFailure() {
return !wasSuccess();
}
/**
* Gets a boolean representation of the result.
*
* <p>A value of <code>true</code> marks that the operation {@link #wasSuccess() was a success}
* and a value of <code>false</code> marks that the operation
* {@link #wasFailure() was a failure}.</p>
*
* @return a boolean representation
*/
default boolean asBoolean() {
return wasSuccess();
}
}

View File

@ -1,670 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import me.lucko.luckperms.api.nodetype.types.DisplayNameType;
import me.lucko.luckperms.api.nodetype.types.InheritanceType;
import me.lucko.luckperms.api.nodetype.types.MetaType;
import me.lucko.luckperms.api.nodetype.types.PrefixType;
import me.lucko.luckperms.api.nodetype.types.SuffixType;
import me.lucko.luckperms.api.nodetype.types.WeightType;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
/**
* Represents a LuckPerms "node".
*
* <p>The {@link Node} class encapsulates more than just permission assignments.
* Nodes are used to store data about inherited groups, as well as assigned
* prefixes, suffixes and meta values.</p>
*
* <p>Combining these various states into one object (a "node") means that a
* holder only has to have one type of data set (a set of nodes) in order to
* take on various properties.</p>
*
* <p>It is recommended that users of the API make use of {@link Stream}s
* to manipulate data and obtain the required information.</p>
*
* <p>This interface provides a number of methods to read the attributes of the
* node, as well as methods to query and extract additional state and properties
* from these settings.</p>
*
* <p>Nodes have the following attributes:</p>
* <p></p>
* <ul>
* <li>{@link #getPermission() permission} - the actual permission string</li>
* <li>{@link #getValue() value} - the value of the node (false for negated)</li>
* <li>{@link #isOverride() override} - if the node is marked as having special priority over other nodes</li>
* <li>{@link #getServer() server} - the specific server where this node should apply</li>
* <li>{@link #getWorld() world} - the specific world where this node should apply</li>
* <li>{@link #getContexts() context} - the additional contexts required for this node to apply </li>
* <li>{@link #getExpiry() expiry} - the time when this node should expire</li>
* </ul>
*
* <p>The 'permission' property of a {@link Node} is also used in some cases to represent state
* beyond a granted permission. This state is encapsulated by extra {@link NodeType} data which
* can be obtained from this instance using {@link #getTypeData(NodeTypeKey)}.</p>
*
* <p>Type data is mapped by {@link NodeTypeKey}s, which are usually stored as static members of the
* corresponding {@link NodeType} class under the <code>KEY</code> field.</p>
*
* <p>The current types are:</p>
* <p></p>
* <ul>
* <li>normal - just a regular permission</li>
* <li>{@link InheritanceType} - an "inheritance node" marks that the holder should inherit data from another group</li>
* <li>{@link PrefixType} - represents an assigned prefix</li>
* <li>{@link SuffixType} - represents an assigned suffix</li>
* <li>{@link MetaType} - represents an assigned meta option</li>
* <li>{@link WeightType} - marks the weight of the object holding this node</li>
* <li>{@link DisplayNameType} - marks the display name of the object holding this node</li>
* </ul>
*
* <p>The core node state must be immutable in all implementations.</p>
*
* @see NodeFactory for obtaining and constructing instances.
* @since 2.6
*/
public interface Node {
/**
* Gets the permission string this node encapsulates.
*
* <p>The exact value of this string may vary for nodes which aren't regular
* permission settings.</p>
*
* @return the actual permission node
*/
@NonNull String getPermission();
/**
* Gets the value of the node.
*
* <p>A negated setting would result in a value of <code>false</code>.</p>
*
* @return the nodes value
*/
boolean getValue();
/**
* Gets the value of this node as a {@link Tristate}.
*
* @return the value of this node as a Tristate
*/
default @NonNull Tristate getTristate() {
return Tristate.fromBoolean(getValue());
}
/**
* Gets if the node is negated.
*
* <p>This is the inverse of the {@link #getValue() value}.</p>
*
* @return true if the node is negated
*/
default boolean isNegated() {
return !getValue();
}
/**
* Gets if this node is set to override explicitly.
*
* <p>This value does not persist across saves, and is therefore only
* useful for transient nodes.</p>
*
* @return true if this node is set to override explicitly
*/
boolean isOverride();
/**
* Gets the server this node applies on, if the node is server specific.
*
* @return an {@link Optional} containing the server, if one is defined
*/
@NonNull Optional<String> getServer();
/**
* Gets the world this node applies on, if the node is world specific.
*
* @return an {@link Optional} containing the world, if one is defined
*/
@NonNull Optional<String> getWorld();
/**
* Gets if this node is server specific.
*
* @return true if this node is server specific
*/
boolean isServerSpecific();
/**
* Gets if this node is server specific.
*
* @return true if this node is server specific
*/
boolean isWorldSpecific();
/**
* Gets if this node applies globally, and therefore has no specific context.
*
* @return true if this node applies globally, and has no specific context
* @since 3.1
*/
boolean appliesGlobally();
/**
* Gets if this node has any specific context in order for it to apply.
*
* @return true if this node has specific context
* @since 3.1
*/
boolean hasSpecificContext();
/**
* Gets if this node should apply in the given context
*
* @param contextSet the context set
* @return true if the node should apply
* @since 2.13
*/
boolean shouldApplyWithContext(@NonNull ContextSet contextSet);
/**
* Resolves any shorthand parts of this node and returns the full list of
* resolved nodes.
*
* <p>The list will not contain the exact permission itself.</p>
*
* @return a list of full nodes
*/
@NonNull List<String> resolveShorthand();
/**
* Gets if this node is assigned temporarily.
*
* @return true if this node will expire in the future
*/
boolean isTemporary();
/**
* Gets if this node is permanent (will not expire).
*
* @return true if this node will not expire
*/
default boolean isPermanent() {
return !isTemporary();
}
/**
* Gets the unix timestamp (in seconds) when this node will expire.
*
* @return the time in Unix time when this node will expire
* @throws IllegalStateException if the node is not temporary
*/
long getExpiryUnixTime() throws IllegalStateException;
/**
* Gets the date when this node will expire.
*
* @return the {@link Date} when this node will expire
* @throws IllegalStateException if the node is not temporary
*/
@NonNull Date getExpiry() throws IllegalStateException;
/**
* Gets the number of seconds until this permission will expire.
*
* <p>Will return a negative value if the node has already expired.</p>
*
* @return the number of seconds until this permission will expire
* @throws IllegalStateException if the node is not temporary
*/
long getSecondsTilExpiry() throws IllegalStateException;
/**
* Gets if the node has expired.
*
* <p>This returns false if the node is not temporary.</p>
*
* @return true if this node has expired
*/
boolean hasExpired();
/**
* Gets the extra contexts required for this node to apply.
*
* @return the extra contexts required for this node to apply
* @since 2.13
*/
@NonNull ContextSet getContexts();
/**
* The same as {@link #getContexts()}, but also includes context pairs for
* "server" and "world" keys if present.
*
* @return the full contexts required for this node to apply
* @see Contexts#SERVER_KEY
* @see Contexts#WORLD_KEY
* @since 3.1
*/
@NonNull ContextSet getFullContexts();
/**
* Gets if this node is a wildcard permission.
*
* @return true if this node is a wildcard permission
*/
boolean isWildcard();
/**
* Gets the level of this wildcard.
*
* <p>The node <code>luckperms.*</code> has a wildcard level of 1.</p>
* <p>The node <code>luckperms.user.permission.*</code> has a wildcard level of 3.</p>
*
* <p>Nodes with a higher wildcard level are more specific and have priority over
* less specific nodes (nodes with a lower wildcard level).</p>
*
* @return the wildcard level
* @throws IllegalStateException if this is not a wildcard
*/
int getWildcardLevel() throws IllegalStateException;
/**
* Gets if this node has any extra {@link NodeType} data attached to it.
*
* @return if this node has any type data
* @since 4.2
*/
boolean hasTypeData();
/**
* Gets the type data corresponding to the given <code>key</code>, if present.
*
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data, if present
* @since 4.2
*/
<T extends NodeType> Optional<T> getTypeData(NodeTypeKey<T> key);
/**
* Gets the type data corresponding to the given <code>key</code>, throwing an exception
* if no data is present.
*
* @param key the key
* @param <T> the {@link NodeType} type
* @return the data
* @throws IllegalStateException if data isn't present
* @since 4.2
*/
default <T extends NodeType> T typeData(NodeTypeKey<T> key) throws IllegalStateException {
return getTypeData(key).orElseThrow(() -> new IllegalStateException("Node '" + getPermission() + "' does not have the '" + key.getTypeName() + "' type."));
}
/**
* Gets if this node has {@link InheritanceType} type data.
*
* @return true if this is a inheritance (group) node.
*/
default boolean isGroupNode() {
return getTypeData(InheritanceType.KEY).isPresent();
}
/**
* Gets the name of the inherited group if this node has {@link InheritanceType} type data,
* throwing an exception if the data is not present.
*
* @return the name of the group
* @throws IllegalStateException if this node doesn't have {@link InheritanceType} data
*/
default @NonNull String getGroupName() throws IllegalStateException {
return typeData(InheritanceType.KEY).getGroupName();
}
/**
* Gets if this node has {@link MetaType} type data.
*
* @return true if this is a meta node.
*/
default boolean isMeta() {
return getTypeData(MetaType.KEY).isPresent();
}
/**
* Gets the meta entry if this node has {@link MetaType} type data,
* throwing an exception if the data is not present.
*
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link MetaType} data
*/
default Map.@NonNull Entry<String, String> getMeta() throws IllegalStateException {
return typeData(MetaType.KEY);
}
/**
* Gets if this node has {@link PrefixType} type data.
*
* @return true if this node is a prefix node
*/
default boolean isPrefix() {
return getTypeData(PrefixType.KEY).isPresent();
}
/**
* Gets the prefix entry if this node has {@link PrefixType} type data,
* throwing an exception if the data is not present.
*
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link PrefixType} data
*/
default Map.@NonNull Entry<Integer, String> getPrefix() throws IllegalStateException {
return typeData(PrefixType.KEY).getAsEntry();
}
/**
* Gets if this node has {@link SuffixType} type data.
*
* @return true if this node is a suffix node
*/
default boolean isSuffix() {
return getTypeData(SuffixType.KEY).isPresent();
}
/**
* Gets the suffix entry if this node has {@link SuffixType} type data,
* throwing an exception if the data is not present.
*
* @return the meta entry
* @throws IllegalStateException if this node doesn't have {@link SuffixType} data
*/
default Map.@NonNull Entry<Integer, String> getSuffix() throws IllegalStateException {
return typeData(SuffixType.KEY).getAsEntry();
}
/**
* Gets if this Node is equal to another node.
*
* @param obj the other node
* @return true if this node is equal to the other provided
* @see StandardNodeEquality#EXACT
*/
@Override
boolean equals(Object obj);
/**
* Gets if this Node is equal to another node as defined by the given
* {@link NodeEqualityPredicate}.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
* @since 4.1
*/
boolean equals(Node other, NodeEqualityPredicate equalityPredicate);
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @see StandardNodeEquality#IGNORE_VALUE
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
*/
@Deprecated
default boolean equalsIgnoringValue(@NonNull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* expiry time or value.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @see StandardNodeEquality#IGNORE_EXPIRY_TIME_AND_VALUE
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
*/
@Deprecated
default boolean almostEquals(@NonNull Node other) {
return equals(other, StandardNodeEquality.IGNORE_EXPIRY_TIME_AND_VALUE);
}
/**
* Similar to {@link Node#equals(Object)}, except doesn't take note of the
* value or if the node is temporary.
*
* @param other the other node
* @return true if the two nodes are almost equal
* @see StandardNodeEquality#IGNORE_VALUE_OR_IF_TEMPORARY
* @since 2.8
* @deprecated in favour of {@link #equals(Node, NodeEqualityPredicate)}
*/
@Deprecated
default boolean equalsIgnoringValueOrTemp(@NonNull Node other) {
return equals(other, StandardNodeEquality.IGNORE_VALUE_OR_IF_TEMPORARY);
}
/**
* Constructs a new builder initially containing the current properties of
* this node.
*
* @return a new builder
* @since 4.1
*/
Builder toBuilder();
/**
* Builds a Node instance
*/
interface Builder {
/**
* Copies the attributes from the given node and applies them to this
* builder.
*
* <p>Note that this copies all attributes <strong>except</strong> the
* permission itself.</p>
*
* @param node the node to copy from
* @return the builder
* @since 4.2
*/
Builder copyFrom(@NonNull Node node);
/**
* Sets the value of negated for the node.
*
* @param negated the value
* @return the builder
* @see Node#isNegated()
*/
@NonNull Builder setNegated(boolean negated);
/**
* Sets the value of the node.
*
* @param value the value
* @return the builder
* @see Node#getValue()
*/
@NonNull Builder setValue(boolean value);
/**
* Sets the override property for the node.
*
* <p>Warning: this value does not persist, and disappears when the holder is re-loaded.
* It is therefore only useful for transient nodes.</p>
*
* @param override the override state
* @return the builder
* @see Node#isOverride()
*/
@NonNull Builder setOverride(boolean override);
/**
* Sets the time when the node should expire.
*
* <p>The parameter passed to this method must be the unix timestamp
* (in seconds) when the node should expire.</p>
*
* @param expiryUnixTimestamp the expiry timestamp (unix seconds)
* @return the builder
* @see Node#getExpiryUnixTime()
*/
@NonNull Builder setExpiry(long expiryUnixTimestamp);
/**
* Sets the time when the node should expire.
*
* <p>The expiry timestamp is calculated relative to the current
* system time.</p>
*
* @param duration how long the node should be added for
* @param unit the unit <code>duration</code> is measured in
* @return the builder
* @since 4.2
*/
default @NonNull Builder setExpiry(long duration, TimeUnit unit) {
Preconditions.checkArgument(duration > 0, "duration must be positive");
long seconds = Objects.requireNonNull(unit, "unit").toSeconds(duration);
long timeNow = System.currentTimeMillis() / 1000L;
return setExpiry(timeNow + seconds);
}
/**
* Marks that the node being built should never expire.
*
* @return the builder
* @since 4.2
*/
@NonNull Builder clearExpiry();
/**
* Sets the world value for the node.
*
* @param world the world value
* @return the builder
* @see Node#getWorld()
*/
@NonNull Builder setWorld(@Nullable String world);
/**
* Sets the server value for the node.
*
* @param server the world value
* @return the builder
* @see Node#getServer()
*/
@NonNull Builder setServer(@Nullable String server);
/**
* Appends an extra context onto the node.
*
* @param key the context key
* @param value the context value
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull Builder withExtraContext(@NonNull String key, @NonNull String value);
/**
* Appends extra contexts onto the node.
*
* @param map a map of contexts
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull Builder withExtraContext(@NonNull Map<String, String> map);
/**
* Appends extra contexts onto the node.
*
* @param context a set of contexts
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull Builder withExtraContext(@NonNull Set<Map.Entry<String, String>> context);
/**
* Appends an extra context onto the node.
*
* @param entry the context
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull Builder withExtraContext(Map.@NonNull Entry<String, String> entry);
/**
* Appends extra contexts onto the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull Builder withExtraContext(@NonNull ContextSet contextSet);
/**
* Sets the extra contexts for the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
* @since 4.2
*/
@NonNull Builder setExtraContext(@NonNull ContextSet contextSet);
/**
* Creates a {@link Node} instance from the builder.
*
* @return a new node instance
*/
@NonNull Node build();
}
}

View File

@ -1,55 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A rule for determining if two nodes are equal.
*
* <p>Generally, individual instances of this interface should fulfil the same
* requirements as the {@link Object#equals(Object)} contract.</p>
*
* <p>Some standard implementations are provided by {@link StandardNodeEquality}.</p>
*
* @since 4.1
*/
@FunctionalInterface
public interface NodeEqualityPredicate {
/**
* Returns if the two nodes are equal.
*
* <p>This method should avoid making calls to {@link Node#equals(Node, NodeEqualityPredicate)}
* with {@code this} as the second argument, directly or otherwise.</p>
*
* @param o1 the first node
* @param o2 the second node
* @return true if equal
*/
boolean areEqual(@NonNull Node o1, @NonNull Node o2);
}

View File

@ -1,119 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Assists with constructing {@link Node} instances.
*
* @since 2.17
*/
public interface NodeFactory {
/**
* Creates a new node builder from a given base permission string
*
* @param permission the permission
* @return a node builder instance
* @throws NullPointerException if the permission is null
*/
Node.@NonNull Builder newBuilder(@NonNull String permission);
/**
* Creates a node builder instance from an existing node
*
* @param other the other node
* @return a node builder instance
* @throws NullPointerException if the other node is null
*/
Node.@NonNull Builder newBuilderFromExisting(@NonNull Node other);
/**
* Creates a node builder from a group
*
* @param group the group
* @return a node builder instance
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 3.1
*/
Node.@NonNull Builder makeGroupNode(@NonNull Group group);
/**
* Creates a node builder from a group
*
* @param groupName the name of the group
* @return a node builder instance
* @throws NullPointerException if the groupName is null
* @since 4.0
*/
Node.@NonNull Builder makeGroupNode(@NonNull String groupName);
/**
* Creates a node builder from a key value pair
*
* @param key the key
* @param value the value
* @return a node builder instance
* @throws NullPointerException if the key or value is null
*/
Node.@NonNull Builder makeMetaNode(@NonNull String key, @NonNull String value);
/**
* Creates a node builder for the given chat meta type
*
* @param type the type
* @param priority the priority
* @param value the value for the prefix/suffix
* @return a node builder instance
* @throws NullPointerException if the type or value is null
* @since 3.2
*/
Node.@NonNull Builder makeChatMetaNode(@NonNull ChatMetaType type, int priority, @NonNull String value);
/**
* Creates a node builder from a prefix string and priority
*
* @param priority the priority
* @param prefix the prefix string
* @return a node builder instance
* @throws NullPointerException if the prefix is null
*/
Node.@NonNull Builder makePrefixNode(int priority, @NonNull String prefix);
/**
* Creates a node builder from a prefix string and priority
*
* @param priority the priority
* @param suffix the suffix string
* @return a node builder instance
* @throws NullPointerException if the suffix is null
*/
Node.@NonNull Builder makeSuffixNode(int priority, @NonNull String suffix);
}

View File

@ -1,777 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.api.caching.CachedData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.manager.GroupManager;
import me.lucko.luckperms.api.manager.UserManager;
import me.lucko.luckperms.api.nodetype.types.MetaType;
import me.lucko.luckperms.api.nodetype.types.PrefixType;
import me.lucko.luckperms.api.nodetype.types.SuffixType;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
/**
* Generic superinterface for an object which holds permissions.
*/
public interface PermissionHolder {
/**
* Gets the objects generic name.
*
* <p>The result of this method is guaranteed to be a unique identifier for distinct instances
* of the same type of object.</p>
*
* <p>For {@link User}s, this method returns a {@link UUID#toString() string} representation of
* the users {@link User#getUuid() unique id}.</p>
*
* <p>For {@link Group}s, this method returns the {@link Group#getName() group name}.</p>
*
* <p>The {@link User#getUuid()}, {@link User#getName()} and {@link Group#getName()} methods
* define a "tighter" specification for obtaining object identifiers.</p>
*
* @return the identifier for this object. Either a uuid string or name.
*/
@NonNull String getObjectName();
/**
* Gets a friendly name for this holder, to be displayed in command output, etc.
*
* <p>This will <strong>always</strong> return a value, eventually falling back to
* {@link #getObjectName()} if no other "friendlier" identifiers are present.</p>
*
* <p>For {@link User}s, this method will attempt to return the {@link User#getName() username},
* before falling back to {@link #getObjectName()}.</p>
*
* <p>For {@link Group}s, this method will attempt to return the groups display name, before
* falling back to {@link #getObjectName()}.</p>
*
* @return a friendly identifier for this holder
* @since 3.2
*/
@NonNull String getFriendlyName();
/**
* Gets the holders {@link CachedData} cache.
*
* @return the holders cached data.
* @since 3.2
*/
@NonNull CachedData getCachedData();
/**
* Refreshes and applies any changes to the cached holder data.
*
* <p>Calling this method is unnecessary in most cases. Cache updates are handled
* behind the scenes by the implementation.</p>
*
* @return the task future
* @since 4.0
*/
@NonNull CompletableFuture<Void> refreshCachedData();
/**
* Gets the backing multimap containing every permission this holder has.
*
* <p>This method <b>does not</b> resolve inheritance rules, and returns a
* view of what's 'in the file'.</p>
*
* @return the holders own permissions
* @since 3.3
*/
@NonNull ImmutableSetMultimap<ImmutableContextSet, Node> getNodes();
/**
* Gets the backing multimap containing every transient permission this holder has.
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Transient permissions only exist for the duration of the session.</p>
*
* @return the holders own permissions
* @since 3.3
*/
@NonNull ImmutableSetMultimap<ImmutableContextSet, Node> getTransientNodes();
/**
* Gets a flattened/squashed view of the holders permissions.
*
* <p>This list is constructed using the {@link Multimap#values()} method
* of both the transient and enduring backing multimaps.</p>
*
* <p>This means that it <b>may contain</b> duplicate entries.</p>
*
* <p>Use {@link #getPermissions()} for a view without duplicates.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* @return a list of the holders own nodes.
* @since 3.3
*/
@NonNull List<Node> getOwnNodes();
/**
* Gets a sorted set of all held permissions.
*
* <p>Effectively a sorted version of {@link #getOwnNodes()}, without duplicates. Use the
* aforementioned method if you don't require either of these attributes.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Although this method is named getPermissions, it will actually return all types of node.</p>
*
* @return an immutable set of permissions in priority order
* @since 2.6
*/
@NonNull SortedSet<? extends Node> getPermissions();
/**
* Similar to {@link #getPermissions()}, except only including permissions from the enduring
* node map. (See {@link #getNodes()})
*
* <p>Unlike transient permissions, enduring permissions will be saved to storage, and exist
* after the session.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Although this method is named getEnduringPermissions, it will actually return all types
* of node.</p>
*
* @return a set of nodes
* @since 2.6
*/
@NonNull Set<? extends Node> getEnduringPermissions();
/**
* Similar to {@link #getPermissions()}, except only including permissions from the enduring
* node map. (See {@link #getTransientNodes()})
*
* <p>Transient permissions only exist for the duration of the session.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Although this method is named getTransientPermissions, it will actually return all types
* of node.</p>
*
* @return a set of nodes
* @since 2.6
*/
@NonNull Set<? extends Node> getTransientPermissions();
/**
* A filtered view of this holders nodes, only including permanent entries.
*
* <p>Data is sourced from {@link #getOwnNodes()}, filtered, and then collected to a set.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Although this method is named getPermanentPermissionNodes, it will actually return all types
* of node.</p>
*
* @return a set of permanent nodes
* @since 2.6
*/
@NonNull Set<Node> getPermanentPermissionNodes();
/**
* A filtered view of this holders nodes, only including temporary entries.
*
* <p>Data is sourced from {@link #getOwnNodes()}, filtered, and then collected to a set.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* <p>Although this method is named getTemporaryPermissionNodes, it will actually return all types
* of node.</p>
*
* @return a set of temporary nodes
* @since 2.6
*/
@NonNull Set<Node> getTemporaryPermissionNodes();
/**
* Recursively resolves this holders permissions.
*
* <p>The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.</p>
*
* <p>This means the list will contain duplicates.</p>
*
* <p>Inheritance is performed according to the platforms rules, and the order will vary
* depending on the accumulation order. By default, the holders own nodes are first in the list,
* with the entries from the end of the inheritance tree appearing last.</p>
*
* @param contexts the contexts for the lookup
* @return a list of nodes
* @since 3.3
*/
@NonNull List<LocalizedNode> resolveInheritances(@NonNull Contexts contexts);
/**
* Recursively resolves this holders permissions.
*
* <p>The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.</p>
*
* <p>This means the list will contain duplicates.</p>
*
* <p>Unlike {@link #resolveInheritances(Contexts)}, this method does not
* filter by context, at all.</p>
*
* <p>Inheritance is performed according to the platforms rules, and the order will vary
* depending on the accumulation order. By default, the holders own nodes are first in the list,
* with the entries from the end of the inheritance tree appearing last.</p>
*
* @return a list of nodes
* @since 3.3
*/
@NonNull List<LocalizedNode> resolveInheritances();
/**
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
*
* <p>Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual
* nodes by context. The context is only used to determine which groups should apply.</p>
*
* <p>Nodes are sorted into priority order. The order of inheritance is only important during
* the process of flattening inherited entries.</p>
*
* @param contexts the context for the lookup
* @return an immutable sorted set of permissions
* @throws NullPointerException if the context is null
* @since 2.11
*/
@NonNull SortedSet<LocalizedNode> getAllNodes(@NonNull Contexts contexts);
/**
* Gets a mutable sorted set of the nodes that this object has and inherits.
*
* <p>Unlike {@link #getAllNodes(Contexts)}, this method does not filter by context, at all.</p>
*
* <p>Nodes are sorted into priority order. The order of inheritance is only important during
* the process of flattening inherited entries.</p>
*
* @return an immutable sorted set of permissions
* @throws NullPointerException if the context is null
* @since 3.3
*/
@NonNull SortedSet<LocalizedNode> getAllNodes();
/**
* Gets a mutable set of the nodes that this object has and inherits, filtered by context.
*
* <p>Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes,
* and only return ones that fully meet the context provided.</p>
*
* @param contexts the context for the lookup
* @return a mutable set of permissions
* @throws NullPointerException if the context is null
* @since 2.11
*/
@NonNull Set<LocalizedNode> getAllNodesFiltered(@NonNull Contexts contexts);
/**
* Converts the output of {@link #getAllNodesFiltered(Contexts)} into string and boolean form,
* and expands shorthand permissions.
*
* @param contexts the context for the lookup
* @param convertToLowercase if the keys should be made lowercase whilst being exported
* @return a mutable map of permissions
*/
@NonNull Map<String, Boolean> exportNodes(@NonNull Contexts contexts, boolean convertToLowercase);
/**
* Removes any temporary permissions that have expired.
*
* <p>This method is called periodically by the platform, so it is only necessary to run
* if you want to guarentee that the current data is totally up-to-date.</p>
*/
void auditTemporaryPermissions();
/**
* Checks to see if the object has a certain permission.
*
* <p>Although this method is named hasPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@NonNull Tristate hasPermission(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission.
*
* <p>Although this method is named hasTransientPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@NonNull Tristate hasTransientPermission(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object inherits a certain permission.
*
* <p>Although this method is named inheritsPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 4.1
*/
@NonNull Tristate inheritsPermission(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate);
/**
* Checks to see if the object has a certain permission.
*
* <p>Although this method is named hasPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 2.6
*/
@NonNull Tristate hasPermission(@NonNull Node node);
/**
* Checks to see if the object has a certain permission.
*
* <p>Although this method is named hasTransientPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 2.6
*/
@NonNull Tristate hasTransientPermission(@NonNull Node node);
/**
* Checks to see if the object inherits a certain permission.
*
* <p>Although this method is named inheritsPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 2.6
*/
@NonNull Tristate inheritsPermission(@NonNull Node node);
/**
* Check to see if this holder inherits another group in the global context.
*
* <p>"Global context" simply means an empty context set.</p>
*
* <p>This method only checks for direct inheritance - one hop up the inheritance tree.</p>
*
* @param group The group to check membership of
* @return true if the group inherits the other group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.0
*/
boolean inheritsGroup(@NonNull Group group);
/**
* Check to see if this holder inherits another group.
*
* <p>This method only checks for direct inheritance - one hop up the inheritance tree.</p>
*
* @param group The group to check membership of
* @param contextSet the context set to filter by
* @return true if the group inherits the other group
* @throws NullPointerException if the group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.0
*/
boolean inheritsGroup(@NonNull Group group, @NonNull ContextSet contextSet);
/**
* Sets a permission node for the permission holder.
*
* <p>Although this method is named setPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be set
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.0
*/
@NonNull DataMutateResult setPermission(@NonNull Node node);
/**
* Sets a permission node for the permission holder.
*
* <p>Although this method is named setPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be set
* @param temporaryMergeBehaviour The behaviour used to merge temporary permission entries
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.3
*/
@NonNull TemporaryDataMutateResult setPermission(@NonNull Node node, @NonNull TemporaryMergeBehaviour temporaryMergeBehaviour);
/**
* Sets a transient permission for the permission holder.
*
* <p>A transient node is a permission that does not persist.
* Whenever a user logs out of the server, or the server restarts, this permission will
* disappear. It is never saved to the datastore, and therefore will not apply on other
* servers.</p>
*
* <p>This is useful if you want to temporarily set a permission for a user while they're
* online, but don't want it to persist, and have to worry about removing it when they log
* out.</p>
*
* <p>For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}.</p>
*
* <p>Although this method is named setTransientPermission, it can be used for all node types.</p>
*
* @param node The node to be set
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.0
*/
@NonNull DataMutateResult setTransientPermission(@NonNull Node node);
/**
* Sets a transient permission for the permission holder.
*
* <p>A transient node is a permission that does not persist.
* Whenever a user logs out of the server, or the server restarts, this permission will
* disappear. It is never saved to the datastore, and therefore will not apply on other
* servers.</p>
*
* <p>This is useful if you want to temporarily set a permission for a user while they're
* online, but don't want it to persist, and have to worry about removing it when they log
* out.</p>
*
* <p>For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}.</p>
*
* <p>Although this method is named setTransientPermission, it can be used for all node types.</p>
*
* @param node The node to be se
* @param temporaryMergeBehaviour The behaviour used to merge temporary permission entries
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.3
*/
@NonNull TemporaryDataMutateResult setTransientPermission(@NonNull Node node, @NonNull TemporaryMergeBehaviour temporaryMergeBehaviour);
/**
* Unsets a permission for the permission holder.
*
* <p>Although this method is named unsetPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be unset
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.0
*/
@NonNull DataMutateResult unsetPermission(@NonNull Node node);
/**
* Unsets a transient permission for the permission holder.
*
* <p>Although this method is named unsetTransientPermission, it can be used for all node types.</p>
*
* @param node The node to be unset
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 4.0
*/
@NonNull DataMutateResult unsetTransientPermission(@NonNull Node node);
/**
* Clears any nodes from the holder which pass the predicate.
*
* <p>This method only targets enduring data.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
void clearMatching(@NonNull Predicate<Node> test);
/**
* Clears any transient nodes from the holder which pass the predicate.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param test the predicate to test for nodes which should be removed
* @since 3.2
*/
void clearMatchingTransient(@NonNull Predicate<Node> test);
/**
* Clears all nodes held by the permission holder.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @since 2.17
*/
void clearNodes();
/**
* Clears all nodes held by the permission holder in a specific context.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearNodes(@NonNull ContextSet contextSet);
/**
* Clears all parent groups.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @since 2.17
*/
void clearParents();
/**
* Clears all parent groups in a specific context.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearParents(@NonNull ContextSet contextSet);
/**
* Clears all meta held by the permission holder.
*
* <p>Meta nodes in this case, are any nodes which have a {@link MetaType}, {@link PrefixType}
* or {@link SuffixType} type.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @since 2.17
*/
void clearMeta();
/**
* Clears all meta held by the permission holder in a specific context.
*
* <p>Meta nodes in this case, are any nodes which have a {@link MetaType}, {@link PrefixType}
* or {@link SuffixType} type.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
* @since 3.2
*/
void clearMeta(@NonNull ContextSet contextSet);
/**
* Clears all transient nodes the permission holder has.
*/
void clearTransientNodes();
/**
* Sets a permission for the permission holder.
*
* @param node The node to be set
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 3.1
* @deprecated now forwards to {@link #setPermission(Node)}.
*/
@Deprecated
default @NonNull DataMutateResult setPermissionUnchecked(@NonNull Node node) {
return setPermission(node);
}
/**
* Sets a transient permission for the permission holder.
*
* @param node The node to be set
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 3.1
* @deprecated now forwards to {@link #setTransientPermission(Node)}
*/
@Deprecated
default @NonNull DataMutateResult setTransientPermissionUnchecked(@NonNull Node node) {
return setTransientPermission(node);
}
/**
* Unsets a permission for the permission holder.
*
* @param node The node to be unset
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 3.1
* @deprecated now forwards to {@link #unsetPermission(Node)}
*/
@Deprecated
default @NonNull DataMutateResult unsetPermissionUnchecked(@NonNull Node node) {
return unsetPermission(node);
}
/**
* Unsets a transient permission for the permission holder.
*
* @param node The node to be unset
* @return the result of the operation
* @throws NullPointerException if the node is null
* @since 3.1
* @deprecated now forwards to {@link #unsetTransientPermission(Node)}
*/
@Deprecated
default @NonNull DataMutateResult unsetTransientPermissionUnchecked(@NonNull Node node) {
return unsetTransientPermission(node);
}
}

View File

@ -23,7 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.actionlog;
import me.lucko.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -33,10 +35,17 @@ import java.util.UUID;
/**
* Represents a logged action.
*
* @see ActionLogger#newEntryBuilder() for creating an instance
*/
public interface LogEntry extends Comparable<LogEntry> {
public interface Action extends Comparable<Action> {
/**
* Gets a {@link Action.Builder}
*
* @return a new builder
*/
static @NonNull Builder builder() {
return LuckPermsProvider.get().getActionLogger().actionBuilder();
}
/**
* Gets the time in unix seconds when the action occurred.
@ -95,9 +104,7 @@ public interface LogEntry extends Comparable<LogEntry> {
@NonNull String getAction();
/**
* Represents the type of a {@link LogEntry}.
*
* @since 3.3
* Represents the type of a {@link Action}.
*/
enum Type {
USER('U'), GROUP('G'), TRACK('T');
@ -108,7 +115,6 @@ public interface LogEntry extends Comparable<LogEntry> {
* @param type the string
* @return a type
* @throws IllegalArgumentException if a type could not be parsed
* @since 4.4
*/
public static @NonNull Type parse(String type) {
try {
@ -168,70 +174,70 @@ public interface LogEntry extends Comparable<LogEntry> {
*
* @param timestamp the timestamp
* @return the builder
* @see LogEntry#getTimestamp()
* @see Action#getTimestamp()
*/
@NonNull Builder setTimestamp(long timestamp);
@NonNull Builder timestamp(long timestamp);
/**
* Sets the actor of the entry.
*
* @param actor the actor
* @return the builder
* @see LogEntry#getActor()
* @see Action#getActor()
*/
@NonNull Builder setActor(@NonNull UUID actor);
@NonNull Builder actor(@NonNull UUID actor);
/**
* Sets the actor name of the entry.
*
* @param actorName the actor name
* @return the builder
* @see LogEntry#getActorName()
* @see Action#getActorName()
*/
@NonNull Builder setActorName(@NonNull String actorName);
@NonNull Builder actorName(@NonNull String actorName);
/**
* Sets the type of the entry.
*
* @param type the type
* @return the builder
* @see LogEntry#getType()
* @see Action#getType()
*/
@NonNull Builder setType(@NonNull Type type);
@NonNull Builder type(@NonNull Type type);
/**
* Sets the acted object for the entry.
*
* @param acted the acted object
* @return the builder
* @see LogEntry#getActed()
* @see Action#getActed()
*/
@NonNull Builder setActed(@Nullable UUID acted);
@NonNull Builder acted(@Nullable UUID acted);
/**
* Sets the acted name for the entry.
*
* @param actedName the acted name
* @return the builder
* @see LogEntry#getActedName()
* @see Action#getActedName()
*/
@NonNull Builder setActedName(@NonNull String actedName);
@NonNull Builder actedName(@NonNull String actedName);
/**
* Sets the action of the entry.
*
* @param action the action
* @return the builder
* @see LogEntry#getAction()
* @see Action#getAction()
*/
@NonNull Builder setAction(@NonNull String action);
@NonNull Builder action(@NonNull String action);
/**
* Creates a {@link LogEntry} instance from the builder.
* Creates a {@link Action} instance from the builder.
*
* @return a new log entry instance
*/
@NonNull LogEntry build();
@NonNull Action build();
}

View File

@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.actionlog;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -36,18 +36,18 @@ import java.util.UUID;
* <p>The returned instance provides a copy of the data at the time of retrieval.</p>
*
* <p>Any changes made to log entries will only apply to this instance of the log.
* You can add to the log using the {@link Storage}, and then request an updated copy.</p>
* You can add to the log using the {@link ActionLogger}, and then request an updated copy.</p>
*
* <p>All methods are thread safe, and return immutable and thread safe collections.</p>
*/
public interface Log {
public interface ActionLog {
/**
* Gets the {@link LogEntry}s that make up this log.
* Gets the {@link Action}s that make up this log.
*
* @return the content
*/
@NonNull SortedSet<LogEntry> getContent();
@NonNull SortedSet<Action> getContent();
/**
* Gets the entries in the log performed by the given actor.
@ -55,7 +55,7 @@ public interface Log {
* @param actor the uuid of the actor to filter by
* @return the content for the given actor
*/
@NonNull SortedSet<LogEntry> getContent(@NonNull UUID actor);
@NonNull SortedSet<Action> getContent(@NonNull UUID actor);
/**
* Gets the log content for a given user
@ -63,7 +63,7 @@ public interface Log {
* @param uuid the uuid to filter by
* @return all content in this log where the user = uuid
*/
@NonNull SortedSet<LogEntry> getUserHistory(@NonNull UUID uuid);
@NonNull SortedSet<Action> getUserHistory(@NonNull UUID uuid);
/**
* Gets the log content for a given group
@ -71,7 +71,7 @@ public interface Log {
* @param name the name to filter by
* @return all content in this log where the group = name
*/
@NonNull SortedSet<LogEntry> getGroupHistory(@NonNull String name);
@NonNull SortedSet<Action> getGroupHistory(@NonNull String name);
/**
* Gets the log content for a given track
@ -79,6 +79,6 @@ public interface Log {
* @param name the name to filter by
* @return all content in this log where the track = name
*/
@NonNull SortedSet<LogEntry> getTrackHistory(@NonNull String name);
@NonNull SortedSet<Action> getTrackHistory(@NonNull String name);
}

View File

@ -23,7 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.actionlog;
import me.lucko.luckperms.api.messaging.MessagingService;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -31,25 +33,22 @@ import java.util.concurrent.CompletableFuture;
/**
* Represents the object responsible for handling action logging.
*
* @since 4.1
*/
public interface ActionLogger {
/**
* Returns a new {@link LogEntry.Builder} instance
* Returns a new {@link Action.Builder} instance
*
* @return a new builder
*/
LogEntry.@NonNull Builder newEntryBuilder();
Action.@NonNull Builder actionBuilder();
/**
* Gets a {@link Log} instance from the plugin storage.
* Gets a {@link ActionLog} instance from the plugin storage.
*
* @return a log instance
* @see Storage#getLog()
*/
@NonNull CompletableFuture<Log> getLog();
@NonNull CompletableFuture<ActionLog> getLog();
/**
* Submits a log entry to the plugin to be handled.
@ -58,7 +57,7 @@ public interface ActionLogger {
* it.</p>
*
* <p>It is therefore roughly equivalent to calling
* {@link #submitToStorage(LogEntry)} and {@link #broadcastAction(LogEntry)},
* {@link #submitToStorage(Action)} and {@link #broadcastAction(Action)},
* however, using this method is preferred to making the calls individually.</p>
*
* <p>If you want to submit a log entry but don't know which method to pick,
@ -67,17 +66,15 @@ public interface ActionLogger {
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@NonNull CompletableFuture<Void> submit(@NonNull LogEntry entry);
@NonNull CompletableFuture<Void> submit(@NonNull Action entry);
/**
* Submits a log entry to the plugins storage handler.
*
* <p>Performs the same action as {@link Storage#logAction(LogEntry)}.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@NonNull CompletableFuture<Void> submitToStorage(@NonNull LogEntry entry);
@NonNull CompletableFuture<Void> submitToStorage(@NonNull Action entry);
/**
* Submits a log entry to the plugins log broadcasting handler.
@ -88,6 +85,6 @@ public interface ActionLogger {
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@NonNull CompletableFuture<Void> broadcastAction(@NonNull LogEntry entry);
@NonNull CompletableFuture<Void> broadcastAction(@NonNull Action entry);
}

View File

@ -23,24 +23,22 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
package me.lucko.luckperms.api.cacheddata;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Holds cached lookup data in a specific set of contexts.
*
* @since 4.1
* Holds cached lookup data for a given set of query options.
*/
public interface CachedDataContainer {
public interface CachedData {
/**
* Gets the contexts this container is holding data for.
* Gets the query options this container is holding data for.
*
* @return the contexts this container is caching
* @return the query options this container is caching
*/
@NonNull Contexts getContexts();
@NonNull QueryOptions getQueryOptions();
}

View File

@ -0,0 +1,212 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.cacheddata;
import me.lucko.luckperms.api.model.PermissionHolder;
import me.lucko.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.concurrent.CompletableFuture;
/**
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. This calls are heavily cached and are therefore
* fast.</p>
*/
public interface CachedDataManager {
/**
* Gets the manager for {@link CachedPermissionData}.
*
* @return the permission data manager
*/
@NonNull Container<CachedPermissionData> permissionData();
/**
* Gets the manager for {@link CachedMetaData}.
*
* @return the meta data manager
*/
@NonNull Container<CachedMetaData> metaData();
/**
* Gets PermissionData from the cache, given a specified context.
*
* @param queryOptions the query options
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
@NonNull CachedPermissionData getPermissionData(@NonNull QueryOptions queryOptions);
/**
* Gets MetaData from the cache, given a specified context.
*
* @param queryOptions the query options
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
@NonNull CachedMetaData getMetaData(@NonNull QueryOptions queryOptions);
/**
* Invalidates all cached {@link CachedPermissionData} and {@link CachedMetaData}
* instances.
*/
void invalidate();
/**
* Invalidates all of the underlying Permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
/**
* Manages a specific type of {@link CachedData cached data} within
* a {@link CachedDataManager} instance.
*
* @param <T> the data type
*/
interface Container<T extends CachedData> {
/**
* Gets {@link T data} from the cache.
*
* @param queryOptions the query options
* @return a data instance
* @throws NullPointerException if contexts is null
*/
@NonNull T get(@NonNull QueryOptions queryOptions);
/**
* Calculates {@link T data}, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #get(QueryOptions)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link T data}, without adding the result to the cache.</p>
*
* @param queryOptions the query options
* @return a data instance
* @throws NullPointerException if contexts is null
*/
@NonNull T calculate(@NonNull QueryOptions queryOptions);
/**
* (Re)calculates data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous data instance associated with
* the given {@link QueryOptions}, then that instance will continue to be returned by
* {@link #get(QueryOptions)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param queryOptions the query options
* @throws NullPointerException if contexts is null
*/
void recalculate(@NonNull QueryOptions queryOptions);
/**
* (Re)loads permission data for a given context.
*
* <p>Unlike {@link #recalculate(QueryOptions)}, this method immediately
* invalidates any previous data values contained within the cache,
* and then schedules a task to reload a new data instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #get(QueryOptions)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param queryOptions the query options.
* @return a future
* @throws NullPointerException if contexts is null
*/
@NonNull CompletableFuture<? extends T> reload(@NonNull QueryOptions queryOptions);
/**
* Recalculates data for all known contexts.
*
* <p>This method returns immediately. The recalculation is performed
* asynchronously and applied to the cache in the background.</p>
*
* <p>The previous data instances will continue to be returned
* by {@link #get(QueryOptions)} until the recalculation is completed.</p>
*/
void recalculate();
/**
* Reloads permission data for all known contexts.
*
* <p>Unlike {@link #recalculate()}, this method immediately
* invalidates all previous data values contained within the cache,
* and then schedules a task to reload new data instances to
* replace the ones which were invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #get(QueryOptions)} will block until
* the result of this operation is complete.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @return a future
*/
@NonNull CompletableFuture<Void> reload();
/**
* Invalidates any cached data instances mapped to the given context.
*
* @param queryOptions the queryOptions to invalidate for
*/
void invalidate(@NonNull QueryOptions queryOptions);
/**
* Invalidates all cached data instances.
*/
void invalidate();
}
}

View File

@ -23,55 +23,50 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
import com.google.common.collect.ListMultimap;
package me.lucko.luckperms.api.cacheddata;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
/**
* Holds cached meta lookup data for a specific set of contexts.
*
* @since 2.13
*/
public interface MetaData extends CachedDataContainer {
public interface CachedMetaData extends CachedData {
/**
* Gets the contexts this container is holding data for.
* Gets a value for the given meta key.
*
* @return the contexts this container is caching
* @param key the key
* @return the value
*/
@NonNull MetaContexts getMetaContexts();
@Nullable String getMetaValue(String key);
/**
* Gets the user's highest priority prefix, or null if the user has no prefixes
*
* @return a prefix string, or null
*/
@Nullable String getPrefix();
/**
* Gets the user's highest priority suffix, or null if the user has no suffixes
*
* @return a suffix string, or null
*/
@Nullable String getSuffix();
/**
* Gets an immutable copy of the meta this user has.
*
* <p>A list multimap is used because when inherited values are included, each key can be
* mapped to multiple values.</p>
*
* <p>The first value to be accumulated (and used to represent the key in {@link #getMeta()} is at index 0
* in the list. Any additional values are stored in order of accumulation.</p>
*
* @return an immutable multimap of meta
* @since 3.3
*/
@NonNull ListMultimap<String, String> getMetaMultimap();
/**
* Gets an immutable copy of the meta this user has.
*
* <p>This map is formed by taking the entries in {@link #getMetaMultimap()}, and mapping each key
* to the value at index 0 in the corresponding list.</p>
*
* @return an immutable map of meta
*/
@NonNull Map<String, String> getMeta();
@NonNull Map<String, List<String>> getMeta();
/**
* Gets an immutable sorted map of all of the prefixes the user has, whereby the first value is the highest priority
@ -89,25 +84,10 @@ public interface MetaData extends CachedDataContainer {
*/
@NonNull SortedMap<Integer, String> getSuffixes();
/**
* Gets the user's highest priority prefix, or null if the user has no prefixes
*
* @return a prefix string, or null
*/
@Nullable String getPrefix();
/**
* Gets the user's highest priority suffix, or null if the user has no suffixes
*
* @return a suffix string, or null
*/
@Nullable String getSuffix();
/**
* Gets the definition used for the prefix stack
*
* @return the definition used for the prefix stack
* @since 3.2
*/
@NonNull MetaStackDefinition getPrefixStackDefinition();
@ -115,7 +95,6 @@ public interface MetaData extends CachedDataContainer {
* Gets the definition used for the suffix stack
*
* @return the definition used for the suffix stack
* @since 3.2
*/
@NonNull MetaStackDefinition getSuffixStackDefinition();

View File

@ -23,9 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
package me.lucko.luckperms.api.cacheddata;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.node.Tristate;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -33,10 +33,8 @@ import java.util.Map;
/**
* Holds cached permission lookup data for a specific set of contexts.
*
* @since 2.13
*/
public interface PermissionData extends CachedDataContainer {
public interface CachedPermissionData extends CachedData {
/**
* Gets a permission check result for the given permission node.
@ -45,7 +43,7 @@ public interface PermissionData extends CachedDataContainer {
* @return a tristate result
* @throws NullPointerException if permission is null
*/
@NonNull Tristate getPermissionValue(@NonNull String permission);
@NonNull Tristate checkPermission(@NonNull String permission);
/**
* Invalidates the underlying permission calculator cache.
@ -59,6 +57,6 @@ public interface PermissionData extends CachedDataContainer {
*
* @return an immutable set of permissions
*/
@NonNull Map<String, Boolean> getImmutableBacking();
@NonNull Map<String, Boolean> getPermissionMap();
}

View File

@ -1,430 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.PermissionHolder;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
*
* <p>All calls will account for inheritance, as well as any default data
* provided by the platform. This calls are heavily cached and are therefore
* fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts}
* are provided. The only difference is that the latter allows you to define
* how the meta stack should be structured internally. Where {@link Contexts}
* are passed, the values from the configuration are used.</p>
*
* @since 4.0
*/
public interface CachedData {
/**
* Gets PermissionData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
@NonNull PermissionData getPermissionData(@NonNull Contexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
* @since 3.2
*/
@NonNull MetaData getMetaData(@NonNull MetaContexts contexts);
/**
* Gets MetaData from the cache, given a specified context.
*
* @param contexts the contexts to get the permission data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
@NonNull MetaData getMetaData(@NonNull Contexts contexts);
/**
* Calculates permission data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getPermissionData(Contexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link PermissionData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get permission data in
* @return a permission data instance
* @throws NullPointerException if contexts is null
*/
@NonNull PermissionData calculatePermissions(@NonNull Contexts contexts);
/**
* Calculates meta data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getMetaData(MetaContexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link MetaData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
* @since 3.2
*/
@NonNull MetaData calculateMeta(@NonNull MetaContexts contexts);
/**
* Calculates meta data, bypassing the cache.
*
* <p>The result of this operation is calculated each time the method is called.
* The result is not added to the internal cache.</p>
*
* <p>It is therefore highly recommended to use {@link #getMetaData(Contexts)} instead.</p>
*
* <p>The use cases of this method are more around constructing one-time
* instances of {@link MetaData}, without adding the result to the cache.</p>
*
* @param contexts the contexts to get meta data in
* @return a meta data instance
* @throws NullPointerException if contexts is null
*/
@NonNull MetaData calculateMeta(@NonNull Contexts contexts);
/**
* (Re)calculates permission data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link PermissionData} instance associated with
* the given {@link Contexts}, then that instance will continue to be returned by
* {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculatePermissions(@NonNull Contexts contexts);
/**
* (Re)calculates meta data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link MetaData} instance associated with
* the given {@link MetaContexts}, then that instance will continue to be returned by
* {@link #getMetaData(MetaContexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
* @since 3.2
*/
void recalculateMeta(@NonNull MetaContexts contexts);
/**
* (Re)calculates meta data for a given context.
*
* <p>This method returns immediately in all cases. The (re)calculation is
* performed asynchronously and applied to the cache in the background.</p>
*
* <p>If there was a previous {@link MetaData} instance associated with
* the given {@link Contexts}, then that instance will continue to be returned by
* {@link #getMetaData(Contexts)} until the recalculation is completed.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* @param contexts the contexts to recalculate in.
* @throws NullPointerException if contexts is null
*/
void recalculateMeta(@NonNull Contexts contexts);
/**
* (Re)loads permission data for a given context.
*
* <p>Unlike {@link #recalculatePermissions(Contexts)}, this method immediately
* invalidates any previous {@link PermissionData} values contained within the cache,
* and then schedules a task to reload a new {@link PermissionData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @return a future
* @throws NullPointerException if contexts is null
* @since 4.0
*/
@NonNull CompletableFuture<? extends PermissionData> reloadPermissions(@NonNull Contexts contexts);
/**
* (Re)loads meta data for a given context.
*
* <p>Unlike {@link #recalculateMeta(MetaContexts)}, this method immediately
* invalidates any previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @return a future
* @throws NullPointerException if contexts is null
* @since 4.0
*/
@NonNull CompletableFuture<? extends MetaData> reloadMeta(@NonNull MetaContexts contexts);
/**
* (Re)loads meta data for a given context.
*
* <p>Unlike {@link #recalculateMeta(Contexts)}, this method immediately
* invalidates any previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instance to
* replace the one which was invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>If there was no value calculated and cached prior to the call of this
* method, then one will be calculated.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @param contexts the contexts to reload in.
* @return a future
* @throws NullPointerException if contexts is null
* @since 4.0
*/
@NonNull CompletableFuture<? extends MetaData> reloadMeta(@NonNull Contexts contexts);
/**
* Recalculates permission data for all known contexts.
*
* <p>This method returns immediately. The recalculation is performed
* asynchronously and applied to the cache in the background.</p>
*
* <p>The previous {@link PermissionData} instances will continue to be returned
* by {@link #getPermissionData(Contexts)} until the recalculation is completed.</p>
*/
void recalculatePermissions();
/**
* Recalculates meta data for all known contexts.
*
* <p>This method returns immediately. The recalculation is performed
* asynchronously and applied to the cache in the background.</p>
*
* <p>The previous {@link MetaData} instances will continue to be returned
* by {@link #getMetaData(MetaContexts)} and {@link #getMetaData(Contexts)}
* until the recalculation is completed.</p>
*/
void recalculateMeta();
/**
* Reloads permission data for all known contexts.
*
* <p>Unlike {@link #recalculatePermissions()}, this method immediately
* invalidates all previous {@link PermissionData} values contained within the cache,
* and then schedules a task to reload a new {@link PermissionData} instances to
* replace the ones which were invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getPermissionData(Contexts)} will block until
* the result of this operation is complete.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @return a future
* @since 4.0
*/
@NonNull CompletableFuture<Void> reloadPermissions();
/**
* Reloads meta data for all known contexts.
*
* <p>Unlike {@link #recalculateMeta()}, this method immediately
* invalidates all previous {@link MetaData} values contained within the cache,
* and then schedules a task to reload a new {@link MetaData} instances to
* replace the ones which were invalidated.</p>
*
* <p>The invalidation happens immediately during the execution of this method.
* The result of the re-computation encapsulated by the future.</p>
*
* <p>Subsequent calls to {@link #getMetaData(MetaContexts)} and
* {@link #getMetaData(Contexts)} will block until the result of this operation
* is complete.</p>
*
* <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p>
*
* @return a future
* @since 4.0
*/
@NonNull CompletableFuture<Void> reloadMeta();
/**
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
* instances for the given contexts.
*
* <p>If the cache already contains a value for the given context,
* no action is taken.</p>
*
* <p>This method blocks until the calculation is completed.</p>
*
* @param contexts a set of contexts
* @throws NullPointerException if contexts is null
*/
default void preCalculate(@NonNull Set<Contexts> contexts) {
contexts.forEach(this::preCalculate);
}
/**
* Pre-calculates and caches {@link PermissionData} and {@link MetaData}
* instances for a given context.
*
* <p>If the cache already contains a value for the given context,
* no action is taken.</p>
*
* <p>This method blocks until the calculation is completed.</p>
*
* @param contexts the contexts to pre-calculate for
* @throws NullPointerException if contexts is null
*/
default void preCalculate(@NonNull Contexts contexts) {
Objects.requireNonNull(contexts, "contexts");
// pre-calculate just by requesting the data from this cache.
// if the data isn't already loaded, it will be calculated.
getPermissionData(contexts);
getMetaData(contexts);
}
/**
* Invalidates any cached {@link PermissionData} instances mapped to the given
* {@link Contexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidatePermissions(@NonNull Contexts contexts);
/**
* Invalidates any cached {@link MetaData} instances mapped to the given
* {@link MetaContexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidateMeta(@NonNull MetaContexts contexts);
/**
* Invalidates any cached {@link MetaData} instances mapped to the given
* {@link Contexts}.
*
* @param contexts the contexts to invalidate for
* @since 4.0
*/
void invalidateMeta(@NonNull Contexts contexts);
/**
* Invalidates all cached {@link PermissionData} instances.
*
* @since 4.2
*/
void invalidatePermissions();
/**
* Invalidates all cached {@link MetaData} instances.
*
* @since 4.2
*/
void invalidateMeta();
/**
* Invalidates all cached {@link PermissionData} and {@link MetaData}
* instances.
*
* @since 4.5
*/
void invalidate();
/**
* Invalidates all of the underlying Permission calculators.
*
* <p>Can be called to allow for an update in defaults.</p>
*/
void invalidatePermissionCalculators();
}

View File

@ -1,45 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Group;
/**
* Holds cached permission and meta lookup data for a {@link Group}.
*
* <p>All calls will account for inheritance, as well as any default data provided
* by the platform. This calls are heavily cached and are therefore fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
* values from the configuration are used.</p>
*
* @since 4.0
*/
public interface GroupData extends CachedData {
}

View File

@ -1,117 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
/**
* Encapsulates the options and settings for a meta lookup.
*
* <p>Consists of a standard {@link Contexts} element, plus options to define how
* the meta stack should be constructed.</p>
*
* @since 3.2
*/
public final class MetaContexts {
/**
* Creates a new meta contexts instance
*
* @param contexts the standard contexts for the query
* @param prefixStackDefinition the prefix stack definition to be used
* @param suffixStackDefinition the suffix stack definition to be used
* @return the new instance
*/
public static MetaContexts of(@NonNull Contexts contexts, @NonNull MetaStackDefinition prefixStackDefinition, @NonNull MetaStackDefinition suffixStackDefinition) {
return new MetaContexts(contexts, prefixStackDefinition, suffixStackDefinition);
}
private final Contexts contexts;
private final MetaStackDefinition prefixStackDefinition;
private final MetaStackDefinition suffixStackDefinition;
// cache hashcode - this class is immutable, and is used as an index in the permission cache.
private final int hashCode;
/**
* Creates a new meta contexts instance
*
* @param contexts the standard contexts for the query
* @param prefixStackDefinition the prefix stack definition to be used
* @param suffixStackDefinition the suffix stack definition to be used
*/
public MetaContexts(@NonNull Contexts contexts, @NonNull MetaStackDefinition prefixStackDefinition, @NonNull MetaStackDefinition suffixStackDefinition) {
this.contexts = Objects.requireNonNull(contexts, "contexts");
this.prefixStackDefinition = Objects.requireNonNull(prefixStackDefinition, "prefixStackDefinition");
this.suffixStackDefinition = Objects.requireNonNull(suffixStackDefinition, "suffixStackDefinition");
this.hashCode = calculateHashCode();
}
public @NonNull Contexts getContexts() {
return this.contexts;
}
public @NonNull MetaStackDefinition getPrefixStackDefinition() {
return this.prefixStackDefinition;
}
public @NonNull MetaStackDefinition getSuffixStackDefinition() {
return this.suffixStackDefinition;
}
@Override
public @NonNull String toString() {
return "MetaContexts(" +
"contexts=" + this.getContexts() + ", " +
"prefixStackDefinition=" + this.getPrefixStackDefinition() + ", " +
"suffixStackDefinition=" + this.getSuffixStackDefinition() +
")";
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof MetaContexts)) return false;
final MetaContexts that = (MetaContexts) o;
return this.contexts.equals(that.contexts) &&
this.prefixStackDefinition.equals(that.prefixStackDefinition) &&
this.suffixStackDefinition.equals(that.suffixStackDefinition);
}
private int calculateHashCode() {
return Objects.hash(this.contexts, this.prefixStackDefinition, this.suffixStackDefinition);
}
@Override
public int hashCode() {
return this.hashCode;
}
}

View File

@ -1,45 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.caching;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.User;
/**
* Holds cached permission and meta lookup data for a {@link User}.
*
* <p>All calls will account for inheritance, as well as any default data provided by
* the platform. This calls are heavily cached and are therefore fast.</p>
*
* <p>For meta, both methods accepting {@link Contexts} and {@link MetaContexts} are provided. The only difference is that
* the latter allows you to define how the meta stack should be structured internally. Where {@link Contexts} are passed, the
* values from the configuration are used.</p>
*
* @since 2.13
*/
public interface UserData extends CachedData {
}

View File

@ -27,23 +27,71 @@ package me.lucko.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
import java.util.function.Function;
/**
* Calculates whether contexts are applicable to a {@link T subject}.
* Calculates the contexts applicable for a contextual subject.
*
* @param <T> the subject type. Is ALWAYS the player class of the platform.
* @since 2.13
* <p>Implementations of this interface should satisfy the following
* requirements:</p>
* <ul>
* <li>Context lookups should be <i>fast</i>: lookup methods are likely to
* be invoked frequently, and should therefore be fast to execute. If
* determining the current contexts involves a particularly time consuming
* lookup (database queries, network requests, etc), then such results
* should be cached ahead of time.</li>
*
* <li>Context lookups should be <i>thread-safe</i>: lookups will sometimes
* be performed from "async" threads, and therefore should not access any
* part of the server only safe for access from a sync context. If
* necessary, such results should be determined ahead of time and stored in
* a thread-safe collection for retrieval later.</li>
*
* <li>Context lookups should <i>not query active contexts</i>: doing so is
* likely to result in a stack overflow, or thread deadlock. Care should be
* taken to avoid (indirect) calls to the same calculator.</li>
* </ul>
* <p></p>
*
* <p>Calculators should be registered using
* {@link ContextManager#registerCalculator(ContextCalculator)}.</p>
*/
@FunctionalInterface
public interface ContextCalculator<T> {
/**
* Gives the subject all of the applicable contexts they meet
* Creates a new {@link ContextCalculator} that provides a single context.
*
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* @since 2.13
* @param key the key of the context provided by the calculator
* @param valueFunction the function used to compute the corresponding value
* for each query. A context will not be "accumulated"
* if the value returned is null.
* @param <T> the contextual type
* @return the resultant calculator
*/
@NonNull MutableContextSet giveApplicableContext(@NonNull T subject, @NonNull MutableContextSet accumulator);
static <T> @NonNull ContextCalculator<T> forSingleContext(@NonNull String key, @NonNull Function<T, String> valueFunction) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valueFunction, "valueFunction");
return (target, consumer) -> {
String value = valueFunction.apply(target);
if (value != null) {
consumer.accept(key, value);
}
};
}
/**
* Submits any contexts this calculator determines to be applicable to
* the {@code target} contextual subject.
*
* <p>Care should be taken to ensure implementations of this method meet the
* general requirements for {@link ContextCalculator}, defined in the class
* doc.</p>
*
* @param target the target contextual subject for this operation
* @param consumer the {@link ContextConsumer} to submit contexts to
*/
void giveApplicableContext(@NonNull T target, @NonNull ContextConsumer consumer);
}

View File

@ -23,31 +23,35 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.nodetype.types;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
package me.lucko.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A sub-type of {@link Node} used to mark the display name of the node's holder.
*
* @since 4.2
*/
public interface DisplayNameType extends NodeType {
import java.util.Map;
/**
* The key for this type.
* Functional interface that accepts context key value pairs.
*/
NodeTypeKey<DisplayNameType> KEY = new NodeTypeKey<DisplayNameType>(){};
@FunctionalInterface
public interface ContextConsumer {
/**
* Gets the display name.
* Accepts a context pair.
*
* @return the display name
* @param key the key
* @param value the value
*/
@NonNull String getDisplayName();
void accept(@NonNull String key, @NonNull String value);
/**
* Accepts a context set.
*
* @param contextSet the context set
*/
default void accept(@NonNull ContextSet contextSet) {
for (Map.Entry<String, String> entry : contextSet) {
accept(entry.getKey(), entry.getValue());
}
}
}

View File

@ -25,8 +25,9 @@
package me.lucko.luckperms.api.context;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.query.QueryMode;
import me.lucko.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -50,8 +51,6 @@ import java.util.Optional;
* <li>{@code cn.nukkit.Player}</li>
* <li>{@code com.velocitypowered.api.proxy.Player}</li>
* </ul>
*
* @since 4.0
*/
public interface ContextManager {
@ -61,15 +60,7 @@ public interface ContextManager {
* @param subject the subject
* @return the applicable context for the subject
*/
@NonNull ImmutableContextSet getApplicableContext(@NonNull Object subject);
/**
* Queries the ContextManager for current context values for the subject.
*
* @param subject the subject
* @return the applicable context for the subject
*/
@NonNull Contexts getApplicableContexts(@NonNull Object subject);
@NonNull ImmutableContextSet getContext(@NonNull Object subject);
/**
* Queries the ContextManager for current context values for the given User.
@ -77,27 +68,14 @@ public interface ContextManager {
* <p>This will only return a value if the player corresponding to the
* {@link User} is online.</p>
*
* <p>If you need to be a {@link Contexts} instance regardless, you should
* initially try this method, and then fallback on {@link #getStaticContext()}.</p>
* <p>If you need to obtain a {@link ImmutableContextSet} instance
* regardless, you should initially try this method, and then fallback on
* {@link #getStaticContext()}.</p>
*
* @param user the user
* @return the applicable context for the subject
*/
@NonNull Optional<ImmutableContextSet> lookupApplicableContext(@NonNull User user);
/**
* Queries the ContextManager for current context values for the given User.
*
* <p>This will only return a value if the player corresponding to the
* {@link User} is online.</p>
*
* <p>If you need to be a {@link Contexts} instance regardless, you should
* initially try this method, and then fallback on {@link #getStaticContexts()}.</p>
*
* @param user the user
* @return the applicable context for the subject
*/
@NonNull Optional<Contexts> lookupApplicableContexts(@NonNull User user);
@NonNull Optional<ImmutableContextSet> lookupContext(@NonNull User user);
/**
* Gets the contexts from the static calculators in this manager.
@ -110,37 +88,64 @@ public interface ContextManager {
@NonNull ImmutableContextSet getStaticContext();
/**
* Gets the contexts from the static calculators in this manager.
* Creates a new {@link QueryOptions.Builder}.
*
* <p>Static calculators provide the same context for all subjects, and are
* marked as such when registered.</p>
*
* @return the current active static contexts
* @param mode the mode
* @return a new query options builder
*/
@NonNull Contexts getStaticContexts();
QueryOptions.@NonNull Builder queryOptionsBuilder(@NonNull QueryMode mode);
/**
* Forms a {@link Contexts} instance from an {@link ImmutableContextSet}.
* Obtains current {@link QueryOptions} for the subject.
*
* @param subject the subject
* @return the query options for the subject
*/
@NonNull QueryOptions getQueryOptions(@NonNull Object subject);
/**
* Obtains current {@link QueryOptions} for the given User.
*
* <p>This will only return a value if the player corresponding to the
* {@link User} is online.</p>
*
* <p>If you need to obtain a {@link QueryOptions} instance regardless, you should
* initially try this method, and then fallback on {@link #getStaticQueryOptions()}.</p>
*
* @param user the user
* @return the query options for the subject
*/
@NonNull Optional<QueryOptions> lookupQueryOptions(@NonNull User user);
/**
* Gets the static query options, using the registered static context calculators.
*
* @return the current static query options
*/
@NonNull QueryOptions getStaticQueryOptions();
/**
* Forms a {@link QueryOptions} instance from an {@link ImmutableContextSet}.
*
* <p>This method relies on the plugins configuration to form the
* {@link Contexts} instance.</p>
* {@link QueryOptions} instance.</p>
*
* @param subject the reference subject
* @param contextSet the context set
* @return a contexts instance
* @return a options instance
*/
@NonNull Contexts formContexts(@NonNull Object subject, @NonNull ImmutableContextSet contextSet);
@NonNull QueryOptions formQueryOptions(@NonNull Object subject, @NonNull ImmutableContextSet contextSet);
/**
* Forms a {@link Contexts} instance from an {@link ImmutableContextSet}.
* Forms a {@link QueryOptions} instance from an {@link ImmutableContextSet}.
*
* <p>This method relies on the plugins configuration to form the
* {@link Contexts} instance.</p>
* {@link QueryOptions} instance.</p>
*
* @param contextSet the context set
* @return a contexts instance
* @return a options instance
*/
@NonNull Contexts formContexts(@NonNull ImmutableContextSet contextSet);
@NonNull QueryOptions formQueryOptions(@NonNull ImmutableContextSet contextSet);
/**
* Registers a context calculator with the manager.
@ -153,10 +158,17 @@ public interface ContextManager {
* Unregisters a context calculator with the manager.
*
* @param calculator the calculator
* @since 4.4
*/
void unregisterCalculator(@NonNull ContextCalculator<?> calculator);
/**
* Gets the {@link ContextSetFactory}, responsible for creating
* {@link ContextSet} instances.
*
* @return the context set factory
*/
@NonNull ContextSetFactory getContextSetFactory();
/**
* Invalidates the lookup cache for a given subject
*

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.Multimap;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Iterator;
@ -58,94 +56,9 @@ import java.util.Set;
* <p>Two default ContextSet implementations are provided.
* {@link MutableContextSet} allows the addition and removal of context keys
* after construction, and {@link ImmutableContextSet} does not.</p>
*
* @since 2.13
*/
public interface ContextSet extends Iterable<Map.Entry<String, String>> {
/**
* Creates an {@link ImmutableContextSet} from a context pair.
*
* @param key the key
* @param value the value
* @return a new ImmutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
static @NonNull ImmutableContextSet singleton(@NonNull String key, @NonNull String value) {
return ImmutableContextSet.singleton(key, value);
}
/**
* Creates an {@link ImmutableContextSet} from two context pairs.
*
* @param key1 the first key
* @param value1 the first value
* @param key2 the second key
* @param value2 the second value
* @return a new ImmutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
static @NonNull ImmutableContextSet of(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2) {
return ImmutableContextSet.of(key1, value1, key2, value2);
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Iterable} of {@link Map.Entry}s.
*
* @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
static @NonNull ImmutableContextSet fromEntries(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
return ImmutableContextSet.fromEntries(iterable);
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Map}.
*
* @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
static @NonNull ImmutableContextSet fromMap(@NonNull Map<String, String> map) {
return ImmutableContextSet.fromMap(map);
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
static @NonNull ImmutableContextSet fromMultimap(@NonNull Multimap<String, String> multimap) {
return ImmutableContextSet.fromMultimap(multimap);
}
/**
* Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
*
* <p>Only really useful for converting between mutable and immutable types.</p>
*
* @param contextSet the context set to copy from
* @return a new ImmutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
static @NonNull ImmutableContextSet fromSet(@NonNull ContextSet contextSet) {
return ImmutableContextSet.fromSet(contextSet);
}
/**
* Returns an empty {@link ImmutableContextSet}.
*
* @return an empty ImmutableContextSet
*/
static @NonNull ImmutableContextSet empty() {
return ImmutableContextSet.empty();
}
/**
* Gets if this {@link ContextSet} is immutable.
*
@ -163,7 +76,7 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
*
* @return an immutable representation of this set
*/
@NonNull ImmutableContextSet makeImmutable();
@NonNull ImmutableContextSet immutableCopy();
/**
* Creates a mutable copy of this {@link ContextSet}.
@ -172,7 +85,6 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
* {@link #isImmutable() mutability} of this set.</p>
*
* @return a mutable ContextSet
* @since 2.16
*/
@NonNull MutableContextSet mutableCopy();
@ -187,6 +99,17 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
*/
@NonNull Set<Map.Entry<String, String>> toSet();
/**
* Returns a {@link Map} representing the current state of this
* {@link ContextSet}.
*
* <p>The returned set is immutable, and is a copy of the current set.
* (will not update live)</p>
*
* @return a map
*/
@NonNull Map<String, Set<String>> toMap();
/**
* Returns a {@link Map} <b>loosely</b> representing the current state of
* this {@link ContextSet}.
@ -197,27 +120,11 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
* <p>As a single context key can be mapped to multiple values, this method
* may not be a true representation of the set.</p>
*
* <p>If you need a representation of the set in a Java collection instance,
* use {@link #toSet()} or {@link #toMultimap()} followed by
* {@link Multimap#asMap()}.</p>
*
* @return an immutable map
* @deprecated because the resultant map may not contain all data in the ContextSet
*/
@Deprecated
@NonNull Map<String, String> toMap();
/**
* Returns a {@link Multimap} representing the current state of this
* {@link ContextSet}.
*
* <p>The returned multimap is immutable, and is a copy of the current set.
* (will not update live)</p>
*
* @return a multimap
* @since 2.16
*/
@NonNull Multimap<String, String> toMultimap();
@NonNull Map<String, String> toFlattenedMap();
/**
* Returns an {@link Iterator} over each of the context pairs in this set.
@ -262,7 +169,6 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
*
* @param key the key to find values for
* @return an optional containing any match
* @since 3.1
*/
default @NonNull Optional<String> getAnyValue(@NonNull String key) {
return getValues(key).stream().findAny();
@ -276,7 +182,7 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
boolean has(@NonNull String key, @NonNull String value);
boolean contains(@NonNull String key, @NonNull String value);
/**
* Returns if the {@link ContextSet} contains a given context pairing.
@ -285,9 +191,9 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
* @return true if the set contains the context pair
* @throws NullPointerException if the key or value is null
*/
default boolean has(Map.@NonNull Entry<String, String> entry) {
default boolean contains(Map.@NonNull Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
return has(entry.getKey(), entry.getValue());
return contains(entry.getKey(), entry.getValue());
}
/**
@ -300,7 +206,6 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
*
* @param other the other set to check
* @return true if all entries in this set are also in the other set
* @since 3.1
*/
default boolean isSatisfiedBy(@NonNull ContextSet other) {
if (this == other) {
@ -320,7 +225,7 @@ public interface ContextSet extends Iterable<Map.Entry<String, String>> {
} else {
// neither are empty, we need to compare the individual entries
for (Map.Entry<String, String> context : toSet()) {
if (!other.has(context)) {
if (!other.contains(context)) {
return false;
}
}

View File

@ -0,0 +1,45 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A factory for creating {@link ContextSet}s.
*/
public interface ContextSetFactory {
ImmutableContextSet.@NonNull Builder immutableBuilder();
@NonNull ImmutableContextSet immutableOf(@NonNull String key, @NonNull String value);
@NonNull ImmutableContextSet immutableOf(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2);
@NonNull ImmutableContextSet immutableEmpty();
@NonNull MutableContextSet mutable();
}

View File

@ -0,0 +1,44 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.context;
/**
* Some default context keys used by the plugin.
*/
public enum DefaultContextKeys {
;
/**
* The context key used to denote the subjects server.
*/
public static final String SERVER_KEY = "server";
/**
* The context key used to denote the subjects world.
*/
public static final String WORLD_KEY = "world";
}

View File

@ -25,35 +25,26 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import me.lucko.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
/**
* An immutable implementation of {@link ContextSet}.
*
* @since 2.16
*/
public final class ImmutableContextSet extends AbstractContextSet implements ContextSet {
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of());
public interface ImmutableContextSet extends ContextSet {
/**
* Creates an {@link ImmutableContextSet.Builder}.
*
* @return a new ImmutableContextSet builder
* @since 4.1
*/
public static @NonNull Builder builder() {
return new Builder();
static @NonNull Builder builder() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableBuilder();
}
/**
@ -64,8 +55,8 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @return a new ImmutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
public static @NonNull ImmutableContextSet singleton(@NonNull String key, @NonNull String value) {
return new ImmutableContextSet(ImmutableSetMultimap.of(sanitizeKey(key), sanitizeValue(value)));
static @NonNull ImmutableContextSet of(@NonNull String key, @NonNull String value) {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableOf(key, value);
}
/**
@ -77,15 +68,9 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @param value2 the second value
* @return a new ImmutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
public static @NonNull ImmutableContextSet of(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2) {
return new ImmutableContextSet(ImmutableSetMultimap.of(
sanitizeKey(key1),
sanitizeValue(value1),
sanitizeKey(key2),
sanitizeValue(value2)
));
static @NonNull ImmutableContextSet of(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2) {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableOf(key1, value1, key2, value2);
}
/**
@ -95,38 +80,15 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @return a new ImmutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static @NonNull ImmutableContextSet fromEntries(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
static @NonNull ImmutableContextSet fromEntries(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
Objects.requireNonNull(iterable, "iterable");
ImmutableContextSet.Builder builder = builder();
Builder builder = builder();
for (Map.Entry<String, String> entry : iterable) {
builder.add(entry);
}
return builder.build();
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Map}.
*
* @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
public static @NonNull ImmutableContextSet fromMap(@NonNull Map<String, String> map) {
return fromEntries(Objects.requireNonNull(map, "map").entrySet());
}
/**
* Creates an {@link ImmutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
public static @NonNull ImmutableContextSet fromMultimap(@NonNull Multimap<String, String> multimap) {
return fromEntries(Objects.requireNonNull(multimap, "multimap").entries());
}
/**
* Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
*
@ -136,8 +98,8 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @return a new ImmutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static @NonNull ImmutableContextSet fromSet(@NonNull ContextSet contextSet) {
return Objects.requireNonNull(contextSet, "contextSet").makeImmutable();
static @NonNull ImmutableContextSet fromSet(@NonNull ContextSet contextSet) {
return Objects.requireNonNull(contextSet, "contextSet").immutableCopy();
}
/**
@ -145,128 +107,21 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
*
* @return an empty ImmutableContextSet
*/
public static @NonNull ImmutableContextSet empty() {
return EMPTY;
}
private final ImmutableSetMultimap<String, String> map;
private final int hashCode;
ImmutableContextSet(ImmutableSetMultimap<String, String> contexts) {
this.map = contexts;
this.hashCode = this.map.hashCode();
}
@Override
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
other.putAll(this.map);
}
@Override
public boolean isImmutable() {
return true;
}
@Deprecated
@Override // This set is already immutable!
public @NonNull ImmutableContextSet makeImmutable() {
return this;
}
@Override
public @NonNull MutableContextSet mutableCopy() {
return MutableContextSet.fromSet(this);
}
@Override
public @NonNull Set<Map.Entry<String, String>> toSet() {
return this.map.entries();
}
@Deprecated
@Override
public @NonNull Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Override
public @NonNull Multimap<String, String> toMultimap() {
return this.map;
}
@Override
public @NonNull Iterator<Map.Entry<String, String>> iterator() {
return this.map.entries().iterator();
}
@Override
public Spliterator<Map.Entry<String, String>> spliterator() {
return this.map.entries().spliterator();
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ContextSet)) return false;
final ContextSet that = (ContextSet) o;
// fast(er) path for ImmutableContextSet comparisons
if (that instanceof ImmutableContextSet) {
ImmutableContextSet immutableThat = (ImmutableContextSet) that;
if (this.hashCode != immutableThat.hashCode) return false;
}
final Multimap<String, String> thatBacking;
if (that instanceof AbstractContextSet) {
thatBacking = ((AbstractContextSet) that).backing();
} else {
thatBacking = that.toMultimap();
}
return backing().equals(thatBacking);
}
@Override
public int hashCode() {
return this.hashCode;
}
@Override
public String toString() {
return "ImmutableContextSet(contexts=" + this.map + ")";
static @NonNull ImmutableContextSet empty() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().immutableEmpty();
}
/**
* A builder for {@link ImmutableContextSet}.
*
* @since 4.1
* @deprecated Already immutable!
*/
public static final class Builder {
private ImmutableSetMultimap.Builder<String, String> builder;
@Override
@Deprecated
@NonNull ImmutableContextSet immutableCopy();
private Builder() {
}
private synchronized ImmutableSetMultimap.Builder<String, String> builder() {
if (this.builder == null) {
this.builder = ImmutableSetMultimap.builder();
}
return this.builder;
}
private void put(String key, String value) {
builder().put(key, value);
}
/**
* A builder for {@link ImmutableContextSet}.
*/
interface Builder {
/**
* Adds a context to the set.
@ -277,10 +132,7 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @throws NullPointerException if the key or value is null
* @see MutableContextSet#add(String, String)
*/
public @NonNull Builder add(@NonNull String key, @NonNull String value) {
put(sanitizeKey(key), sanitizeValue(value));
return this;
}
@NonNull Builder add(@NonNull String key, @NonNull String value);
/**
* Adds a context to the set.
@ -290,7 +142,7 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @throws NullPointerException if the entry is null
* @see MutableContextSet#add(Map.Entry)
*/
public @NonNull Builder add(Map.@NonNull Entry<String, String> entry) {
default @NonNull Builder add(Map.@NonNull Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
add(entry.getKey(), entry.getValue());
return this;
@ -304,40 +156,13 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @throws NullPointerException if iterable is null
* @see MutableContextSet#addAll(Iterable)
*/
public @NonNull Builder addAll(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
default @NonNull Builder addAll(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
for (Map.Entry<String, String> e : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
return this;
}
/**
* Adds the contexts contained in the given {@link Map} to the set.
*
* @param map the map to add from
* @return the builder
* @throws NullPointerException if the map is null
* @see MutableContextSet#addAll(Map)
*/
public @NonNull Builder addAll(@NonNull Map<String, String> map) {
addAll(Objects.requireNonNull(map, "map").entrySet());
return this;
}
/**
* Adds the contexts contained in the given {@link Multimap} to the set.
*
* @param multimap the multimap to add from
* @return the builder
* @throws NullPointerException if the map is null
* @since 3.4
* @see MutableContextSet#addAll(Multimap)
*/
public @NonNull Builder addAll(@NonNull Multimap<String, String> multimap) {
addAll(Objects.requireNonNull(multimap, "multimap").entries());
return this;
}
/**
* Adds of of the contexts in another {@link ContextSet} to the set.
*
@ -346,18 +171,7 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
* @throws NullPointerException if the contextSet is null
* @see MutableContextSet#addAll(ContextSet)
*/
public @NonNull Builder addAll(@NonNull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof AbstractContextSet) {
AbstractContextSet other = ((AbstractContextSet) contextSet);
if (!other.isEmpty()) {
builder().putAll(other.backing());
}
} else {
addAll(contextSet.toMultimap());
}
return this;
}
@NonNull Builder addAll(@NonNull ContextSet contextSet);
/**
* Creates a {@link ImmutableContextSet} from the values previously
@ -365,12 +179,6 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
*
* @return an {@link ImmutableContextSet} from the builder
*/
public @NonNull ImmutableContextSet build() {
if (this.builder == null) {
return empty();
} else {
return new ImmutableContextSet(this.builder.build());
}
}
@NonNull ImmutableContextSet build();
}
}

View File

@ -25,28 +25,18 @@
package me.lucko.luckperms.api.context;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
import me.lucko.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
/**
* A mutable implementation of {@link ContextSet}.
*
* @since 2.16
*/
public final class MutableContextSet extends AbstractContextSet implements ContextSet {
public interface MutableContextSet extends ContextSet {
/**
* Creates a {@link MutableContextSet} from a context pair.
@ -56,10 +46,10 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @return a new MutableContextSet containing one context pair
* @throws NullPointerException if key or value is null
*/
public static @NonNull MutableContextSet singleton(@NonNull String key, @NonNull String value) {
static @NonNull MutableContextSet of(@NonNull String key, @NonNull String value) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
MutableContextSet set = MutableContextSet.create();
MutableContextSet set = create();
set.add(key, value);
return set;
}
@ -73,9 +63,8 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param value2 the second value
* @return a new MutableContextSet containing the two pairs
* @throws NullPointerException if any of the keys or values are null
* @since 3.1
*/
public static @NonNull MutableContextSet of(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2) {
static @NonNull MutableContextSet of(@NonNull String key1, @NonNull String value1, @NonNull String key2, @NonNull String value2) {
Objects.requireNonNull(key1, "key1");
Objects.requireNonNull(value1, "value1");
Objects.requireNonNull(key2, "key2");
@ -93,42 +82,13 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @return a new MutableContextSet representing the pairs in the iterable
* @throws NullPointerException if the iterable is null
*/
public static @NonNull MutableContextSet fromEntries(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
static @NonNull MutableContextSet fromEntries(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
Objects.requireNonNull(iterable, "iterable");
MutableContextSet set = create();
set.addAll(iterable);
return set;
}
/**
* Creates a {@link MutableContextSet} from an existing {@link Map}.
*
* @param map the map to copy from
* @return a new MutableContextSet representing the pairs from the map
* @throws NullPointerException if the map is null
*/
public static @NonNull MutableContextSet fromMap(@NonNull Map<String, String> map) {
Objects.requireNonNull(map, "map");
MutableContextSet set = create();
set.addAll(map);
return set;
}
/**
* Creates a {@link MutableContextSet} from an existing {@link Multimap}.
*
* @param multimap the multimap to copy from
* @return a new MutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null
* @since 2.16
*/
public static @NonNull MutableContextSet fromMultimap(@NonNull Multimap<String, String> multimap) {
Objects.requireNonNull(multimap, "multimap");
MutableContextSet set = create();
set.addAll(multimap);
return set;
}
/**
* Creates a new {@link MutableContextSet} from an existing {@link Set}.
*
@ -138,19 +98,8 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @return a new MutableContextSet with the same content and the one provided
* @throws NullPointerException if contextSet is null
*/
public static @NonNull MutableContextSet fromSet(@NonNull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof ImmutableContextSet) {
SetMultimap<String, String> map = ((ImmutableContextSet) contextSet).backing();
return new MutableContextSet(map);
} else if (contextSet instanceof MutableContextSet) {
static @NonNull MutableContextSet fromSet(@NonNull ContextSet contextSet) {
return contextSet.mutableCopy();
} else {
MutableContextSet set = create();
set.addAll(contextSet);
return set;
}
}
/**
@ -158,90 +107,8 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
*
* @return a new MutableContextSet
*/
public static @NonNull MutableContextSet create() {
return new MutableContextSet();
}
private final SetMultimap<String, String> map;
public MutableContextSet() {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create());
}
private MutableContextSet(SetMultimap<String, String> other) {
this.map = Multimaps.synchronizedSetMultimap(HashMultimap.create(other));
}
@Override
protected SetMultimap<String, String> backing() {
return this.map;
}
@Override
protected void copyTo(SetMultimap<String, String> other) {
synchronized (this.map) {
other.putAll(this.map);
}
}
@Override
public boolean isImmutable() {
return false;
}
@Override
public @NonNull ImmutableContextSet makeImmutable() {
// if the map is empty, don't create a new instance
if (this.map.isEmpty()) {
return ImmutableContextSet.empty();
}
synchronized (this.map) {
return new ImmutableContextSet(ImmutableSetMultimap.copyOf(this.map));
}
}
@Override
public @NonNull MutableContextSet mutableCopy() {
synchronized (this.map) {
return new MutableContextSet(this.map);
}
}
@Override
public @NonNull Set<Map.Entry<String, String>> toSet() {
synchronized (this.map) {
// map.entries() returns immutable Map.Entry instances, so we can just call copyOf
return ImmutableSet.copyOf(this.map.entries());
}
}
@Deprecated
@Override
public @NonNull Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
synchronized (this.map) {
for (Map.Entry<String, String> e : this.map.entries()) {
m.put(e.getKey(), e.getValue());
}
}
return m.build();
}
@Override
public @NonNull Multimap<String, String> toMultimap() {
synchronized (this.map) {
return ImmutableSetMultimap.copyOf(this.map);
}
}
@Override
public @NonNull Iterator<Map.Entry<String, String>> iterator() {
return toSet().iterator();
}
@Override
public Spliterator<Map.Entry<String, String>> spliterator() {
return toSet().spliterator();
static @NonNull MutableContextSet create() {
return LuckPermsProvider.get().getContextManager().getContextSetFactory().mutable();
}
/**
@ -251,9 +118,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param value the value to add
* @throws NullPointerException if the key or value is null
*/
public void add(@NonNull String key, @NonNull String value) {
this.map.put(sanitizeKey(key), sanitizeValue(value));
}
void add(@NonNull String key, @NonNull String value);
/**
* Adds a context to this set.
@ -261,7 +126,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param entry the entry to add
* @throws NullPointerException if the entry is null
*/
public void add(Map.@NonNull Entry<String, String> entry) {
default void add(Map.@NonNull Entry<String, String> entry) {
Objects.requireNonNull(entry, "entry");
add(entry.getKey(), entry.getValue());
}
@ -272,50 +137,19 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param iterable an iterable of key value context pairs
* @throws NullPointerException if iterable is null
*/
public void addAll(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
default void addAll(@NonNull Iterable<? extends Map.Entry<String, String>> iterable) {
for (Map.Entry<String, String> e : Objects.requireNonNull(iterable, "iterable")) {
add(e);
}
}
/**
* Adds the contexts contained in the given {@link Map} to this set.
*
* @param map the map to add from
* @throws NullPointerException if the map is null
*/
public void addAll(@NonNull Map<String, String> map) {
addAll(Objects.requireNonNull(map, "map").entrySet());
}
/**
* Adds the contexts contained in the given {@link Multimap} to this set.
*
* @param multimap the multimap to add from
* @throws NullPointerException if the map is null
* @since 3.4
*/
public void addAll(@NonNull Multimap<String, String> multimap) {
addAll(Objects.requireNonNull(multimap, "multimap").entries());
}
/**
* Adds of of the contexts in another {@link ContextSet} to this set.
*
* @param contextSet the set to add from
* @throws NullPointerException if the contextSet is null
*/
public void addAll(@NonNull ContextSet contextSet) {
Objects.requireNonNull(contextSet, "contextSet");
if (contextSet instanceof AbstractContextSet) {
AbstractContextSet other = ((AbstractContextSet) contextSet);
synchronized (this.map) {
other.copyTo(this.map);
}
} else {
addAll(contextSet.toMultimap());
}
}
void addAll(@NonNull ContextSet contextSet);
/**
* Removes a context from this set.
@ -324,9 +158,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param value the value to remove
* @throws NullPointerException if the key or value is null
*/
public void remove(@NonNull String key, @NonNull String value) {
this.map.remove(sanitizeKey(key), sanitizeValue(value));
}
void remove(@NonNull String key, @NonNull String value);
/**
* Removes all contexts from this set with the given key.
@ -334,35 +166,11 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
* @param key the key to remove
* @throws NullPointerException if the key is null
*/
public void removeAll(@NonNull String key) {
this.map.removeAll(sanitizeKey(key));
}
void removeAll(@NonNull String key);
/**
* Removes all contexts from the set.
*/
public void clear() {
this.map.clear();
}
void clear();
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ContextSet)) return false;
final ContextSet that = (ContextSet) o;
final Multimap<String, String> thatBacking;
if (that instanceof AbstractContextSet) {
thatBacking = ((AbstractContextSet) that).backing();
} else {
thatBacking = that.toMultimap();
}
return backing().equals(thatBacking);
}
@Override
public String toString() {
return "MutableContextSet(contexts=" + this.map + ")";
}
}

View File

@ -26,36 +26,50 @@
package me.lucko.luckperms.api.context;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
import java.util.function.Supplier;
/**
* Extension of {@link ContextCalculator} which provides the same context
* regardless of the subject.
*
* @since 4.0
*/
@FunctionalInterface
public interface StaticContextCalculator extends ContextCalculator<Object> {
/**
* Adds this calculators context to the given accumulator.
* Creates a new {@link StaticContextCalculator} that provides a single context.
*
* @param accumulator a map of contexts to add to
* @return the map
* @param key the key of the context provided by the calculator
* @param valueFunction the function used to compute the corresponding value
* for each query. A context will not be "accumulated"
* if the value returned is null.
* @return the resultant calculator
*/
@NonNull MutableContextSet giveApplicableContext(@NonNull MutableContextSet accumulator);
static StaticContextCalculator forSingleContext(String key, Supplier<String> valueFunction) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valueFunction, "valueFunction");
return consumer -> {
String value = valueFunction.get();
if (value != null) {
consumer.accept(key, value);
}
};
}
/**
* Gives the subject all of the applicable contexts they meet
* Submits any contexts this calculator determines to be applicable.
*
* @param subject the subject to add contexts to
* @param accumulator a map of contexts to add to
* @return the map
* <p>Care should be taken to ensure implementations of this method meet the
* general requirements for {@link ContextCalculator}, defined in the class
* doc.</p>
*
* @param consumer the {@link ContextConsumer} to submit contexts to
*/
@Deprecated
@Override
default @NonNull MutableContextSet giveApplicableContext(@Nullable Object subject, @NonNull MutableContextSet accumulator) {
return giveApplicableContext(accumulator);
}
void giveApplicableContext(@NonNull ContextConsumer consumer);
@Override
default void giveApplicableContext(@NonNull Object target, @NonNull ContextConsumer consumer) {
giveApplicableContext(consumer);
}
}

View File

@ -39,13 +39,13 @@ public interface Cancellable {
*
* @return the cancellation
*/
@NonNull @Param(-1) AtomicBoolean getCancellationState();
@Param(-1)
@NonNull AtomicBoolean getCancellationState();
/**
* Returns true if the event is currently cancelled.
*
* @return if the event is cancelled
* @since 4.1
*/
default boolean isCancelled() {
return getCancellationState().get();
@ -55,7 +55,6 @@ public interface Cancellable {
* Returns true if the event is not currently cancelled.
*
* @return if the event is not cancelled
* @since 4.1
*/
default boolean isNotCancelled() {
return !isCancelled();
@ -66,7 +65,6 @@ public interface Cancellable {
*
* @param cancelled the new state
* @return the previous state
* @since 4.1
*/
default boolean setCancelled(boolean cancelled) {
return getCancellationState().getAndSet(cancelled);

View File

@ -34,15 +34,13 @@ import java.util.function.Consumer;
* The LuckPerms event bus.
*
* <p>Used to subscribe (or "listen") to LuckPerms events.</p>
*
* @since 3.0
*/
public interface EventBus {
/**
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* <p>The returned {@link EventSubscription} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
@ -51,18 +49,18 @@ public interface EventBus {
* @param <T> the event class
* @return an event handler instance representing this subscription
*/
@NonNull <T extends LuckPermsEvent> EventHandler<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> handler);
@NonNull <T extends LuckPermsEvent> EventSubscription<T> subscribe(@NonNull Class<T> eventClass, @NonNull Consumer<? super T> handler);
/**
* Registers a new subscription to the given event.
*
* <p>The returned {@link EventHandler} instance encapsulates the subscription state. It has
* <p>The returned {@link EventSubscription} instance encapsulates the subscription state. It has
* methods which can be used to terminate the subscription, or view stats about the nature of
* the subscription.</p>
*
* <p>Unlike {@link #subscribe(Class, Consumer)}, this method accepts an additional parameter
* for {@code plugin}. This object must be a "plugin" instance on the platform, and is used to
* automatically {@link EventHandler#unregister() unregister} the subscription when the
* automatically {@link EventSubscription#close() unregister} the subscription when the
* corresponding plugin is disabled.</p>
*
* @param <T> the event class
@ -71,7 +69,7 @@ public interface EventBus {
* @param handler the event handler
* @return an event handler instance representing this subscription
*/
@NonNull <T extends LuckPermsEvent> EventHandler<T> subscribe(Object plugin, @NonNull Class<T> eventClass, @NonNull Consumer<? super T> handler);
@NonNull <T extends LuckPermsEvent> EventSubscription<T> subscribe(Object plugin, @NonNull Class<T> eventClass, @NonNull Consumer<? super T> handler);
/**
* Gets a set of all registered handlers for a given event.
@ -80,6 +78,6 @@ public interface EventBus {
* @param <T> the event class
* @return an immutable set of event handlers
*/
@NonNull <T extends LuckPermsEvent> Set<EventHandler<T>> getHandlers(@NonNull Class<T> eventClass);
@NonNull <T extends LuckPermsEvent> Set<EventSubscription<T>> getSubscriptions(@NonNull Class<T> eventClass);
}

View File

@ -34,7 +34,7 @@ import java.util.function.Consumer;
*
* @param <T> the event class
*/
public interface EventHandler<T extends LuckPermsEvent> extends AutoCloseable {
public interface EventSubscription<T extends LuckPermsEvent> extends AutoCloseable {
/**
* Gets the class this handler is listening to
@ -51,28 +51,15 @@ public interface EventHandler<T extends LuckPermsEvent> extends AutoCloseable {
boolean isActive();
/**
* Unregisters this handler from the event bus
*
* @return true if the handler wasn't already unregistered
* Unregisters this handler from the event bus.
*/
boolean unregister();
@Override
void close();
/**
* Gets the event consumer responsible for handling the event
*
* @return the event consumer
*/
@NonNull Consumer<? super T> getConsumer();
/**
* Gets the number of times this handler has been called
*
* @return the number of times this handler has been called
*/
int getCallCount();
@Override
default void close() {
unregister();
}
@NonNull Consumer<? super T> getHandler();
}

View File

@ -25,14 +25,12 @@
package me.lucko.luckperms.api.event;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.LuckPerms;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A superinterface for all LuckPerms events.
*
* @since 3.0
*/
public interface LuckPermsEvent {
@ -41,13 +39,12 @@ public interface LuckPermsEvent {
*
* @return the api instance
*/
@NonNull LuckPermsApi getApi();
@NonNull LuckPerms getLuckPerms();
/**
* Gets the type of the event.
*
* @return the type of the event
* @since 4.4
*/
@NonNull Class<? extends LuckPermsEvent> getEventType();

View File

@ -31,8 +31,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Represents an event with a {@link Source}.
*
* @since 4.1
*/
public interface Sourced {

View File

@ -25,17 +25,15 @@
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.caching.GroupData;
import me.lucko.luckperms.api.cacheddata.CachedDataManager;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a groups {@link GroupData} is loaded.
*
* @since 4.0
* Called when a groups {@link CachedDataManager} is loaded.
*/
public interface GroupCacheLoadEvent extends LuckPermsEvent {
@ -44,13 +42,15 @@ public interface GroupCacheLoadEvent extends LuckPermsEvent {
*
* @return the group
*/
@NonNull @Param(0) Group getGroup();
@Param(0)
@NonNull Group getGroup();
/**
* Gets the data that was loaded
*
* @return the loaded data
*/
@NonNull @Param(1) GroupData getLoadedData();
@Param(1)
@NonNull CachedDataManager getLoadedData();
}

View File

@ -25,10 +25,10 @@
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -42,13 +42,15 @@ public interface GroupCreateEvent extends LuckPermsEvent {
*
* @return the new group
*/
@NonNull @Param(0) Group getGroup();
@Param(0)
@NonNull Group getGroup();
/**
* Gets the cause of the creation
*
* @return the cause of the creation
*/
@NonNull @Param(1) CreationCause getCause();
@Param(1)
@NonNull CreationCause getCause();
}

View File

@ -25,17 +25,15 @@
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.caching.GroupData;
import me.lucko.luckperms.api.cacheddata.CachedDataManager;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a groups cached data is refreshed
*
* @since 4.0
*/
public interface GroupDataRecalculateEvent extends LuckPermsEvent {
@ -44,13 +42,15 @@ public interface GroupDataRecalculateEvent extends LuckPermsEvent {
*
* @return the group
*/
@NonNull @Param(0) Group getGroup();
@Param(0)
@NonNull Group getGroup();
/**
* Gets the data that was recalculated
*
* @return the data
*/
@NonNull @Param(1) GroupData getData();
@Param(1)
@NonNull CachedDataManager getData();
}

View File

@ -25,10 +25,10 @@
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -44,20 +44,23 @@ public interface GroupDeleteEvent extends LuckPermsEvent {
*
* @return the name of the deleted group
*/
@NonNull @Param(0) String getGroupName();
@Param(0)
@NonNull String getGroupName();
/**
* Gets an immutable copy of the groups existing data
*
* @return a copy of the groups existing data
*/
@NonNull @Param(1) Set<Node> getExistingData();
@Param(1)
@NonNull Set<Node> getExistingData();
/**
* Gets the cause of the deletion
*
* @return the cause of the deletion
*/
@NonNull @Param(2) DeletionCause getCause();
@Param(2)
@NonNull DeletionCause getCause();
}

View File

@ -25,9 +25,9 @@
package me.lucko.luckperms.api.event.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.group.Group;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -43,6 +43,7 @@ public interface GroupLoadEvent extends LuckPermsEvent {
*
* @return the group that was loaded
*/
@NonNull @Param(0) Group getGroup();
@Param(0)
@NonNull Group getGroup();
}

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
@ -42,20 +42,19 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be broadcasted
*/
@NonNull @Param(0) LogEntry getEntry();
@Param(0)
@NonNull Action getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
* @since 3.3
*/
@NonNull @Param(1) Origin getOrigin();
@Param(1)
@NonNull Origin getOrigin();
/**
* Represents where a log entry is from
*
* @since 3.3
*/
enum Origin {

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
@ -36,8 +36,6 @@ import java.util.UUID;
/**
* Called when a log is about to be published to the network via the MessagingService
*
* @since 3.3
*/
public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
@ -46,13 +44,15 @@ public interface LogNetworkPublishEvent extends LuckPermsEvent, Cancellable {
*
* @return the id of the log entry being published
*/
@NonNull @Param(0) UUID getLogId();
@Param(0)
@NonNull UUID getLogId();
/**
* Gets the log entry to be published
*
* @return the log entry to be published
*/
@NonNull @Param(1) LogEntry getEntry();
@Param(1)
@NonNull Action getEntry();
}

View File

@ -25,11 +25,11 @@
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.Entity;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.platform.PlatformEntity;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -40,8 +40,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* <p>This event is not called for players without the notify permission,
* but is called for objects which are ignoring log notifications (called with
* the cancelled flag set to true).</p>
*
* @since 4.1
*/
public interface LogNotifyEvent extends LuckPermsEvent, Cancellable {
@ -50,21 +48,24 @@ public interface LogNotifyEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be sent
*/
@NonNull @Param(0) LogEntry getEntry();
@Param(0)
@NonNull Action getEntry();
/**
* Gets where the log entry originated from.
*
* @return the origin of the log
*/
@NonNull @Param(1) Origin getOrigin();
@Param(1)
@NonNull Origin getOrigin();
/**
* Gets the object to be notified.
*
* @return the object to notify
*/
@NonNull @Param(2) Entity getNotifiable();
@Param(2)
@NonNull PlatformEntity getNotifiable();
/**
* Represents where a log entry is from

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.Cancellable;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
@ -42,6 +42,7 @@ public interface LogPublishEvent extends LuckPermsEvent, Cancellable {
*
* @return the log entry to be published
*/
@NonNull @Param(0) LogEntry getEntry();
@Param(0)
@NonNull Action getEntry();
}

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.event.log;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
@ -35,8 +35,6 @@ import java.util.UUID;
/**
* Called when a log entry is received via the MessagingService
*
* @since 3.3
*/
public interface LogReceiveEvent extends LuckPermsEvent {
@ -45,13 +43,15 @@ public interface LogReceiveEvent extends LuckPermsEvent {
*
* @return the id of the log entry being received
*/
@NonNull @Param(0) UUID getLogId();
@Param(0)
@NonNull UUID getLogId();
/**
* Gets the log entry being received
*
* @return the log entry being received
*/
@NonNull @Param(1) LogEntry getEntry();
@Param(1)
@NonNull Action getEntry();
}

View File

@ -25,8 +25,8 @@
package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -40,6 +40,7 @@ public interface NodeAddEvent extends NodeMutateEvent {
*
* @return the node that was added
*/
@NonNull @Param(3) Node getNode();
@Param(3)
@NonNull Node getNode();
}

View File

@ -25,12 +25,12 @@
package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.PermissionHolder;
import me.lucko.luckperms.api.model.group.Group;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -46,24 +46,27 @@ public interface NodeMutateEvent extends LuckPermsEvent {
*
* @return the event target
*/
@NonNull @Param(0) PermissionHolder getTarget();
@Param(0)
@NonNull PermissionHolder getTarget();
/**
* Gets an immutable copy of the holders data before the change
*
* @return the data before the change
*/
@NonNull @Param(1) Set<Node> getDataBefore();
@Param(1)
@NonNull Set<Node> getDataBefore();
/**
* Gets an immutable copy of the holders data after the change
*
* @return the data after the change
*/
@NonNull @Param(2) Set<Node> getDataAfter();
@Param(2)
@NonNull Set<Node> getDataAfter();
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.User}
* Gets whether the target of this event is a {@link User}
*
* <p>This is equivalent to checking if getTarget() instanceof User</p>
*
@ -74,7 +77,7 @@ public interface NodeMutateEvent extends LuckPermsEvent {
}
/**
* Gets whether the target of this event is a {@link me.lucko.luckperms.api.Group}
* Gets whether the target of this event is a {@link Group}
*
* <p>This is equivalent to checking if getTarget() instanceof Group</p>
*

View File

@ -25,8 +25,8 @@
package me.lucko.luckperms.api.event.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -40,6 +40,7 @@ public interface NodeRemoveEvent extends NodeMutateEvent {
*
* @return the node that was removed
*/
@NonNull @Param(3) Node getNode();
@Param(3)
@NonNull Node getNode();
}

View File

@ -25,10 +25,10 @@
package me.lucko.luckperms.api.event.player;
import me.lucko.luckperms.api.PlayerSaveResult;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.manager.UserManager;
import me.lucko.luckperms.api.model.PlayerSaveResult;
import me.lucko.luckperms.api.model.user.UserManager;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -38,8 +38,6 @@ import java.util.UUID;
* Called when player data is saved to the storage.
*
* <p>Data can be saved using {@link UserManager#savePlayerData(UUID, String)}.</p>
*
* @since 4.3
*/
public interface PlayerDataSaveEvent extends LuckPermsEvent {
@ -48,20 +46,23 @@ public interface PlayerDataSaveEvent extends LuckPermsEvent {
*
* @return the uuid
*/
@NonNull @Param(0) UUID getUuid();
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the username that was saved.
*
* @return the username
*/
@NonNull @Param(1) String getUsername();
@Param(1)
@NonNull String getUsername();
/**
* Gets the result of the operation.
*
* @return the result
*/
@NonNull @Param(2) PlayerSaveResult getResult();
@Param(2)
@NonNull PlayerSaveResult getResult();
}

View File

@ -25,9 +25,10 @@
package me.lucko.luckperms.api.event.player;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.util.Result;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -49,30 +50,31 @@ import java.util.UUID;
* for all connections, even if the operation to load User data was not
* successful. Note that LuckPerms will usually cancel the platform connection
* event if data could not be loaded.</p>
*
* @since 4.4
*/
public interface PlayerLoginProcessEvent extends LuckPermsEvent {
public interface PlayerLoginProcessEvent extends LuckPermsEvent, Result {
/**
* Gets the UUID of the connection which was processed
*
* @return the uuid of the connection which was processed
*/
@NonNull @Param(0) UUID getUuid();
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the username of the connection which was processed
*
* @return the username of the connection which was processed
*/
@NonNull @Param(1) String getUsername();
@Param(1)
@NonNull String getUsername();
/**
* Gets if the login was processed successfully.
*
* @return true if the login was successful
*/
@Override
default boolean wasSuccessful() {
return getUser() != null;
}
@ -85,6 +87,7 @@ public interface PlayerLoginProcessEvent extends LuckPermsEvent {
*
* @return the user instance
*/
@Nullable @Param(2) User getUser();
@Param(2)
@Nullable User getUser();
}

View File

@ -25,14 +25,12 @@
package me.lucko.luckperms.api.event.source;
import me.lucko.luckperms.api.Entity;
import me.lucko.luckperms.api.platform.PlatformEntity;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Represents an {@link Entity} which was the {@link Source} of something.
*
* @since 4.1
* Represents an {@link PlatformEntity} which was the {@link Source} of something.
*/
public interface EntitySource extends Source {
@ -41,6 +39,6 @@ public interface EntitySource extends Source {
*
* @return the entity
*/
@NonNull Entity getEntity();
@NonNull PlatformEntity getEntity();
}

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.event.source;
import me.lucko.luckperms.api.Entity;
import me.lucko.luckperms.api.platform.PlatformEntity;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -33,8 +33,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* Represents the source of an event.
*
* <p>Could also be described as the "thing" that caused an event to occur.</p>
*
* @since 4.1
*/
public interface Source {
@ -51,7 +49,7 @@ public interface Source {
enum Type {
/**
* Represents an {@link Entity} source
* Represents an {@link PlatformEntity} source
*
* @see EntitySource
*/

View File

@ -43,6 +43,7 @@ public interface PreNetworkSyncEvent extends LuckPermsEvent, Cancellable {
*
* @return the id of the sync request
*/
@NonNull @Param(0) UUID getSyncId();
@Param(0)
@NonNull UUID getSyncId();
}

View File

@ -25,10 +25,10 @@
package me.lucko.luckperms.api.event.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.track.Track;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -42,13 +42,15 @@ public interface TrackCreateEvent extends LuckPermsEvent {
*
* @return the new track
*/
@NonNull @Param(0) Track getTrack();
@Param(0)
@NonNull Track getTrack();
/**
* Gets the cause of the creation
*
* @return the cause of the creation
*/
@NonNull @Param(1) CreationCause getCause();
@Param(1)
@NonNull CreationCause getCause();
}

View File

@ -43,20 +43,23 @@ public interface TrackDeleteEvent extends LuckPermsEvent {
*
* @return the name of the deleted track
*/
@NonNull @Param(0) String getTrackName();
@Param(0)
@NonNull String getTrackName();
/**
* Gets an immutable copy of the tracks existing data
*
* @return a copy of the tracks existing data
*/
@NonNull @Param(1) List<String> getExistingData();
@Param(1)
@NonNull List<String> getExistingData();
/**
* Gets the cause of the deletion
*
* @return the cause of the deletion
*/
@NonNull @Param(2) DeletionCause getCause();
@Param(2)
@NonNull DeletionCause getCause();
}

View File

@ -25,9 +25,9 @@
package me.lucko.luckperms.api.event.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.track.Track;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -43,6 +43,7 @@ public interface TrackLoadEvent extends LuckPermsEvent {
*
* @return the track that was loaded
*/
@NonNull @Param(0) Track getTrack();
@Param(0)
@NonNull Track getTrack();
}

View File

@ -39,6 +39,7 @@ public interface TrackAddGroupEvent extends TrackMutateEvent {
*
* @return the group that was added
*/
@NonNull @Param(3) String getGroup();
@Param(3)
@NonNull String getGroup();
}

View File

@ -25,9 +25,9 @@
package me.lucko.luckperms.api.event.track.mutate;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.track.Track;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -43,20 +43,23 @@ public interface TrackMutateEvent extends LuckPermsEvent {
*
* @return the track that was mutated
*/
@NonNull @Param(0) Track getTrack();
@Param(0)
@NonNull Track getTrack();
/**
* Gets an immutable copy of the tracks data before the change
*
* @return the data before the change
*/
@NonNull @Param(1) List<String> getDataBefore();
@Param(1)
@NonNull List<String> getDataBefore();
/**
* Gets an immutable copy of the tracks data after the change
*
* @return the data after the change
*/
@NonNull @Param(2) List<String> getDataAfter();
@Param(2)
@NonNull List<String> getDataAfter();
}

View File

@ -39,6 +39,7 @@ public interface TrackRemoveGroupEvent extends TrackMutateEvent {
*
* @return the group that was removed
*/
@NonNull @Param(3) String getGroup();
@Param(3)
@NonNull String getGroup();
}

View File

@ -25,15 +25,15 @@
package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.cacheddata.CachedDataManager;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.user.User;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Called when a users {@link UserData} is loaded.
* Called when a users {@link CachedDataManager} is loaded.
*/
public interface UserCacheLoadEvent extends LuckPermsEvent {
@ -42,13 +42,15 @@ public interface UserCacheLoadEvent extends LuckPermsEvent {
*
* @return the user
*/
@NonNull @Param(0) User getUser();
@Param(0)
@NonNull User getUser();
/**
* Gets the data that was loaded
*
* @return the loaded data
*/
@NonNull @Param(1) UserData getLoadedData();
@Param(1)
@NonNull CachedDataManager getLoadedData();
}

View File

@ -25,10 +25,10 @@
package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.cacheddata.CachedDataManager;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.user.User;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -42,13 +42,15 @@ public interface UserDataRecalculateEvent extends LuckPermsEvent {
*
* @return the user
*/
@NonNull @Param(0) User getUser();
@Param(0)
@NonNull User getUser();
/**
* Gets the data that was recalculated
*
* @return the data
*/
@NonNull @Param(1) UserData getData();
@Param(1)
@NonNull CachedDataManager getData();
}

View File

@ -50,13 +50,15 @@ public interface UserFirstLoginEvent extends LuckPermsEvent {
*
* @return the uuid of the user
*/
@NonNull @Param(0) UUID getUuid();
@Param(0)
@NonNull UUID getUniqueId();
/**
* Gets the username of the user
*
* @return the username of the user
*/
@NonNull @Param(1) String getUsername();
@Param(1)
@NonNull String getUsername();
}

View File

@ -25,9 +25,9 @@
package me.lucko.luckperms.api.event.user;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.model.user.User;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -41,6 +41,7 @@ public interface UserLoadEvent extends LuckPermsEvent {
*
* @return the user that was loaded
*/
@NonNull @Param(0) User getUser();
@Param(0)
@NonNull User getUser();
}

View File

@ -25,11 +25,11 @@
package me.lucko.luckperms.api.event.user.track;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.event.LuckPermsEvent;
import me.lucko.luckperms.api.event.Param;
import me.lucko.luckperms.api.event.Sourced;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.track.Track;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -45,14 +45,16 @@ public interface UserTrackEvent extends LuckPermsEvent, Sourced {
*
* @return the track involved in the event
*/
@NonNull @Param(0) Track getTrack();
@Param(0)
@NonNull Track getTrack();
/**
* Gets the user who was promoted or demoted
*
* @return the user involved in the event
*/
@NonNull @Param(1) User getUser();
@Param(1)
@NonNull User getUser();
/**
* Gets the action performed
@ -68,13 +70,15 @@ public interface UserTrackEvent extends LuckPermsEvent, Sourced {
*
* @return the group the user was promoted/demoted from
*/
@NonNull @Param(2) Optional<String> getGroupFrom();
@Param(2)
@NonNull Optional<String> getGroupFrom();
/**
* Gets the group the user was promoted/demoted to
*
* @return the group the user was promoted/demoted to
*/
@NonNull @Param(3) Optional<String> getGroupTo();
@Param(3)
@NonNull Optional<String> getGroupTo();
}

View File

@ -23,14 +23,15 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.messaging;
import me.lucko.luckperms.api.LuckPerms;
import me.lucko.luckperms.api.model.user.User;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A means to push changes to other servers using the platforms networking
*
* @since 2.14
*/
public interface MessagingService {
@ -38,7 +39,6 @@ public interface MessagingService {
* Gets the name of this messaging service
*
* @return the name of this messaging service
* @since 4.1
*/
String getName();
@ -48,7 +48,7 @@ public interface MessagingService {
*
* <p>The standard response by other servers will be to execute a overall
* sync of all live data, equivalent to calling
* {@link LuckPermsApi#runUpdateTask()}.</p>
* {@link LuckPerms#runUpdateTask()}.</p>
*
* <p>This will push the update asynchronously, and this method will return
* immediately. Note that this method will not cause an update to be
@ -69,7 +69,6 @@ public interface MessagingService {
* processed on the local server.</p>
*
* @param user the user to push the update for
* @since 4.1
*/
void pushUserUpdate(@NonNull User user);

View File

@ -33,8 +33,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Encapsulates the LuckPerms system which accepts incoming {@link Message}s
* from implementations of {@link Messenger}.
*
* @since 4.1
*/
public interface IncomingMessageConsumer {

View File

@ -32,8 +32,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Represents an object which dispatches {@link OutgoingMessage}s.
*
* @since 4.1
*/
public interface Messenger extends AutoCloseable {

View File

@ -25,7 +25,7 @@
package me.lucko.luckperms.api.messenger;
import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.LuckPerms;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -35,8 +35,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* <p>Users wishing to provide their own implementation for the plugins
* "Messaging Service" should implement and register this interface.</p>
*
* @see LuckPermsApi#registerMessengerProvider(MessengerProvider)
* @since 4.1
* @see LuckPerms#registerMessengerProvider(MessengerProvider)
*/
public interface MessengerProvider {

View File

@ -33,8 +33,6 @@ import java.util.UUID;
/**
* Represents a message sent received via a {@link Messenger}.
*
* @since 4.1
*/
public interface Message {

View File

@ -38,8 +38,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* <p>Note that all implementations of this interface are guaranteed to be an
* instance of one of the interfaces extending {@link Message} in the
* 'api.messenger.message.type' package.</p>
*
* @since 4.1
*/
public interface OutgoingMessage extends Message {

View File

@ -25,25 +25,23 @@
package me.lucko.luckperms.api.messenger.message.type;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.messenger.message.Message;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Represents an "log" message.
* Represents an "action log" message.
*
* <p>Used to dispatch live log updates to other servers.</p>
*
* @since 4.1
* <p>Used to dispatch live action log updates to other servers.</p>
*/
public interface LogMessage extends Message {
public interface ActionLogMessage extends Message {
/**
* Gets the log entry being sent
* Gets the action being sent
*
* @return the log entry
* @return the action
*/
@NonNull LogEntry getLogEntry();
@NonNull Action getAction();
}

View File

@ -31,8 +31,6 @@ import me.lucko.luckperms.api.messenger.message.Message;
* Represents an "update" message.
*
* <p>Used to notify other servers of general changes.</p>
*
* @since 4.1
*/
public interface UpdateMessage extends Message {

View File

@ -35,8 +35,6 @@ import java.util.UUID;
* Represents an "user update" message.
*
* <p>Used to notify other servers of a change to a specific user.</p>
*
* @since 4.1
*/
public interface UserUpdateMessage extends Message {
@ -45,6 +43,6 @@ public interface UserUpdateMessage extends Message {
*
* @return the user
*/
@NonNull UUID getUser();
@NonNull UUID getUserUniqueId();
}

View File

@ -36,8 +36,6 @@ import java.util.Set;
* Functional interface which removes duplicate entries from a list.
*
* <p>Used by LuckPerms to remove duplicate entries from a MetaStack.</p>
*
* @since 4.4
*/
public interface DuplicateRemovalFunction {
@ -72,7 +70,7 @@ public interface DuplicateRemovalFunction {
@SuppressWarnings("Java8CollectionRemoveIf")
@Override
public <T> void processDuplicates(@NonNull List<T> list) {
Set<T> seen = new HashSet<>();
Set<T> seen = new HashSet<>(list.size());
for (ListIterator<T> it = list.listIterator(); it.hasNext(); ) {
T next = it.next();
if (!seen.add(next)) {
@ -93,7 +91,7 @@ public interface DuplicateRemovalFunction {
DuplicateRemovalFunction LAST_ONLY = new DuplicateRemovalFunction() {
@Override
public <T> void processDuplicates(@NonNull List<T> list) {
Set<T> seen = new HashSet<>();
Set<T> seen = new HashSet<>(list.size());
for (ListIterator<T> it = list.listIterator(list.size()); it.hasPrevious(); ) {
T next = it.previous();
if (!seen.add(next)) {

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.api.metastacking;
import me.lucko.luckperms.api.query.OptionKey;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
@ -37,11 +39,19 @@ import java.util.List;
*
* <p>Definitions can be passed to a users UserData instance using MetaContexts, and the result of this stack can be
* retrieved from the returned MetaData instance.</p>
*
* @since 2.3
*/
public interface MetaStackDefinition {
/**
* The {@link OptionKey} for the prefix {@link MetaStackDefinition}.
*/
OptionKey<MetaStackDefinition> PREFIX_STACK_KEY = new OptionKey<MetaStackDefinition>(){};
/**
* The {@link OptionKey} for the suffix {@link MetaStackDefinition}.
*/
OptionKey<MetaStackDefinition> SUFFIX_STACK_KEY = new OptionKey<MetaStackDefinition>(){};
/**
* Gets an immutable list of the elements in this stack definition
*
@ -54,7 +64,6 @@ public interface MetaStackDefinition {
* formatting takes place.
*
* @return the duplicate removal function
* @since 4.4
*/
@NonNull DuplicateRemovalFunction getDuplicateRemovalFunction();

View File

@ -25,34 +25,27 @@
package me.lucko.luckperms.api.metastacking;
import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.node.ChatMetaType;
import me.lucko.luckperms.api.node.types.ChatMetaNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Map;
/**
* Represents an element within a {@link MetaStackDefinition}.
*
* <p>The element itself does not contain any mutable state.</p>
*
* @since 3.2
*/
public interface MetaStackElement {
/**
* Returns if the given node should be accumulated onto the stack.
*
* <p>The element being considered can be retrieved using {@link ChatMetaType#getEntry(Node)}.</p>
*
* @param node the node being considered
* @param type the type of entry being accumulated
* @param node the node being considered
* @param current the current value being used. If this returns true, the current value will be replaced by this entry
* @return true if the node should be accumulated into this element, replacing the current value
*/
boolean shouldAccumulate(@NonNull LocalizedNode node, @NonNull ChatMetaType type, Map.@Nullable Entry<Integer, String> current);
boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current);
}

View File

@ -32,8 +32,6 @@ import java.util.Optional;
/**
* Factory to create meta stack elements and definitions.
*
* @since 3.2
*/
public interface MetaStackFactory {
@ -77,7 +75,6 @@ public interface MetaStackFactory {
* @param middleSpacer the spacer to be included between stack elements
* @param endSpacer the spacer to be included at the end of the stacks output
* @return the new stack definition instance
* @since 4.4
*/
@NonNull MetaStackDefinition createDefinition(@NonNull List<MetaStackElement> elements, @NonNull DuplicateRemovalFunction duplicateRemovalFunction, @NonNull String startSpacer, @NonNull String middleSpacer, @NonNull String endSpacer);

View File

@ -23,14 +23,17 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model;
import me.lucko.luckperms.api.track.Track;
import me.lucko.luckperms.api.util.Result;
/**
* Represents the result of a data mutation call on a LuckPerms object.
*
* <p>Usually as the result to a call on a {@link PermissionHolder} or {@link Track}.</p>
*/
public enum DataMutateResult implements MutateResult {
public enum DataMutateResult implements Result {
/**
* Indicates the mutation was a success
@ -59,7 +62,7 @@ public enum DataMutateResult implements MutateResult {
}
@Override
public boolean wasSuccess() {
public boolean wasSuccessful() {
return this.success;
}
}

View File

@ -0,0 +1,468 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.model;
import me.lucko.luckperms.api.cacheddata.CachedDataManager;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.model.group.Group;
import me.lucko.luckperms.api.model.group.GroupManager;
import me.lucko.luckperms.api.model.user.User;
import me.lucko.luckperms.api.model.user.UserManager;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeEqualityPredicate;
import me.lucko.luckperms.api.node.Tristate;
import me.lucko.luckperms.api.node.types.MetaNode;
import me.lucko.luckperms.api.node.types.PrefixNode;
import me.lucko.luckperms.api.node.types.SuffixNode;
import me.lucko.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
/**
* Generic superinterface for an object which holds permissions.
*/
public interface PermissionHolder {
/**
* Gets the objects generic name.
*
* <p>The result of this method is guaranteed to be a unique identifier for distinct instances
* of the same type of object.</p>
*
* <p>For {@link User}s, this method returns a {@link UUID#toString() string} representation of
* the users {@link User#getUniqueId() unique id}.</p>
*
* <p>For {@link Group}s, this method returns the {@link Group#getName() group name}.</p>
*
* <p>The {@link User#getUniqueId()}, {@link User#getUsername()} and {@link Group#getName()} methods
* define a "tighter" specification for obtaining object identifiers.</p>
*
* @return the identifier for this object. Either a uuid string or name.
*/
@NonNull String getObjectName();
/**
* Gets a friendly name for this holder, to be displayed in command output, etc.
*
* <p>This will <strong>always</strong> return a value, eventually falling back to
* {@link #getObjectName()} if no other "friendlier" identifiers are present.</p>
*
* <p>For {@link User}s, this method will attempt to return the {@link User#getUsername() username},
* before falling back to {@link #getObjectName()}.</p>
*
* <p>For {@link Group}s, this method will attempt to return the groups display name, before
* falling back to {@link #getObjectName()}.</p>
*
* @return a friendly identifier for this holder
*/
@NonNull String getFriendlyName();
/**
* Gets the holders {@link CachedDataManager} cache.
*
* @return the holders cached data.
*/
@NonNull CachedDataManager getCachedData();
/**
* Refreshes and applies any changes to the cached holder data.
*
* <p>Calling this method is unnecessary in most cases. Cache updates are handled
* behind the scenes by the implementation.</p>
*
* @return the task future
*/
@NonNull CompletableFuture<Void> refreshCachedData();
/**
* Gets the {@link Data} of a particular type.
*
* @param dataType the data type
* @return the data
*/
Data getData(@NonNull DataType dataType);
/**
* Gets the holders {@link DataType#NORMAL} data.
*
* @return the normal data
*/
@NonNull Data data();
/**
* Gets the holders {@link DataType#TRANSIENT} data.
*
* <p>Transient permissions only exist for the duration of the session.</p>
*
* <p>A transient node is a permission that does not persist.
* Whenever a user logs out of the server, or the server restarts, this permission will
* disappear. It is never saved to the datastore, and therefore will not apply on other
* servers.</p>
*
* <p>This is useful if you want to temporarily set a permission for a user while they're
* online, but don't want it to persist, and have to worry about removing it when they log
* out.</p>
*
* @return the transient data
*/
@NonNull Data transientData();
/**
* Represents a type of data.
*/
enum DataType {
/**
* Normal data.
*/
NORMAL,
/**
* Data which expires automatically at the end of a session.
* (when a user logs off)
*
* <p>This data is never saved to the backend storage provider.</p>
*/
TRANSIENT
}
interface Data {
/**
* Gets the backing map containing every permission this holder has.
*
* <p>This method <b>does not</b> resolve inheritance rules, and returns a
* view of what's 'in the file'.</p>
*
* @return the holders own nodes
*/
@NonNull Map<ImmutableContextSet, Collection<Node>> getNodes();
/**
* Gets a flattened set of {@link Node}s the holder has.
*
* <p>Effectively combines the value collections of the map returned by
* {@link #getNodes()}.</p>
*
* @return a flattened set of the holders own nodes
*/
@NonNull Set<Node> getFlattenedNodes();
/**
* Checks to see if the object has a certain permission.
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
*/
@NonNull Tristate hasNode(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate);
/**
* Sets a permission node for the permission holder.
*
* <p>Although this method is named setPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be set
* @return the result of the operation
* @throws NullPointerException if the node is null
*/
@NonNull DataMutateResult addNode(@NonNull Node node);
/**
* Sets a permission node for the permission holder.
*
* <p>Although this method is named setPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be set
* @param temporaryMergeBehaviour The behaviour used to merge temporary permission entries
* @return the result of the operation
* @throws NullPointerException if the node is null
*/
@NonNull TemporaryDataMutateResult addNode(@NonNull Node node, @NonNull TemporaryMergeBehaviour temporaryMergeBehaviour);
/**
* Unsets a permission for the permission holder.
*
* <p>Although this method is named unsetPermission, it can be used for all node types.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param node The node to be unset
* @return the result of the operation
* @throws NullPointerException if the node is null
*/
@NonNull DataMutateResult removeNode(@NonNull Node node);
/**
* Clears any nodes from the holder which pass the predicate.
*
* <p>This method only targets enduring data.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param test the predicate to test for nodes which should be removed
*/
void clearMatching(@NonNull Predicate<? super Node> test);
/**
* Clears all nodes held by the permission holder.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*/
void clearNodes();
/**
* Clears all nodes held by the permission holder in a specific context.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
*/
void clearNodes(@NonNull ContextSet contextSet);
/**
* Clears all parent groups.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*/
void clearParents();
/**
* Clears all parent groups in a specific context.
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
*/
void clearParents(@NonNull ContextSet contextSet);
/**
* Clears all meta held by the permission holder.
*
* <p>Meta nodes in this case, are any nodes which have a {@link MetaNode}, {@link PrefixNode}
* or {@link SuffixNode} type.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*/
void clearMeta();
/**
* Clears all meta held by the permission holder in a specific context.
*
* <p>Meta nodes in this case, are any nodes which have a {@link MetaNode}, {@link PrefixNode}
* or {@link SuffixNode} type.</p>
*
* <p>The effect of this mutate operation will not persist in storage unless changes are
* explicitly saved. If changes are not saved, the effect will only be observed until the next
* time the holders permission data is (re)loaded. Changes to {@link User}s should be saved
* using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved
* using {@link GroupManager#saveGroup(Group)}.</p>
*
* <p>Before making changes to a user or group, it may be a good idea to load a fresh copy of
* the backing data from the storage if you haven't done so already, to avoid overwriting changes
* made already. This can be done via {@link UserManager#loadUser(UUID)} or
* {@link GroupManager#loadGroup(String)} respectively.</p>
*
* @param contextSet the contexts to filter by
*/
void clearMeta(@NonNull ContextSet contextSet);
}
/**
* Gets a flattened/squashed view of the holders permissions.
*
* <p>This list is constructed using the values
* of both the transient and enduring backing multimaps.</p>
*
* <p>This means that it <b>may contain</b> duplicate entries.</p>
*
* <p>Use {@link #getDistinctNodes()} for a view without duplicates.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* @return a list of the holders own nodes.
*/
@NonNull List<Node> getNodes();
/**
* Gets a sorted set of all held nodes.
*
* <p>Effectively a sorted version of {@link #getNodes()}, without duplicates. Use the
* aforementioned method if you don't require either of these attributes.</p>
*
* <p>This method <b>does not</b> resolve inheritance rules.</p>
*
* @return an immutable set of permissions in priority order
*/
@NonNull SortedSet<Node> getDistinctNodes();
/**
* Recursively resolves this holders permissions.
*
* <p>The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.</p>
*
* <p>This means the list will contain duplicates.</p>
*
* <p>Inheritance is performed according to the platforms rules, and the order will vary
* depending on the accumulation order. By default, the holders own nodes are first in the list,
* with the entries from the end of the inheritance tree appearing last.</p>
*
* @param queryOptions the query options
* @return a list of nodes
*/
@NonNull List<Node> resolveInheritedNodes(@NonNull QueryOptions queryOptions);
/**
* Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
*
* <p>Nodes are sorted into priority order. The order of inheritance is only important during
* the process of flattening inherited entries.</p>
*
* @param queryOptions the query options
* @return an immutable sorted set of permissions
* @throws NullPointerException if the context is null
*/
@NonNull SortedSet<Node> resolveDistinctInheritedNodes(@NonNull QueryOptions queryOptions);
/**
* Removes any temporary permissions that have expired.
*
* <p>This method is called periodically by the platform, so it is only necessary to run
* if you want to guarantee that the current data is totally up-to-date.</p>
*/
void auditTemporaryPermissions();
/**
* Checks to see if the object inherits a certain permission.
*
* <p>Although this method is named inheritsPermission, it can be used for all node types.</p>
*
* @param node the node to check for
* @param equalityPredicate how to determine if a node matches
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
*/
@NonNull Tristate inheritsNode(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate);
}

View File

@ -23,9 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model;
import me.lucko.luckperms.api.manager.UserManager;
import me.lucko.luckperms.api.model.user.UserManager;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -39,8 +39,6 @@ import java.util.UUID;
*
* <p>The corresponding method can be found at
* {@link UserManager#savePlayerData(UUID, String)}.</p>
*
* @since 4.2
*/
public interface PlayerSaveResult {
@ -49,45 +47,45 @@ public interface PlayerSaveResult {
*
* @return the status
*/
@NonNull Set<Status> getStatus();
@NonNull Set<Outcome> getOutcomes();
/**
* Gets if the result includes a certain status code.
* Gets if the result includes a certain outcome.
*
* @param status the status to check for
* @return if the result includes the status
* @param outcome the outcome to check for
* @return if the result includes the outcome
*/
default boolean includes(@NonNull Status status) {
Objects.requireNonNull(status, "status");
return getStatus().contains(status);
default boolean includes(@NonNull Outcome outcome) {
Objects.requireNonNull(outcome, "outcome");
return getOutcomes().contains(outcome);
}
/**
* Gets the old username involved in the result.
*
* <p>Returns null when the result doesn't {@link #includes(Status) include} the
* {@link Status#USERNAME_UPDATED} status.</p>
* <p>Returns null when the result doesn't {@link #includes(Outcome) include} the
* {@link Outcome#USERNAME_UPDATED} status.</p>
*
* @return the old username
* @see Status#USERNAME_UPDATED
* @see Outcome#USERNAME_UPDATED
*/
@Nullable String getOldUsername();
/**
* Gets the other uuids involved in the result.
*
* <p>Returns null when the result doesn't {@link #includes(Status) include} the
* {@link Status#OTHER_UUIDS_PRESENT_FOR_USERNAME} status.</p>
* <p>Returns null when the result doesn't {@link #includes(Outcome) include} the
* {@link Outcome#OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME} status.</p>
*
* @return the other uuids
* @see Status#OTHER_UUIDS_PRESENT_FOR_USERNAME
* @see Outcome#OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME
*/
@Nullable Set<UUID> getOtherUuids();
@Nullable Set<UUID> getOtherUniqueIds();
/**
* The various states the result can take
*/
enum Status {
enum Outcome {
/**
* There was no existing data saved for either the uuid or username
@ -119,6 +117,6 @@ public interface PlayerSaveResult {
* that the user of the plugin is running a network off a shared database with one
* server in online mode and another in offline mode.</p>
*/
OTHER_UUIDS_PRESENT_FOR_USERNAME,
OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME,
}
}

View File

@ -23,16 +23,17 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.util.Result;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Extension of {@link DataMutateResult} for temporary set operations.
*
* @since 4.3
*/
public interface TemporaryDataMutateResult {
public interface TemporaryDataMutateResult extends Result {
/**
* Gets the underlying result.
@ -52,4 +53,9 @@ public interface TemporaryDataMutateResult {
*/
@NonNull Node getMergedNode();
@Override
default boolean wasSuccessful() {
return getResult().wasSuccessful();
}
}

View File

@ -23,20 +23,20 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model;
import me.lucko.luckperms.api.node.Node;
/**
* Controls how the implementation should behave when new temporary nodes are set
* that would otherwise conflict with existing entries.
*
* <p>The default behaviour of {@link PermissionHolder#setPermission(Node)} is
* <p>The default behaviour of {@link PermissionHolder.Data#addNode(Node)} is
* to return a result of {@link DataMutateResult#ALREADY_HAS} when an equivalent
* node is found. This can be replicated using {@link #FAIL_WITH_ALREADY_HAS}.</p>
*
* <p>However, the {@link PermissionHolder#setPermission(Node, TemporaryMergeBehaviour)}
* <p>However, the {@link PermissionHolder.Data#addNode(Node, TemporaryMergeBehaviour)}
* method allows this behaviour to be customized for temporary permissions.</p>
*
* @since 4.3
*/
public enum TemporaryMergeBehaviour {

View File

@ -23,10 +23,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model.group;
import me.lucko.luckperms.api.caching.GroupData;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.model.PermissionHolder;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -54,7 +54,6 @@ public interface Group extends PermissionHolder {
* {@link #getName() actual name}.</p>
*
* @return the display name
* @since 4.3
*/
@Nullable String getDisplayName();
@ -66,7 +65,6 @@ public interface Group extends PermissionHolder {
*
* @param contextSet the contexts to lookup in
* @return the display name
* @since 4.3
*/
@Nullable String getDisplayName(@NonNull ContextSet contextSet);
@ -74,17 +72,7 @@ public interface Group extends PermissionHolder {
* Gets the weight of this group, if present.
*
* @return the group weight
* @since 2.17
*/
@NonNull OptionalInt getWeight();
/**
* Gets the groups's {@link GroupData} cache.
*
* @return the groups cached data.
* @since 4.0
*/
@Override
@NonNull GroupData getCachedData();
}

View File

@ -23,11 +23,9 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.manager;
package me.lucko.luckperms.api.model.group;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.node.HeldNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -51,8 +49,6 @@ import java.util.function.Consumer;
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface GroupManager {
@ -62,17 +58,9 @@ public interface GroupManager {
*
* <p>If a group by the same name already exists, it will be loaded.</p>
*
* <p>This method is effectively the same as
* {@link Storage#createAndLoadGroup(String)}, however, the Future returns
* the resultant group instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the group
* @return the resultant group
* @throws NullPointerException if the name is null
* @since 4.1
*/
@NonNull CompletableFuture<Group> createAndLoadGroup(@NonNull String name);
@ -82,17 +70,9 @@ public interface GroupManager {
* <p>Returns an {@link Optional#empty() empty optional} if the group does
* not exist.</p>
*
* <p>This method is effectively the same as
* {@link Storage#loadGroup(String)}, however, the Future returns
* the resultant group instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param name the name of the group
* @return the resultant group
* @throws NullPointerException if the name is null
* @since 4.1
*/
@NonNull CompletableFuture<Optional<Group>> loadGroup(@NonNull String name);
@ -101,48 +81,27 @@ public interface GroupManager {
*
* <p>You should call this after you make any changes to a group.</p>
*
* <p>This method is effectively the same as {@link Storage#saveGroup(Group)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be saved,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param group the group to save
* @return a future to encapsulate the operation.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.1
*/
@NonNull CompletableFuture<Void> saveGroup(@NonNull Group group);
/**
* Permanently deletes a group from the plugin's storage provider.
*
* <p>This method is effectively the same as {@link Storage#deleteGroup(Group)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be deleted,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param group the group to delete
* @return a future to encapsulate the operation.
* @throws NullPointerException if group is null
* @throws IllegalStateException if the group instance was not obtained from LuckPerms.
* @since 4.1
*/
@NonNull CompletableFuture<Void> deleteGroup(@NonNull Group group);
/**
* Loads all groups into memory.
*
* <p>This method is effectively the same as {@link Storage#loadAllTracks()},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a group cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @return a future to encapsulate the operation.
* @since 4.1
*/
@NonNull CompletableFuture<Void> loadAllGroups();
@ -152,9 +111,8 @@ public interface GroupManager {
* @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
* @since 4.2
*/
@NonNull CompletableFuture<List<HeldPermission<String>>> getWithPermission(@NonNull String permission);
@NonNull CompletableFuture<List<HeldNode<String>>> getWithPermission(@NonNull String permission);
/**
* Gets a loaded group.
@ -165,19 +123,6 @@ public interface GroupManager {
*/
@Nullable Group getGroup(@NonNull String name);
/**
* Gets a loaded group.
*
* <p>This method does not return null, unlike {@link #getGroup}</p>
*
* @param name the name of the group to get
* @return an optional {@link Group} object
* @throws NullPointerException if the name is null
*/
default @NonNull Optional<Group> getGroupOpt(@NonNull String name) {
return Optional.ofNullable(getGroup(name));
}
/**
* Gets a set of all loaded groups.
*

View File

@ -23,9 +23,10 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.model.user;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.api.model.DataMutateResult;
import me.lucko.luckperms.api.model.PermissionHolder;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -42,7 +43,7 @@ public interface User extends PermissionHolder {
*
* @return the users Mojang assigned unique id
*/
@NonNull UUID getUuid();
@NonNull UUID getUniqueId();
/**
* Gets the users username
@ -51,7 +52,7 @@ public interface User extends PermissionHolder {
*
* @return the users username
*/
@Nullable String getName();
@Nullable String getUsername();
/**
* Gets the users current primary group.
@ -77,32 +78,4 @@ public interface User extends PermissionHolder {
*/
@NonNull DataMutateResult setPrimaryGroup(@NonNull String group);
/**
* Gets the user's {@link UserData} cache.
*
* @return the users cached data.
* @since 3.2
*/
@Override
@NonNull UserData getCachedData();
/**
* Refresh and re-assign the users permissions.
*
* @deprecated Calling this method is no longer necessary. Permissions data is now refreshed on
* demand, as changes are made. Consider use of {@link #refreshCachedData()}
* instead. This method is now implemented as a no-op.
*/
@Deprecated
void refreshPermissions();
/**
* Pre-calculates some values in the user's data cache.
*
* @since 2.17
* @deprecated Use of this method is no longer necessary. It is implemented as a no-op.
*/
@Deprecated
void setupDataCache();
}

View File

@ -23,18 +23,15 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.manager;
package me.lucko.luckperms.api.model.user;
import me.lucko.luckperms.api.HeldPermission;
import me.lucko.luckperms.api.PlayerSaveResult;
import me.lucko.luckperms.api.Storage;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.model.PlayerSaveResult;
import me.lucko.luckperms.api.node.HeldNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -56,43 +53,25 @@ import java.util.function.Consumer;
* <strong>not</strong> be called on the main server thread. If you need to use
* the result of these operations on the main server thread, register a
* callback using {@link CompletableFuture#thenAcceptAsync(Consumer, Executor)}.</p>
*
* @since 4.0
*/
public interface UserManager {
/**
* Loads a user from the plugin's storage provider into memory.
*
* <p>This method is effectively the same as
* {@link Storage#loadUser(UUID, String)}, however, the Future returns the
* resultant user instance instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param uuid the uuid of the user
* @param username the username, if known
* @return the resultant user
* @throws NullPointerException if the uuid is null
* @since 4.1
*/
@NonNull CompletableFuture<User> loadUser(@NonNull UUID uuid, @Nullable String username);
/**
* Loads a user from the plugin's storage provider into memory.
*
* <p>This method is effectively the same as {@link Storage#loadUser(UUID)},
* however, the Future returns the resultant user instance instead of a
* boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be loaded,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param uuid the uuid of the user
* @return the resultant user
* @throws NullPointerException if the uuid is null
* @since 4.1
*/
default @NonNull CompletableFuture<User> loadUser(@NonNull UUID uuid) {
return loadUser(uuid, null);
@ -107,9 +86,8 @@ public interface UserManager {
* @return a uuid, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@NonNull CompletableFuture<UUID> lookupUuid(@NonNull String username);
@NonNull CompletableFuture<UUID> lookupUniqueId(@NonNull String username);
/**
* Uses the LuckPerms cache to find a username for the given uuid.
@ -118,7 +96,6 @@ public interface UserManager {
* @return a username, could be null
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@NonNull CompletableFuture<String> lookupUsername(@NonNull UUID uuid);
@ -127,17 +104,10 @@ public interface UserManager {
*
* <p>You should call this after you make any changes to a user.</p>
*
* <p>This method is effectively the same as {@link Storage#saveUser(User)},
* however, the Future returns void instead of a boolean flag.</p>
*
* <p>Unlike the method in {@link Storage}, when a user cannot be saved,
* the future will be {@link CompletableFuture completed exceptionally}.</p>
*
* @param user the user to save
* @return a future to encapsulate the operation.
* @throws NullPointerException if user is null
* @throws IllegalStateException if the user instance was not obtained from LuckPerms.
* @since 4.1
*/
@NonNull CompletableFuture<Void> saveUser(@NonNull User user);
@ -149,7 +119,6 @@ public interface UserManager {
* @return the result of the operation.
* @throws NullPointerException if either parameters are null
* @throws IllegalArgumentException if the username is invalid
* @since 4.2
*/
@NonNull CompletableFuture<PlayerSaveResult> savePlayerData(@NonNull UUID uuid, @NonNull String username);
@ -159,7 +128,6 @@ public interface UserManager {
* <p>"Unique" meaning the user isn't just a member of the "default" group.</p>
*
* @return a set of uuids
* @since 4.2
*/
@NonNull CompletableFuture<Set<UUID>> getUniqueUsers();
@ -169,9 +137,8 @@ public interface UserManager {
* @param permission the permission to search for
* @return a list of held permissions
* @throws NullPointerException if the permission is null
* @since 4.2
*/
@NonNull CompletableFuture<List<HeldPermission<UUID>>> getWithPermission(@NonNull String permission);
@NonNull CompletableFuture<List<HeldNode<UUID>>> getWithPermission(@NonNull String permission);
/**
* Gets a loaded user.
@ -182,17 +149,6 @@ public interface UserManager {
*/
@Nullable User getUser(@NonNull UUID uuid);
/**
* Gets a loaded user.
*
* @param uuid the uuid of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the uuid is null
*/
default @NonNull Optional<User> getUserOpt(@NonNull UUID uuid) {
return Optional.ofNullable(getUser(uuid));
}
/**
* Gets a loaded user.
*
@ -202,17 +158,6 @@ public interface UserManager {
*/
@Nullable User getUser(@NonNull String name);
/**
* Gets a loaded user.
*
* @param name the username of the user to get
* @return an optional {@link User} object
* @throws NullPointerException if the name is null
*/
default @NonNull Optional<User> getUserOpt(@NonNull String name) {
return Optional.ofNullable(getUser(name));
}
/**
* Gets a set of all loaded users.
*

View File

@ -23,45 +23,47 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.nodetype.types;
package me.lucko.luckperms.api.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import me.lucko.luckperms.api.node.types.ChatMetaNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Map;
/**
* Represents a type of chat meta
*/
public enum ChatMetaType {
/**
* A sub-type of {@link Node} used to store meta assignments.
* Represents a prefix
*/
PREFIX(NodeType.PREFIX),
/**
* Represents a suffix
*/
SUFFIX(NodeType.SUFFIX);
private final String name;
private final NodeType<? extends ChatMetaNode<?, ?>> nodeType;
ChatMetaType(NodeType<? extends ChatMetaNode<?, ?>> nodeType) {
this.name = nodeType.name().toLowerCase();
this.nodeType = nodeType;
}
/**
* Gets the {@link NodeType} for the {@link ChatMetaType}.
*
* @since 4.2
* @return the node type
*/
public interface MetaType extends NodeType, Map.Entry<String, String> {
/**
* The key for this type.
*/
NodeTypeKey<MetaType> KEY = new NodeTypeKey<MetaType>(){};
/**
* Gets the meta key.
*
* @return the meta key
*/
@NonNull String getKey();
/**
* Gets the meta value.
*
* @return the meta value
*/
@NonNull String getValue();
public @NonNull NodeType<? extends ChatMetaNode<?, ?>> nodeType() {
return this.nodeType;
}
@Override
@Deprecated
default String setValue(String value) {
throw new UnsupportedOperationException();
public String toString() {
return this.name;
}
}

View File

@ -23,29 +23,31 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.nodetype.types;
package me.lucko.luckperms.api.node;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.nodetype.NodeType;
import me.lucko.luckperms.api.nodetype.NodeTypeKey;
import me.lucko.luckperms.api.model.PermissionHolder;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A sub-type of {@link Node} used to mark the weight of the node's holder.
* A relationship between a {@link PermissionHolder} and a {@link Node}.
*
* @since 4.2
* @param <T> the identifier type of the holder
*/
public interface WeightType extends NodeType {
public interface HeldNode<T> {
/**
* The key for this type.
*/
NodeTypeKey<WeightType> KEY = new NodeTypeKey<WeightType>(){};
/**
* Gets the weight value.
* Gets the holder of the node
*
* @return the weight
* @return the holder
*/
int getWeight();
@NonNull T getHolder();
/**
* Gets the node
*
* @return the node
*/
@NonNull Node getNode();
}

View File

@ -0,0 +1,237 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.node;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.node.metadata.NodeMetadata;
import me.lucko.luckperms.api.node.metadata.NodeMetadataKey;
import me.lucko.luckperms.api.node.types.DisplayNameNode;
import me.lucko.luckperms.api.node.types.InheritanceNode;
import me.lucko.luckperms.api.node.types.MetaNode;
import me.lucko.luckperms.api.node.types.PermissionNode;
import me.lucko.luckperms.api.node.types.PrefixNode;
import me.lucko.luckperms.api.node.types.RegexPermissionNode;
import me.lucko.luckperms.api.node.types.SuffixNode;
import me.lucko.luckperms.api.node.types.WeightNode;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
/**
* Represents a LuckPerms "node".
*
* <p>The {@link Node} class encapsulates more than just permission assignments.
* Nodes are used to store data about inherited groups, as well as assigned
* prefixes, suffixes and meta values.</p>
*
* <p>Combining these various states into one object (a "node") means that a
* holder only has to have one type of data set (a set of nodes) in order to
* take on various properties.</p>
*
* <p>It is recommended that users of the API make use of {@link Stream}s
* to manipulate data and obtain the required information.</p>
*
* <p>This interface provides a number of methods to read the attributes of the
* node, as well as methods to query and extract additional state and properties
* from these settings.</p>
*
* <p>Nodes have the following attributes:</p>
* <p></p>
* <ul>
* <li>{@link #getKey() key} - the key of the node</li>
* <li>{@link #getValue() value} - the value of the node (false for negated)</li>
* <li>{@link #getContexts() context} - the contexts required for this node to apply </li>
* <li>{@link #getExpiry() expiry} - the time when this node should expire</li>
* </ul>
*
* <p>There are a number of node types, all of which extend from this class:</p>
* <p></p>
* <ul>
* <li>{@link PermissionNode} - represents an assigned permission</li>
* <li>{@link RegexPermissionNode} - represents an assigned regex permission</li>
* <li>{@link InheritanceNode} - an "inheritance node" marks that the holder should inherit data from another group</li>
* <li>{@link PrefixNode} - represents an assigned prefix</li>
* <li>{@link SuffixNode} - represents an assigned suffix</li>
* <li>{@link MetaNode} - represents an assigned meta option</li>
* <li>{@link WeightNode} - marks the weight of the object holding this node</li>
* <li>{@link DisplayNameNode} - marks the display name of the object holding this node</li>
* </ul>
*
* <p>The core node state must be immutable in all implementations.</p>
*/
public interface Node {
/**
* Gets a {@link NodeBuilder} for the given node {@link #getKey() key}.
*
* @param key the key
* @return the node builder
*/
static @NonNull NodeBuilder builder(@NonNull String key) {
return LuckPermsProvider.get().getNodeBuilderRegistry().forKey(key);
}
/**
* Gets the key ({@link String}) of the node.
*
* @return the key
*/
@NonNull String getKey();
/**
* Gets the value of the node.
*
* <p>A negated setting would result in a value of <code>false</code>.</p>
*
* @return the nodes value
*/
boolean getValue();
/**
* Gets if the node is negated.
*
* <p>This is the inverse of the {@link #getValue() value}.</p>
*
* @return true if the node is negated
*/
default boolean isNegated() {
return !getValue();
}
/**
* Gets if this node applies globally, and therefore has no specific context.
*
* @return true if this node applies globally, and has no specific context
*/
boolean appliesGlobally();
/**
* Gets if this node should apply in the given context
*
* @param contextSet the context set
* @return true if the node should apply
*/
boolean shouldApplyWithContext(@NonNull ContextSet contextSet);
/**
* Resolves any shorthand parts of this node and returns the full list of
* resolved nodes.
*
* <p>The list will not contain the exact permission itself.</p>
*
* @return a list of full nodes
*/
@NonNull List<String> resolveShorthand();
/**
* Gets if this node is assigned temporarily.
*
* @return true if this node will expire in the future
*/
boolean hasExpiry();
/**
* Gets the time when this node will expire.
*
* @return the {@link Instant} when this node will expire, or null if it
* doesn't have an expiry time
*/
@Nullable Instant getExpiry() throws IllegalStateException;
/**
* Gets if the node has expired.
*
* <p>This returns false if the node is not temporary.</p>
*
* @return true if this node has expired
*/
boolean hasExpired();
/**
* Gets the contexts required for this node to apply.
*
* @return the contexts required for this node to apply
*/
@NonNull ImmutableContextSet getContexts();
/**
* Gets the metadata corresponding to the given <code>key</code>, if present.
*
* @param key the key
* @param <T> the {@link NodeMetadata} type
* @return the data, if present
*/
<T extends NodeMetadata> Optional<T> getMetadata(NodeMetadataKey<T> key);
/**
* Gets the metadata corresponding to the given <code>key</code>, throwing an exception
* if no data is present.
*
* @param key the key
* @param <T> the {@link NodeMetadata} type
* @return the data
* @throws IllegalStateException if data isn't present
*/
default <T extends NodeMetadata> T metadata(NodeMetadataKey<T> key) throws IllegalStateException {
return getMetadata(key).orElseThrow(() -> new IllegalStateException("Node '" + getKey() + "' does not have '" + key.name() + "' attached."));
}
/**
* Gets if this Node is equal to another node.
*
* @param obj the other node
* @return true if this node is equal to the other provided
* @see NodeEqualityPredicate#EXACT
*/
@Override
boolean equals(Object obj);
/**
* Gets if this Node is equal to another node as defined by the given
* {@link NodeEqualityPredicate}.
*
* @param other the other node
* @param equalityPredicate the predicate
* @return true if this node is considered equal
*/
boolean equals(@NonNull Node other, @NonNull NodeEqualityPredicate equalityPredicate);
/**
* Gets a {@link NodeBuilder}, with the attributes of this node already
* applied.
*
* @return an editable, builder form of this node
*/
@NonNull NodeBuilder<?, ?> toBuilder();
}

View File

@ -0,0 +1,149 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.node.metadata.NodeMetadata;
import me.lucko.luckperms.api.node.metadata.NodeMetadataKey;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* Builder for {@link Node}s.
*
* @param <N> the node type
* @param <B> the node builder type
*/
public interface NodeBuilder<N extends ScopedNode<N, B>, B extends NodeBuilder<N, B>> {
/**
* Sets the value of the node.
*
* @param value the value
* @return the builder
* @see Node#getValue()
*/
@NonNull B value(boolean value);
/**
* Sets the value of negated for the node.
*
* @param negated the value
* @return the builder
* @see Node#isNegated()
*/
@NonNull B negated(boolean negated);
/**
* Sets the time when the node should expire.
*
* <p>The parameter passed to this method must be the unix timestamp
* (in seconds) when the node should expire.</p>
*
* @param expiryUnixTimestamp the expiry timestamp (unix seconds)
* @return the builder
* @see Node#getExpiry()
*/
@NonNull B expiry(long expiryUnixTimestamp);
/**
* Sets the time when the node should expire.
*
* <p>The expiry timestamp is calculated relative to the current
* system time.</p>
*
* @param duration how long the node should be added for
* @param unit the unit <code>duration</code> is measured in
* @return the builder
*/
default @NonNull B expiry(long duration, TimeUnit unit) {
if (duration <= 0) {
throw new IllegalArgumentException("duration must be positive");
}
long seconds = Objects.requireNonNull(unit, "unit").toSeconds(duration);
long timeNow = System.currentTimeMillis() / 1000L;
return expiry(timeNow + seconds);
}
/**
* Marks that the node being built should never expire.
*
* @return the builder
*/
@NonNull B clearExpiry();
/**
* Sets the extra contexts for the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull B context(@NonNull ContextSet contextSet);
/**
* Appends an extra context onto the node.
*
* @param key the context key
* @param value the context value
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull B withContext(@NonNull String key, @NonNull String value);
/**
* Appends extra contexts onto the node.
*
* @param contextSet a context set
* @return the builder
* @see ContextSet
* @see Node#getContexts()
*/
@NonNull B withContext(@NonNull ContextSet contextSet);
/**
* Sets the given metadata for the node.
*
* @param key the metadata key
* @param metadata the metadata
* @param <T> the metadata type
* @return the builder
*/
@NonNull <T extends NodeMetadata> B withMetadata(@NonNull NodeMetadataKey<T> key, @Nullable T metadata);
/**
* Creates a {@link Node} instance from the builder.
*
* @return a new node instance
*/
@NonNull N build();
}

View File

@ -0,0 +1,109 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.node;
import me.lucko.luckperms.api.node.types.DisplayNameNode;
import me.lucko.luckperms.api.node.types.InheritanceNode;
import me.lucko.luckperms.api.node.types.MetaNode;
import me.lucko.luckperms.api.node.types.PermissionNode;
import me.lucko.luckperms.api.node.types.PrefixNode;
import me.lucko.luckperms.api.node.types.RegexPermissionNode;
import me.lucko.luckperms.api.node.types.SuffixNode;
import me.lucko.luckperms.api.node.types.WeightNode;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A registry of methods for obtaining {@link NodeBuilder}s for the various
* node types.
*/
public interface NodeBuilderRegistry {
/**
* Gets a {@link NodeBuilder} applicable for the given key.
*
* @param key the key
* @return the node builder
*/
@NonNull NodeBuilder<?, ?> forKey(String key);
/**
* Gets a {@link NodeBuilder} for {@link PermissionNode}s.
*
* @return the node builder
*/
PermissionNode.@NonNull Builder forPermission();
/**
* Gets a {@link NodeBuilder} for {@link RegexPermissionNode}s.
*
* @return the node builder
*/
RegexPermissionNode.@NonNull Builder forRegexPermission();
/**
* Gets a {@link NodeBuilder} for {@link InheritanceNode}s.
*
* @return the node builder
*/
InheritanceNode.@NonNull Builder forInheritance();
/**
* Gets a {@link NodeBuilder} for {@link PrefixNode}s.
*
* @return the node builder
*/
PrefixNode.@NonNull Builder forPrefix();
/**
* Gets a {@link NodeBuilder} for {@link SuffixNode}s.
*
* @return the node builder
*/
SuffixNode.@NonNull Builder forSuffix();
/**
* Gets a {@link NodeBuilder} for {@link MetaNode}s.
*
* @return the node builder
*/
MetaNode.@NonNull Builder forMeta();
/**
* Gets a {@link NodeBuilder} for {@link WeightNode}s.
*
* @return the node builder
*/
WeightNode.@NonNull Builder forWeight();
/**
* Gets a {@link NodeBuilder} for {@link DisplayNameNode}s.
*
* @return the node builder
*/
DisplayNameNode.@NonNull Builder forDisplayName();
}

View File

@ -23,16 +23,39 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.node;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Standard {@link NodeEqualityPredicate}s.
* A rule for determining if two nodes are equal.
*
* @since 4.1
* <p>Generally, implementations of this interface should fulfil the same
* requirements as the {@link Object#equals(Object)} contract.</p>
*/
@FunctionalInterface
public interface NodeEqualityPredicate {
/**
* Returns if the two nodes are equal.
*
* <p>This method should avoid making calls to {@link Node#equals(Node, NodeEqualityPredicate)}
* with {@code this} as the second argument, directly or otherwise.</p>
*
* @param o1 the first node
* @param o2 the second node
* @return true if equal
*/
boolean areEqual(@NonNull Node o1, @NonNull Node o2);
/*
* Some 'default' implementations of NodeEqualityPredicate are provided below.
*
* These are implemented in the common code, by a special case in the
* implementation of Node#equals. As noted above, this should generally be
* avoided.
*/
public enum StandardNodeEquality implements NodeEqualityPredicate {
/**
* Represents an exact match.
@ -40,13 +63,17 @@ public enum StandardNodeEquality implements NodeEqualityPredicate {
* <p>All attributes of the nodes must match for them to be considered
* equal.</p>
*/
EXACT,
NodeEqualityPredicate EXACT = new NodeEqualityPredicate() {
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
};
/**
* All attributes must match, except for
* {@link Node#getValue() value}, which is ignored.
*/
IGNORE_VALUE,
NodeEqualityPredicate IGNORE_VALUE = new NodeEqualityPredicate() {
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
};
/**
* All attributes must match, except for the
@ -55,24 +82,26 @@ public enum StandardNodeEquality implements NodeEqualityPredicate {
* <p>Note that with this setting, whether a node is temporary or not is
* still considered.</p>
*/
IGNORE_EXPIRY_TIME,
NodeEqualityPredicate IGNORE_EXPIRY_TIME = new NodeEqualityPredicate() {
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
};
/**
* All attributes must match, except for
* {@link Node#getValue() value} and the
* {@link Node#getExpiry() expiry time}, which are ignored.
*/
IGNORE_EXPIRY_TIME_AND_VALUE,
NodeEqualityPredicate IGNORE_EXPIRY_TIME_AND_VALUE = new NodeEqualityPredicate() {
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
};
/**
* All attributes must match, except for
* {@link Node#getValue() value} and the if the node is
* {@link Node#isTemporary() temporary}, which are ignored.
* {@link Node#hasExpiry() temporary}, which are ignored.
*/
IGNORE_VALUE_OR_IF_TEMPORARY;
NodeEqualityPredicate IGNORE_VALUE_OR_IF_TEMPORARY = new NodeEqualityPredicate() {
@Override public boolean areEqual(@NonNull Node o1, @NonNull Node o2) { return o1.equals(o2, this); }
};
@Override
public boolean areEqual(@NonNull Node o1, @NonNull Node o2) {
return o1.equals(o2, this);
}
}

View File

@ -0,0 +1,166 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.node;
import me.lucko.luckperms.api.node.types.ChatMetaNode;
import me.lucko.luckperms.api.node.types.DisplayNameNode;
import me.lucko.luckperms.api.node.types.InheritanceNode;
import me.lucko.luckperms.api.node.types.MetaNode;
import me.lucko.luckperms.api.node.types.PermissionNode;
import me.lucko.luckperms.api.node.types.PrefixNode;
import me.lucko.luckperms.api.node.types.RegexPermissionNode;
import me.lucko.luckperms.api.node.types.SuffixNode;
import me.lucko.luckperms.api.node.types.WeightNode;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Represents a type of {@link Node}.
*/
public interface NodeType<T extends Node> {
/**
* Node type for {@link PermissionNode}.
*/
NodeType<PermissionNode> PERMISSION = new SimpleNodeType<>("PERMISSION", n -> n instanceof PermissionNode, n -> ((PermissionNode) n));
/**
* Node type for {@link RegexPermissionNode}.
*/
NodeType<RegexPermissionNode> REGEX_PERMISSION = new SimpleNodeType<>("REGEX_PERMISSION", n -> n instanceof RegexPermissionNode, n -> ((RegexPermissionNode) n));
/**
* Node type for {@link InheritanceNode}.
*/
NodeType<InheritanceNode> INHERITANCE = new SimpleNodeType<>("INHERITANCE", n -> n instanceof InheritanceNode, n -> ((InheritanceNode) n));
/**
* Node type for {@link PrefixNode}.
*/
NodeType<PrefixNode> PREFIX = new SimpleNodeType<>("PREFIX", n -> n instanceof PrefixNode, n -> ((PrefixNode) n));
/**
* Node type for {@link SuffixNode}.
*/
NodeType<SuffixNode> SUFFIX = new SimpleNodeType<>("SUFFIX", n -> n instanceof SuffixNode, n -> ((SuffixNode) n));
/**
* Node type for {@link MetaNode}.
*/
NodeType<MetaNode> META = new SimpleNodeType<>("META", n -> n instanceof MetaNode, n -> ((MetaNode) n));
/**
* Node type for {@link WeightNode}.
*/
NodeType<WeightNode> WEIGHT = new SimpleNodeType<>("WEIGHT", n -> n instanceof WeightNode, n -> ((WeightNode) n));
/**
* Node type for {@link DisplayNameNode}.
*/
NodeType<DisplayNameNode> DISPLAY_NAME = new SimpleNodeType<>("DISPLAY_NAME", n -> n instanceof DisplayNameNode, n -> ((DisplayNameNode) n));
/**
* Node type for {@link ChatMetaNode}.
*/
NodeType<ChatMetaNode<?, ?>> CHAT_META = new SimpleNodeType<>("CHAT_META", n -> n instanceof ChatMetaNode<?, ?>, n -> ((ChatMetaNode<?, ?>) n));
/**
* Node type for {@link ChatMetaNode} or {@link MetaNode}.
*/
NodeType<Node> META_OR_CHAT_META = new SimpleNodeType<>("META_OR_CHAT_META", n -> META.matches(n) || CHAT_META.matches(n), Function.identity());
/**
* Gets a name for the node type.
*
* @return a name
*/
String name();
/**
* Returns if the passed node matches the type
*
* @param node the node to test
* @return true if the node has the same type
*/
boolean matches(Node node);
/**
* Casts the given {@link Node} to the type defined by the {@link NodeType}.
*
* <p>An {@link IllegalArgumentException} is thrown if the node to cast does
* not {@link #matches(Node) match} the type.</p>
*
* @param node the node to cast
* @return the casted node
* @throws IllegalArgumentException if the node to cast does not match the type
*/
T cast(Node node);
/**
* Attempts to cast the given {@link Node} to the type defined by the
* {@link NodeType}.
*
* <p>Returns an {@link Optional#empty() empty optional} if the node to cast
* does not {@link #matches(Node) match} the type.</p>
*
* @param node the node to cast
* @return an optional, possibly containing a casted node
*/
default Optional<T> tryCast(Node node) {
Objects.requireNonNull(node, "node");
if (!matches(node)) {
return Optional.empty();
} else {
return Optional.of(cast(node));
}
}
/**
* Returns a {@link Predicate}, returning whether a {@link Node}
* {@link #matches(Node) matches} this type.
*
* @return a predicate for the {@link #matches(Node)} method.
*/
default Predicate<Node> predicate() {
return this::matches;
}
/**
* Returns a {@link Predicate}, returning whether a {@link Node}
* {@link #matches(Node) matches} this type, and passes the given
* {@code and} {@link Predicate}.
*
* @param and a predicate to AND with the result of the type match check
* @return a matching predicate, ANDed with the given predicate parameter
*/
default Predicate<Node> predicate(Predicate<? super T> and) {
return node -> matches(node) && and.test(cast(node));
}
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.api.node;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* A {@link Node}, with its own type and the type of its associated builder
* defined as a type parameter.
*
* @param <N> the node type
* @param <B> the node builder type
*/
public interface ScopedNode<N extends ScopedNode<N, B>, B extends NodeBuilder<N, B>> extends Node {
@Override
@NonNull B toBuilder();
}

View File

@ -23,45 +23,44 @@
* SOFTWARE.
*/
package me.lucko.luckperms.common.node.model;
import me.lucko.luckperms.api.Node;
package me.lucko.luckperms.api.node;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Holds a Node and plus an owning object. All calls are passed onto the contained Node instance.
*/
public final class ImmutableTransientNode<O> extends ForwardingNode implements Node {
public static <O> ImmutableTransientNode<O> of(Node node, O owner) {
Objects.requireNonNull(node, "node");
Objects.requireNonNull(owner, "owner");
return new ImmutableTransientNode<>(node, owner);
}
final class SimpleNodeType<T extends Node> implements NodeType<T> {
private final String name;
private final Predicate<Node> matches;
private final Function<Node, T> cast;
private final Node node;
private final O owner;
private ImmutableTransientNode(Node node, O owner) {
this.node = node;
this.owner = owner;
SimpleNodeType(String name, Predicate<Node> matches, Function<Node, T> cast) {
this.name = name;
this.matches = matches;
this.cast = cast;
}
@Override
public Node delegate() {
return this.node;
public String name() {
return this.name;
}
public Node getNode() {
return this.node;
@Override
public boolean matches(Node node) {
Objects.requireNonNull(node, "node");
return this.matches.test(node);
}
public O getOwner() {
return this.owner;
@Override
public T cast(Node node) {
if (!matches(node)) {
throw new IllegalArgumentException("Node " + node.getClass() + " does not match " + this.name);
}
return this.cast.apply(node);
}
@Override
public String toString() {
return "ImmutableTransientNode(node=" + this.getNode() + ", owner=" + this.getOwner() + ")";
return name();
}
}

View File

@ -23,7 +23,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api;
package me.lucko.luckperms.api.node;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -61,22 +61,21 @@ public enum Tristate {
* @param val the boolean value
* @return {@link #TRUE} or {@link #FALSE}, if the value is <code>true</code> or <code>false</code>, respectively.
*/
public static @NonNull Tristate fromBoolean(boolean val) {
public static @NonNull Tristate of(boolean val) {
return val ? TRUE : FALSE;
}
/**
* Returns a {@link Tristate} from a nullable boolean.
*
* <p>Unlike {@link #fromBoolean(boolean)}, this method returns {@link #UNDEFINED}
* <p>Unlike {@link #of(boolean)}, this method returns {@link #UNDEFINED}
* if the value is null.</p>
*
* @param val the boolean value
* @return {@link #UNDEFINED}, {@link #TRUE} or {@link #FALSE}, if the value
* is <code>null</code>, <code>true</code> or <code>false</code>, respectively.
* @since 4.1
*/
public static @NonNull Tristate fromNullableBoolean(Boolean val) {
public static @NonNull Tristate of(Boolean val) {
return val == null ? UNDEFINED : val ? TRUE : FALSE;
}

Some files were not shown because too many files have changed in this diff Show More