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