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