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.impl.util;
018
019import com.github.benmanes.caffeine.cache.Caffeine;
020
021import java.util.Collections;
022import java.util.Set;
023import java.util.concurrent.ConcurrentHashMap;
024import java.util.concurrent.ConcurrentMap;
025import java.util.function.Consumer;
026
027import static java.util.Objects.requireNonNull;
028
029/**
030 *  Tracks object listeners for a cache
031 *
032 * @param <Key> The cache key type
033 * @param <CacheType> The cache value type
034 */
035public class CacheListenerHolder<Key, CacheType> {
036    private final ConcurrentMap<Key, Set<Consumer<CacheType>>> listeners = new ConcurrentHashMap<>();
037
038    private Set<Consumer<CacheType>> getListeners(Key key) {
039        requireNonNull(key, "key");
040        return this.listeners.computeIfAbsent(key, k -> Collections.newSetFromMap(Caffeine.newBuilder().weakKeys().<Consumer<CacheType>, Boolean>build().asMap()));
041    }
042
043    public void call(Key key, CacheType newData) {
044        requireNonNull(key, "key");
045        requireNonNull(newData, "newData");
046
047        for (Consumer<CacheType> listener : getListeners(key)) {
048            listener.accept(newData);
049        }
050    }
051
052    public void addListener(Key key, Consumer<CacheType> listener) {
053        requireNonNull(key, "key");
054        requireNonNull(listener, "listener");
055
056        getListeners(key).add(listener);
057    }
058
059    public void removeListener(Key key, Consumer<CacheType> listener) {
060        requireNonNull(key, "key");
061        requireNonNull(listener, "listener");
062
063        getListeners(key).remove(listener);
064    }
065
066    public Iterable<Key> getAllKeys() {
067        return Collections.unmodifiableSet(this.listeners.keySet());
068    }
069
070    public void removeAll(Key key) {
071        this.listeners.remove(key);
072    }
073}