View Javadoc

1   package com.atlassian.vcache.internal.legacy;
2   
3   import com.atlassian.cache.Cache;
4   import com.atlassian.vcache.JvmCache;
5   import com.atlassian.vcache.internal.core.RecursionDetector;
6   import com.atlassian.vcache.internal.core.service.LocalCacheUtils;
7   
8   import java.util.Arrays;
9   import java.util.HashSet;
10  import java.util.Map;
11  import java.util.Optional;
12  import java.util.Set;
13  import java.util.concurrent.locks.ReentrantLock;
14  import java.util.function.Function;
15  import java.util.function.Supplier;
16  
17  import static java.util.Objects.requireNonNull;
18  
19  /**
20   * Implementation of {@link JvmCache} that backs onto a legacy {@link Cache}.
21   *
22   * @param <K> the key type
23   * @param <V> the value type
24   * @since 1.0.0
25   */
26  class LegacyJvmCache<K, V> implements JvmCache<K, V> {
27      private final ReentrantLock globalLock = new ReentrantLock();
28      private final Cache<K, V> delegate;
29      private final RecursionDetector<K> recursionDetector = new RecursionDetector<>();
30  
31      LegacyJvmCache(Cache<K, V> delegate) {
32          this.delegate = requireNonNull(delegate);
33      }
34  
35      @Override
36      public Set<K> getKeys() {
37          return withLock(() -> new HashSet<>(delegate.getKeys()));
38      }
39  
40      @Override
41      public Optional<V> get(K key) {
42          return withLock(() -> Optional.ofNullable(delegate.get(key)));
43      }
44  
45      @Override
46      public V get(K key, Supplier<? extends V> supplier) {
47          try (RecursionDetector.Guard<K> ignored = recursionDetector.guardOn(key)) {
48              return withLock(() -> delegate.get(key, supplier::get));
49          }
50      }
51  
52      @SafeVarargs
53      @Override
54      public final Map<K, V> getBulk(Function<Set<K>, Map<K, V>> factory, K... keys) {
55          // This method needs to be final to prevent subclasses bypassing the locking enforced by this class.
56          return getBulk(factory, Arrays.asList(keys));
57      }
58  
59      @Override
60      public Map<K, V> getBulk(Function<Set<K>, Map<K, V>> factory, Iterable<K> keys) {
61          return withLock(() -> LocalCacheUtils.getBulk(
62                  factory,
63                  keys,
64                  this::get,
65                  args -> put(args.key, args.value),
66                  recursionDetector));
67      }
68  
69      @Override
70      public void put(K key, V value) {
71          withLock(() -> delegate.put(key, value));
72      }
73  
74      @Override
75      public Optional<V> putIfAbsent(K key, V value) {
76          return withLock(() -> Optional.ofNullable(delegate.putIfAbsent(key, value)));
77      }
78  
79      @Override
80      public boolean replaceIf(K key, V currentValue, V newValue) {
81          return withLock(() -> delegate.replace(key, currentValue, newValue));
82      }
83  
84      @Override
85      public boolean removeIf(K key, V value) {
86          return withLock(() -> delegate.remove(key, value));
87      }
88  
89      @Override
90      public void remove(K key) {
91          withLock(() -> delegate.remove(key));
92      }
93  
94      @Override
95      public void removeAll() {
96          withLock(delegate::removeAll);
97      }
98  
99      @Override
100     public String getName() {
101         return delegate.getName();
102     }
103 
104     private <R> R withLock(Supplier<R> supplier) {
105         globalLock.lock();
106         try {
107             return supplier.get();
108         } finally {
109             globalLock.unlock();
110         }
111     }
112 
113     private void withLock(Runnable runner) {
114         globalLock.lock();
115         try {
116             runner.run();
117         } finally {
118             globalLock.unlock();
119         }
120     }
121 }