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.uuid;
020
021import com.google.common.cache.Cache;
022import com.google.common.cache.CacheBuilder;
023import org.checkerframework.checker.nullness.qual.NonNull;
024import org.checkerframework.checker.nullness.qual.Nullable;
025
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.Collections;
029import java.util.List;
030import java.util.UUID;
031import java.util.function.Consumer;
032
033/**
034 * UUID service backed by a Guava Cache
035 */
036public class CacheUUIDService implements UUIDService, Consumer<List<UUIDMapping>> {
037
038    private final Cache<String, UUIDMapping> usernameCache;
039    private final Cache<UUID, UUIDMapping> uuidCache;
040
041    /**
042     * Construct a new Cache UUID service with a maximum number of entries.
043     * Because it stores the mappings in two ways, the actual number
044     * of entries is two times the specified size
045     *
046     * @param size Maximum number of entries
047     */
048    public CacheUUIDService(final int size) {
049        this.usernameCache = CacheBuilder.newBuilder().maximumSize(size).build();
050        this.uuidCache = CacheBuilder.newBuilder().maximumSize(size).build();
051    }
052
053    @Override
054    public @NonNull List<UUIDMapping> getNames(final @NonNull List<@NonNull UUID> uuids) {
055        final List<UUIDMapping> mappings = new ArrayList<>(uuids.size());
056        mappings.addAll(this.uuidCache.getAllPresent(uuids).values());
057        return mappings;
058    }
059
060    @Override
061    public @NonNull List<UUIDMapping> getUUIDs(final @NonNull List<@NonNull String> usernames) {
062        final List<UUIDMapping> mappings = new ArrayList<>(usernames.size());
063        mappings.addAll(this.usernameCache.getAllPresent(usernames).values());
064        return mappings;
065    }
066
067    @Override
068    public void accept(final @NonNull List<@NonNull UUIDMapping> uuidMappings) {
069        for (final UUIDMapping mapping : uuidMappings) {
070            this.uuidCache.put(mapping.uuid(), mapping);
071            this.usernameCache.put(mapping.username(), mapping);
072        }
073    }
074
075    @Override
076    public @NonNull Collection<@NonNull UUIDMapping> getImmediately() {
077        return this.usernameCache.asMap().values();
078    }
079
080    @Override
081    public boolean canBeSynchronous() {
082        return true;
083    }
084
085    @Override
086    public @Nullable UUIDMapping getImmediately(final @NonNull Object object) {
087        final List<UUIDMapping> list;
088        if (object instanceof String) {
089            list = getUUIDs(Collections.singletonList((String) object));
090        } else if (object instanceof UUID) {
091            list = getNames(Collections.singletonList((UUID) object));
092        } else {
093            list = Collections.emptyList();
094        }
095        if (list.isEmpty()) {
096            return null;
097        }
098        return list.get(0);
099    }
100
101}