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}