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.context.ContextValue;
020import ca.stellardrift.permissionsex.util.Change;
021import io.leangen.geantyref.TypeToken;
022import org.immutables.value.Value;
023
024import java.util.Set;
025import java.util.concurrent.CompletableFuture;
026import java.util.function.Consumer;
027import java.util.function.UnaryOperator;
028
029/**
030 * A reference to a specific subject.
031 *
032 * @param <I> identifier type
033 * @since 2.0.0
034 */
035@Value.Immutable(builder = false)
036public interface SubjectRef<I> {
037    TypeToken<SubjectRef<?>> TYPE = new TypeToken<SubjectRef<?>>() {};
038
039    /**
040     * Create a new subject reference.
041     *
042     * @param type the subject type's collection
043     * @param identifier the subject's identifier
044     * @param <I> the identifier type
045     * @return a new subject reference
046     * @since 2.0.0
047     */
048    static <I> SubjectRef<I> subject(final SubjectTypeCollection<I> type, final I identifier) {
049        return new SubjectRefImpl<>(type.type(), identifier);
050    }
051
052    /**
053     * Create a new subject reference.
054     *
055     * @param type the subject's type
056     * @param identifier the subject's identifier
057     * @param <I> the identifier type
058     * @return a new subject reference
059     * @since 2.0.0
060     */
061    static <I> SubjectRef<I> subject(final SubjectType<I> type, final I identifier) {
062        return new SubjectRefImpl<>(type, identifier);
063    }
064
065    /**
066     * Return a sanitized subject reference that can safely be used as a map key.
067     *
068     * @param existing the existing reference
069     * @param <I> the identifier type
070     * @return a sanitized reference
071     * @since 2.0.0
072     */
073    static <I> SubjectRef<I> mapKeySafe(final SubjectRef<I> existing) {
074        return SubjectRefImpl.copyOf(existing);
075    }
076
077    /**
078     * The subject's type.
079     *
080     * @return the type referred to.
081     * @since 2.0.0
082     */
083    @Value.Parameter
084    SubjectType<I> type();
085
086    /**
087     * An identifier.
088     *
089     * @return the subject identifier
090     * @since 2.0.0
091     */
092    @Value.Parameter
093    I identifier();
094
095    /**
096     * Compute the serialized form of the identifier.
097     *
098     * @return the canonical serialized form of the subject identifier
099     */
100    default String serializedIdentifier() {
101        return this.type().serializeIdentifier(this.identifier());
102    }
103
104    /**
105     * A resolved reference to a subject's data in a specific collection.
106     *
107     * @param <I> identifier type
108     * @since 2.0.0
109     */
110    interface ToData<I> extends SubjectRef<I> {
111        /**
112         * Get the current subject data.
113         *
114         * @return The current data
115         * @since 2.0.0
116         */
117        ImmutableSubjectData get();
118
119        /**
120         * Update the contained data based on the result of a function.
121         *
122         * @param modifierFunc The function that will be called to update the data
123         * @return A future completing when data updates have been written to the data store
124         * @since 2.0.0
125         */
126        CompletableFuture<Change<ImmutableSubjectData>> update(UnaryOperator<ImmutableSubjectData> modifierFunc);
127
128        /**
129         * Update a single segment of the contained data based on the provided operator.
130         *
131         * @param contexts the contexts to update in
132         * @param modifierFunc the function that will be called to update the data
133         * @return A future completing when data updates have been written to the data store
134         * @since 2.0.0
135         */
136        default CompletableFuture<Change<ImmutableSubjectData>> update(final Set<ContextValue<?>> contexts, UnaryOperator<Segment> modifierFunc) {
137            return this.update(data -> data.withSegment(contexts, modifierFunc));
138        }
139
140        /**
141         * Get whether or not this reference will hold strong references to stored listeners.
142         * If the return value  is false, registering a listener object with this reference will
143         * not prevent it from being garbage collected, so the listener must be held somewhere
144         * else for it to continue being called.
145         *
146         * @return Whether or not listeners are held strongly.
147         * @since 2.0.0
148         */
149        boolean holdsListenersStrongly();
150
151        /**
152         * Register a listener to be called when an update is performed.
153         *
154         * @param listener The listener to register
155         * @since 2.0.0
156         */
157        void onUpdate(Consumer<ImmutableSubjectData> listener);
158
159        /**
160         * Confirm whether or not the subject data referenced is actually registered.
161         *
162         * @return a future completing with registration state
163         * @since 2.0.0
164         */
165        CompletableFuture<Boolean> isRegistered();
166
167        /**
168         * Remove the subject data referenced.
169         *
170         * @return A future completing with the previous data for this subject.
171         * @see SubjectDataCache#remove(Object)
172         * @since 2.0.0
173         */
174        CompletableFuture<ImmutableSubjectData> remove();
175    }
176}