001package com.identityworksllc.iiq.common.cache; 002 003import java.util.Objects; 004import java.util.Optional; 005import java.util.function.BiPredicate; 006 007/** 008 * A cache value wrapper that allows access based on matching an 009 * arbitrary guard value. If the guard value is not matched, the 010 * {@link #getValue(Object)} method returns an empty Optional. 011 * 012 * This can be used, for example, to detect changes to permissions 013 * or logged in users and clear the cache accordingly. 014 * 015 * @param <ValueType> The type of the thing being stored here 016 * @param <GuardType> The type of the guard value 017 */ 018public class GuardedCacheValue<ValueType, GuardType> { 019 020 /** 021 * The value that must be matched for the value to return 022 */ 023 private final GuardType guardToken; 024 025 /** 026 * The token value matcher 027 */ 028 private final BiPredicate<GuardType, GuardType> matcher; 029 030 /** 031 * The actual value wrapped by this object 032 */ 033 private final ValueType value; 034 035 /** 036 * Constructs a new cache value with the given token and value. The token 037 * will be matched using Object.equals. 038 * 039 * @param value The value wrapped by this cache token 040 * @param token The token that must be matched to retrieve the value 041 */ 042 public GuardedCacheValue(ValueType value, GuardType token) { 043 this(value, token, Object::equals); 044 } 045 046 /** 047 * Constructs a new cache value with the given token, value, and token 048 * matcher. At getValue time, the matcher will be used to decide whether 049 * the input actually matches the token. 050 * 051 * @param value The value wrapped by this cache token 052 * @param token The token that must be matched to retrieve the value 053 * @param matcher The predicate that decides whether the input token matches 054 */ 055 public GuardedCacheValue(ValueType value, GuardType token, BiPredicate<GuardType, GuardType> matcher) { 056 this.value = Objects.requireNonNull(value); 057 this.guardToken = Objects.requireNonNull(token); 058 059 if (matcher == null) { 060 this.matcher = Objects::equals; 061 } else { 062 this.matcher = matcher; 063 } 064 } 065 066 /** 067 * 068 * @param guardTest The guard test value 069 * @return An optional containing the stored value, if the guard value input matches, or else an empty optional object 070 */ 071 public Optional<ValueType> getValue(GuardType guardTest) { 072 if (this.matcher.test(guardTest, guardToken)) { 073 return Optional.of(value); 074 } else { 075 return Optional.empty(); 076 } 077 } 078}