1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.cache; 16 17 import static com.google.common.base.Preconditions.checkNotNull; 18 19 import com.google.common.annotations.GwtCompatible; 20 import com.google.common.annotations.GwtIncompatible; 21 import com.google.common.collect.Maps; 22 import com.google.common.util.concurrent.Futures; 23 import com.google.common.util.concurrent.ListenableFuture; 24 import java.util.Map; 25 import java.util.concurrent.atomic.AtomicInteger; 26 import org.checkerframework.checker.nullness.compatqual.NullableDecl; 27 28 /** 29 * Utility {@link CacheLoader} implementations intended for use in testing. 30 * 31 * @author mike nonemacher 32 */ 33 @GwtCompatible(emulated = true) 34 class TestingCacheLoaders { 35 36 /** 37 * Returns a {@link CacheLoader} that implements a naive {@link CacheLoader#loadAll}, delegating 38 * {@link CacheLoader#load} calls to {@code loader}. 39 */ bulkLoader(final CacheLoader<K, V> loader)40 static <K, V> CacheLoader<K, V> bulkLoader(final CacheLoader<K, V> loader) { 41 checkNotNull(loader); 42 return new CacheLoader<K, V>() { 43 @Override 44 public V load(K key) throws Exception { 45 return loader.load(key); 46 } 47 48 @Override 49 public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception { 50 Map<K, V> result = Maps.newHashMap(); // allow nulls 51 for (K key : keys) { 52 result.put(key, load(key)); 53 } 54 return result; 55 } 56 }; 57 } 58 59 /** Returns a {@link CacheLoader} that returns the given {@code constant} for every request. */ 60 static <K, V> ConstantLoader<K, V> constantLoader(@NullableDecl V constant) { 61 return new ConstantLoader<>(constant); 62 } 63 64 /** Returns a {@link CacheLoader} that returns the given {@code constant} for every request. */ 65 static IncrementingLoader incrementingLoader() { 66 return new IncrementingLoader(); 67 } 68 69 /** Returns a {@link CacheLoader} that throws the given error for every request. */ 70 static <K, V> CacheLoader<K, V> errorLoader(final Error e) { 71 checkNotNull(e); 72 return new CacheLoader<K, V>() { 73 @Override 74 public V load(K key) { 75 throw e; 76 } 77 }; 78 } 79 80 /** Returns a {@link CacheLoader} that throws the given exception for every request. */ 81 static <K, V> CacheLoader<K, V> exceptionLoader(final Exception e) { 82 checkNotNull(e); 83 return new CacheLoader<K, V>() { 84 @Override 85 public V load(K key) throws Exception { 86 throw e; 87 } 88 }; 89 } 90 91 /** Returns a {@link CacheLoader} that returns the key for every request. */ 92 static <T> IdentityLoader<T> identityLoader() { 93 return new IdentityLoader<T>(); 94 } 95 96 /** 97 * Returns a {@code new Object()} for every request, and increments a counter for every request. 98 * The count is accessible via {@link #getCount}. 99 */ 100 static class CountingLoader extends CacheLoader<Object, Object> { 101 private final AtomicInteger count = new AtomicInteger(); 102 103 @Override 104 public Object load(Object from) { 105 count.incrementAndGet(); 106 return new Object(); 107 } 108 109 public int getCount() { 110 return count.get(); 111 } 112 } 113 114 static final class ConstantLoader<K, V> extends CacheLoader<K, V> { 115 private final V constant; 116 117 ConstantLoader(V constant) { 118 this.constant = constant; 119 } 120 121 @Override 122 public V load(K key) { 123 return constant; 124 } 125 } 126 127 /** 128 * Returns a {@code new Object()} for every request, and increments a counter for every request. 129 * An {@code Integer} loader that returns the key for {@code load} requests, and increments the 130 * old value on {@code reload} requests. The load counts are accessible via {@link #getLoadCount} 131 * and {@link #getReloadCount}. 132 */ 133 static class IncrementingLoader extends CacheLoader<Integer, Integer> { 134 private final AtomicInteger countLoad = new AtomicInteger(); 135 private final AtomicInteger countReload = new AtomicInteger(); 136 137 @Override 138 public Integer load(Integer key) { 139 countLoad.incrementAndGet(); 140 return key; 141 } 142 143 @GwtIncompatible // reload 144 @Override 145 public ListenableFuture<Integer> reload(Integer key, Integer oldValue) { 146 countReload.incrementAndGet(); 147 return Futures.immediateFuture(oldValue + 1); 148 } 149 150 public int getLoadCount() { 151 return countLoad.get(); 152 } 153 154 public int getReloadCount() { 155 return countReload.get(); 156 } 157 } 158 159 static final class IdentityLoader<T> extends CacheLoader<T, T> { 160 @Override 161 public T load(T key) { 162 return key; 163 } 164 } 165 } 166