Improve various javadocs, add LogNotifyEvent

This commit is contained in:
Luck 2017-12-27 17:00:54 +00:00
parent ab115c4a6b
commit 3d6aa69ca1
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
38 changed files with 990 additions and 225 deletions

View File

@ -0,0 +1,100 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api;
import java.util.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.
*
* <p>Returns the same result as {@link Storage#getLog()}.</p>
*
* @return a log instance
* @see Storage#getLog()
*/
@Nonnull
CompletableFuture<Log> getLog();
/**
* Submits a log entry to the plugin to be handled.
*
* <p>This method submits the log to the storage provider and broadcasts
* it.</p>
*
* <p>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.</p>
*
* <p>If you want to submit a log entry but don't know which method to pick,
* use this one.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> submit(@Nonnull LogEntry entry);
/**
* Submits a log entry to the plugins storage handler.
*
* <p>Performs the same action as {@link Storage#logAction(LogEntry)}.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> submitToStorage(@Nonnull LogEntry entry);
/**
* Submits a log entry to the plugins log broadcasting handler.
*
* <p>If enabled, this method will also dispatch the log entry via the
* plugins {@link MessagingService}.</p>
*
* @param entry the entry to submit
* @return a future which will complete when the action is done
*/
@Nonnull
CompletableFuture<Void> broadcastAction(@Nonnull LogEntry entry);
}

View File

