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.google.common.base.Objects;
022import com.google.common.base.Preconditions;
023import com.google.inject.TypeLiteral;
024import com.plotsquared.core.synchronization.LockKey;
025import org.checkerframework.checker.nullness.qual.NonNull;
026
027import java.util.HashMap;
028import java.util.Map;
029
030/**
031 * Key used to access meta data
032 *
033 * @param <T> Meta data type
034 */
035public final class MetaDataKey<T> {
036
037    private static final Map<String, MetaDataKey<?>> keyMap = new HashMap<>();
038    private static final Object keyMetaData = new Object();
039
040    private final String key;
041    private final TypeLiteral<T> type;
042    private final LockKey lockKey;
043
044    private MetaDataKey(final @NonNull String key, final @NonNull TypeLiteral<T> type) {
045        this.key = Preconditions.checkNotNull(key, "Key may not be null");
046        this.type = Preconditions.checkNotNull(type, "Type may not be null");
047        this.lockKey = LockKey.of(this.key);
048    }
049
050    /**
051     * Get a new named lock key
052     *
053     * @param key  Key name
054     * @param type type
055     * @param <T>  Type
056     * @return MetaData key instance
057     */
058    @SuppressWarnings("unchecked")
059    public static @NonNull <T> MetaDataKey<T> of(final @NonNull String key, final @NonNull TypeLiteral<T> type) {
060        synchronized (keyMetaData) {
061            return (MetaDataKey<T>)
062                    keyMap.computeIfAbsent(key, missingKey -> new MetaDataKey<>(missingKey, type));
063        }
064    }
065
066    @Override
067    public String toString() {
068        return this.key;
069    }
070
071    @Override
072    public boolean equals(final Object o) {
073        if (this == o) {
074            return true;
075        }
076        if (o == null || getClass() != o.getClass()) {
077            return false;
078        }
079        final MetaDataKey<?> lockKey = (MetaDataKey<?>) o;
080        return Objects.equal(this.key, lockKey.key);
081    }
082
083    @Override
084    public int hashCode() {
085        return Objects.hashCode(this.key);
086    }
087
088    /**
089     * Get the {@link LockKey} associated with this key
090     *
091     * @return Lock key
092     */
093    public @NonNull LockKey getLockKey() {
094        return this.lockKey;
095    }
096
097    /**
098     * Get the meta data type
099     *
100     * @return Meta data type
101     */
102    public @NonNull TypeLiteral<T> getType() {
103        return this.type;
104    }
105
106}