001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.player;
020
021import com.plotsquared.core.synchronization.LockRepository;
022import org.checkerframework.checker.nullness.qual.NonNull;
023import org.checkerframework.checker.nullness.qual.Nullable;
024
025import java.util.Optional;
026
027/**
028 * Access to player meta data
029 *
030 * @param <T> Meta data type
031 */
032public abstract class MetaDataAccess<T> implements AutoCloseable {
033
034    private final PlotPlayer<?> player;
035    private final MetaDataKey<T> metaDataKey;
036    private final LockRepository.LockAccess lockAccess;
037    private boolean closed = false;
038
039    MetaDataAccess(
040            final @NonNull PlotPlayer<?> player,
041            final @NonNull MetaDataKey<T> metaDataKey,
042            final LockRepository.@NonNull LockAccess lockAccess
043    ) {
044        this.player = player;
045        this.metaDataKey = metaDataKey;
046        this.lockAccess = lockAccess;
047    }
048
049    @SuppressWarnings("unchecked")
050    private static <E extends Throwable> void sneakyThrow(final Throwable e) throws E {
051        throw (E) e;
052    }
053
054    /**
055     * Check if the player has meta data stored with the given key
056     *
057     * @return {@code true} if player has meta data with this key, or
058     *         {@code false}
059     */
060    public abstract boolean isPresent();
061
062    /**
063     * Remove the stored value meta data
064     *
065     * @return Old value, or {@code null}
066     */
067    public @Nullable
068    abstract T remove();
069
070    /**
071     * Set the meta data value
072     *
073     * @param value New value
074     */
075    public abstract void set(final @NonNull T value);
076
077    /**
078     * Get the stored meta data value
079     *
080     * @return Stored value, or {@link Optional#empty()}
081     */
082    public @NonNull
083    abstract Optional<T> get();
084
085    @Override
086    public final void close() {
087        this.lockAccess.close();
088        this.closed = true;
089    }
090
091    /**
092     * Get the owner of the meta data
093     *
094     * @return Player
095     */
096    public @NonNull PlotPlayer<?> getPlayer() {
097        return this.player;
098    }
099
100    /**
101     * Get the meta data key
102     *
103     * @return Meta data key
104     */
105    public @NonNull MetaDataKey<T> getMetaDataKey() {
106        return this.metaDataKey;
107    }
108
109    /**
110     * Check whether or not the meta data access has been closed.
111     * After being closed, all attempts to access the meta data
112     * through the instance, will lead to {@link IllegalAccessException}
113     * being thrown
114     *
115     * @return {@code true} if the access has been closed
116     */
117    public boolean isClosed() {
118        return this.closed;
119    }
120
121    protected void checkClosed() {
122        if (this.closed) {
123            sneakyThrow(new IllegalAccessException("The meta data access instance has been closed"));
124        }
125    }
126
127
128}