001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.jcs3.jcache; 020 021import javax.cache.Cache; 022import javax.cache.CacheManager; 023import javax.cache.configuration.CacheEntryListenerConfiguration; 024import javax.cache.configuration.CompleteConfiguration; 025import javax.cache.configuration.Configuration; 026import javax.cache.integration.CompletionListener; 027import javax.cache.processor.EntryProcessor; 028import javax.cache.processor.EntryProcessorException; 029import javax.cache.processor.EntryProcessorResult; 030 031import static org.apache.commons.jcs3.jcache.Asserts.assertNotNull; 032 033import java.util.Collection; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.LinkedList; 038import java.util.Map; 039import java.util.Set; 040 041// kind of transactional view for a Cache<K, V>, to use with EntryProcessor 042public class TempStateCacheView<K, V> implements Cache<K, V> 043{ 044 private final JCSCache<K, V> cache; 045 private final Map<K, V> put = new HashMap<>(); 046 private final Collection<K> remove = new LinkedList<>(); 047 private boolean removeAll; 048 private boolean clear; 049 050 public TempStateCacheView(final JCSCache<K, V> entries) 051 { 052 this.cache = entries; 053 } 054 055 @Override 056 public V get(final K key) 057 { 058 if (ignoreKey(key)) 059 { 060 return null; 061 } 062 063 final V v = put.get(key); 064 if (v != null) 065 { 066 return v; 067 } 068 069 // for an EntryProcessor we already incremented stats - to enhance 070 // surely 071 if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled()) 072 { 073 final Statistics statistics = cache.getStatistics(); 074 if (cache.containsKey(key)) 075 { 076 statistics.increaseHits(-1); 077 } 078 else 079 { 080 statistics.increaseMisses(-1); 081 } 082 } 083 return cache.get(key); 084 } 085 086 private boolean ignoreKey(final K key) 087 { 088 return removeAll || clear || remove.contains(key); 089 } 090 091 @Override 092 public Map<K, V> getAll(final Set<? extends K> keys) 093 { 094 final Map<K, V> v = new HashMap<>(keys.size()); 095 final Set<K> missing = new HashSet<>(); 096 for (final K k : keys) 097 { 098 final V value = put.get(k); 099 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}