@ -31,14 +31,16 @@ import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet;
import javax.annotation.Nonnull; 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.
* *
* <p>This class is immutable.</p> * <p>This class is immutable.</p>
* *
* @since 2.11 * @since 2.11
*/ */
@Immutable
public class Contexts { public class Contexts {
/** /**

View File

@ -36,12 +36,12 @@ public enum DataMutateResult {
SUCCESS(true), 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), 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), LACKS(false),

View File

@ -31,13 +31,15 @@ import java.util.Optional;
import java.util.OptionalLong; import java.util.OptionalLong;
import javax.annotation.Nonnull; 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 <T> the identifier type of the holder * @param <T> the identifier type of the holder
* @since 2.17 * @since 2.17
*/ */
@Immutable
public interface HeldPermission<T> { public interface HeldPermission<T> {
/** /**

View File

@ -26,12 +26,14 @@
package me.lucko.luckperms.api; package me.lucko.luckperms.api;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/** /**
* A node with a traceable origin * A node with a traceable origin
* *
* @since 2.11 * @since 2.11
*/ */
@Immutable
public interface LocalizedNode extends Node { public interface LocalizedNode extends Node {
/** /**

View File

@ -30,6 +30,7 @@ import java.util.SortedSet;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/** /**
* Represents the internal LuckPerms log. * Represents the internal LuckPerms log.
@ -41,6 +42,7 @@ import javax.annotation.Nonnull;
* *
* <p>All methods are thread safe, and return immutable and thread safe collections.</p> * <p>All methods are thread safe, and return immutable and thread safe collections.</p>
*/ */
@Immutable
public interface Log { public interface Log {
/** /**

View File

@ -30,12 +30,14 @@ import java.util.UUID;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/** /**
* Represents a logged action. * Represents a logged action.
* *
* @see LuckPermsApi#newLogEntryBuilder() for creating an instance * @see ActionLogger#newEntryBuilder() for creating an instance
*/ */
@Immutable
public interface LogEntry extends Comparable<LogEntry> { public interface LogEntry extends Comparable<LogEntry> {
/** /**
@ -143,27 +145,81 @@ public interface LogEntry extends Comparable<LogEntry> {
*/ */
interface Builder { interface Builder {
/**
* Sets the timestamp of the entry.
*
* @param timestamp the timestamp
* @return the builder
* @see LogEntry#getTimestamp()
*/
@Nonnull @Nonnull
Builder setTimestamp(long timestamp); Builder setTimestamp(long timestamp);
/**
* Sets the actor of the entry.
*
* @param actor the actor
* @return the builder
* @see LogEntry#getActor()
*/
@Nonnull @Nonnull
Builder setActor(@Nonnull UUID actor); Builder setActor(@Nonnull UUID actor);
/**
* Sets the actor name of the entry.
*
* @param actorName the actor name
* @return the builder
* @see LogEntry#getActorName()
*/
@Nonnull @Nonnull
Builder setActorName(@Nonnull String actorName); Builder setActorName(@Nonnull String actorName);
/**
* Sets the type of the entry.
*
* @param type the type
* @return the builder
* @see LogEntry#getType()
*/
@Nonnull @Nonnull
Builder setType(@Nonnull Type type); Builder setType(@Nonnull Type type);
/**
* Sets the acted object for the entry.
*
* @param acted the acted object
* @return the builder
* @see LogEntry#getActed()
*/
@Nonnull @Nonnull
Builder setActed(@Nullable UUID acted); Builder setActed(@Nullable UUID acted);
/**
* Sets the acted name for the entry.
*
* @param actedName the acted name
* @return the builder
* @see LogEntry#getActedName()
*/
@Nonnull @Nonnull
Builder setActedName(@Nonnull String actedName); Builder setActedName(@Nonnull String actedName);
/**
* Sets the action of the entry.
*
* @param action the action
* @return the builder
* @see LogEntry#getAction()
*/
@Nonnull @Nonnull
Builder setAction(@Nonnull String action); Builder setAction(@Nonnull String action);
/**
* Creates a {@link LogEntry} instance from the builder.
*
* @return a new log entry instance
*/
@Nonnull @Nonnull
LogEntry build(); LogEntry build();

View File

@ -65,7 +65,14 @@ public interface LuckPermsApi {
PlatformInfo getPlatformInfo(); PlatformInfo getPlatformInfo();
/** /**
* Gets the user manager * Gets the {@link UserManager}, responsible for managing
* {@link User} instances.
*
* <p>This manager can be used to retrieve instances of {@link User} by uuid
* or name, or query all loaded users.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save users.</p>
* *
* @return the user manager * @return the user manager
* @since 4.0 * @since 4.0
@ -74,7 +81,14 @@ public interface LuckPermsApi {
UserManager getUserManager(); UserManager getUserManager();
/** /**
* Gets the group manager * Gets the {@link GroupManager}, responsible for managing
* {@link Group} instances.
*
* <p>This manager can be used to retrieve instances of {@link Group} by
* name, or query all loaded groups.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete groups.</p>
* *
* @return the group manager * @return the group manager
* @since 4.0 * @since 4.0
@ -83,7 +97,14 @@ public interface LuckPermsApi {
GroupManager getGroupManager(); GroupManager getGroupManager();
/** /**
* Gets the track manager * Gets the {@link TrackManager}, responsible for managing
* {@link Track} instances.
*
* <p>This manager can be used to retrieve instances of {@link Track} by
* name, or query all loaded tracks.</p>
*
* <p>The {@link #getStorage() storage} instance should be used to
* load/create/save/delete tracks.</p>
* *
* @return the track manager * @return the track manager
* @since 4.0 * @since 4.0
@ -92,15 +113,23 @@ public interface LuckPermsApi {
TrackManager getTrackManager(); 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}.
* *
* <p>The exact actions performed in an update task remains an
* implementation detail of the plugin, however, as a minimum, it is
* expected to perform a full reload of user, group and track data, and
* ensure that any changes are fully applied and propagated.</p>
*
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
CompletableFuture<Void> runUpdateTask(); CompletableFuture<Void> 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 * @return the event bus
* @since 3.0 * @since 3.0
@ -109,15 +138,18 @@ public interface LuckPermsApi {
EventBus getEventBus(); EventBus getEventBus();
/** /**
* Gets the configuration * Gets a representation of the plugins configuration
* *
* @return a configuration instance * @return the configuration
*/ */
@Nonnull @Nonnull
LPConfiguration getConfiguration(); LPConfiguration getConfiguration();
/** /**
* Gets the backend storage dao * Gets an object representing the plugins primary {@link Storage} backend.
*
* <p>The instance propagates calls to the internal DAO (Data Access Object),
* and applies any changes to the storage provider.</p>
* *
* @return a storage instance * @return a storage instance
* @since 2.14 * @since 2.14
@ -126,24 +158,47 @@ public interface LuckPermsApi {
Storage getStorage(); Storage getStorage();
/** /**
* Gets the messaging service * Gets the {@link MessagingService}, if present.
* *
* @return an optional that may contain a messaging service instance. * <p>The MessagingService is used to dispatch updates throughout a network
* of servers running the plugin.</p>
*
* <p>Not all instances of LuckPerms will have a messaging service setup and
* configured, but it is recommended that all users of the API account for
* and make use of this.</p>
*
* @return the messaging service instance, if present.
*/ */
@Nonnull @Nonnull
Optional<MessagingService> getMessagingService(); Optional<MessagingService> getMessagingService();
/** /**
* Gets a {@link UuidCache} instance, providing read access to the LuckPerms * Gets the {@link ActionLogger}.
* internal uuid caching system
* *
* @return a uuid cache instance * <p>The action logger is responsible for saving and broadcasting defined
* actions occurring on the platform.</p>
*
* @return the action logger
* @since 4.1
*/
ActionLogger getActionLogger();
/**
* Gets a {@link UuidCache}.
*
* <p>The uuid cache provides read access to the internal LuckPerms uuid
* mapping system.</p>
*
* @return the uuid cache
*/ */
@Nonnull @Nonnull
UuidCache getUuidCache(); UuidCache getUuidCache();
/** /**
* Gets the context manager * Gets the {@link ContextManager}.
*
* <p>The context manager manages {@link ContextCalculator}s, and calculates
* applicable contexts for a given type.</p>
* *
* @return the context manager * @return the context manager
* @since 4.0 * @since 4.0
@ -151,7 +206,9 @@ public interface LuckPermsApi {
ContextManager getContextManager(); ContextManager getContextManager();
/** /**
* Gets the node factory * Gets the {@link NodeFactory}.
*
* <p>The node factory provides methods for building {@link Node} instances.</p>
* *
* @return the node factory * @return the node factory
*/ */
@ -159,7 +216,11 @@ public interface LuckPermsApi {
NodeFactory getNodeFactory(); NodeFactory getNodeFactory();
/** /**
* Gets the MetaStackFactory * Gets the {@link MetaStackFactory}.
*
* <p>The metastack factory provides methods for retrieving
* {@link me.lucko.luckperms.api.metastacking.MetaStackElement}s and constructing
* {@link me.lucko.luckperms.api.metastacking.MetaStackDefinition}s.</p>
* *
* @return the meta stack factory * @return the meta stack factory
* @since 3.2 * @since 3.2
@ -167,7 +228,18 @@ public interface LuckPermsApi {
@Nonnull @Nonnull
MetaStackFactory getMetaStackFactory(); 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 * Gets a wrapped user object from the user storage
@ -350,7 +422,9 @@ public interface LuckPermsApi {
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
LogEntry.Builder newLogEntryBuilder(); default LogEntry.Builder newLogEntryBuilder() {
return getActionLogger().newEntryBuilder();
}
/** /**
* Returns a permission builder instance * Returns a permission builder instance

View File

@ -35,6 +35,7 @@ import java.util.Set;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/** /**
* Represents a permission node. * Represents a permission node.
@ -45,6 +46,7 @@ import javax.annotation.Nullable;
* *
* @since 2.6 * @since 2.6
*/ */
@Immutable
public interface Node extends Map.Entry<String, Boolean> { public interface Node extends Map.Entry<String, Boolean> {
/** /**
@ -356,7 +358,7 @@ public interface Node extends Map.Entry<String, Boolean> {
interface Builder { interface Builder {
/** /**
* Sets the value of negated for the node * Sets the value of negated for the node.
* *
* @param negated the value * @param negated the value
* @return the builder * @return the builder
@ -366,7 +368,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setNegated(boolean negated); Builder setNegated(boolean negated);
/** /**
* Sets the value of the node * Sets the value of the node.
* *
* @param value the value * @param value the value
* @return the builder * @return the builder
@ -376,7 +378,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setValue(boolean value); Builder setValue(boolean value);
/** /**
* Sets the override property for the node * Sets the override property for the node.
* *
* <p>Warning: this value does not persist, and disappears when the holder is re-loaded. * <p>Warning: this value does not persist, and disappears when the holder is re-loaded.
* It is therefore only useful for transient nodes.</p> * It is therefore only useful for transient nodes.</p>
@ -389,7 +391,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setOverride(boolean override); 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 * @param expireAt the expiry time
* @return the builder * @return the builder
@ -399,7 +401,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setExpiry(long expireAt); Builder setExpiry(long expireAt);
/** /**
* Sets the world value for the node * Sets the world value for the node.
* *
* @param world the world value * @param world the world value
* @return the builder * @return the builder
@ -409,7 +411,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setWorld(@Nullable String world); Builder setWorld(@Nullable String world);
/** /**
* Sets the server value for the node * Sets the server value for the node.
* *
* @param server the world value * @param server the world value
* @return the builder * @return the builder
@ -419,7 +421,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder setServer(@Nullable String server); 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 key the context key
* @param value the context value * @param value the context value
@ -431,9 +433,10 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder withExtraContext(@Nonnull String key, @Nonnull String value); 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 * @param map a map of contexts
* @return the builder
* @see ContextSet * @see ContextSet
* @see Node#getContexts() * @see Node#getContexts()
*/ */
@ -441,9 +444,10 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder withExtraContext(@Nonnull Map<String, String> map); Builder withExtraContext(@Nonnull Map<String, String> map);
/** /**
* Appends extra contexts onto the node * Appends extra contexts onto the node.
* *
* @param context a set of contexts * @param context a set of contexts
* @return the builder
* @see ContextSet * @see ContextSet
* @see Node#getContexts() * @see Node#getContexts()
*/ */
@ -451,7 +455,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder withExtraContext(@Nonnull Set<Map.Entry<String, String>> context); Builder withExtraContext(@Nonnull Set<Map.Entry<String, String>> context);
/** /**
* Appends an extra context onto the node * Appends an extra context onto the node.
* *
* @param entry the context * @param entry the context
* @return the builder * @return the builder
@ -462,9 +466,10 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder withExtraContext(@Nonnull Map.Entry<String, String> entry); Builder withExtraContext(@Nonnull Map.Entry<String, String> entry);
/** /**
* Appends extra contexts onto the node * Appends extra contexts onto the node.
* *
* @param set a contextset * @param set a contextset
* @return the builder
* @see ContextSet * @see ContextSet
* @see Node#getContexts() * @see Node#getContexts()
*/ */
@ -472,7 +477,7 @@ public interface Node extends Map.Entry<String, Boolean> {
Builder withExtraContext(@Nonnull ContextSet set); 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 * @return a new node instance
*/ */

View File

@ -92,6 +92,7 @@ public interface NodeFactory {
/** /**
* Creates a node builder for the given chat meta type * Creates a node builder for the given chat meta type
* *
* @param type the type
* @param priority the priority * @param priority the priority
* @param value the value for the prefix/suffix * @param value the value for the prefix/suffix
* @return a node builder instance * @return a node builder instance

View File

@ -88,8 +88,10 @@ public interface Storage {
* @param entry the log entry to be saved * @param entry the log entry to be saved
* @return true if the operation completed successfully. * @return true if the operation completed successfully.
* @throws NullPointerException if entry is null * @throws NullPointerException if entry is null
* @deprecated in favour of {@link ActionLogger#submit(LogEntry)}.
*/ */
@Nonnull @Nonnull
@Deprecated
CompletableFuture<Boolean> logAction(@Nonnull LogEntry entry); CompletableFuture<Boolean> logAction(@Nonnull LogEntry entry);
/** /**

View File

@ -30,33 +30,40 @@ import java.util.UUID;
import javax.annotation.Nonnull; 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.
* *
* <p>A user's internal LuckPerms UUID is always the same as their Mojang one, * <p>A user's internal LuckPerms UUID is always the same as their Mojang one,
* unless <code>use-server-uuids</code> is disabled.</p> * unless <code>use-server-uuids</code> is disabled.</p>
* *
* <p>When this setting is disabled, this cache becomes active, and allows you to convert * <p>When this setting is disabled, this cache becomes active, and allows you
* between 'internal' and 'server provided' uuids.</p> * to convert between 'internal' and 'server provided' uuids.</p>
* *
* <p><strong>This is only effective for online players. Use {@link Storage#getUUID(String)} for offline players.</strong></p> * <p><strong>This is only effective for online players.
* Use {@link Storage#getUUID(String)} for offline players.</strong></p>
*/ */
public interface UuidCache { public interface UuidCache {
/** /**
* Gets a users "internal" LuckPerms UUID, from the one given by the server. * Gets a users "internal" LuckPerms UUID, from the one given by the server.
* *
* <p>When <code>use-server-uuids</code> is true, this returns the same UUID instance.</p> * <p>When <code>use-server-uuids</code> is true, this returns the same UUID
* instance.</p>
* *
* @param mojangUuid the UUID assigned by the server, through <code>Player#getUniqueId</code> or <code>ProxiedPlayer#getUniqueId</code> * @param mojangUuid the UUID assigned by the server, through
* <code>Player#getUniqueId</code> or
* <code>ProxiedPlayer#getUniqueId</code>
* @return the corresponding internal UUID * @return the corresponding internal UUID
*/ */
@Nonnull @Nonnull
UUID getUUID(@Nonnull UUID mojangUuid); 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 <code>User#getUuid</code> * @param internalUuid the UUID used within LuckPerms, through
* <code>User#getUuid</code>
* @return the corresponding external UUID * @return the corresponding external UUID
*/ */
@Nonnull @Nonnull

View File

@ -210,6 +210,7 @@ public interface CachedData {
* *
* @param contexts the contexts to reload in. * @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null * @throws NullPointerException if contexts is null
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
@ -237,6 +238,7 @@ public interface CachedData {
* *
* @param contexts the contexts to reload in. * @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null * @throws NullPointerException if contexts is null
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
@ -264,6 +266,7 @@ public interface CachedData {
* *
* @param contexts the contexts to reload in. * @param contexts the contexts to reload in.
* @throws NullPointerException if contexts is null * @throws NullPointerException if contexts is null
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
@ -309,6 +312,7 @@ public interface CachedData {
* <p>This method returns a Future so users can optionally choose to wait * <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p> * until the recalculation has been performed.</p>
* *
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull
@ -332,6 +336,7 @@ public interface CachedData {
* <p>This method returns a Future so users can optionally choose to wait * <p>This method returns a Future so users can optionally choose to wait
* until the recalculation has been performed.</p> * until the recalculation has been performed.</p>
* *
* @return a future
* @since 4.0 * @since 4.0
*/ */
@Nonnull @Nonnull

View File

@ -0,0 +1,47 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.api.caching;
import me.lucko.luckperms.api.Contexts;
import 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();
}

View File

@ -31,15 +31,17 @@ import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import javax.annotation.Nonnull; 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.
* *
* <p>Consisting of a standard {@link Contexts} element, plus options to define how * <p>Consists of a standard {@link Contexts} element, plus options to define how
* the meta stack should be constructed.</p> * the meta stack should be constructed.</p>
* *
* @since 3.2 * @since 3.2
*/ */
@Immutable
public final class MetaContexts { public final class MetaContexts {
/** /**

View File

@ -36,11 +36,19 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; 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 * @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. * Gets an immutable copy of the meta this user has.

View File

@ -32,14 +32,14 @@ import java.util.Map;
import javax.annotation.Nonnull; 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 * @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 * @param permission the permission node
* @return a tristate result * @return a tristate result

View File

@ -25,10 +25,12 @@
package me.lucko.luckperms.api.context; package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -39,6 +41,17 @@ abstract class AbstractContextSet implements ContextSet {
protected abstract Multimap<String, String> backing(); protected abstract Multimap<String, String> backing();
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : backing().entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Override @Override
public boolean containsKey(@Nonnull String key) { public boolean containsKey(@Nonnull String key) {
return backing().containsKey(sanitizeKey(key)); return backing().containsKey(sanitizeKey(key));

View File

@ -40,9 +40,14 @@ import javax.annotation.Nonnull;
* on specific server implementations. In all cases, the "player" or "subject" type for * on specific server implementations. In all cases, the "player" or "subject" type for
* the platform must be used. * the platform must be used.
* *
* Specifically, {@code org.bukkit.entity.Player}, * Specifically:
* {@code net.md_5.bungee.api.connection.ProxiedPlayer} and *
* {@code org.spongepowered.api.service.permission.Subject}. * <p></p>
* <ul>
* <li>{@code org.bukkit.entity.Player}</li>
* <li>{@code net.md_5.bungee.api.connection.ProxiedPlayer}</li>
* <li>{@code org.spongepowered.api.service.permission.Subject}</li>
* </ul>
* *
* @since 4.0 * @since 4.0
*/ */

View File

@ -35,26 +35,38 @@ import java.util.Set;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
* A set of context pairs. * A set of contexts.
* *
* <p>You can think of ContextSets as a wrapped <code>Multimap&lt;String, String&gt;</code>. * <p>Context in the most basic sense simply means the circumstances where
* Each key can be mapped to multiple values.</p> * something will apply.</p>
* *
* <p>Keys are automatically converted to lowercase when added, and are therefore * <p>A single "context" consists of a key and a value, both strings. The key
* case-insensitive. Values however are not.</p> * represents the type of context, and the value represents the setting of the
* context key.</p>
* *
* <p>Implementations may be either mutable or immutable.</p> * <p>Contexts can be combined with each other to form so called
* "context sets" - simply a collection of context pairs.</p>
*
* <p>Context keys are case-insensitive, and will be converted to
* {@link String#toLowerCase() lowercase} by all implementations.
* Values however are case-sensitive.</p>
*
* <p>Context keys and values may not be null.</p>
*
* <p>Two default ContextSet implementations are provided.
* {@link MutableContextSet} allows the addition and removal of context keys
* after construction, and {@link ImmutableContextSet} does not.</p>
* *
* @since 2.13 * @since 2.13
*/ */
public interface ContextSet { public interface ContextSet {
/** /**
* Creates an ImmutableContextSet from a context pair * Creates an {@link ImmutableContextSet} from a context pair.
* *
* @param key the key * @param key the key
* @param value the value * @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 * @throws NullPointerException if key or value is null
*/ */
@Nonnull @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 key1 the first key
* @param value1 the first value * @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 * @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable * @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 * @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map * @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 * @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap * @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. * Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
* Only really useful for converting between mutable and immutable types. *
* <p>Only really useful for converting between mutable and immutable types.</p>
* *
* @param contextSet the context set to copy from * @param contextSet the context set to copy from
* @return a new ImmutableContextSet with the same content and the one provided * @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 @Nonnull
static ImmutableContextSet empty() { 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.
*
* <p>The state of immutable instances will never change.</p>
* *
* @return true if the set is immutable * @return true if the set is immutable
*/ */
boolean isImmutable(); 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 * <p>If the set is already immutable, the same object will be returned.
* If the set is mutable, an immutable copy will be made.</p>
*
* @return an immutable representation of this set
*/ */
@Nonnull @Nonnull
ImmutableContextSet makeImmutable(); ImmutableContextSet makeImmutable();
/** /**
* Creates a mutable copy of this set. * Creates a mutable copy of this {@link ContextSet}.
*
* <p>A new copy is returned regardless of the
* {@link #isImmutable() mutability} of this set.</p>
* *
* @return a mutable ContextSet * @return a mutable ContextSet
* @since 2.16 * @since 2.16
@ -163,7 +184,11 @@ public interface ContextSet {
MutableContextSet mutableCopy(); 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}.
*
* <p>The returned set is immutable, and is a copy of the current set.
* (will not update live)</p>
* *
* @return an immutable set * @return an immutable set
*/ */
@ -171,10 +196,18 @@ public interface ContextSet {
Set<Map.Entry<String, String>> toSet(); Set<Map.Entry<String, String>> toSet();
/** /**
* Converts this ContextSet to an immutable {@link Map} * Returns a {@link Map} <b>loosely</b> representing the current state of
* this {@link ContextSet}.
* *
* <b>IMPORTANT: Use of this method may result in data being lost. ContextSets can contain lots of different values for * <p>The returned map is immutable, and is a copy of the current set.
* one key.</b> * (will not update live)</p>
*
* <p>As a single context key can be mapped to multiple values, this method
* may not be a true representation of the set.</p>
*
* <p>If you need a representation of the set in a Java collection instance,
* use {@link #toSet()} or {@link #toMultimap()} followed by
* {@link Multimap#asMap()}.</p>
* *
* @return an immutable map * @return an immutable map
* @deprecated because the resultant map may not contain all data in the ContextSet * @deprecated because the resultant map may not contain all data in the ContextSet
@ -184,7 +217,11 @@ public interface ContextSet {
Map<String, String> toMap(); Map<String, String> toMap();
/** /**
* Converts this ContextSet to an immutable {@link Multimap} * Returns a {@link Multimap} representing the current state of this
* {@link ContextSet}.
*
* <p>The returned multimap is immutable, and is a copy of the current set.
* (will not update live)</p>
* *
* @return a multimap * @return a multimap
* @since 2.16 * @since 2.16
@ -193,7 +230,8 @@ public interface ContextSet {
Multimap<String, String> toMultimap(); Multimap<String, String> 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 * @param key the key to check for
* @return true if the set contains a value for the key * @return true if the set contains a value for the key
@ -202,9 +240,12 @@ public interface ContextSet {
boolean containsKey(@Nonnull String key); 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 * <p>The returned set is immutable, and only represents the current state
* of the {@link ContextSet}. (will not update live)</p>
*
* @param key the key to get values for
* @return a set of values * @return a set of values
* @throws NullPointerException if the key is null * @throws NullPointerException if the key is null
*/ */
@ -212,7 +253,10 @@ public interface ContextSet {
Set<String> getValues(@Nonnull String key); Set<String> 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.
*
* <p>Note that context keys can be mapped to multiple values.
* Use {@link #getValues(String)} to retrieve all associated values.</p>
* *
* @param key the key to find values for * @param key the key to find values for
* @return an optional containing any match * @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.
*
* <p>This lookup is case-sensitive on the value.</p>
* *
* @param key the key to look for * @param key the key to look for
* @param value the value to look for (case sensitive) * @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 * @throws NullPointerException if the key or value is null
*/ */
boolean has(@Nonnull String key, @Nonnull String value); 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.
*
* <p>This lookup is case-insensitive on the value.</p>
*
* @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.
*
* <p>This lookup is case-sensitive on the value.</p>
* *
* @param entry the entry to look for * @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 * @throws NullPointerException if the key or value is null
* @since 3.4
*/ */
default boolean has(@Nonnull Map.Entry<String, String> entry) { default boolean has(@Nonnull Map.Entry<String, String> entry) {
Preconditions.checkNotNull(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 * <p>This lookup is case-insensitive on the value.</p>
* @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.
* *
* @param entry the entry to look for * @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 * @throws NullPointerException if the key or value is null
* @since 3.4
*/ */
default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) { default boolean hasIgnoreCase(@Nonnull Map.Entry<String, String> entry) {
Preconditions.checkNotNull(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.
*
* <p>For a context set to "satisfy" another, it must itself contain all of
* the context pairings in the other set.</p>
*
* <p>Mathematically, this method returns true if this set is a <b>subset</b> of the other.</p>
*
* <p>This check is case-sensitive. For a case-insensitive check,
* use {@link #isSatisfiedBy(ContextSet, boolean)}.</p>
* *
* @param other the other set to check * @param other the other set to check
* @return true if all entries in this set are also in the other set * @return true if all entries in this set are also in the other set
* @since 3.1 * @since 3.1
*/ */
default boolean isSatisfiedBy(@Nonnull ContextSet other) { 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.
*
* <p>For a context set to "satisfy" another, it must itself contain all of
* the context pairings in the other set.</p>
*
* <p>Mathematically, this method returns true if this set is a <b>subset</b> of the other.</p>
* *
* @param other the other set to check * @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 * @return true if all entries in this set are also in the other set
* @since 3.4 * @since 3.4
*/ */
@ -305,31 +370,30 @@ public interface ContextSet {
return false; return false;
} else { } else {
// neither are empty, we need to compare the individual entries // neither are empty, we need to compare the individual entries
for (Map.Entry<String, String> pair : toSet()) { for (Map.Entry<String, String> context : toSet()) {
if (caseSensitive) { if (caseSensitive) {
if (!other.has(pair)) { if (!other.has(context)) {
return false; return false;
} }
} else { } else {
if (!other.hasIgnoreCase(pair)) { if (!other.hasIgnoreCase(context)) {
return false; return false;
} }
} }
} }
return true; return true;
} }
} }
/** /**
* Check if the set is empty * Returns if the {@link ContextSet} is empty.
* *
* @return true if the set is empty * @return true if the set is empty
*/ */
boolean isEmpty(); 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 * @return the size of the set
*/ */

View File

@ -25,15 +25,14 @@
package me.lucko.luckperms.api.context; package me.lucko.luckperms.api.context;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -42,13 +41,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
* *
* @since 2.16 * @since 2.16
*/ */
@Immutable
public final class ImmutableContextSet extends AbstractContextSet implements ContextSet { public final class ImmutableContextSet extends AbstractContextSet implements ContextSet {
private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of()); private static final ImmutableContextSet EMPTY = new ImmutableContextSet(ImmutableSetMultimap.of());
/** /**
* Creates a builder * Creates an {@link ImmutableContextSet.Builder}.
* *
* @return a new ImmutableContextSet builder * @return a new ImmutableContextSet builder
* @since 4.1
*/ */
@Nonnull @Nonnull
public static Builder builder() { 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 key the key
* @param value the value * @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 * @throws NullPointerException if key or value is null
*/ */
@Nonnull @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 key1 the first key
* @param value1 the first value * @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 * @param iterable the iterable to copy from
* @return a new ImmutableContextSet representing the pairs in the iterable * @return a new ImmutableContextSet representing the pairs in the iterable
@ -99,22 +100,15 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
@Nonnull @Nonnull
public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) { public static ImmutableContextSet fromEntries(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) {
checkNotNull(iterable, "iterable"); checkNotNull(iterable, "iterable");
ImmutableContextSet.Builder builder = builder();
Iterator<? extends Map.Entry<String, String>> iterator = iterable.iterator(); for (Map.Entry<String, String> entry : iterable) {
if (!iterator.hasNext()) { builder.add(entry);
return empty();
} }
return builder.build();
ImmutableSetMultimap.Builder<String, String> b = ImmutableSetMultimap.builder();
while (iterator.hasNext()) {
Map.Entry<String, String> e = checkNotNull(iterator.next(), "entry");
b.put(sanitizeKey(e.getKey()), sanitizeValue(e.getValue()));
}
return new ImmutableContextSet(b.build());
} }
/** /**
* Creates an ImmutableContextSet from an existing map * Creates an {@link ImmutableContextSet} from an existing {@link Map}.
* *
* @param map the map to copy from * @param map the map to copy from
* @return a new ImmutableContextSet representing the pairs from the map * @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 * @param multimap the multimap to copy from
* @return a new ImmutableContextSet representing the pairs in the multimap * @return a new ImmutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null * @throws NullPointerException if the multimap is null
* @since 2.16
*/ */
@Nonnull @Nonnull
public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) { public static ImmutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
@ -138,8 +133,9 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
} }
/** /**
* Creates a new ImmutableContextSet from an existing set. * Creates an new {@link ImmutableContextSet} from an existing {@link Set}.
* Only really useful for converting between mutable and immutable types. *
* <p>Only really useful for converting between mutable and immutable types.</p>
* *
* @param contextSet the context set to copy from * @param contextSet the context set to copy from
* @return a new ImmutableContextSet with the same content and the one provided * @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 @Nonnull
public static ImmutableContextSet empty() { public static ImmutableContextSet empty() {
@ -197,18 +193,6 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
return map.entries(); return map.entries();
} }
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Nonnull @Nonnull
@Override @Override
public Multimap<String, String> toMultimap() { public Multimap<String, String> 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 { public static final class Builder {
private ImmutableSetMultimap.Builder<String, String> builder; private ImmutableSetMultimap.Builder<String, String> builder;
@ -242,24 +228,32 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
return builder; 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 key the key to add
* @param value the value to add * @param value the value to add
* @return the builder
* @throws NullPointerException if the key or value is null * @throws NullPointerException if the key or value is null
* @see MutableContextSet#add(String, String)
*/ */
@Nonnull @Nonnull
public Builder add(@Nonnull String key, @Nonnull String value) { public Builder add(@Nonnull String key, @Nonnull String value) {
builder().put(sanitizeKey(key), sanitizeValue(value)); put(sanitizeKey(key), sanitizeValue(value));
return this; return this;
} }
/** /**
* Adds a new key value pair to the set * Adds a context to the set.
* *
* @param entry the entry to add * @param entry the entry to add
* @return the builder
* @throws NullPointerException if the entry is null * @throws NullPointerException if the entry is null
* @see MutableContextSet#add(Map.Entry)
*/ */
@Nonnull @Nonnull
public Builder add(@Nonnull Map.Entry<String, String> entry) { public Builder add(@Nonnull Map.Entry<String, String> 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 * @param iterable an iterable of key value context pairs
* @return the builder
* @throws NullPointerException if iterable is null * @throws NullPointerException if iterable is null
* @see MutableContextSet#addAll(Iterable)
*/ */
@Nonnull @Nonnull
public Builder addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> iterable) { public Builder addAll(@Nonnull Iterable<? extends Map.Entry<String, String>> 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 * @param map the map to add from
* @return the builder
* @throws NullPointerException if the map is null * @throws NullPointerException if the map is null
* @see MutableContextSet#addAll(Map)
*/ */
@Nonnull @Nonnull
public Builder addAll(@Nonnull Map<String, String> map) { public Builder addAll(@Nonnull Map<String, String> 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 * @param multimap the multimap to add from
* @return the builder
* @throws NullPointerException if the map is null * @throws NullPointerException if the map is null
* @since 3.4 * @since 3.4
* @see MutableContextSet#addAll(Multimap)
*/ */
@Nonnull @Nonnull
public Builder addAll(@Nonnull Multimap<String, String> multimap) { public Builder addAll(@Nonnull Multimap<String, String> 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 * @param contextSet the set to add from
* @return the builder
* @throws NullPointerException if the contextSet is null * @throws NullPointerException if the contextSet is null
* @see MutableContextSet#addAll(ContextSet)
*/ */
@Nonnull @Nonnull
public Builder addAll(@Nonnull ContextSet contextSet) { public Builder addAll(@Nonnull ContextSet contextSet) {
@ -327,6 +329,12 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
return this; return this;
} }
/**
* Creates a {@link ImmutableContextSet} from the values previously
* added to the builder.
*
* @return an {@link ImmutableContextSet} from the builder
*/
@Nonnull @Nonnull
public ImmutableContextSet build() { public ImmutableContextSet build() {
if (builder == null) { if (builder == null) {
@ -335,6 +343,5 @@ public final class ImmutableContextSet extends AbstractContextSet implements Con
return new ImmutableContextSet(builder.build()); return new ImmutableContextSet(builder.build());
} }
} }
} }
} }

View File

@ -27,7 +27,6 @@ package me.lucko.luckperms.api.context;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Multimap; 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 { 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 key the key
* @param value the value * @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 * @throws NullPointerException if key or value is null
*/ */
@Nonnull @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 key1 the first key
* @param value1 the first value * @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 * @param iterable the iterable to copy from
* @return a new MutableContextSet representing the pairs in the iterable * @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 * @param map the map to copy from
* @return a new MutableContextSet representing the pairs from the map * @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 * @param multimap the multimap to copy from
* @return a new MutableContextSet representing the pairs in the multimap * @return a new MutableContextSet representing the pairs in the multimap
* @throws NullPointerException if the multimap is null * @throws NullPointerException if the multimap is null
* @since 2.16
*/ */
@Nonnull @Nonnull
public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) { public static MutableContextSet fromMultimap(@Nonnull Multimap<String, String> multimap) {
@ -135,8 +135,9 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
} }
/** /**
* Creates a new MutableContextSet from an existing set. * Creates a new {@link MutableContextSet} from an existing {@link Set}.
* Only really useful for converting between mutable and immutable types. *
* <p>Only really useful for converting between mutable and immutable types.</p>
* *
* @param contextSet the context set to copy from * @param contextSet the context set to copy from
* @return a new MutableContextSet with the same content and the one provided * @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 @Nonnull
@Override @Override
public ImmutableContextSet makeImmutable() { public ImmutableContextSet makeImmutable() {
// if the map is empty, don't create a new instance
if (map.isEmpty()) { if (map.isEmpty()) {
return ImmutableContextSet.empty(); return ImmutableContextSet.empty();
} }
@ -201,17 +203,6 @@ public final class MutableContextSet extends AbstractContextSet implements Conte
return ImmutableSet.copyOf(map.entries()); return ImmutableSet.copyOf(map.entries());
} }
@Nonnull
@Override
@Deprecated
public Map<String, String> toMap() {
ImmutableMap.Builder<String, String> m = ImmutableMap.builder();
for (Map.Entry<String, String> e : map.entries()) {
m.put(e.getKey(), e.getValue());
}
return m.build();
}
@Nonnull @Nonnull
@Override @Override
public Multimap<String, String> toMultimap() { public Multimap<String, String> 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 key the key to add
* @param value the value 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 * @param entry the entry to add
* @throws NullPointerException if the entry is null * @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 * @param iterable an iterable of key value context pairs
* @throws NullPointerException if iterable is null * @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 * @param map the map to add from
* @throws NullPointerException if the map is null * @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 * @param multimap the multimap to add from
* @throws NullPointerException if the map is null * @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 * @param contextSet the set to add from
* @throws NullPointerException if the contextSet is null * @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 key the key to remove
* @param value the value to remove (case sensitive) * @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 key the key to remove
* @param value the value 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 * @param key the key to remove
* @throws NullPointerException if the key is null * @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() { public void clear() {
map.clear(); map.clear();

View File

@ -42,4 +42,35 @@ public interface Cancellable {
@Nonnull @Nonnull
AtomicBoolean getCancellationState(); 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);
}
} }

View File

@ -31,14 +31,16 @@ import java.util.function.Consumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
* The LuckPerms event bus. Used for subscribing (or registering listeners) to events. * The internal LuckPerms event bus.
*
* <p>LuckPerms events are posted to any listeners registered with the bus.</p>
* *
* @since 3.0 * @since 3.0
*/ */
public interface EventBus { public interface EventBus {
/** /**
* Subscribe to an event * Subscribes to an event.
* *
* @param eventClass the event class * @param eventClass the event class
* @param handler the event handler * @param handler the event handler
@ -49,7 +51,7 @@ public interface EventBus {
<T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<T> handler); <T extends LuckPermsEvent> EventHandler<T> subscribe(@Nonnull Class<T> eventClass, @Nonnull Consumer<T> 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 eventClass the event to find handlers for
* @param <T> the event class * @param <T> the event class

View File

@ -34,7 +34,7 @@ import javax.annotation.Nonnull;
* *
* @param <T> the event class * @param <T> the event class
*/ */
public interface EventHandler<T extends LuckPermsEvent> { public interface EventHandler<T extends LuckPermsEvent> extends AutoCloseable {
/** /**
* Gets the class this handler is listening to * Gets the class this handler is listening to
@ -73,4 +73,8 @@ public interface EventHandler<T extends LuckPermsEvent> {
*/ */
int getCallCount(); int getCallCount();
@Override
default void close() {
unregister();
}
} }

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.api.LuckPermsApi;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
* The base event interface * A superinterface for all LuckPerms events.
* *
* @since 3.0 * @since 3.0
*/ */

View File

@ -61,12 +61,17 @@ public interface LogBroadcastEvent extends LuckPermsEvent, Cancellable {
enum Origin { 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, 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 REMOTE
} }

View File

@ -0,0 +1,113 @@
/*
* 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.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.
*
* <p>This event is not called for players without the notify permission,
* but is called for objects which are ignoring log notifications (called with
* the cancelled flag set to true).</p>
*
* @since 4.1
*/
public interface LogNotifyEvent extends LuckPermsEvent, Cancellable {
/**
* 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.
*
* <p>For Players, this method returns their unique id.</p>
*
* @return the uuid of the object, if available
*/
@Nonnull
Optional<UUID> 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();
}
}

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.metastacking;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/** /**
* Represents a meta stack model, consisting of a chain of elements, separated by spacers. * 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 * @since 2.3
*/ */
@Immutable
public interface MetaStackDefinition { public interface MetaStackDefinition {
/** /**

View File

@ -33,12 +33,16 @@ import java.util.Map;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/** /**
* Represents an element within a {@link MetaStackDefinition}. * Represents an element within a {@link MetaStackDefinition}.
* *
* <p>The element itself does not contain any mutable state.</p>
*
* @since 3.2 * @since 3.2
*/ */
@Immutable
public interface MetaStackElement { public interface MetaStackElement {
/** /**

View File

@ -42,6 +42,21 @@ import java.util.Optional;
public class LogDispatcher { public class LogDispatcher {
private final LuckPermsPlugin plugin; 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) { public void dispatch(ExtendedLogEntry entry, Sender sender) {
// set the event to cancelled if the sender is import // set the event to cancelled if the sender is import
if (!plugin.getApiProvider().getEventFactory().handleLogPublish(sender.isImport(), entry)) { if (!plugin.getApiProvider().getEventFactory().handleLogPublish(sender.isImport(), entry)) {
@ -58,35 +73,37 @@ public class LogDispatcher {
messagingService.get().pushLog(entry); messagingService.get().pushLog(entry);
} }
if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(!plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY), entry, LogBroadcastEvent.Origin.LOCAL)) { boolean shouldCancel = !plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY);
plugin.getOnlineSenders() if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(shouldCancel, entry, LogBroadcastEvent.Origin.LOCAL)) {
.filter(CommandPermission.LOG_NOTIFY::isAuthorized) broadcast(entry, LogBroadcastEvent.Origin.LOCAL, sender);
.filter(s -> !LogNotify.isIgnoring(plugin, s.getUuid())) }
.filter(s -> !s.getUuid().equals(sender.getUuid())) }
.forEach(s -> Message.LOG.send(s,
entry.getActorFriendlyString(), public void dispatchFromApi(ExtendedLogEntry entry) {
Character.toString(entry.getType().getCode()), if (!plugin.getApiProvider().getEventFactory().handleLogPublish(false, entry)) {
entry.getActedFriendlyString(), try {
entry.getAction() 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) { public void dispatchFromRemote(ExtendedLogEntry entry) {
if (!plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES)) { boolean shouldCancel = !plugin.getConfiguration().get(ConfigKeys.BROADCAST_RECEIVED_LOG_ENTRIES) || !plugin.getConfiguration().get(ConfigKeys.LOG_NOTIFY);
return; if (!plugin.getApiProvider().getEventFactory().handleLogBroadcast(shouldCancel, entry, LogBroadcastEvent.Origin.REMOTE)) {
} broadcast(entry, LogBroadcastEvent.Origin.LOCAL_API, null);
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()
));
} }
} }
} }

View File

@ -28,8 +28,8 @@ package me.lucko.luckperms.common.api;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import me.lucko.luckperms.api.ActionLogger;
import me.lucko.luckperms.api.LPConfiguration; import me.lucko.luckperms.api.LPConfiguration;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.api.LuckPermsApi; import me.lucko.luckperms.api.LuckPermsApi;
import me.lucko.luckperms.api.MessagingService; import me.lucko.luckperms.api.MessagingService;
import me.lucko.luckperms.api.NodeFactory; 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.manager.UserManager;
import me.lucko.luckperms.api.metastacking.MetaStackFactory; import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.api.platform.PlatformInfo; 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.ApiContextManager;
import me.lucko.luckperms.common.api.delegates.manager.ApiGroupManager; 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.ApiTrackManager;
import me.lucko.luckperms.common.api.delegates.manager.ApiUserManager; 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.ApiMetaStackFactory;
import me.lucko.luckperms.common.api.delegates.misc.ApiNodeFactory; import me.lucko.luckperms.common.api.delegates.misc.ApiNodeFactory;
import me.lucko.luckperms.common.api.delegates.misc.ApiPlatformInfo; import me.lucko.luckperms.common.api.delegates.misc.ApiPlatformInfo;
@ -71,6 +71,7 @@ public class ApiProvider implements LuckPermsApi {
private final GroupManager groupManager; private final GroupManager groupManager;
private final TrackManager trackManager; private final TrackManager trackManager;
private final LuckPermsEventBus eventBus; private final LuckPermsEventBus eventBus;
private final ActionLogger actionLogger;
private final ContextManager contextManager; private final ContextManager contextManager;
private final MetaStackFactory metaStackFactory; private final MetaStackFactory metaStackFactory;
private final EventFactory eventFactory; private final EventFactory eventFactory;
@ -83,6 +84,7 @@ public class ApiProvider implements LuckPermsApi {
this.groupManager = new ApiGroupManager(plugin.getGroupManager()); this.groupManager = new ApiGroupManager(plugin.getGroupManager());
this.trackManager = new ApiTrackManager(plugin.getTrackManager()); this.trackManager = new ApiTrackManager(plugin.getTrackManager());
this.eventBus = new LuckPermsEventBus(plugin); this.eventBus = new LuckPermsEventBus(plugin);
this.actionLogger = new ApiActionLogger(plugin);
this.contextManager = new ApiContextManager(plugin, plugin.getContextManager()); this.contextManager = new ApiContextManager(plugin, plugin.getContextManager());
this.metaStackFactory = new ApiMetaStackFactory(plugin); this.metaStackFactory = new ApiMetaStackFactory(plugin);
this.eventFactory = new EventFactory(eventBus); this.eventFactory = new EventFactory(eventBus);
@ -137,6 +139,11 @@ public class ApiProvider implements LuckPermsApi {
return plugin.getMessagingService().map(Function.identity()); return plugin.getMessagingService().map(Function.identity());
} }
@Override
public ActionLogger getActionLogger() {
return actionLogger;
}
@Override @Override
public UuidCache getUuidCache() { public UuidCache getUuidCache() {
return plugin.getUuidCache().getDelegate(); return plugin.getUuidCache().getDelegate();
@ -157,8 +164,4 @@ public class ApiProvider implements LuckPermsApi {
return metaStackFactory; return metaStackFactory;
} }
@Override
public LogEntry.Builder newLogEntryBuilder() {
return ExtendedLogEntry.build();
}
} }

View File

@ -0,0 +1,67 @@
/*
* 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.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<Log> getLog() {
return plugin.getStorage().noBuffer().getLog().thenApply(log -> log == null ? null : new ApiLog(log));
}
@Override
public CompletableFuture<Void> submit(LogEntry entry) {
return CompletableFuture.runAsync(() -> plugin.getLogDispatcher().dispatchFromApi((ExtendedLogEntry) entry), plugin.getScheduler().async());
}
@Override
public CompletableFuture<Void> submitToStorage(LogEntry entry) {
return plugin.getStorage().noBuffer().logAction(entry);
}
@Override
public CompletableFuture<Void> broadcastAction(LogEntry entry) {
return CompletableFuture.runAsync(() -> plugin.getLogDispatcher().broadcastFromApi((ExtendedLogEntry) entry), plugin.getScheduler().async());
}
}

View File

@ -108,7 +108,7 @@ public abstract class HolderCachedData<T extends PermissionHolder> implements Ca
*/ */
private MetaCache calculateMeta(@NonNull MetaContexts contexts, MetaCache data) { private MetaCache calculateMeta(@NonNull MetaContexts contexts, MetaCache data) {
if (data == null) { if (data == null) {
data = new MetaCache(); data = new MetaCache(contexts);
} }
if (contexts.getContexts() == Contexts.allowAll()) { if (contexts.getContexts() == Contexts.allowAll()) {

View File

@ -27,13 +27,15 @@ package me.lucko.luckperms.common.caching.type;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor;
import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ListMultimap; 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.caching.MetaData;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.common.metastacking.MetaStack; import me.lucko.luckperms.common.metastacking.MetaStack;
@ -48,11 +50,16 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* Holds cached meta for a given context * Holds cached meta for a given context
*/ */
@Getter @Getter
@NoArgsConstructor @RequiredArgsConstructor
public class MetaCache implements MetaData { public class MetaCache implements MetaData {
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* The contexts this container is holding data for
*/
private final MetaContexts metaContexts;
private ListMultimap<String, String> metaMultimap = ImmutableListMultimap.of(); private ListMultimap<String, String> metaMultimap = ImmutableListMultimap.of();
private Map<String, String> meta = ImmutableMap.of(); private Map<String, String> meta = ImmutableMap.of();
private SortedMap<Integer, String> prefixes = ImmutableSortedMap.of(); private SortedMap<Integer, String> prefixes = ImmutableSortedMap.of();
@ -118,4 +125,9 @@ public class MetaCache implements MetaData {
return suffixStack.getDefinition(); return suffixStack.getDefinition();
} }
@Override
public Contexts getContexts() {
return metaContexts.getContexts();
}
} }

View File

@ -25,6 +25,7 @@
package me.lucko.luckperms.common.caching.type; package me.lucko.luckperms.common.caching.type;
import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.Contexts;
@ -44,6 +45,12 @@ import java.util.concurrent.ConcurrentHashMap;
*/ */
public class PermissionCache implements PermissionData { public class PermissionCache implements PermissionData {
/**
* The contexts this container is holding data for
*/
@Getter
private final Contexts contexts;
/** /**
* The raw set of permission strings. * The raw set of permission strings.
*/ */
@ -62,6 +69,7 @@ public class PermissionCache implements PermissionData {
private final PermissionCalculator calculator; private final PermissionCalculator calculator;
public PermissionCache(Contexts contexts, PermissionCalculatorMetadata metadata, CalculatorFactory calculatorFactory) { public PermissionCache(Contexts contexts, PermissionCalculatorMetadata metadata, CalculatorFactory calculatorFactory) {
this.contexts = contexts;
permissions = new ConcurrentHashMap<>(); permissions = new ConcurrentHashMap<>();
permissionsUnmodifiable = Collections.unmodifiableMap(permissions); permissionsUnmodifiable = Collections.unmodifiableMap(permissions);

View File

@ -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.CreationCause;
import me.lucko.luckperms.api.event.cause.DeletionCause; import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.api.event.log.LogBroadcastEvent; 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.EventConfigReload;
import me.lucko.luckperms.common.event.impl.EventGroupCacheLoad; import me.lucko.luckperms.common.event.impl.EventGroupCacheLoad;
import me.lucko.luckperms.common.event.impl.EventGroupCreate; 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.EventGroupLoadAll;
import me.lucko.luckperms.common.event.impl.EventLogBroadcast; import me.lucko.luckperms.common.event.impl.EventLogBroadcast;
import me.lucko.luckperms.common.event.impl.EventLogNetworkPublish; 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.EventLogPublish;
import me.lucko.luckperms.common.event.impl.EventLogReceive; import me.lucko.luckperms.common.event.impl.EventLogReceive;
import me.lucko.luckperms.common.event.impl.EventNodeAdd; import me.lucko.luckperms.common.event.impl.EventNodeAdd;
@ -142,6 +144,13 @@ public final class EventFactory {
return cancel.get(); 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) { public void handleLogReceive(UUID id, LogEntry entry) {
EventLogReceive event = new EventLogReceive(id, entry); EventLogReceive event = new EventLogReceive(id, entry);
fireEventAsync(event); fireEventAsync(event);

View File

@ -0,0 +1,93 @@
/*
* 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.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<UUID> 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();
}
}
}