diff --git a/api/src/main/java/me/lucko/luckperms/api/ActionLogger.java b/api/src/main/java/me/lucko/luckperms/api/ActionLogger.java new file mode 100644 index 000000000..2fd0b239f --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/ActionLogger.java @@ -0,0 +1,100 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api; + +import java.util.concurrent.CompletableFuture; + +import javax.annotation.Nonnull; + +/** + * Represents the object responsible for handling action logging. + * + * @since 4.1 + */ +public interface ActionLogger { + + /** + * Returns a new {@link LogEntry.Builder} instance + * + * @return a new builder + */ + @Nonnull + LogEntry.Builder newEntryBuilder(); + + /** + * Gets a {@link Log} instance from the plugin storage. + * + *

Returns the same result as {@link Storage#getLog()}.

+ * + * @return a log instance + * @see Storage#getLog() + */ + @Nonnull + CompletableFuture getLog(); + + /** + * Submits a log entry to the plugin to be handled. + * + *

This method submits the log to the storage provider and broadcasts + * it.

+ * + *

It is therefore roughly equivalent to calling + * {@link #submitToStorage(LogEntry)} and {@link #broadcastAction(LogEntry)}, + * however, using this method is preferred to making the calls individually.

+ * + *

If you want to submit a log entry but don't know which method to pick, + * use this one.

+ * + * @param entry the entry to submit + * @return a future which will complete when the action is done + */ + @Nonnull + CompletableFuture submit(@Nonnull LogEntry entry); + + /** + * Submits a log entry to the plugins storage handler. + * + *

Performs the same action as {@link Storage#logAction(LogEntry)}.

+ * + * @param entry the entry to submit + * @return a future which will complete when the action is done + */ + @Nonnull + CompletableFuture submitToStorage(@Nonnull LogEntry entry); + + /** + * Submits a log entry to the plugins log broadcasting handler. + * + *

If enabled, this method will also dispatch the log entry via the + * plugins {@link MessagingService}.

+ * + * @param entry the entry to submit + * @return a future which will complete when the action is done + */ + @Nonnull + CompletableFuture broadcastAction(@Nonnull LogEntry entry); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/Contexts.java b/api/src/main/java/me/lucko/luckperms/api/Contexts.java index 287464ae8..b1cb7af30 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Contexts.java +++ b/api/src/main/java/me/lucko/luckperms/api/Contexts.java @@ -31,14 +31,16 @@ import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** - * Encapsulates the options and settings for a permission lookup. + * Encapsulates the options and settings for a permission or meta lookup. * *

This class is immutable.

* * @since 2.11 */ +@Immutable public class Contexts { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/DataMutateResult.java b/api/src/main/java/me/lucko/luckperms/api/DataMutateResult.java index e67105400..374939862 100644 --- a/api/src/main/java/me/lucko/luckperms/api/DataMutateResult.java +++ b/api/src/main/java/me/lucko/luckperms/api/DataMutateResult.java @@ -36,12 +36,12 @@ public enum DataMutateResult { SUCCESS(true), /** - * Indicates the mutation failed because the subject already has something + * Indicates the mutation failed because the subject of the action already has something */ ALREADY_HAS(false), /** - * Indicates the mutation failed because the subject lacks something + * Indicates the mutation failed because the subject of the action lacks something */ LACKS(false), diff --git a/api/src/main/java/me/lucko/luckperms/api/HeldPermission.java b/api/src/main/java/me/lucko/luckperms/api/HeldPermission.java index 589636a26..157f4baff 100644 --- a/api/src/main/java/me/lucko/luckperms/api/HeldPermission.java +++ b/api/src/main/java/me/lucko/luckperms/api/HeldPermission.java @@ -31,13 +31,15 @@ import java.util.Optional; import java.util.OptionalLong; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** - * A relationship between a PermissionHolder and a permission + * A relationship between a {@link PermissionHolder} and a permission. * * @param the identifier type of the holder * @since 2.17 */ +@Immutable public interface HeldPermission { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java b/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java index 8ec58956b..b6c3cab41 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java +++ b/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java @@ -26,12 +26,14 @@ package me.lucko.luckperms.api; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** * A node with a traceable origin * * @since 2.11 */ +@Immutable public interface LocalizedNode extends Node { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/Log.java b/api/src/main/java/me/lucko/luckperms/api/Log.java index 1bb0ce079..2ae3f8d90 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Log.java +++ b/api/src/main/java/me/lucko/luckperms/api/Log.java @@ -30,6 +30,7 @@ import java.util.SortedSet; import java.util.UUID; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** * Represents the internal LuckPerms log. @@ -41,6 +42,7 @@ import javax.annotation.Nonnull; * *

All methods are thread safe, and return immutable and thread safe collections.

*/ +@Immutable public interface Log { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/LogEntry.java b/api/src/main/java/me/lucko/luckperms/api/LogEntry.java index 1ac044ffb..ea53df674 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LogEntry.java +++ b/api/src/main/java/me/lucko/luckperms/api/LogEntry.java @@ -30,12 +30,14 @@ import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; /** * Represents a logged action. * - * @see LuckPermsApi#newLogEntryBuilder() for creating an instance + * @see ActionLogger#newEntryBuilder() for creating an instance */ +@Immutable public interface LogEntry extends Comparable { /** @@ -143,27 +145,81 @@ public interface LogEntry extends Comparable { */ interface Builder { + /** + * Sets the timestamp of the entry. + * + * @param timestamp the timestamp + * @return the builder + * @see LogEntry#getTimestamp() + */ @Nonnull Builder setTimestamp(long timestamp); + /** + * Sets the actor of the entry. + * + * @param actor the actor + * @return the builder + * @see LogEntry#getActor() + */ @Nonnull Builder setActor(@Nonnull UUID actor); + /** + * Sets the actor name of the entry. + * + * @param actorName the actor name + * @return the builder + * @see LogEntry#getActorName() + */ @Nonnull Builder setActorName(@Nonnull String actorName); + /** + * Sets the type of the entry. + * + * @param type the type + * @return the builder + * @see LogEntry#getType() + */ @Nonnull Builder setType(@Nonnull Type type); + /** + * Sets the acted object for the entry. + * + * @param acted the acted object + * @return the builder + * @see LogEntry#getActed() + */ @Nonnull Builder setActed(@Nullable UUID acted); + /** + * Sets the acted name for the entry. + * + * @param actedName the acted name + * @return the builder + * @see LogEntry#getActedName() + */ @Nonnull Builder setActedName(@Nonnull String actedName); + /** + * Sets the action of the entry. + * + * @param action the action + * @return the builder + * @see LogEntry#getAction() + */ @Nonnull Builder setAction(@Nonnull String action); + /** + * Creates a {@link LogEntry} instance from the builder. + * + * @return a new log entry instance + */ @Nonnull LogEntry build(); diff --git a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java index 1dd91b4ea..3d97be978 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java +++ b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java @@ -65,7 +65,14 @@ public interface LuckPermsApi { PlatformInfo getPlatformInfo(); /** - * Gets the user manager + * Gets the {@link UserManager}, responsible for managing + * {@link User} instances. + * + *

This manager can be used to retrieve instances of {@link User} by uuid + * or name, or query all loaded users.

+ * + *

The {@link #getStorage() storage} instance should be used to + * load/create/save users.

* * @return the user manager * @since 4.0 @@ -74,7 +81,14 @@ public interface LuckPermsApi { UserManager getUserManager(); /** - * Gets the group manager + * Gets the {@link GroupManager}, responsible for managing + * {@link Group} instances. + * + *

This manager can be used to retrieve instances of {@link Group} by + * name, or query all loaded groups.

+ * + *

The {@link #getStorage() storage} instance should be used to + * load/create/save/delete groups.

* * @return the group manager * @since 4.0 @@ -83,7 +97,14 @@ public interface LuckPermsApi { GroupManager getGroupManager(); /** - * Gets the track manager + * Gets the {@link TrackManager}, responsible for managing + * {@link Track} instances. + * + *

This manager can be used to retrieve instances of {@link Track} by + * name, or query all loaded tracks.

+ * + *

The {@link #getStorage() storage} instance should be used to + * load/create/save/delete tracks.

* * @return the track manager * @since 4.0 @@ -92,15 +113,23 @@ public interface LuckPermsApi { TrackManager getTrackManager(); /** - * Schedules an update task to run + * Schedules the execution of an update task, and returns an encapsulation + * of the task as a {@link CompletableFuture}. * + *

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.

+ * + * @return a future * @since 4.0 */ @Nonnull CompletableFuture runUpdateTask(); /** - * Gets the event bus, used for subscribing to events + * Gets the {@link EventBus}, used for subscribing to internal LuckPerms + * events. * * @return the event bus * @since 3.0 @@ -109,15 +138,18 @@ public interface LuckPermsApi { EventBus getEventBus(); /** - * Gets the configuration + * Gets a representation of the plugins configuration * - * @return a configuration instance + * @return the configuration */ @Nonnull LPConfiguration getConfiguration(); /** - * Gets the backend storage dao + * Gets an object representing the plugins primary {@link Storage} backend. + * + *

The instance propagates calls to the internal DAO (Data Access Object), + * and applies any changes to the storage provider.

* * @return a storage instance * @since 2.14 @@ -126,24 +158,47 @@ public interface LuckPermsApi { Storage getStorage(); /** - * Gets the messaging service + * Gets the {@link MessagingService}, if present. * - * @return an optional that may contain a messaging service instance. + *

The MessagingService is used to dispatch updates throughout a network + * of servers running the plugin.

+ * + *

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.

+ * + * @return the messaging service instance, if present. */ @Nonnull Optional getMessagingService(); /** - * Gets a {@link UuidCache} instance, providing read access to the LuckPerms - * internal uuid caching system + * Gets the {@link ActionLogger}. * - * @return a uuid cache instance + *

The action logger is responsible for saving and broadcasting defined + * actions occurring on the platform.

+ * + * @return the action logger + * @since 4.1 + */ + ActionLogger getActionLogger(); + + /** + * Gets a {@link UuidCache}. + * + *

The uuid cache provides read access to the internal LuckPerms uuid + * mapping system.

+ * + * @return the uuid cache */ @Nonnull UuidCache getUuidCache(); /** - * Gets the context manager + * Gets the {@link ContextManager}. + * + *

The context manager manages {@link ContextCalculator}s, and calculates + * applicable contexts for a given type.

* * @return the context manager * @since 4.0 @@ -151,7 +206,9 @@ public interface LuckPermsApi { ContextManager getContextManager(); /** - * Gets the node factory + * Gets the {@link NodeFactory}. + * + *

The node factory provides methods for building {@link Node} instances.

* * @return the node factory */ @@ -159,7 +216,11 @@ public interface LuckPermsApi { NodeFactory getNodeFactory(); /** - * Gets the MetaStackFactory + * Gets the {@link MetaStackFactory}. + * + *

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.

* * @return the meta stack factory * @since 3.2 @@ -167,7 +228,18 @@ public interface LuckPermsApi { @Nonnull MetaStackFactory getMetaStackFactory(); - // convenience methods + + + + /* + * 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 @@ -350,7 +422,9 @@ public interface LuckPermsApi { * @since 4.0 */ @Nonnull - LogEntry.Builder newLogEntryBuilder(); + default LogEntry.Builder newLogEntryBuilder() { + return getActionLogger().newEntryBuilder(); + } /** * Returns a permission builder instance diff --git a/api/src/main/java/me/lucko/luckperms/api/Node.java b/api/src/main/java/me/lucko/luckperms/api/Node.java index a99c35183..38af3a2b6 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Node.java +++ b/api/src/main/java/me/lucko/luckperms/api/Node.java @@ -35,6 +35,7 @@ import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; /** * Represents a permission node. @@ -45,6 +46,7 @@ import javax.annotation.Nullable; * * @since 2.6 */ +@Immutable public interface Node extends Map.Entry { /** @@ -356,7 +358,7 @@ public interface Node extends Map.Entry { interface Builder { /** - * Sets the value of negated for the node + * Sets the value of negated for the node. * * @param negated the value * @return the builder @@ -366,7 +368,7 @@ public interface Node extends Map.Entry { Builder setNegated(boolean negated); /** - * Sets the value of the node + * Sets the value of the node. * * @param value the value * @return the builder @@ -376,7 +378,7 @@ public interface Node extends Map.Entry { Builder setValue(boolean value); /** - * Sets the override property for the node + * Sets the override property for the node. * *

Warning: this value does not persist, and disappears when the holder is re-loaded. * It is therefore only useful for transient nodes.

@@ -389,7 +391,7 @@ public interface Node extends Map.Entry { Builder setOverride(boolean override); /** - * Sets the nodes expiry as a unix timestamp in seconds + * Sets the nodes expiry as a unix timestamp in seconds. * * @param expireAt the expiry time * @return the builder @@ -399,7 +401,7 @@ public interface Node extends Map.Entry { Builder setExpiry(long expireAt); /** - * Sets the world value for the node + * Sets the world value for the node. * * @param world the world value * @return the builder @@ -409,7 +411,7 @@ public interface Node extends Map.Entry { Builder setWorld(@Nullable String world); /** - * Sets the server value for the node + * Sets the server value for the node. * * @param server the world value * @return the builder @@ -419,7 +421,7 @@ public interface Node extends Map.Entry { Builder setServer(@Nullable String server); /** - * Appends an extra context onto the node + * Appends an extra context onto the node. * * @param key the context key * @param value the context value @@ -431,9 +433,10 @@ public interface Node extends Map.Entry { Builder withExtraContext(@Nonnull String key, @Nonnull String value); /** - * Appends extra contexts onto the node + * Appends extra contexts onto the node. * * @param map a map of contexts + * @return the builder * @see ContextSet * @see Node#getContexts() */ @@ -441,9 +444,10 @@ public interface Node extends Map.Entry { Builder withExtraContext(@Nonnull Map map); /** - * Appends extra contexts onto the node + * Appends extra contexts onto the node. * * @param context a set of contexts + * @return the builder * @see ContextSet * @see Node#getContexts() */ @@ -451,7 +455,7 @@ public interface Node extends Map.Entry { Builder withExtraContext(@Nonnull Set> context); /** - * Appends an extra context onto the node + * Appends an extra context onto the node. * * @param entry the context * @return the builder @@ -462,9 +466,10 @@ public interface Node extends Map.Entry { Builder withExtraContext(@Nonnull Map.Entry entry); /** - * Appends extra contexts onto the node + * Appends extra contexts onto the node. * * @param set a contextset + * @return the builder * @see ContextSet * @see Node#getContexts() */ @@ -472,7 +477,7 @@ public interface Node extends Map.Entry { Builder withExtraContext(@Nonnull ContextSet set); /** - * Creates a node instance from the builder + * Creates a {@link Node} instance from the builder. * * @return a new node instance */ diff --git a/api/src/main/java/me/lucko/luckperms/api/NodeFactory.java b/api/src/main/java/me/lucko/luckperms/api/NodeFactory.java index 1609538d2..e62554aba 100644 --- a/api/src/main/java/me/lucko/luckperms/api/NodeFactory.java +++ b/api/src/main/java/me/lucko/luckperms/api/NodeFactory.java @@ -92,6 +92,7 @@ public interface NodeFactory { /** * 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 diff --git a/api/src/main/java/me/lucko/luckperms/api/Storage.java b/api/src/main/java/me/lucko/luckperms/api/Storage.java index b4315bd2c..bede6fbcd 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Storage.java +++ b/api/src/main/java/me/lucko/luckperms/api/Storage.java @@ -88,8 +88,10 @@ public interface Storage { * @param entry the log entry to be saved * @return true if the operation completed successfully. * @throws NullPointerException if entry is null + * @deprecated in favour of {@link ActionLogger#submit(LogEntry)}. */ @Nonnull + @Deprecated CompletableFuture logAction(@Nonnull LogEntry entry); /** diff --git a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java index d637b276b..5314001c6 100644 --- a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java +++ b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java @@ -30,33 +30,40 @@ import java.util.UUID; import javax.annotation.Nonnull; /** - * A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs. + * A UUID cache for online users, between external Mojang UUIDs, and internal + * LuckPerms UUIDs. * *

A user's internal LuckPerms UUID is always the same as their Mojang one, * unless use-server-uuids is disabled.

* - *

When this setting is disabled, this cache becomes active, and allows you to convert - * between 'internal' and 'server provided' uuids.

+ *

When this setting is disabled, this cache becomes active, and allows you + * to convert between 'internal' and 'server provided' uuids.

* - *

This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.

+ *

This is only effective for online players. + * Use {@link Storage#getUUID(String)} for offline players.

*/ public interface UuidCache { /** * Gets a users "internal" LuckPerms UUID, from the one given by the server. * - *

When use-server-uuids is true, this returns the same UUID instance.

+ *

When use-server-uuids is true, this returns the same UUID + * instance.

* - * @param mojangUuid the UUID assigned by the server, through Player#getUniqueId or ProxiedPlayer#getUniqueId + * @param mojangUuid the UUID assigned by the server, through + * Player#getUniqueId or + * ProxiedPlayer#getUniqueId * @return the corresponding internal UUID */ @Nonnull UUID getUUID(@Nonnull UUID mojangUuid); /** - * Gets a users "external", server assigned unique id, from the internal one used within LuckPerms. + * Gets a users "external", server assigned unique id, from the internal + * one used within LuckPerms. * - * @param internalUuid the UUID used within LuckPerms, through User#getUuid + * @param internalUuid the UUID used within LuckPerms, through + * User#getUuid * @return the corresponding external UUID */ @Nonnull diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java b/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java index 3c81b50cf..255dc0f59 100644 --- a/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java +++ b/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java @@ -210,6 +210,7 @@ public interface CachedData { * * @param contexts the contexts to reload in. * @throws NullPointerException if contexts is null + * @return a future * @since 4.0 */ @Nonnull @@ -237,6 +238,7 @@ public interface CachedData { * * @param contexts the contexts to reload in. * @throws NullPointerException if contexts is null + * @return a future * @since 4.0 */ @Nonnull @@ -264,6 +266,7 @@ public interface CachedData { * * @param contexts the contexts to reload in. * @throws NullPointerException if contexts is null + * @return a future * @since 4.0 */ @Nonnull @@ -309,6 +312,7 @@ public interface CachedData { *

This method returns a Future so users can optionally choose to wait * until the recalculation has been performed.

* + * @return a future * @since 4.0 */ @Nonnull @@ -332,6 +336,7 @@ public interface CachedData { *

This method returns a Future so users can optionally choose to wait * until the recalculation has been performed.

* + * @return a future * @since 4.0 */ @Nonnull diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/CachedDataContainer.java b/api/src/main/java/me/lucko/luckperms/api/caching/CachedDataContainer.java new file mode 100644 index 000000000..7f22193d7 --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/caching/CachedDataContainer.java @@ -0,0 +1,47 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.caching; + +import me.lucko.luckperms.api.Contexts; + +import javax.annotation.Nonnull; + +/** + * Holds cached lookup data in a specific set of contexts. + * + * @since 4.1 + */ +public interface CachedDataContainer { + + /** + * Gets the contexts this container is holding data for. + * + * @return the contexts this container is caching + */ + @Nonnull + Contexts getContexts(); + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/MetaContexts.java b/api/src/main/java/me/lucko/luckperms/api/caching/MetaContexts.java index 946e98b46..1b53b4be7 100644 --- a/api/src/main/java/me/lucko/luckperms/api/caching/MetaContexts.java +++ b/api/src/main/java/me/lucko/luckperms/api/caching/MetaContexts.java @@ -31,15 +31,17 @@ import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** - * Represents the context for a meta lookup. + * Encapsulates the options and settings for a meta lookup. * - *

Consisting of a standard {@link Contexts} element, plus options to define how + *

Consists of a standard {@link Contexts} element, plus options to define how * the meta stack should be constructed.

* * @since 3.2 */ +@Immutable public final class MetaContexts { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/MetaData.java b/api/src/main/java/me/lucko/luckperms/api/caching/MetaData.java index 3918e5ef3..dbb46c605 100644 --- a/api/src/main/java/me/lucko/luckperms/api/caching/MetaData.java +++ b/api/src/main/java/me/lucko/luckperms/api/caching/MetaData.java @@ -36,11 +36,19 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * Holds cached Meta lookup data for a specific set of contexts + * Holds cached meta lookup data for a specific set of contexts. * * @since 2.13 */ -public interface MetaData { +public interface MetaData extends CachedDataContainer { + + /** + * Gets the contexts this container is holding data for. + * + * @return the contexts this container is caching + */ + @Nonnull + MetaContexts getMetaContexts(); /** * Gets an immutable copy of the meta this user has. diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/PermissionData.java b/api/src/main/java/me/lucko/luckperms/api/caching/PermissionData.java index 6ea53e600..45ac7d9a4 100644 --- a/api/src/main/java/me/lucko/luckperms/api/caching/PermissionData.java +++ b/api/src/main/java/me/lucko/luckperms/api/caching/PermissionData.java @@ -32,14 +32,14 @@ import java.util.Map; import javax.annotation.Nonnull; /** - * Holds cached Permission lookup data for a specific set of contexts + * Holds cached permission lookup data for a specific set of contexts. * * @since 2.13 */ -public interface PermissionData { +public interface PermissionData extends CachedDataContainer { /** - * Gets a permission value for the given permission node + * Gets a permission check result for the given permission node. * * @param permission the permission node * @return a tristate result diff --git a/api/src/main/java/me/lucko/luckperms/api/context/AbstractContextSet.java b/api/src/main/java/me/lucko/luckperms/api/context/AbstractContextSet.java index 11ea9e794..342e1a5c5 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/AbstractContextSet.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/AbstractContextSet.java @@ -25,10 +25,12 @@ package me.lucko.luckperms.api.context; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import java.util.Collection; +import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; @@ -39,6 +41,17 @@ abstract class AbstractContextSet implements ContextSet { protected abstract Multimap backing(); + @Nonnull + @Override + @Deprecated + public Map toMap() { + ImmutableMap.Builder m = ImmutableMap.builder(); + for (Map.Entry e : backing().entries()) { + m.put(e.getKey(), e.getValue()); + } + return m.build(); + } + @Override public boolean containsKey(@Nonnull String key) { return backing().containsKey(sanitizeKey(key)); diff --git a/api/src/main/java/me/lucko/luckperms/api/context/ContextManager.java b/api/src/main/java/me/lucko/luckperms/api/context/ContextManager.java index d498da52e..2ff0f1e4c 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/ContextManager.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/ContextManager.java @@ -40,9 +40,14 @@ import javax.annotation.Nonnull; * on specific server implementations. In all cases, the "player" or "subject" type for * the platform must be used. * - * Specifically, {@code org.bukkit.entity.Player}, - * {@code net.md_5.bungee.api.connection.ProxiedPlayer} and - * {@code org.spongepowered.api.service.permission.Subject}. + * Specifically: + * + *

+ *
    + *
  • {@code org.bukkit.entity.Player}
  • + *
  • {@code net.md_5.bungee.api.connection.ProxiedPlayer}
  • + *
  • {@code org.spongepowered.api.service.permission.Subject}
  • + *
* * @since 4.0 */ diff --git a/api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java b/api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java index ee91da426..caf088ab5 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java @@ -35,26 +35,38 @@ import java.util.Set; import javax.annotation.Nonnull; /** - * A set of context pairs. + * A set of contexts. * - *

You can think of ContextSets as a wrapped Multimap<String, String>. - * Each key can be mapped to multiple values.

+ *

Context in the most basic sense simply means the circumstances where + * something will apply.

* - *

Keys are automatically converted to lowercase when added, and are therefore - * case-insensitive. Values however are not.

+ *

A single "context" consists of a key and a value, both strings. The key + * represents the type of context, and the value represents the setting of the + * context key.

* - *

Implementations may be either mutable or immutable.

+ *

Contexts can be combined with each other to form so called + * "context sets" - simply a collection of context pairs.

+ * + *

Context keys are case-insensitive, and will be converted to + * {@link String#toLowerCase() lowercase} by all implementations. + * Values however are case-sensitive.

+ * + *

Context keys and values may not be null.

+ * + *

Two default ContextSet implementations are provided. + * {@link MutableContextSet} allows the addition and removal of context keys + * after construction, and {@link ImmutableContextSet} does not.

* * @since 2.13 */ public interface ContextSet { /** - * Creates an ImmutableContextSet from a context pair + * Creates an {@link ImmutableContextSet} from a context pair. * * @param key the key * @param value the value - * @return a new ImmutableContextSet containing one KV pair + * @return a new ImmutableContextSet containing one context pair * @throws NullPointerException if key or value is null */ @Nonnull @@ -63,7 +75,7 @@ public interface ContextSet { } /** - * Creates an ImmutableContextSet from two context pairs + * Creates an {@link ImmutableContextSet} from two context pairs. * * @param key1 the first key * @param value1 the first value @@ -79,7 +91,7 @@ public interface ContextSet { } /** - * Creates an ImmutableContextSet from an existing iterable of Map Entries + * 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 @@ -91,7 +103,7 @@ public interface ContextSet { } /** - * Creates an ImmutableContextSet from an existing map + * 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 @@ -103,7 +115,7 @@ public interface ContextSet { } /** - * Creates an ImmutableContextSet from an existing multimap + * 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 @@ -116,8 +128,9 @@ public interface ContextSet { } /** - * Creates an new ImmutableContextSet from an existing set. - * Only really useful for converting between mutable and immutable types. + * Creates an new {@link ImmutableContextSet} from an existing {@link Set}. + * + *

Only really useful for converting between mutable and immutable types.

* * @param contextSet the context set to copy from * @return a new ImmutableContextSet with the same content and the one provided @@ -129,9 +142,9 @@ public interface ContextSet { } /** - * Creates a new empty ImmutableContextSet. + * Returns an empty {@link ImmutableContextSet}. * - * @return a new ImmutableContextSet + * @return an empty ImmutableContextSet */ @Nonnull static ImmutableContextSet empty() { @@ -139,22 +152,30 @@ public interface ContextSet { } /** - * Gets if this set is in an immutable form + * Gets if this {@link ContextSet} is immutable. + * + *

The state of immutable instances will never change.

* * @return true if the set is immutable */ boolean isImmutable(); /** - * If the set is mutable, this method will return an immutable copy. Otherwise just returns itself. + * Returns an immutable representation of this {@link ContextSet}. * - * @return an immutable ContextSet + *

If the set is already immutable, the same object will be returned. + * If the set is mutable, an immutable copy will be made.

+ * + * @return an immutable representation of this set */ @Nonnull ImmutableContextSet makeImmutable(); /** - * Creates a mutable copy of this set. + * Creates a mutable copy of this {@link ContextSet}. + * + *

A new copy is returned regardless of the + * {@link #isImmutable() mutability} of this set.

* * @return a mutable ContextSet * @since 2.16 @@ -163,7 +184,11 @@ public interface ContextSet { MutableContextSet mutableCopy(); /** - * Converts this ContextSet to an immutable {@link Set} of {@link Map.Entry}s. + * Returns a {@link Set} of {@link Map.Entry}s representing the current + * state of this {@link ContextSet}. + * + *

The returned set is immutable, and is a copy of the current set. + * (will not update live)

* * @return an immutable set */ @@ -171,10 +196,18 @@ public interface ContextSet { Set> toSet(); /** - * Converts this ContextSet to an immutable {@link Map} + * Returns a {@link Map} loosely representing the current state of + * this {@link ContextSet}. * - * IMPORTANT: Use of this method may result in data being lost. ContextSets can contain lots of different values for - * one key. + *

The returned map is immutable, and is a copy of the current set. + * (will not update live)

+ * + *

As a single context key can be mapped to multiple values, this method + * may not be a true representation of the set.

+ * + *

If you need a representation of the set in a Java collection instance, + * use {@link #toSet()} or {@link #toMultimap()} followed by + * {@link Multimap#asMap()}.

* * @return an immutable map * @deprecated because the resultant map may not contain all data in the ContextSet @@ -184,7 +217,11 @@ public interface ContextSet { Map toMap(); /** - * Converts this ContextSet to an immutable {@link Multimap} + * Returns a {@link Multimap} representing the current state of this + * {@link ContextSet}. + * + *

The returned multimap is immutable, and is a copy of the current set. + * (will not update live)

* * @return a multimap * @since 2.16 @@ -193,7 +230,8 @@ public interface ContextSet { Multimap toMultimap(); /** - * Check if the set contains at least one value for the given key. + * Returns if the {@link ContextSet} contains at least one value for the + * given key. * * @param key the key to check for * @return true if the set contains a value for the key @@ -202,9 +240,12 @@ public interface ContextSet { boolean containsKey(@Nonnull String key); /** - * Gets a set of all of the values mapped to the given key + * Returns a {@link Set} of the values mapped to the given key. * - * @param key the key to find values for + *

The returned set is immutable, and only represents the current state + * of the {@link ContextSet}. (will not update live)

+ * + * @param key the key to get values for * @return a set of values * @throws NullPointerException if the key is null */ @@ -212,7 +253,10 @@ public interface ContextSet { Set getValues(@Nonnull String key); /** - * Returns any value from this set matching the key, if present. + * Returns any value from this {@link ContextSet} matching the key, if present. + * + *

Note that context keys can be mapped to multiple values. + * Use {@link #getValues(String)} to retrieve all associated values.

* * @param key the key to find values for * @return an optional containing any match @@ -224,22 +268,38 @@ public interface ContextSet { } /** - * Check if thr set contains a given key mapped to a given value + * Returns if the {@link ContextSet} contains a given context pairing. + * + *

This lookup is case-sensitive on the value.

* * @param key the key to look for * @param value the value to look for (case sensitive) - * @return true if the set contains the KV pair + * @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); /** - * Check if thr set contains a given key mapped to a given value + * Returns if the {@link ContextSet} contains a given context pairing, + * ignoring the case of values. + * + *

This lookup is case-insensitive on the value.

+ * + * @param key the key to look for + * @param value the value to look for + * @return true if the set contains the context pair + * @throws NullPointerException if the key or value is null + */ + boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value); + + /** + * Returns if the {@link ContextSet} contains a given context pairing. + * + *

This lookup is case-sensitive on the value.

* * @param entry the entry to look for - * @return true if the set contains the KV pair + * @return true if the set contains the context pair * @throws NullPointerException if the key or value is null - * @since 3.4 */ default boolean has(@Nonnull Map.Entry entry) { Preconditions.checkNotNull(entry, "entry"); @@ -247,22 +307,14 @@ public interface ContextSet { } /** - * Same as {@link #has(String, String)}, except ignores the case of the value. + * Returns if the {@link ContextSet} contains a given context pairing, + * ignoring the case of values. * - * @param key the key to look for - * @param value the value to look for - * @return true if the set contains the KV pair - * @throws NullPointerException if the key or value is null - */ - boolean hasIgnoreCase(@Nonnull String key, @Nonnull String value); - - /** - * Same as {@link #has(Map.Entry)}, except ignores the case of the value. + *

This lookup is case-insensitive on the value.

* * @param entry the entry to look for - * @return true if the set contains the KV pair + * @return true if the set contains the context pair * @throws NullPointerException if the key or value is null - * @since 3.4 */ default boolean hasIgnoreCase(@Nonnull Map.Entry entry) { Preconditions.checkNotNull(entry, "entry"); @@ -270,21 +322,34 @@ public interface ContextSet { } /** - * Checks to see if all entries in this context set are also included in another set. + * Returns if this {@link ContextSet} is fully "satisfied" by another set. + * + *

For a context set to "satisfy" another, it must itself contain all of + * the context pairings in the other set.

+ * + *

Mathematically, this method returns true if this set is a subset of the other.

+ * + *

This check is case-sensitive. For a case-insensitive check, + * use {@link #isSatisfiedBy(ContextSet, boolean)}.

* * @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) { - return this == other || isSatisfiedBy(other, true); + return isSatisfiedBy(other, true); } /** - * Checks to see if all entries in this context set are also included in another set. + * Returns if this {@link ContextSet} is fully "satisfied" by another set. + * + *

For a context set to "satisfy" another, it must itself contain all of + * the context pairings in the other set.

+ * + *

Mathematically, this method returns true if this set is a subset of the other.

* * @param other the other set to check - * @param caseSensitive if the lookup should be case sensitive. see {@link #has(Map.Entry)} and {@link #hasIgnoreCase(Map.Entry)}. + * @param caseSensitive if the check should be case sensitive * @return true if all entries in this set are also in the other set * @since 3.4 */ @@ -305,31 +370,30 @@ public interface ContextSet { return false; } else { // neither are empty, we need to compare the individual entries - for (Map.Entry pair : toSet()) { + for (Map.Entry context : toSet()) { if (caseSensitive) { - if (!other.has(pair)) { + if (!other.has(context)) { return false; } } else { - if (!other.hasIgnoreCase(pair)) { + if (!other.hasIgnoreCase(context)) { return false; } } } - return true; } } /** - * Check if the set is empty + * Returns if the {@link ContextSet} is empty. * * @return true if the set is empty */ boolean isEmpty(); /** - * Gets the number of key-value context pairs in the set + * Gets the number of context pairs in the {@link ContextSet}. * * @return the size of the set */ diff --git a/api/src/main/java/me/lucko/luckperms/api/context/ImmutableContextSet.java b/api/src/main/java/me/lucko/luckperms/api/context/ImmutableContextSet.java index 8f6a4ea28..51f04c05c 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/ImmutableContextSet.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/ImmutableContextSet.java @@ -25,15 +25,14 @@ 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 java.util.Iterator; import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; import static com.google.common.base.Preconditions.checkNotNull; @@ -42,13 +41,15 @@ import static com.google.common.base.Preconditions.checkNotNull; * * @since 2.16 */ +@Immutable public final class ImmutableContextSet extends AbstractContextSet implements ContextSet { private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of()); /** - * Creates a builder + * Creates an {@link ImmutableContextSet.Builder}. * * @return a new ImmutableContextSet builder + * @since 4.1 */ @Nonnull public static Builder builder() { @@ -56,11 +57,11 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates an ImmutableContextSet from a context pair + * Creates an {@link ImmutableContextSet} from a context pair. * * @param key the key * @param value the value - * @return a new ImmutableContextSet containing one KV pair + * @return a new ImmutableContextSet containing one context pair * @throws NullPointerException if key or value is null */ @Nonnull @@ -69,7 +70,7 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates an ImmutableContextSet from two context pairs + * Creates an {@link ImmutableContextSet} from two context pairs. * * @param key1 the first key * @param value1 the first value @@ -90,7 +91,7 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates an ImmutableContextSet from an existing iterable of Map Entries + * 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 @@ -99,22 +100,15 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con @Nonnull public static ImmutableContextSet fromEntries(@Nonnull Iterable> iterable) { checkNotNull(iterable, "iterable"); - - Iterator> iterator = iterable.iterator(); - if (!iterator.hasNext()) { - return empty(); + ImmutableContextSet.Builder builder = builder(); + for (Map.Entry entry : iterable) { + builder.add(entry); } - - ImmutableSetMultimap.Builder b = ImmutableSetMultimap.builder(); - while (iterator.hasNext()) { - Map.Entry e = checkNotNull(iterator.next(), "entry"); - b.put(sanitizeKey(e.getKey()), sanitizeValue(e.getValue())); - } - return new ImmutableContextSet(b.build()); + return builder.build(); } /** - * Creates an ImmutableContextSet from an existing map + * 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 @@ -126,11 +120,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates an ImmutableContextSet from an existing multimap + * 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 */ @Nonnull public static ImmutableContextSet fromMultimap(@Nonnull Multimap multimap) { @@ -138,8 +133,9 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates a new ImmutableContextSet from an existing set. - * Only really useful for converting between mutable and immutable types. + * Creates an new {@link ImmutableContextSet} from an existing {@link Set}. + * + *

Only really useful for converting between mutable and immutable types.

* * @param contextSet the context set to copy from * @return a new ImmutableContextSet with the same content and the one provided @@ -151,9 +147,9 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Creates an new empty ContextSet. + * Returns an empty {@link ImmutableContextSet}. * - * @return a new ContextSet + * @return an empty ImmutableContextSet */ @Nonnull public static ImmutableContextSet empty() { @@ -197,18 +193,6 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con return map.entries(); } - @Nonnull - @Override - @Deprecated - public Map toMap() { - ImmutableMap.Builder m = ImmutableMap.builder(); - for (Map.Entry e : map.entries()) { - m.put(e.getKey(), e.getValue()); - } - - return m.build(); - } - @Nonnull @Override public Multimap toMultimap() { @@ -226,7 +210,9 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * A builder for {@link ImmutableContextSet} + * A builder for {@link ImmutableContextSet}. + * + * @since 4.1 */ public static final class Builder { private ImmutableSetMultimap.Builder builder; @@ -242,24 +228,32 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con return builder; } + private void put(String key, String value) { + builder().put(key, value); + } + /** - * Adds a new key value pair to the set + * Adds a context to the set. * * @param key the key to add * @param value the value to add + * @return the builder * @throws NullPointerException if the key or value is null + * @see MutableContextSet#add(String, String) */ @Nonnull public Builder add(@Nonnull String key, @Nonnull String value) { - builder().put(sanitizeKey(key), sanitizeValue(value)); + put(sanitizeKey(key), sanitizeValue(value)); return this; } /** - * Adds a new key value pair to the set + * Adds a context to the set. * * @param entry the entry to add + * @return the builder * @throws NullPointerException if the entry is null + * @see MutableContextSet#add(Map.Entry) */ @Nonnull public Builder add(@Nonnull Map.Entry entry) { @@ -269,10 +263,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Adds an iterable containing contexts to the set + * Adds the contexts contained in the given {@link Iterable} to the set. * * @param iterable an iterable of key value context pairs + * @return the builder * @throws NullPointerException if iterable is null + * @see MutableContextSet#addAll(Iterable) */ @Nonnull public Builder addAll(@Nonnull Iterable> iterable) { @@ -283,10 +279,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Adds the entry set of a map to the set + * 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) */ @Nonnull public Builder addAll(@Nonnull Map map) { @@ -295,11 +293,13 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Adds the entries of a multimap to the set + * 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) */ @Nonnull public Builder addAll(@Nonnull Multimap multimap) { @@ -308,10 +308,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con } /** - * Adds of of the values in another ContextSet to this set + * Adds of of the contexts in another {@link ContextSet} to the set. * * @param contextSet the set to add from + * @return the builder * @throws NullPointerException if the contextSet is null + * @see MutableContextSet#addAll(ContextSet) */ @Nonnull public Builder addAll(@Nonnull ContextSet contextSet) { @@ -327,6 +329,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con return this; } + /** + * Creates a {@link ImmutableContextSet} from the values previously + * added to the builder. + * + * @return an {@link ImmutableContextSet} from the builder + */ @Nonnull public ImmutableContextSet build() { if (builder == null) { @@ -335,6 +343,5 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con return new ImmutableContextSet(builder.build()); } } - } } diff --git a/api/src/main/java/me/lucko/luckperms/api/context/MutableContextSet.java b/api/src/main/java/me/lucko/luckperms/api/context/MutableContextSet.java index a82bf8155..b3f7d94f3 100644 --- a/api/src/main/java/me/lucko/luckperms/api/context/MutableContextSet.java +++ b/api/src/main/java/me/lucko/luckperms/api/context/MutableContextSet.java @@ -27,7 +27,6 @@ package me.lucko.luckperms.api.context; import com.google.common.base.Preconditions; 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; @@ -50,11 +49,11 @@ import static com.google.common.base.Preconditions.checkNotNull; public final class MutableContextSet extends AbstractContextSet implements ContextSet { /** - * Make a singleton MutableContextSet from a context pair + * Creates a {@link MutableContextSet} from a context pair. * * @param key the key * @param value the value - * @return a new MutableContextSet containing one KV pair + * @return a new MutableContextSet containing one context pair * @throws NullPointerException if key or value is null */ @Nonnull @@ -67,7 +66,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Makes a MutableContextSet from two context pairs + * Creates a {@link MutableContextSet} from two context pairs. * * @param key1 the first key * @param value1 the first value @@ -90,7 +89,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Creates a MutableContextSet from an existing iterable of Map Entries + * Creates a {@link MutableContextSet} from an existing {@link Iterable} of {@link Map.Entry}s. * * @param iterable the iterable to copy from * @return a new MutableContextSet representing the pairs in the iterable @@ -105,7 +104,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Creates a MutableContextSet from an existing map + * 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 @@ -120,11 +119,12 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Creates a MutableContextSet from an existing multimap + * 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 */ @Nonnull public static MutableContextSet fromMultimap(@Nonnull Multimap multimap) { @@ -135,8 +135,9 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Creates a new MutableContextSet from an existing set. - * Only really useful for converting between mutable and immutable types. + * Creates a new {@link MutableContextSet} from an existing {@link Set}. + * + *

Only really useful for converting between mutable and immutable types.

* * @param contextSet the context set to copy from * @return a new MutableContextSet with the same content and the one provided @@ -183,6 +184,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte @Nonnull @Override public ImmutableContextSet makeImmutable() { + // if the map is empty, don't create a new instance if (map.isEmpty()) { return ImmutableContextSet.empty(); } @@ -201,17 +203,6 @@ public final class MutableContextSet extends AbstractContextSet implements Conte return ImmutableSet.copyOf(map.entries()); } - @Nonnull - @Override - @Deprecated - public Map toMap() { - ImmutableMap.Builder m = ImmutableMap.builder(); - for (Map.Entry e : map.entries()) { - m.put(e.getKey(), e.getValue()); - } - return m.build(); - } - @Nonnull @Override public Multimap toMultimap() { @@ -219,7 +210,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds a new key value pair to the set + * Adds a context to this set. * * @param key the key to add * @param value the value to add @@ -230,7 +221,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds a new key value pair to the set + * Adds a context to this set. * * @param entry the entry to add * @throws NullPointerException if the entry is null @@ -241,7 +232,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds an iterable containing contexts to the set + * Adds the contexts contained in the given {@link Iterable} to this set. * * @param iterable an iterable of key value context pairs * @throws NullPointerException if iterable is null @@ -253,7 +244,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds the entry set of a map to the set + * 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 @@ -263,7 +254,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds the entries of a multimap to the set + * 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 @@ -274,7 +265,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Adds of of the values in another ContextSet to this set + * 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 @@ -290,7 +281,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Remove a key value pair from this set + * Removes a context from this set. * * @param key the key to remove * @param value the value to remove (case sensitive) @@ -301,7 +292,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Same as {@link #remove(String, String)}, except ignores the case of the value + * Removes a context from this set. (case-insensitive) * * @param key the key to remove * @param value the value to remove @@ -316,7 +307,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Removes all pairs with the given key + * Removes all contexts from this set with the given key. * * @param key the key to remove * @throws NullPointerException if the key is null @@ -326,7 +317,7 @@ public final class MutableContextSet extends AbstractContextSet implements Conte } /** - * Clears the set + * Removes all contexts from the set. */ public void clear() { map.clear(); diff --git a/api/src/main/java/me/lucko/luckperms/api/event/Cancellable.java b/api/src/main/java/me/lucko/luckperms/api/event/Cancellable.java index 4df77003a..1d656bc05 100644 --- a/api/src/main/java/me/lucko/luckperms/api/event/Cancellable.java +++ b/api/src/main/java/me/lucko/luckperms/api/event/Cancellable.java @@ -42,4 +42,35 @@ public interface Cancellable { @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(); + } + + /** + * Returns true if the event is not currently cancelled. + * + * @return if the event is not cancelled + * @since 4.1 + */ + default boolean isNotCancelled() { + return !isCancelled(); + } + + /** + * Sets the cancellation state of the event. + * + * @param cancelled the new state + * @return the previous state + * @since 4.1 + */ + default boolean setCancelled(boolean cancelled) { + return getCancellationState().getAndSet(cancelled); + } + } diff --git a/api/src/main/java/me/lucko/luckperms/api/event/EventBus.java b/api/src/main/java/me/lucko/luckperms/api/event/EventBus.java index 5345113f4..a0b5470da 100644 --- a/api/src/main/java/me/lucko/luckperms/api/event/EventBus.java +++ b/api/src/main/java/me/lucko/luckperms/api/event/EventBus.java @@ -31,14 +31,16 @@ import java.util.function.Consumer; import javax.annotation.Nonnull; /** - * The LuckPerms event bus. Used for subscribing (or registering listeners) to events. + * The internal LuckPerms event bus. + * + *

LuckPerms events are posted to any listeners registered with the bus.

* * @since 3.0 */ public interface EventBus { /** - * Subscribe to an event + * Subscribes to an event. * * @param eventClass the event class * @param handler the event handler @@ -49,7 +51,7 @@ public interface EventBus { EventHandler subscribe(@Nonnull Class eventClass, @Nonnull Consumer handler); /** - * Gets a set of all registered handlers for a given event + * Gets a set of all registered handlers for a given event. * * @param eventClass the event to find handlers for * @param the event class diff --git a/api/src/main/java/me/lucko/luckperms/api/event/EventHandler.java b/api/src/main/java/me/lucko/luckperms/api/event/EventHandler.java index f20857be9..11daf89c8 100644 --- a/api/src/main/java/me/lucko/luckperms/api/event/EventHandler.java +++ b/api/src/main/java/me/lucko/luckperms/api/event/EventHandler.java @@ -34,7 +34,7 @@ import javax.annotation.Nonnull; * * @param the event class */ -public interface EventHandler { +public interface EventHandler extends AutoCloseable { /** * Gets the class this handler is listening to @@ -73,4 +73,8 @@ public interface EventHandler { */ int getCallCount(); + @Override + default void close() { + unregister(); + } } diff --git a/api/src/main/java/me/lucko/luckperms/api/event/LuckPermsEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/LuckPermsEvent.java index 56050c5e8..2bff5ae09 100644 --- a/api/src/main/java/me/lucko/luckperms/api/event/LuckPermsEvent.java +++ b/api/src/main/java/me/lucko/luckperms/api/event/LuckPermsEvent.java @@ -30,7 +30,7 @@ import me.lucko.luckperms.api.LuckPermsApi; import javax.annotation.Nonnull; /** - * The base event interface + * A superinterface for all LuckPerms events. * * @since 3.0 */ diff --git a/api/src/main/java/me/lucko/luckperms/api/event/log/LogBroadcastEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/log/LogBroadcastEvent.java index 00e8d51bf..8a4f0e6d7 100644 --- a/api/src/main/java/me/lucko/luckperms/api/event/log/LogBroadcastEvent.java +++ b/api/src/main/java/me/lucko/luckperms/api/event/log/LogBroadcastEvent.java @@ -61,12 +61,17 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable { enum Origin { /** - * Represents a log entry which originated from the current server instance + * Marks a log entry which originated from the current server instance */ LOCAL, /** - * Represents a log entry which was sent to this server via the messaging service + * Marks a log entry which originated from an API call on the current server instance + */ + LOCAL_API, + + /** + * Marks a log entry which was sent to this server via the messaging service */ REMOTE } diff --git a/api/src/main/java/me/lucko/luckperms/api/event/log/LogNotifyEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/log/LogNotifyEvent.java new file mode 100644 index 000000000..20a7d2726 --- /dev/null +++ b/api/src/main/java/me/lucko/luckperms/api/event/log/LogNotifyEvent.java @@ -0,0 +1,113 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.event.log; + +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.event.Cancellable; +import me.lucko.luckperms.api.event.LuckPermsEvent; + +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Nonnull; + +/** + * Called when a log entry is about to be sent to specific notifiable object on + * the platform. + * + *

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).

+ * + * @since 4.1 + */ +public interface LogNotifyEvent extends LuckPermsEvent, Cancellable { + + /** + * Gets the log entry to be sent + * + * @return the log entry to be sent + */ + @Nonnull + LogEntry getEntry(); + + /** + * Gets where the log entry originated from. + * + * @return the origin of the log + */ + @Nonnull + LogBroadcastEvent.Origin getOrigin(); + + /** + * Gets the object to be notified. + * + * @return the object to notify + */ + @Nonnull + Notifiable getNotifiable(); + + /** + * Represents an object which could be notified as a result of a + * {@link LogNotifyEvent}. + */ + interface Notifiable { + + /** + * Gets a {@link UUID} for the object, if it has one. + * + *

For Players, this method returns their unique id.

+ * + * @return the uuid of the object, if available + */ + @Nonnull + Optional getUuid(); + + /** + * Gets the name of the object + * + * @return the name + */ + @Nonnull + String getName(); + + /** + * Gets if the object is a console + * + * @return if the object is a console + */ + boolean isConsole(); + + /** + * Gets if the object is a player + * + * @return if the object is a player + */ + boolean isPlayer(); + + } + +} diff --git a/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackDefinition.java b/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackDefinition.java index 5baea00f1..4d6b7f097 100644 --- a/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackDefinition.java +++ b/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackDefinition.java @@ -28,6 +28,7 @@ package me.lucko.luckperms.api.metastacking; import java.util.List; import javax.annotation.Nonnull; +import javax.annotation.concurrent.Immutable; /** * Represents a meta stack model, consisting of a chain of elements, separated by spacers. @@ -40,6 +41,7 @@ import javax.annotation.Nonnull; * * @since 2.3 */ +@Immutable public interface MetaStackDefinition { /** diff --git a/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackElement.java b/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackElement.java index 048b4a611..daddc2695 100644 --- a/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackElement.java +++ b/api/src/main/java/me/lucko/luckperms/api/metastacking/MetaStackElement.java @@ -33,12 +33,16 @@ import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import javax.annotation.concurrent.Immutable; /** * Represents an element within a {@link MetaStackDefinition}. * + *

The element itself does not contain any mutable state.

+ * * @since 3.2 */ +@Immutable public interface MetaStackElement { /** diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java index ed78f756a..fdec37a1f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java +++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java @@ -42,6 +42,21 @@ import java.util.Optional; public class LogDispatcher { private final LuckPermsPlugin plugin; + private void broadcast(ExtendedLogEntry entry, LogBroadcastEvent.Origin origin, Sender sender) { + plugin.getOnlineSenders() + .filter(CommandPermission.LOG_NOTIFY::isAuthorized) + .filter(s -> { + boolean shouldCancel = LogNotify.isIgnoring(plugin, s.getUuid()) || (sender != null && s.getUuid().equals(sender.getUuid())); + return !plugin.getApiProvider().getEventFactory().handleLogNotify(shouldCancel, entry, origin, s); + }) + .forEach(s -> Message.LOG.send(s, + entry.getActorFriendlyString(), + Character.toString(entry.getType().getCode()), + entry.getActedFriendlyString(), + entry.getAction() + )); + } + public void dispatch(ExtendedLogEntry entry, Sender sender) { // set the event to cancelled if the sender is import if (!plugin.getApiProvider().getEventFactory().handleLogPublish(sender.isImport(), entry)) { @@ -58,35 +73,37 @@ public class LogDispatcher { messagingService.get().pushLog(entry); } - if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.LOCAL)) { - plugin.getOnlineSenders() - .filter(CommandPermission.LOG_NOTIFY::isAuthorized) - .filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid())) - .filter(s -> !s.getUuid().equals(sender.getUuid())) - .forEach(s -> Message.LOG.send(s, - entry.getActorFriendlyString(), - Character.toString(entry.getType().getCode()), - entry.getActedFriendlyString(), - entry.getAction() - )); + boolean shouldCancel = !plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY); + if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(shouldCancel, entry, LogBroadcastEvent.Origin.LOCAL)) { + broadcast(entry, LogBroadcastEvent.Origin.LOCAL, sender); + } + } + + public void dispatchFromApi(ExtendedLogEntry entry) { + if (!plugin.getApiProvider().getEventFactory().handleLogPublish(false, entry)) { + try { + plugin.getStorage().logAction(entry).get(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + broadcastFromApi(entry); + } + + public void broadcastFromApi(ExtendedLogEntry entry) { + plugin.getMessagingService().ifPresent(extendedMessagingService -> extendedMessagingService.pushLog(entry)); + + boolean shouldCancel = !plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY); + if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(shouldCancel, entry, LogBroadcastEvent.Origin.LOCAL_API)) { + broadcast(entry, LogBroadcastEvent.Origin.LOCAL_API, null); } } public void dispatchFromRemote(ExtendedLogEntry entry) { - if (!plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES)) { - return; - } - - if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.REMOTE)) { - plugin.getOnlineSenders() - .filter(CommandPermission.LOG_NOTIFY::isAuthorized) - .filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid())) - .forEach(s -> Message.LOG.send(s, - entry.getActorFriendlyString(), - Character.toString(entry.getType().getCode()), - entry.getActedFriendlyString(), - entry.getAction() - )); + boolean shouldCancel = !plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES) || !plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY); + if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(shouldCancel, entry, LogBroadcastEvent.Origin.REMOTE)) { + broadcast(entry, LogBroadcastEvent.Origin.LOCAL_API, null); } } } diff --git a/common/src/main/java/me/lucko/luckperms/common/api/ApiProvider.java b/common/src/main/java/me/lucko/luckperms/common/api/ApiProvider.java index bcd77d88e..76d06926f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/ApiProvider.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/ApiProvider.java @@ -28,8 +28,8 @@ package me.lucko.luckperms.common.api; import lombok.AccessLevel; import lombok.Getter; +import me.lucko.luckperms.api.ActionLogger; import me.lucko.luckperms.api.LPConfiguration; -import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.api.LuckPermsApi; import me.lucko.luckperms.api.MessagingService; import me.lucko.luckperms.api.NodeFactory; @@ -42,11 +42,11 @@ import me.lucko.luckperms.api.manager.TrackManager; import me.lucko.luckperms.api.manager.UserManager; import me.lucko.luckperms.api.metastacking.MetaStackFactory; import me.lucko.luckperms.api.platform.PlatformInfo; -import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; import me.lucko.luckperms.common.api.delegates.manager.ApiContextManager; import me.lucko.luckperms.common.api.delegates.manager.ApiGroupManager; import me.lucko.luckperms.common.api.delegates.manager.ApiTrackManager; import me.lucko.luckperms.common.api.delegates.manager.ApiUserManager; +import me.lucko.luckperms.common.api.delegates.misc.ApiActionLogger; import me.lucko.luckperms.common.api.delegates.misc.ApiMetaStackFactory; import me.lucko.luckperms.common.api.delegates.misc.ApiNodeFactory; import me.lucko.luckperms.common.api.delegates.misc.ApiPlatformInfo; @@ -71,6 +71,7 @@ public class ApiProvider implements LuckPermsApi { private final GroupManager groupManager; private final TrackManager trackManager; private final LuckPermsEventBus eventBus; + private final ActionLogger actionLogger; private final ContextManager contextManager; private final MetaStackFactory metaStackFactory; private final EventFactory eventFactory; @@ -83,6 +84,7 @@ public class ApiProvider implements LuckPermsApi { this.groupManager = new ApiGroupManager(plugin.getGroupManager()); this.trackManager = new ApiTrackManager(plugin.getTrackManager()); this.eventBus = new LuckPermsEventBus(plugin); + this.actionLogger = new ApiActionLogger(plugin); this.contextManager = new ApiContextManager(plugin, plugin.getContextManager()); this.metaStackFactory = new ApiMetaStackFactory(plugin); this.eventFactory = new EventFactory(eventBus); @@ -137,6 +139,11 @@ public class ApiProvider implements LuckPermsApi { return plugin.getMessagingService().map(Function.identity()); } + @Override + public ActionLogger getActionLogger() { + return actionLogger; + } + @Override public UuidCache getUuidCache() { return plugin.getUuidCache().getDelegate(); @@ -157,8 +164,4 @@ public class ApiProvider implements LuckPermsApi { return metaStackFactory; } - @Override - public LogEntry.Builder newLogEntryBuilder() { - return ExtendedLogEntry.build(); - } } diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiActionLogger.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiActionLogger.java new file mode 100644 index 000000000..7e8d280aa --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/misc/ApiActionLogger.java @@ -0,0 +1,67 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.api.delegates.misc; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.ActionLogger; +import me.lucko.luckperms.api.Log; +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; +import me.lucko.luckperms.common.api.delegates.model.ApiLog; +import me.lucko.luckperms.common.plugin.LuckPermsPlugin; + +import java.util.concurrent.CompletableFuture; + +@RequiredArgsConstructor +public class ApiActionLogger implements ActionLogger { + private final LuckPermsPlugin plugin; + + @Override + public LogEntry.Builder newEntryBuilder() { + return ExtendedLogEntry.build(); + } + + @Override + public CompletableFuture getLog() { + return plugin.getStorage().noBuffer().getLog().thenApply(log -> log == null ? null : new ApiLog(log)); + } + + @Override + public CompletableFuture submit(LogEntry entry) { + return CompletableFuture.runAsync(() -> plugin.getLogDispatcher().dispatchFromApi((ExtendedLogEntry) entry), plugin.getScheduler().async()); + } + + @Override + public CompletableFuture submitToStorage(LogEntry entry) { + return plugin.getStorage().noBuffer().logAction(entry); + } + + @Override + public CompletableFuture broadcastAction(LogEntry entry) { + return CompletableFuture.runAsync(() -> plugin.getLogDispatcher().broadcastFromApi((ExtendedLogEntry) entry), plugin.getScheduler().async()); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java b/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java index cf8ef7a51..aec63c31f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java @@ -108,7 +108,7 @@ public abstract class HolderCachedData implements Ca */ private MetaCache calculateMeta(@NonNull MetaContexts contexts, MetaCache data) { if (data == null) { - data = new MetaCache(); + data = new MetaCache(contexts); } if (contexts.getContexts() == Contexts.allowAll()) { diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/type/MetaCache.java b/common/src/main/java/me/lucko/luckperms/common/caching/type/MetaCache.java index 6ad3d7372..e9d9772f7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/type/MetaCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/type/MetaCache.java @@ -27,13 +27,15 @@ package me.lucko.luckperms.common.caching.type; import lombok.AccessLevel; import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ListMultimap; +import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.caching.MetaContexts; import me.lucko.luckperms.api.caching.MetaData; import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.common.metastacking.MetaStack; @@ -48,11 +50,16 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * Holds cached meta for a given context */ @Getter -@NoArgsConstructor +@RequiredArgsConstructor public class MetaCache implements MetaData { @Getter(AccessLevel.NONE) private final ReadWriteLock lock = new ReentrantReadWriteLock(); + /** + * The contexts this container is holding data for + */ + private final MetaContexts metaContexts; + private ListMultimap metaMultimap = ImmutableListMultimap.of(); private Map meta = ImmutableMap.of(); private SortedMap prefixes = ImmutableSortedMap.of(); @@ -118,4 +125,9 @@ public class MetaCache implements MetaData { return suffixStack.getDefinition(); } + @Override + public Contexts getContexts() { + return metaContexts.getContexts(); + } + } diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java b/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java index daf3b97df..1bf2bf3e8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java @@ -25,6 +25,7 @@ package me.lucko.luckperms.common.caching.type; +import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.api.Contexts; @@ -44,6 +45,12 @@ import java.util.concurrent.ConcurrentHashMap; */ public class PermissionCache implements PermissionData { + /** + * The contexts this container is holding data for + */ + @Getter + private final Contexts contexts; + /** * The raw set of permission strings. */ @@ -62,6 +69,7 @@ public class PermissionCache implements PermissionData { private final PermissionCalculator calculator; public PermissionCache(Contexts contexts, PermissionCalculatorMetadata metadata, CalculatorFactory calculatorFactory) { + this.contexts = contexts; permissions = new ConcurrentHashMap<>(); permissionsUnmodifiable = Collections.unmodifiableMap(permissions); diff --git a/common/src/main/java/me/lucko/luckperms/common/event/EventFactory.java b/common/src/main/java/me/lucko/luckperms/common/event/EventFactory.java index 87db31960..74078f3a2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/event/EventFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/event/EventFactory.java @@ -38,6 +38,7 @@ import me.lucko.luckperms.api.event.LuckPermsEvent; import me.lucko.luckperms.api.event.cause.CreationCause; import me.lucko.luckperms.api.event.cause.DeletionCause; import me.lucko.luckperms.api.event.log.LogBroadcastEvent; +import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.event.impl.EventConfigReload; import me.lucko.luckperms.common.event.impl.EventGroupCacheLoad; import me.lucko.luckperms.common.event.impl.EventGroupCreate; @@ -47,6 +48,7 @@ import me.lucko.luckperms.common.event.impl.EventGroupLoad; import me.lucko.luckperms.common.event.impl.EventGroupLoadAll; import me.lucko.luckperms.common.event.impl.EventLogBroadcast; import me.lucko.luckperms.common.event.impl.EventLogNetworkPublish; +import me.lucko.luckperms.common.event.impl.EventLogNotify; import me.lucko.luckperms.common.event.impl.EventLogPublish; import me.lucko.luckperms.common.event.impl.EventLogReceive; import me.lucko.luckperms.common.event.impl.EventNodeAdd; @@ -142,6 +144,13 @@ public final class EventFactory { return cancel.get(); } + public boolean handleLogNotify(boolean initialState, LogEntry entry, LogBroadcastEvent.Origin origin, Sender sender) { + AtomicBoolean cancel = new AtomicBoolean(initialState); + EventLogNotify event = new EventLogNotify(cancel, entry, origin, sender); + fireEvent(event); + return cancel.get(); + } + public void handleLogReceive(UUID id, LogEntry entry) { EventLogReceive event = new EventLogReceive(id, entry); fireEventAsync(event); diff --git a/common/src/main/java/me/lucko/luckperms/common/event/impl/EventLogNotify.java b/common/src/main/java/me/lucko/luckperms/common/event/impl/EventLogNotify.java new file mode 100644 index 000000000..319473df2 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/event/impl/EventLogNotify.java @@ -0,0 +1,93 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.event.impl; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.event.log.LogBroadcastEvent; +import me.lucko.luckperms.api.event.log.LogNotifyEvent; +import me.lucko.luckperms.common.commands.sender.Sender; +import me.lucko.luckperms.common.event.AbstractEvent; + +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +@Getter +@ToString +@RequiredArgsConstructor +public class EventLogNotify extends AbstractEvent implements LogNotifyEvent { + + private final AtomicBoolean cancellationState; + private final LogEntry entry; + private final LogBroadcastEvent.Origin origin; + private final Sender sender; + + @Getter(AccessLevel.NONE) + private Notifiable notifiable; + + @Override + public synchronized Notifiable getNotifiable() { + if (notifiable == null) { + notifiable = new SenderNotifiable(sender); + } + return notifiable; + } + + @AllArgsConstructor + private static final class SenderNotifiable implements Notifiable { + private final Sender sender; + + @Override + public Optional getUuid() { + if (sender.isConsole()) { + return Optional.empty(); + } + return Optional.of(sender.getUuid()); + } + + @Override + public String getName() { + return sender.getName(); + } + + @Override + public boolean isConsole() { + return sender.isConsole(); + } + + @Override + public boolean isPlayer() { + return !sender.isConsole(); + } + } + +}