View Javadoc
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.base.Function;
22  import com.google.common.base.Supplier;
23  import com.google.common.util.concurrent.Futures;
24  import com.google.common.util.concurrent.ListenableFuture;
25  import com.google.common.util.concurrent.ListenableFutureTask;
26  import java.io.Serializable;
27  import java.util.Map;
28  import java.util.concurrent.Callable;
29  import java.util.concurrent.Executor;
30  
31  /**
32   * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
33   *
34   * <p>Most implementations will only need to implement {@link #load}. Other methods may be
35   * overridden as desired.
36   *
37   * <p>Usage example:
38   *
39   * <pre>{@code
40   * CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() {
41   *   public Graph load(Key key) throws AnyException {
42   *     return createExpensiveGraph(key);
43   *   }
44   * };
45   * LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);
46   * }</pre>
47   *
48   * <p>Since this example doesn't support reloading or bulk loading, it can also be specified much
49   * more simply:
50   *
51   * <pre>{@code
52   * CacheLoader<Key, Graph> loader = CacheLoader.from(key -> createExpensiveGraph(key));
53   * }</pre>
54   *
55   * @author Charles Fry
56   * @since 10.0
57   */
58  @GwtCompatible(emulated = true)
59  public abstract class CacheLoader<K, V> {
60    /**
61     * Constructor for use by subclasses.
62     */
63    protected CacheLoader() {}
64  
65    /**
66     * Computes or retrieves the value corresponding to {@code key}.
67     *
68     * @param key the non-null key whose value should be loaded
69     * @return the value associated with {@code key}; <b>must not be null</b>
70     * @throws Exception if unable to load the result
71     * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
72     *     treated like any other {@code Exception} in all respects except that, when it is caught,
73     *     the thread's interrupt status is set
74     */
75    public abstract V load(K key) throws Exception;
76  
77    /**
78     * Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This
79     * method is called when an existing cache entry is refreshed by
80     * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}.
81     *
82     * <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
83     * overridden with an asynchronous implementation when using
84     * {@link CacheBuilder#refreshAfterWrite}.
85     *
86     * <p><b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>.
87     *
88     * @param key the non-null key whose value should be loaded
89     * @param oldValue the non-null old value corresponding to {@code key}
90     * @return the future new value associated with {@code key}; <b>must not be null, must not return
91     *     null</b>
92     * @throws Exception if unable to reload the result
93     * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
94     *     treated like any other {@code Exception} in all respects except that, when it is caught,
95     *     the thread's interrupt status is set
96     * @since 11.0
97     */
98    @GwtIncompatible // Futures
99    public ListenableFuture<V> reload(K key, V oldValue) throws Exception {
100     checkNotNull(key);
101     checkNotNull(oldValue);
102     return Futures.immediateFuture(load(key));
103   }
104 
105   /**
106    * Computes or retrieves the values corresponding to {@code keys}. This method is called by
107    * {@link LoadingCache#getAll}.
108    *
109    * <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
110    * contain will be cached, but {@code getAll} will throw an exception. If the returned map
111    * contains extra keys not present in {@code keys} then all returned entries will be cached, but
112    * only the entries for {@code keys} will be returned from {@code getAll}.
113    *
114    * <p>This method should be overridden when bulk retrieval is significantly more efficient than
115    * many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls
116    * to {@link LoadingCache#get} if this method is not overridden.
117    *
118    * @param keys the unique, non-null keys whose values should be loaded
119    * @return a map from each key in {@code keys} to the value associated with that key; <b>may not
120    *     contain null values</b>
121    * @throws Exception if unable to load the result
122    * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
123    *     treated like any other {@code Exception} in all respects except that, when it is caught,
124    *     the thread's interrupt status is set
125    * @since 11.0
126    */
127   public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
128     // This will be caught by getAll(), causing it to fall back to multiple calls to
129     // LoadingCache.get
130     throw new UnsupportedLoadingOperationException();
131   }
132 
133   /**
134    * Returns a cache loader that uses {@code function} to load keys, without supporting either
135    * reloading or bulk loading. This allows creating a cache loader using a lambda expression.
136    *
137    * @param function the function to be used for loading values; must never return {@code null}
138    * @return a cache loader that loads values by passing each key to {@code function}
139    */
140   public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
141     return new FunctionToCacheLoader<>(function);
142   }
143 
144   private static final class FunctionToCacheLoader<K, V> extends CacheLoader<K, V>
145       implements Serializable {
146     private final Function<K, V> computingFunction;
147 
148     public FunctionToCacheLoader(Function<K, V> computingFunction) {
149       this.computingFunction = checkNotNull(computingFunction);
150     }
151 
152     @Override
153     public V load(K key) {
154       return computingFunction.apply(checkNotNull(key));
155     }
156 
157     private static final long serialVersionUID = 0;
158   }
159 
160   /**
161    * Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need
162    * to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and
163    * implement {@link #load load} instead.
164    *
165    * @param supplier the supplier to be used for loading values; must never return {@code null}
166    * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the
167    *     key
168    */
169   public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
170     return new SupplierToCacheLoader<V>(supplier);
171   }
172 
173   /**
174    * Returns a {@code CacheLoader} which wraps {@code loader}, executing calls to
175    * {@link CacheLoader#reload} using {@code executor}.
176    *
177    * <p>This method is useful only when {@code loader.reload} has a synchronous implementation, such
178    * as {@linkplain #reload the default implementation}.
179    *
180    * @since 17.0
181    */
182   @GwtIncompatible // Executor + Futures
183   public static <K, V> CacheLoader<K, V> asyncReloading(
184       final CacheLoader<K, V> loader, final Executor executor) {
185     checkNotNull(loader);
186     checkNotNull(executor);
187     return new CacheLoader<K, V>() {
188       @Override
189       public V load(K key) throws Exception {
190         return loader.load(key);
191       }
192 
193       @Override
194       public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception {
195         ListenableFutureTask<V> task =
196             ListenableFutureTask.create(
197                 new Callable<V>() {
198                   @Override
199                   public V call() throws Exception {
200                     return loader.reload(key, oldValue).get();
201                   }
202                 });
203         executor.execute(task);
204         return task;
205       }
206 
207       @Override
208       public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
209         return loader.loadAll(keys);
210       }
211     };
212   }
213 
214   private static final class SupplierToCacheLoader<V> extends CacheLoader<Object, V>
215       implements Serializable {
216     private final Supplier<V> computingSupplier;
217 
218     public SupplierToCacheLoader(Supplier<V> computingSupplier) {
219       this.computingSupplier = checkNotNull(computingSupplier);
220     }
221 
222     @Override
223     public V load(Object key) {
224       checkNotNull(key);
225       return computingSupplier.get();
226     }
227 
228     private static final long serialVersionUID = 0;
229   }
230 
231   /**
232    * Exception thrown by {@code loadAll()} to indicate that it is not supported.
233    *
234    * @since 19.0
235    */
236   public static final class UnsupportedLoadingOperationException
237       extends UnsupportedOperationException {
238     // Package-private because this should only be thrown by loadAll() when it is not overridden.
239     // Cache implementors may want to catch it but should not need to be able to throw it.
240     UnsupportedLoadingOperationException() {}
241   }
242 
243   /**
244    * Thrown to indicate that an invalid response was returned from a call to {@link CacheLoader}.
245    *
246    * @since 11.0
247    */
248   public static final class InvalidCacheLoadException extends RuntimeException {
249     public InvalidCacheLoadException(String message) {
250       super(message);
251     }
252   }
253 }