001/*
002 * PermissionsEx
003 * Copyright (C) zml and PermissionsEx contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package ca.stellardrift.permissionsex.datastore;
018
019import ca.stellardrift.permissionsex.context.ContextInheritance;
020import ca.stellardrift.permissionsex.subject.ImmutableSubjectData;
021import ca.stellardrift.permissionsex.rank.RankLadder;
022import ca.stellardrift.permissionsex.subject.SubjectRef;
023import ca.stellardrift.permissionsex.subject.SubjectType;
024import org.checkerframework.checker.nullness.qual.Nullable;
025import org.spongepowered.configurate.util.UnmodifiableCollections;
026
027import java.util.Map;
028import java.util.Set;
029import java.util.concurrent.CompletableFuture;
030import java.util.function.Consumer;
031import java.util.function.Function;
032import java.util.stream.Stream;
033
034
035/**
036 * Data type abstraction for permissions data.
037 *
038 * <p>This is the low-level interface used by the engine for querying data. It should perform
039 * minimal caching, but is responsible for update notifications.</p>
040 *
041 * @since 2.0.0
042 */
043public interface DataStore {
044
045    /**
046     * Get the identifier that refers to this instance of the data store uniquely.
047     *
048     * <p>This is generally user-defined in the configuration.</p>
049     *
050     * @return The name of the current data store instance.
051     * @since 2.0.0
052     */
053    String name();
054
055    /**
056     * Get whether or not this is this data store's first run.
057     *
058     * <p>If this is the first run for a data store, PermissionsEx will try to populate
059     * it with default data.</p>
060     *
061     * @return if this is the first run
062     * @since 2.0.0
063     */
064    boolean firstRun();
065
066    /**
067     * Free any resources this data store may be using.
068     *
069     * @since 2.0.0
070     */
071    void close();
072
073    /**
074     * Loads the data at the specified type and identifier.
075     *
076     * <p>Implementations of this method do not need to perform any caching.</p>
077     *
078     * @param type The type of subject to get
079     * @param identifier The subject's identifier
080     * @param listener The update listener for this subject
081     * @return The relevant subject data
082     * @since 2.0.0
083     */
084    CompletableFuture<ImmutableSubjectData> getData(String type, String identifier, @Nullable Consumer<ImmutableSubjectData> listener);
085
086    /**
087     * Loads the data at the specified type and identifier.
088     *
089     * <p>Implementations of this method do not need to perform any caching.</p>
090     *
091     * @param subject The identity of the subject data is being set for
092     * @param listener The update listener for this subject
093     * @return The relevant subject data
094     * @since 2.0.0
095     */
096    default CompletableFuture<ImmutableSubjectData> getData(final SubjectRef<?> subject, final @Nullable Consumer<ImmutableSubjectData> listener) {
097        return getData(subject.type().name(), subject.serializedIdentifier(), listener);
098    }
099
100    /**
101     * Sets the data at the specified type and identifier.
102     *
103     * @param type The type of subject data is being fetched for
104     * @param identifier The identifier of the subject data is being fetched for
105     * @param data The data to commit to this backend. This being null deletes any data for the given identifier
106     * @return A future that can be used to listen for completion of writing the changed data
107     * @since 2.0.0
108     */
109    CompletableFuture<ImmutableSubjectData> setData(String type, String identifier, @Nullable ImmutableSubjectData data);
110    /**
111     * Sets the data at the specified type and identifier.
112     *
113     * @param subject The identity of the subject data is being set for
114     * @param data The data to commit to this backend. This being null deletes any data for the given subject
115     * @return A future that can be used to listen for completion of writing the changed data
116     * @since 2.0.0
117     */
118    default CompletableFuture<ImmutableSubjectData> setData(final SubjectRef<?> subject, final @Nullable ImmutableSubjectData data) {
119        return setData(subject.type().name(), subject.serializedIdentifier(), data);
120    }
121
122    /**
123     * Move data from one subject to another
124     *
125     * @param oldType The old subject's type
126     * @param oldIdentifier The old subject's identifier
127     * @param newType The new subject's type
128     * @param newIdentifier The new subject's identifier
129     * @return A future that will complete when the move is complete
130     * @since 2.0.0
131     */
132    CompletableFuture<Void> moveData(String oldType, String oldIdentifier, String newType, String newIdentifier);
133
134    /**
135     * Move data from one subject to another
136     *
137     * @param from the old subject
138     * @param to the new subject
139     * @return A future that will complete when the move is complete
140     * @since 2.0.0
141     */
142    default CompletableFuture<Void> moveData(final SubjectRef<?> from, final SubjectRef<?> to) {
143        return moveData(from.type().name(), from.serializedIdentifier(), to.type().name(), to.serializedIdentifier());
144    }
145
146    /**
147     * Return if the given subject has any data stored in this store.
148     *
149     * @param type The subject's type
150     * @param identifier The subject's identifier
151     * @return whether any data is stored
152     * @since 2.0.0
153     */
154    CompletableFuture<Boolean> isRegistered(String type, String identifier);
155
156    /**
157     * Return if the given subject has any data stored in this store.
158     *
159     * @param subject the subject to check
160     * @return whether any data is stored
161     * @since 2.0.0
162     */
163    default CompletableFuture<Boolean> isRegistered(final SubjectRef<?> subject) {
164        return isRegistered(subject.type().name(), subject.serializedIdentifier());
165    }
166
167    /**
168     * Get all data for subjects of the specified type. This {@link Stream} may be filled asynchronously
169     * @param type The type to get all data for
170     * @return An iterable providing data
171     * @since 2.0.0
172     */
173    Stream<Map.Entry<String, ImmutableSubjectData>> getAll(String type);
174
175    /**
176     * Get all data for subjects of the specified type. This {@link Stream} may be filled asynchronously.
177     *
178     * @param type The type to get all data for
179     * @return An iterable providing data
180     * @since 2.0.0
181     */
182     default <I> Stream<Map.Entry<I, ImmutableSubjectData>> getAll(final SubjectType<I> type) {
183         return this.getAll(type.name())
184                 .map(entry -> UnmodifiableCollections.immutableMapEntry(type.parseIdentifier(entry.getKey()), entry.getValue()));
185
186     }
187
188    /**
189     * Get all subject identifiers for subjects of the given type.
190     *
191     * @param type The type of subject to get identifiers for
192     * @return The registered identifiers of subjects of type {@code type}
193     * @since 2.0.0
194     */
195    Stream<String> getAllIdentifiers(String type);
196
197    /**
198     * Return all subject types that contain data
199     *
200     * @return The registered subject types
201     * @since 2.0.0
202     */
203    Set<String> getRegisteredTypes();
204
205    /**
206     * Enumerate all contexts defined within this data store
207     *
208     * @return The contexts available within this data store
209     * @since 2.0.0
210     */
211    CompletableFuture<Set<String>> getDefinedContextKeys();
212
213    /**
214     * Returns all subjects present in this data store
215     *
216     * @return An iterable containing all subjects
217     * @since 2.0.0
218     */
219    Stream<Map.Entry<SubjectRef<?>, ImmutableSubjectData>> getAll();
220
221    /**
222     * Perform a bulk operation on this data store. While this operation is in progress, all writes must be suppressed
223     * (meaning changes must be cached in memory until the operation is complete).
224     *
225     * Bulk operations may be executed asynchronously.
226     *
227     * @param <T> return value type
228     * @param function The function to call containing the operation.
229     * @return a future completing with the result of the operation or an error
230     * @since 2.0.0
231     */
232    <T> CompletableFuture<T> performBulkOperation(Function<DataStore, T> function);
233
234    /**
235     * Get all rank ladders.
236     *
237     * @return The names of all rank ladders
238     * @since 2.0.0
239     */
240    Stream<String> getAllRankLadders();
241
242    /**
243     * Get a specific rank ladder, with a possible update listener.
244     *
245     * @param ladder The ladder to get. Case-insensitive
246     * @param listener The listener to track possible updates
247     * @return the ladder
248     * @since 2.0.0
249     */
250    CompletableFuture<RankLadder> getRankLadder(String ladder, @Nullable Consumer<RankLadder> listener);
251
252    /**
253     * Whether a rank ladder by the given name is present.
254     *
255     * @param ladder The ladder to check. Case-insensitive
256     * @return Whether a ladder by the provided name exists
257     * @since 2.0.0
258     */
259    CompletableFuture<Boolean> hasRankLadder(String ladder);
260
261    /**
262     * Set the rank ladder at the given identifier.
263     *
264     * @param identifier The name of the ladder. Case-insensitive for overwriting existing ladders
265     * @param ladder The ladder to update
266     * @return a future tracking the status of this operation
267     * @since 2.0.0
268     */
269    CompletableFuture<RankLadder> setRankLadder(String identifier, @Nullable RankLadder ladder);
270
271    /**
272     * Get context inheritance information.
273     *
274     * @param inheritance The listener to notify about changes
275     * @return A future that will supply context inheritance
276     * @since 2.0.0
277     */
278    CompletableFuture<ContextInheritance> getContextInheritance(@Nullable Consumer<ContextInheritance> inheritance);
279
280    /**
281     * Uppdate the stored context inheritance information.
282     *
283     * @param inheritance inheritance to apply
284     * @return a future completing with the previous inheritance data
285     * @since 2.0.0
286     */
287    CompletableFuture<ContextInheritance> setContextInheritance(ContextInheritance inheritance);
288}
289