View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.jcs3.jcache;
20  
21  import javax.cache.Cache;
22  import javax.cache.CacheManager;
23  import javax.cache.configuration.CacheEntryListenerConfiguration;
24  import javax.cache.configuration.CompleteConfiguration;
25  import javax.cache.configuration.Configuration;
26  import javax.cache.integration.CompletionListener;
27  import javax.cache.processor.EntryProcessor;
28  import javax.cache.processor.EntryProcessorException;
29  import javax.cache.processor.EntryProcessorResult;
30  
31  import static org.apache.commons.jcs3.jcache.Asserts.assertNotNull;
32  
33  import java.util.Collection;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.Iterator;
37  import java.util.LinkedList;
38  import java.util.Map;
39  import java.util.Set;
40  
41  // kind of transactional view for a Cache<K, V>, to use with EntryProcessor
42  public class TempStateCacheView<K, V> implements Cache<K, V>
43  {
44      private final JCSCache<K, V> cache;
45      private final Map<K, V> put = new HashMap<>();
46      private final Collection<K> remove = new LinkedList<>();
47      private boolean removeAll;
48      private boolean clear;
49  
50      public TempStateCacheView(final JCSCache<K, V> entries)
51      {
52          this.cache = entries;
53      }
54  
55      @Override
56      public V get(final K key)
57      {
58          if (ignoreKey(key))
59          {
60              return null;
61          }
62  
63          final V v = put.get(key);
64          if (v != null)
65          {
66              return v;
67          }
68  
69          // for an EntryProcessor we already incremented stats - to enhance
70          // surely
71          if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled())
72          {
73              final Statistics statistics = cache.getStatistics();
74              if (cache.containsKey(key))
75              {
76                  statistics.increaseHits(-1);
77              }
78              else
79              {
80                  statistics.increaseMisses(-1);
81              }
82          }
83          return cache.get(key);
84      }
85  
86      private boolean ignoreKey(final K key)
87      {
88          return removeAll || clear || remove.contains(key);
89      }
90  
91      @Override
92      public Map<K, V> getAll(final Set<? extends K> keys)
93      {
94          final Map<K, V> v = new HashMap<>(keys.size());
95          final Set<K> missing = new HashSet<>();
96          for (final K k : keys)
97          {
98              final V value = put.get(k);
99              if (value != null)
100             {
101                 v.put(k, value);
102             }
103             else if (!ignoreKey(k))
104             {
105                 missing.add(k);
106             }
107         }
108         if (!missing.isEmpty())
109         {
110             v.putAll(cache.getAll(missing));
111         }
112         return v;
113     }
114 
115     @Override
116     public boolean containsKey(final K key)
117     {
118         return !ignoreKey(key) && (put.containsKey(key) || cache.containsKey(key));
119     }
120 
121     @Override
122     public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
123     {
124         cache.loadAll(keys, replaceExistingValues, completionListener);
125     }
126 
127     @Override
128     public void put(final K key, final V value)
129     {
130         assertNotNull(key, "key");
131         assertNotNull(value, "value");
132         put.put(key, value);
133         remove.remove(key);
134     }
135 
136     @Override
137     public V getAndPut(final K key, final V value)
138     {
139         final V v = get(key);
140         put(key, value);
141         return v;
142     }
143 
144     @Override
145     public void putAll(final Map<? extends K, ? extends V> map)
146     {
147         put.putAll(map);
148         for (final K k : map.keySet())
149         {
150             remove.remove(k);
151         }
152     }
153 
154     @Override
155     public boolean putIfAbsent(final K key, final V value)
156     {
157         if (!put.containsKey(key))
158         {
159             put.put(key, value);
160             remove.remove(key);
161             return true;
162         }
163         return false;
164     }
165 
166     @Override
167     public boolean remove(final K key)
168     {
169         final boolean noop = put.containsKey(key);
170         put.remove(key);
171         if (!ignoreKey(key))
172         {
173             if (!noop)
174             {
175                 remove.add(key);
176             }
177             return true;
178         }
179         return false;
180     }
181 
182     @Override
183     public boolean remove(final K key, final V oldValue)
184     {
185         put.remove(key);
186         if (!ignoreKey(key) && oldValue.equals(cache.get(key)))
187         {
188             remove.add(key);
189             return true;
190         }
191         return false;
192     }
193 
194     @Override
195     public V getAndRemove(final K key)
196     {
197         final V v = get(key);
198         remove.add(key);
199         put.remove(key);
200         return v;
201     }
202 
203     @Override
204     public boolean replace(final K key, final V oldValue, final V newValue)
205     {
206         if (oldValue.equals(get(key)))
207         {
208             put(key, newValue);
209             return true;
210         }
211         return false;
212     }
213 
214     @Override
215     public boolean replace(final K key, final V value)
216     {
217         if (containsKey(key))
218         {
219             remove(key);
220             return true;
221         }
222         return false;
223     }
224 
225     @Override
226     public V getAndReplace(final K key, final V value)
227     {
228         if (containsKey(key))
229         {
230             final V oldValue = get(key);
231             put(key, value);
232             return oldValue;
233         }
234         return null;
235     }
236 
237     @Override
238     public void removeAll(final Set<? extends K> keys)
239     {
240         remove.addAll(keys);
241         for (final K k : keys)
242         {
243             put.remove(k);
244         }
245     }
246 
247     @Override
248     public void removeAll()
249     {
250         removeAll = true;
251         put.clear();
252         remove.clear();
253     }
254 
255     @Override
256     public void clear()
257     {
258         clear = true;
259         put.clear();
260         remove.clear();
261     }
262 
263     @Override
264     public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
265     {
266         return cache.getConfiguration(clazz);
267     }
268 
269     @Override
270     public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
271     {
272         return cache.invoke(key, entryProcessor, arguments);
273     }
274 
275     @Override
276     public <T> Map<K, EntryProcessorResult<T>> invokeAll(final Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
277             final Object... arguments)
278     {
279         return cache.invokeAll(keys, entryProcessor, arguments);
280     }
281 
282     @Override
283     public String getName()
284     {
285         return cache.getName();
286     }
287 
288     @Override
289     public CacheManager getCacheManager()
290     {
291         return cache.getCacheManager();
292     }
293 
294     @Override
295     public void close()
296     {
297         cache.close();
298     }
299 
300     @Override
301     public boolean isClosed()
302     {
303         return cache.isClosed();
304     }
305 
306     @Override
307     public <T> T unwrap(final Class<T> clazz)
308     {
309         return cache.unwrap(clazz);
310     }
311 
312     @Override
313     public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
314     {
315         cache.registerCacheEntryListener(cacheEntryListenerConfiguration);
316     }
317 
318     @Override
319     public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
320     {
321         cache.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
322     }
323 
324     @Override
325     public Iterator<Entry<K, V>> iterator()
326     {
327         return cache.iterator();
328     }
329 
330     public void merge()
331     {
332         if (removeAll)
333         {
334             cache.removeAll();
335         }
336         if (clear)
337         {
338             cache.clear();
339         }
340 
341         for (final Map.Entry<K, V> entry : put.entrySet())
342         {
343             cache.put(entry.getKey(), entry.getValue());
344         }
345         put.clear();
346         for (final K entry : remove)
347         {
348             cache.remove(entry);
349         }
350         remove.clear();
351     }
352 }