Allow data query order to be specified via the API

This commit is contained in:
Luck committed 2019-08-26 14:04:49 +01:00
1 parent bafada4f17
commit 4667ffc681
31 files changed
+345 -280

No files matched your search

@@ -28,8 +28,10 @@ package me.lucko.luckperms.api.context;
/**
* Some default context keys used by the plugin.
*/
public enum DefaultContextKeys {
;
public final class DefaultContextKeys {
private DefaultContextKeys() {
throw new AssertionError();
}
/**
* The context key used to denote the subjects server.
@@ -57,34 +57,64 @@ import java.util.function.Predicate;
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.
* Represents a way to identify distinct {@link PermissionHolder}s.
*/
@NonNull String getObjectName();
interface Identifier {
/**
* The {@link #getType() type} of {@link User} permission holders.
*/
String USER_TYPE = "user";
/**
* The {@link #getType() type} of {@link Group} permission holders.
*/
String GROUP_TYPE = "group";
/**
* Gets the {@link PermissionHolder}s 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 getName();
/**
* Gets the type of the {@link PermissionHolder}.
*
* @return the type
*/
@NonNull String getType();
}
/**
* Gets the identifier of the holder.
*
* @return the identifier
*/
@NonNull Identifier getIdentifier();
/**
* 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>
* {@link Identifier#getName()} 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>
* before falling back to {@link Identifier#getName()}.</p>
*
* <p>For {@link Group}s, this method will attempt to return the groups display name, before
* falling back to {@link #getObjectName()}.</p>
* falling back to {@link Identifier#getName()}.</p>
*
* @return a friendly identifier for this holder
*/
@@ -28,7 +28,6 @@ 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;
@@ -188,21 +187,21 @@ public interface Node {
* Gets the metadata corresponding to the given <code>key</code>, if present.
*
* @param key the key
* @param <T> the {@link NodeMetadata} type
* @param <T> the metadata type
* @return the data, if present
*/
<T extends NodeMetadata> Optional<T> getMetadata(NodeMetadataKey<T> key);
<T> 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
* @param <T> the metadata type
* @return the data
* @throws IllegalStateException if data isn't present
*/
default <T extends NodeMetadata> T metadata(NodeMetadataKey<T> key) throws IllegalStateException {
default <T> T metadata(NodeMetadataKey<T> key) throws IllegalStateException {
return getMetadata(key).orElseThrow(() -> new IllegalStateException("Node '" + getKey() + "' does not have '" + key.name() + "' attached."));
}
@@ -26,7 +26,6 @@
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;
@@ -138,7 +137,7 @@ public interface NodeBuilder<N extends ScopedNode<N, B>, B extends NodeBuilder<N
* @param <T> the metadata type
* @return the builder
*/
@NonNull <T extends NodeMetadata> B withMetadata(@NonNull NodeMetadataKey<T> key, @Nullable T metadata);
@NonNull <T> B withMetadata(@NonNull NodeMetadataKey<T> key, @Nullable T metadata);
/**
* Creates a {@link Node} instance from the builder.
@@ -30,7 +30,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Objects;
/**
* Represents a key for a specific type of {@link NodeMetadata}.
* Represents a key for a specific type of node metadata.
*
* <p>Metadata keys are compared using reference equality, the
* {@link #equals(Object)} method should not be implemented.</p>
@@ -43,7 +43,7 @@ import java.util.Objects;
*
* @param <T> the metadata type
*/
public interface NodeMetadataKey<T extends NodeMetadata> {
public interface NodeMetadataKey<T> {
/**
* Creates a new {@link NodeMetadataKey} for the given name and type.
@@ -55,7 +55,7 @@ public interface NodeMetadataKey<T extends NodeMetadata> {
* @param <T> the type parameter
* @return the key
*/
static <T extends NodeMetadata> @NonNull NodeMetadataKey<T> of(@NonNull String name, @NonNull Class<T> type) {
static <T> @NonNull NodeMetadataKey<T> of(@NonNull String name, @NonNull Class<T> type) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(type, "type");
return new SimpleNodeMetadataKey<>(name, type);
@@ -27,7 +27,7 @@ package me.lucko.luckperms.api.node.metadata;
import org.checkerframework.checker.nullness.qual.NonNull;
final class SimpleNodeMetadataKey<T extends NodeMetadata> implements NodeMetadataKey<T> {
final class SimpleNodeMetadataKey<T> implements NodeMetadataKey<T> {
private final String name;
private final Class<T> type;
@@ -27,15 +27,14 @@ package me.lucko.luckperms.api.node.metadata.types;
import me.lucko.luckperms.api.model.PermissionHolder;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.metadata.NodeMetadata;
import me.lucko.luckperms.api.node.metadata.NodeMetadataKey;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* {@link NodeMetadata} indicating where a node was inherited from.
* Node metadata indicating where a node was inherited from.
*/
public interface InheritanceOriginMetadata extends NodeMetadata {
public interface InheritanceOriginMetadata {
/**
* The {@link NodeMetadataKey} for {@link InheritanceOriginMetadata}.
@@ -45,10 +44,10 @@ public interface InheritanceOriginMetadata extends NodeMetadata {
/**
* Gets the location where the {@link Node} is inherited from.
*
* <p>The resultant string is the {@link PermissionHolder#getObjectName() object name} of the
* <p>The resultant string is the {@link PermissionHolder.Identifier#getName() object name} of the
* permission holder the node was inherited from.</p>
*
* <p>If the node was not inherited, the {@link PermissionHolder#getObjectName() object name}
* <p>If the node was not inherited, the {@link PermissionHolder.Identifier#getName() object name}
* of the permission holder itself (the one that defined the node) will be returned.</p>
*
* @return where the node was inherited from.
@@ -32,8 +32,10 @@ import java.util.EnumSet;
/**
* Some default {@link QueryOptions} instances.
*/
enum DefaultQueryOptions {
;
final class DefaultQueryOptions {
private DefaultQueryOptions() {
throw new AssertionError();
}
private static final EnumSet<Flag> DEFAULT_FLAGS = EnumSet.allOf(Flag.class);
@@ -0,0 +1,121 @@
/*
* 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.query.dataorder;
import me.lucko.luckperms.api.model.DataType;
import me.lucko.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
/**
* Represents the order in which to query different {@link DataType}s.
*
* <p>The {@link DataQueryOrder} enum simply represents some default
* implementations of the {@link Comparator} required by {@link QueryOptions}
* and the {@link #queryInOrder(Comparator, Consumer)} or
* {@link #order(Comparator)} methods.</p>
*
* <p>Users are free to implement their own comparator. However, be aware that
* it is possible that more {@link DataType}s may be added in the future.
* Ideally the {@link Comparator} implementations should be able to handle these
* smoothly.</p>
*/
public enum DataQueryOrder implements Comparator<DataType> {
/**
* A data query order indicating that {@link DataType#TRANSIENT} should be queried first.
*/
TRANSIENT_FIRST {
@Override
public int compare(DataType o1, DataType o2) {
if (o1 == o2) {
return 0;
}
return Boolean.compare(
o1 == DataType.TRANSIENT,
o2 == DataType.TRANSIENT
);
}
},
/**
* A data query order indicating that {@link DataType#TRANSIENT} should be queried last.
*/
TRANSIENT_LAST {
@Override
public int compare(DataType o1, DataType o2) {
if (o1 == o2) {
return 0;
}
return -Boolean.compare(
o1 == DataType.TRANSIENT,
o2 == DataType.TRANSIENT
);
}
};
private static final List<DataType> TRANSIENT_FIRST_LIST = Collections.unmodifiableList(Arrays.asList(DataType.TRANSIENT, DataType.NORMAL));
private static final List<DataType> TRANSIENT_LAST_LIST = Collections.unmodifiableList(Arrays.asList(DataType.NORMAL, DataType.TRANSIENT));
/**
* Gets a {@link List} of all {@link DataType}s, in the order defined by
* the {@code comparator}.
*
* @param comparator the comparator
* @return the ordered data types
*/
public static List<DataType> order(@NonNull Comparator<? super DataType> comparator) {
int compare = comparator.compare(DataType.TRANSIENT, DataType.NORMAL);
if (compare > 0) {
// transient first
return TRANSIENT_FIRST_LIST;
} else if (compare < 0) {
// transient last
return TRANSIENT_LAST_LIST;
} else {
// ??? - no defined order
throw new IllegalStateException("Comparator " + comparator + " does not define an order between DataType.NORMAL and DataType.TRANSIENT!");
}
}
/**
* Calls the {@code action} {@link Consumer} for each {@link DataType}, in
* the order defined by the {@code comparator}.
*
* @param comparator the comparator
* @param action the action
*/
public static void queryInOrder(@NonNull Comparator<? super DataType> comparator, @NonNull Consumer<? super DataType> action) {
order(comparator).forEach(action);
}
}
@@ -23,14 +23,34 @@
* SOFTWARE.
*/
package me.lucko.luckperms.api.node.metadata;
package me.lucko.luckperms.api.query.dataorder;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.model.DataType;
import me.lucko.luckperms.api.model.PermissionHolder;
import me.lucko.luckperms.api.query.OptionKey;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.Comparator;
/**
* Generic interface for an {@link Object} which can be attached to a
* {@link Node} as metadata.
* A function that generates a {@link DataQueryOrder} comparator for
* {@link PermissionHolder}s as required during inheritance.
*/
public interface NodeMetadata {
public interface DataQueryOrderFunction {
/**
* The {@link OptionKey} for {@link DataQueryOrderFunction}.
*/
OptionKey<DataQueryOrderFunction> KEY = new OptionKey<DataQueryOrderFunction>(){};
/**
* Gets the {@link DataQueryOrder} comparator for the given
* {@link PermissionHolder.Identifier holder identifier}.
*
* @param holderIdentifier the holder identifier
* @return the comparator to use
*/
@NonNull Comparator<DataType> getOrderComparator(PermissionHolder.@NonNull Identifier holderIdentifier);
}