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.subject;
018
019import ca.stellardrift.permissionsex.datastore.DataStore;
020import org.checkerframework.checker.nullness.qual.Nullable;
021
022import java.util.concurrent.CompletableFuture;
023import java.util.function.Consumer;
024import java.util.function.UnaryOperator;
025import java.util.stream.Stream;
026
027/**
028 * A cached view of the subject data within a particular {@link DataStore}.
029 *
030 * <p>Provides operations to manage querying, writing, and updating
031 * {@link ImmutableSubjectData} objects.</p>
032 *
033 * @since 2.0.0
034 */
035public interface SubjectDataCache<I> {
036    /**
037     * Get the subject type for this cache.
038     *
039     * @return the subject type this cache contains data for
040     * @since 2.0.0
041     */
042    SubjectType<I> type();
043
044    /**
045     * Get data for a given subject.
046     *
047     * <p>This will return a data object even if the subject is not registered; the data object will
048     * just be empty.</p>
049     *
050     * <p>For most longer-lifetime use cases, {@link #referenceTo(Object)} will be the preferred
051     * method to get a reference to the latest subject data.</p>
052     *
053     * @param identifier The identifier of the subject to query
054     * @param listener A callback that will be notified whenever a change is made to the data object
055     * @return A future returning when the data is available
056     */
057    CompletableFuture<ImmutableSubjectData> data(final I identifier, final @Nullable Consumer<ImmutableSubjectData> listener);
058
059    /**
060     * Get a reference to subject data for a given subject. The reference will update as changes are made to the backing
061     * data store, and can always be used to query a specific subject's raw data.
062     *
063     * @param identifier The identifier of the subject to get data for
064     * @return A future returning with a full reference to the given subject's data.
065     */
066    CompletableFuture<? extends SubjectRef.ToData<I>> referenceTo(final I identifier);
067
068    /**
069     * Get a reference to subject data for a given subject
070     *
071     * @param identifier The identifier of the subject to get data for
072     * @param strongListeners Whether to hold listeners to this subject data even after they would be otherwise GC'd
073     * @return A future completing with the subject data reference
074     */
075    CompletableFuture<? extends SubjectRef.ToData<I>> referenceTo(final I identifier, boolean strongListeners);
076
077    /**
078     * Update data for a given subject, acting on the latest data available.
079     * The {@code action} callback may be called within an asynchronous task.
080     *
081     * @param identifier The identifier of the subject to be updated
082     * @param action     A function taking an old subject data instance and returning an updated one
083     * @return A future completing with the latest subject data after modifications are made
084     */
085    CompletableFuture<ImmutableSubjectData> update(final I identifier, final UnaryOperator<ImmutableSubjectData> action);
086
087    /**
088     * Load data (if any) known for the given identifier
089     *
090     * @param identifier The subject identifier
091     */
092    void load(final I identifier);
093
094    /**
095     * Remove a given subject identifier from the cache
096     *
097     * @param identifier The identifier of the subject to be removed
098     */
099    void invalidate(final I identifier);
100
101    /**
102     * Enter all subjects of this type into cache
103     */
104    void cacheAll();
105
106    /**
107     * Check if a given subject is registered. This operation occurs asynchronously
108     * Registered means that a subject has any sort of data stored.
109     *
110     * @param identifier The identifier of the subject to check
111     * @return A future returning whether the subject has data stored
112     */
113    CompletableFuture<Boolean> isRegistered(final I identifier);
114
115    /**
116     * Remove a subject from the backing data store
117     *
118     * @param identifier The identifier of the subject to remove
119     * @return A future returning the previous subject data.
120     */
121    CompletableFuture<ImmutableSubjectData> remove(final I identifier);
122
123    /**
124     * Set the data for {@code identifier}.
125     *
126     * @param identifier identifier of the target subject
127     * @param newData data to set for the subject, {@code null} to clear all data.
128     * @return a future completing with the newly set subject data.
129     */
130    CompletableFuture<ImmutableSubjectData> set(final I identifier, final @Nullable ImmutableSubjectData newData);
131
132    /**
133     * Add a listener to be notified on updates to the given subject
134     *
135     * @param identifier The identifier of the subject to receive notifications about
136     * @param listener The callback function to notify
137     */
138    void addListener(final I identifier, final Consumer<ImmutableSubjectData> listener);
139
140    /**
141     * Get a set of identifiers for all registered subjects of this type
142     *
143     * @return The set of identifiers
144     */
145    Stream<I> getAllIdentifiers();
146
147    /**
148     * Get the identifier for the subject holding default data for subjects of this type
149     *
150     * @return The id for the default subject of this type
151     */
152    SubjectRef<String> getDefaultIdentifier();
153}