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.jcs.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  import java.util.Collection;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.Iterator;
34  import java.util.LinkedList;
35  import java.util.Map;
36  import java.util.Set;
37  
38  import static org.apache.commons.jcs.jcache.Asserts.assertNotNull;
39  
40  // kind of transactional view for a Cache<K, V>, to use with EntryProcessor
41  public class TempStateCacheView<K, V> implements Cache<K, V>
42  {
43      private final JCSCache<K, V> cache;
44      private final Map<K, V> put = new HashMap<K, V>();
45      private final Collection<K> remove = new LinkedList<K>();
46      private boolean removeAll = false;
47      private boolean clear = false;
48  
49      public TempStateCacheView(final JCSCache<K, V> entries)
50      {
51          this.cache = entries;
52      }
53  
54      public V get(final K key)
55      {
56          if (ignoreKey(key))
57          {
58              return null;
59          }
60  
61          final V v = put.get(key);
62          if (v != null)
63          {
64              return v;
65          }
66  
67          // for an EntryProcessor we already incremented stats - to enhance
68          // surely
69          if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled())
70          {
71              final Statistics statistics = cache.getStatistics();
72              if (cache.containsKey(key))
73              {
74                  statistics.increaseHits(-1);
75              }
76              else
77              {
78                  statistics.increaseMisses(-1);
79              }
80          }
81          return cache.get(key);
82      }
83  
84      private boolean ignoreKey(final K key)
85      {
86          return removeAll || clear || remove.contains(key);
87      }
88  
89      public Map<K, V> getAll(final Set<? extends K> keys)
90      {
91          final Map<K, V> v = new HashMap<K, V>(keys.size());
92          final Set<K> missing = new HashSet<K>();
93          for (final K k : keys)
94          {
95              final V value = put.get(k);
96              if (value != null)
97              {
98                  v.put(k, value);
99              }
100             else if (!ignoreKey(k))
101             {
102                 missing.add(k);
103             }
104         }
105         if (!missing.isEmpty())
106         {
107             v.putAll(cache.getAll(missing));
108         }
109         return v;
110     }
111 
112     public boolean containsKey(final K key)
113     {
114         return !ignoreKey(key) && (put.containsKey(key) || cache.containsKey(key));
115     }
116 
117     public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
118     {
119         cache.loadAll(keys, replaceExistingValues, completionListener);
120     }
121 
122     public void put(final K key, final V value)
123     {
124         assertNotNull(key, "key");
125         assertNotNull(value, "value");
126         put.put(key, value);
127         remove.remove(key);
128     }
129 
130     public V getAndPut(final K key, final V value)
131     {
132         final V v = get(key);
133         put(key, value);
134         return v;
135     }
136 
137     public void putAll(final Map<? extends K, ? extends V> map)
138     {
139         put.putAll(map);
140         for (final K k : map.keySet())
141         {
142             remove.remove(k);
143         }
144     }
145 
146     public boolean putIfAbsent(final K key, final V value)
147     {
148         if (!put.containsKey(key))
149         {
150             put.put(key, value);
151             remove.remove(key);
152             return true;
153         }
154         return false;
155     }
156 
157     public boolean remove(final K key)
158     {
159         final boolean noop = put.containsKey(key);
160         put.remove(key);
161         if (!ignoreKey(key))
162         {
163             if (!noop)
164             {
165                 remove.add(key);
166             }
167             return true;
168         }
169         return false;
170     }
171 
172     public boolean remove(final K key, final V oldValue)
173     {
174         put.remove(key);
175         if (!ignoreKey(key) && oldValue.equals(cache.get(key)))
176         {
177             remove.add(key);
178             return true;
179         }
180         return false;
181     }
182 
183     public V getAndRemove(final K key)
184     {
185         final V v = get(key);
186         remove.add(key);
187         put.remove(key);
188         return v;
189     }
190 
191     public boolean replace(final K key, final V oldValue, final V newValue)
192     {
193         if (oldValue.equals(get(key)))
194         {
195             put(key, newValue);
196             return true;
197         }
198         return false;
199     }
200 
201     public boolean replace(final K key, final V value)
202     {
203         if (containsKey(key))
204         {
205             remove(key);
206             return true;
207         }
208         return false;
209     }
210 
211     public V getAndReplace(final K key, final V value)
212     {
213         if (containsKey(key))
214         {
215             final V oldValue = get(key);
216             put(key, value);
217             return oldValue;
218         }
219         return null;
220     }
221 
222     public void removeAll(final Set<? extends K> keys)
223     {
224         remove.addAll(keys);
225         for (final K k : keys)
226         {
227             put.remove(k);
228         }
229     }
230 
231     @Override
232     public void removeAll()
233     {
234         removeAll = true;
235         put.clear();
236         remove.clear();
237     }
238 
239     @Override
240     public void clear()
241     {
242         clear = true;
243         put.clear();
244         remove.clear();
245     }
246 
247     public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
248     {
249         return cache.getConfiguration(clazz);
250     }
251 
252     public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
253     {
254         return cache.invoke(key, entryProcessor, arguments);
255     }
256 
257     public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor,
258             final Object... arguments)
259     {
260         return cache.invokeAll(keys, entryProcessor, arguments);
261     }
262 
263     @Override
264     public String getName()
265     {
266         return cache.getName();
267     }
268 
269     @Override
270     public CacheManager getCacheManager()
271     {
272         return cache.getCacheManager();
273     }
274 
275     @Override
276     public void close()
277     {
278         cache.close();
279     }
280 
281     @Override
282     public boolean isClosed()
283     {
284         return cache.isClosed();
285     }
286 
287     @Override
288     public <T> T unwrap(final Class<T> clazz)
289     {
290         return cache.unwrap(clazz);
291     }
292 
293     public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
294     {
295         cache.registerCacheEntryListener(cacheEntryListenerConfiguration);
296     }
297 
298     public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
299     {
300         cache.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
301     }
302 
303     @Override
304     public Iterator<Entry<K, V>> iterator()
305     {
306         return cache.iterator();
307     }
308 
309     public void merge()
310     {
311         if (removeAll)
312         {
313             cache.removeAll();
314         }
315         if (clear)
316         {
317             cache.clear();
318         }
319 
320         for (final Map.Entry<K, V> entry : put.entrySet())
321         {
322             cache.put(entry.getKey(), entry.getValue());
323         }
324         put.clear();
325         for (final K entry : remove)
326         {
327             cache.remove(entry);
328         }
329         remove.clear();
330     }
331 }