View Javadoc
1   package com.atlassian.cache.vcache;
2   
3   import java.io.Serializable;
4   import java.util.Collection;
5   import java.util.Optional;
6   import java.util.concurrent.CompletionException;
7   import javax.annotation.Nonnull;
8   import javax.annotation.Nullable;
9   
10  import com.atlassian.cache.Cache;
11  import com.atlassian.cache.CacheEntryListener;
12  import com.atlassian.cache.CacheException;
13  import com.atlassian.cache.CacheLoader;
14  import com.atlassian.cache.CacheSettings;
15  import com.atlassian.cache.Supplier;
16  import com.atlassian.vcache.DirectExternalCache;
17  import com.atlassian.vcache.IdentifiedValue;
18  import com.atlassian.vcache.PutPolicy;
19  
20  import static com.atlassian.cache.vcache.Utils.asSerializable;
21  import static com.atlassian.cache.vcache.Utils.asString;
22  import static com.atlassian.vcache.VCacheUtils.fold;
23  import static com.atlassian.vcache.VCacheUtils.join;
24  import static java.util.Objects.requireNonNull;
25  
26  class ExternalCacheDelegate<K, V>
27          extends ManagedCacheSupport
28          implements Cache<K, V>
29  {
30      private final DirectExternalCache<Serializable> delegate;
31      private final CacheLoader<String, Serializable> cacheLoader;
32  
33      public ExternalCacheDelegate(
34              String name,
35              DirectExternalCache<Serializable> delegate,
36              @Nullable CacheLoader<String, Serializable> cacheLoader,
37              CacheSettings settings)
38      {
39          super(name, settings);
40          this.delegate = requireNonNull(delegate);
41          this.cacheLoader = cacheLoader;
42      }
43  
44      @Override
45      public void clear()
46      {
47          join(delegate.removeAll());
48      }
49  
50      @Override
51      public boolean isLocal()
52      {
53          return false;
54      }
55  
56      @Override
57      public boolean containsKey(@Nonnull K key)
58      {
59          return join(delegate.get(asString(key))).isPresent();
60      }
61  
62      @Nonnull
63      @Override
64      public Collection<K> getKeys()
65      {
66          throw new UnsupportedOperationException("Not supported on non-local caches");
67      }
68  
69      @Nullable
70      @Override
71      public V get(@Nonnull K key)
72      {
73          final String strKey = asString(key);
74          try
75          {
76              if (cacheLoader == null)
77              {
78                  return (V) join(delegate.get(strKey)).orElse(null);
79              }
80              else
81              {
82                  return (V) join(delegate.get(strKey, () -> asSerializable(cacheLoader.load(strKey))));
83              }
84          }
85          catch (CompletionException ce)
86          {
87              throw new CacheException(ce);
88          }
89      }
90  
91      @Nonnull
92      @Override
93      public V get(@Nonnull K key, @Nonnull Supplier<? extends V> valueSupplier)
94      {
95          return (V) join(delegate.get(asString(key), () -> asSerializable(valueSupplier.get())));
96      }
97  
98      @Override
99      public void put(@Nonnull K key, @Nonnull V value)
100     {
101         fold(delegate.put(asString(key), asSerializable(value), PutPolicy.PUT_ALWAYS),
102                 success -> success,
103                 failure -> {
104                     throw new CacheException("put() operation failed", failure);
105                 });
106     }
107 
108     @Nullable
109     @Override
110     public V putIfAbsent(@Nonnull K key, @Nonnull V value)
111     {
112         for (; ; )
113         {
114             final Optional<Serializable> current = join(delegate.get(asString(key)));
115             if (current.isPresent())
116             {
117                 return (V) current.get();
118             }
119             else
120             {
121                 final boolean added = join(delegate.put(asString(key), asSerializable(value), PutPolicy.ADD_ONLY));
122                 if (added)
123                 {
124                     return null; // We are happy chaps
125                 }
126             }
127         }
128     }
129 
130     @Override
131     public void remove(@Nonnull K key)
132     {
133         join(delegate.remove(asString(key)));
134     }
135 
136     @Override
137     public boolean remove(@Nonnull K key, @Nonnull V value)
138     {
139         for (; ; )
140         {
141             final Optional<IdentifiedValue<Serializable>> current = join(delegate.getIdentified(asString(key)));
142             if (current.isPresent() && current.get().value().equals(value))
143             {
144                 final boolean removed = join(delegate.removeIf(asString(key), current.get().identifier()));
145                 if (removed)
146                 {
147                     return true;
148                 }
149                 // Time to loop and try again
150             }
151             else
152             {
153                 return false; // Not a matching value
154             }
155         }
156     }
157 
158     @Override
159     public void removeAll()
160     {
161         join(delegate.removeAll());
162     }
163 
164     @Override
165     public boolean replace(@Nonnull K key, @Nonnull V oldValue, @Nonnull V newValue)
166     {
167         for (; ; )
168         {
169             final Optional<IdentifiedValue<Serializable>> current = join(delegate.getIdentified(asString(key)));
170             if (current.isPresent() && current.get().value().equals(oldValue))
171             {
172                 final boolean replaced = join(delegate.replaceIf(
173                         asString(key), current.get().identifier(), asSerializable(newValue)));
174                 if (replaced)
175                 {
176                     return true;
177                 }
178                 // Time to loop and try again
179             }
180             else
181             {
182                 return false; // Not a matching value
183             }
184         }
185     }
186 
187     @Override
188     public void addListener(@Nonnull CacheEntryListener<K, V> listener, boolean includeValues)
189     {
190         throw new UnsupportedOperationException("Not supported on non-local caches");
191     }
192 
193     @Override
194     public void removeListener(@Nonnull CacheEntryListener<K, V> listener)
195     {
196         throw new UnsupportedOperationException("Not supported on non-local caches");
197     }
198 }