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.jcs.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; 030import java.util.Collection; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.Iterator; 034import java.util.LinkedList; 035import java.util.Map; 036import java.util.Set; 037 038import static org.apache.commons.jcs.jcache.Asserts.assertNotNull; 039 040// kind of transactional view for a Cache<K, V>, to use with EntryProcessor 041public class TempStateCacheView<K, V> implements Cache<K, V> 042{ 043 private final JCSCache<K, V> cache; 044 private final Map<K, V> put = new HashMap<K, V>(); 045 private final Collection<K> remove = new LinkedList<K>(); 046 private boolean removeAll = false; 047 private boolean clear = false; 048 049 public TempStateCacheView(final JCSCache<K, V> entries) 050 { 051 this.cache = entries; 052 } 053 054 public V get(final K key) 055 { 056 if (ignoreKey(key)) 057 { 058 return null; 059 } 060 061 final V v = put.get(key); 062 if (v != null) 063 { 064 return v; 065 } 066 067 // for an EntryProcessor we already incremented stats - to enhance 068 // surely 069 if (cache.getConfiguration(CompleteConfiguration.class).isStatisticsEnabled()) 070 { 071 final Statistics statistics = cache.getStatistics(); 072 if (cache.containsKey(key)) 073 { 074 statistics.increaseHits(-1); 075 } 076 else 077 { 078 statistics.increaseMisses(-1); 079 } 080 } 081 return cache.get(key); 082 } 083 084 private boolean ignoreKey(final K key) 085 { 086 return removeAll || clear || remove.contains(key); 087 } 088 089 public Map<K, V> getAll(final Set<? extends K> keys) 090 { 091 final Map<K, V> v = new HashMap<K, V>(keys.size()); 092 final Set<K> missing = new HashSet<K>(); 093 for (final K k : keys) 094 { 095 final V value = put.get(k); 096 if (value != null) 097 { 098 v.put(k, value); 099 } 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}