org.spongepowered.api.service.permission.SubjectCollection Maven / Gradle / Ivy
Show all versions of spongeapi Show documentation
/*
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered
* 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 org.spongepowered.api.service.permission;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.service.context.Context;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* An object which manages subjects of a certain type (user, group, etc).
*
* A distinction is made between subjects which exist and are loaded, and
* subjects which exist but are not currently loaded into memory. The methods to
* "load" data return {@link CompletableFuture}s, and will load the data into
* memory if it isn't already loaded. The methods to "get" data return
* {@link Optional}s, which will only be filled if the data is currently
* loaded.
*
* Note: the default subject must already be cached when the subject
* collection is fetched.
*
* When Subjects are loaded, it may not be necessary to load data about all
* parent subjects immediately, however, lookups should still honour inheritance
* rules.
*/
public interface SubjectCollection {
/**
* Return the identifier for this collection.
*
* @return The identifier
*/
String identifier();
/**
* Returns a predicate which determines whether or not a given identifier is
* valid for a subject held by this collection.
*
* It is expected that the {@link PermissionService#SUBJECTS_USER}
* collection should accept identifiers in UUID RFC4122 string format. (In
* the format produced by {@link UUID#toString()}
*
* @return The predicate
*/
Predicate identifierValidityPredicate();
/**
* Loads and returns a subject with the given identifier.
*
* The returned future will complete exceptionally if the subject with
* the given identifier cannot be loaded.
*
* A {@link IllegalArgumentException} will be thrown directly by this
* method if the identifier does not pass the identifier validity
* predicate.
*
* @param identifier The identifier. All identifiers are case-insensitive
* @return A subject for the given identifier
* @throws IllegalArgumentException If the subject identifier does not pass
* the validity predicate for this
* collection.
*/
CompletableFuture extends Subject> loadSubject(String identifier);
/**
* Returns a subject with the given identifier, if the subject is already
* loaded within this collection.
*
* It is important to note that a subject with the given identifier
* may still exist, even if this method returns an empty
* optional. Checking for the presence of a subject should be
* done using {@link #hasSubject(String)}.
*
* If the subject identifier does not pass the validity predicate, this
* method will return an empty optional, and not throw an exception.
*
* @param identifier The identifier
* @return A subject for the given identifier
*/
Optional extends Subject> subject(String identifier);
/**
* Returns whether a subject with the given identifier currently exists.
*
* The return value of this function does not influence whether or
* not the results from any subject lookups should be obtained.
*
* @param identifier The identifier of the subject
* @return If the subject currently exists
*/
CompletableFuture hasSubject(String identifier);
/**
* Gets a map of subjects from the provided set of identifiers.
*
* If any of the identifiers do not pass the collections
* {@link #identifierValidityPredicate()}, a subject will not be returned
* for that identifier.
*
* @param identifiers A set of identifiers to get subjects for
* @return a map of subjects corresponding to the identifiers passed
*/
CompletableFuture extends Map> loadSubjects(Iterable identifiers);
/**
* Returns an immutable copy of all subjects currently loaded in this
* collection.
*
* @return A collection containing the subjects currently loaded into this
* subject collection.
*/
Collection extends Subject> loadedSubjects();
/**
* Gets a set of Subject identifiers being stored in the collection. This
* method must return a complete list, including identifiers of subjects not
* currently loaded.
*
* The results of this method should not be passed directly to
* {@link #loadSubjects(Iterable)}. Instead, each individual subject should be
* loaded, processed, and then allowed to be unloaded using
* {@link #suggestUnload(String)}.
*
* If you simply need to process each subject in the collection, you can
* use {@link #applyToAll(Consumer)} and gather data.
*
* @return A set containing the identifiers of every Subject in this
* collection
*/
CompletableFuture extends Set> allIdentifiers();
/**
* Creates a new subject reference to represent the expressed subject.
*
* Note that instances of SubjectReference must be capable of resolving
* the identifier to a Subject without being passed a reference to the
* service.
*
* A {@link IllegalArgumentException} will be thrown directly by this
* method if the identifier does not pass the identifier validity
* predicate.
*
* @param subjectIdentifier The identifier of the subject
* @return A subject reference to represent the expressed subject
* @throws IllegalArgumentException If the subject identifier does not pass
* the validity predicate for this
* collection.
*/
SubjectReference newSubjectReference(String subjectIdentifier);
/**
* Performs an action on each Subject in the collection.
*
* Subjects are loaded, supplied to the consumer, and then allowed to be
* uncached by the implementation.
*
* This should be used to apply bulk changes or gather data about all
* Subjects in the collection. The provided consumer will be supplied
* asynchronously. Acting upon a large collection may be particularly
* resource intensive.
*
* Implementations may choose to load and process subjects in
* parallel.
*
* @param action The action to perform on each subject
* @return A future which will complete when the operation has finished
*/
default CompletableFuture applyToAll(final Consumer action) {
Objects.requireNonNull(action, "action");
return CompletableFuture.runAsync(() -> {
final Set identifiers = this.allIdentifiers().join();
this.applyToAll(identifiers, action).join();
});
}
/**
* Performs an action on each Subject in the provided set.
*
* Subjects are loaded, supplied to the consumer, and then allowed to be
* uncached by the implementation.
*
* This should be used to apply bulk changes or gather data about all
* Subjects in the collection. The provided consumer will be supplied
* asynchronously. Acting upon a large collection may be particularly
* resource intensive.
*
* Implementations may choose to load and process subjects in
* parallel.
*
* @param identifiers a set of identifiers to apply the action to
* @param action The action to perform on each subject
* @return A future which will complete when the operation has finished
*/
default CompletableFuture applyToAll(final Iterable identifiers, final Consumer action) {
Objects.requireNonNull(action, "action");
Objects.requireNonNull(identifiers, "identifiers");
return CompletableFuture.runAsync(() -> {
for (final String id : identifiers) {
final Subject subject = this.loadSubject(id).join();
action.accept(subject);
this.suggestUnload(subject.identifier());
}
});
}
/**
* Return the identifiers of all known subjects with the given permission
* set.
*
* This method DOES NOT consider inheritance, and will
* only query the data set to the subjects {@link Subject#subjectData()}.
* Transient data is not considered.
*
* As no context is passed, it is up to the implementation to decide
* which contexts to use. When available, it is likely that
* {@link SubjectData#GLOBAL_CONTEXT} will be used.
* Contexts will be extracted from the current cause for each lookup.
*
* @param permission The permission to check
* @return A reference to any subject known to have this permission
* set, and the value this permission is set to
*/
CompletableFuture extends Map extends SubjectReference, Boolean>> allWithPermission(String permission);
/**
* Return the identifiers of all known subjects with the given permission
* set.
*
* This method DOES NOT consider inheritance, and will only query
* the data set to the subjects {@link Subject#subjectData()}. Transient
* data is not considered.
*
* @param permission The permission to check
* @param cause The cause to extract context information from
* @return A reference to any subject known to have this permission
* set, and the value this permission is set to
*/
CompletableFuture extends Map extends SubjectReference, Boolean>> allWithPermission(String permission, Cause cause);
/**
* Return all loaded subjects with the given permission set.
*
* This method DOES NOT consider inheritance, and will only query
* the data set to the subjects {@link Subject#subjectData()}. Transient
* data is not considered.
*
* Contexts will be extracted from the current cause for each lookup.
*
* @param permission The permission to check
* @return A map containing any subject known to have this permission set,
* and the value this permission is set to
*/
Map extends Subject, Boolean> loadedWithPermission(String permission);
/**
* Return all loaded subjects with the given permission set.
*
* This method DOES NOT consider inheritance, and will only query
* the data set to the subjects {@link Subject#subjectData()}. Transient
* data is not considered.
*
* @param permission The permission to check
* @param cause The cause to extract context information from
* @return A map containing any subject known to have this permission set,
* and the value this permission is set to
*/
Map extends Subject, Boolean> loadedWithPermission(String permission, Cause cause);
/**
* Gets the subject holding data that is applied by default to all
* subjects in this collection.
*
* This subject is at the root of all inheritance trees for subjects in
* this collection, but at a higher priority chan defaults expressed to
* {@link PermissionService#defaults()}.
*
* Note: This data may be persisted, so plugins that add
* permissions to this subject must take care to not override
* permissions already set or modified.
*
* It is also recommended to use
* {@link Subject#transientSubjectData()} where possible to avoid
* persisting unnecessary data.
*
* Assigning default permissions should be used sparingly, and by
* convention, only in situations where "default" game behaviour is restored
* by granting a certain permission.
*
* @return The subject holding defaults for this collection
*/
Subject defaults();
/**
* Indicate that a certain subject may be unloaded by the implementation.
*
* This is only a hint to the implementation, and does not guarantee that
* the subject will be unloaded.
*
* @param identifier The subject to be unloaded
*/
void suggestUnload(String identifier);
}