001/*
002 * Copyright (C) 2011 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 */
014
015package com.google.common.cache;
016
017import static com.google.common.base.Preconditions.checkNotNull;
018
019import com.google.common.annotations.GwtCompatible;
020import com.google.common.annotations.GwtIncompatible;
021import com.google.common.base.Function;
022import com.google.common.base.Supplier;
023import com.google.common.util.concurrent.Futures;
024import com.google.common.util.concurrent.ListenableFuture;
025import com.google.common.util.concurrent.ListenableFutureTask;
026import java.io.Serializable;
027import java.util.Map;
028import java.util.concurrent.Callable;
029import java.util.concurrent.Executor;
030
031/**
032 * Computes or retrieves values, based on a key, for use in populating a {@link LoadingCache}.
033 *
034 * <p>Most implementations will only need to implement {@link #load}. Other methods may be
035 * overridden as desired.
036 *
037 * <p>Usage example: <pre>   {@code
038 *
039 *   CacheLoader<Key, Graph> loader = new CacheLoader<Key, Graph>() {
040 *     public Graph load(Key key) throws AnyException {
041 *       return createExpensiveGraph(key);
042 *     }
043 *   };
044 *   LoadingCache<Key, Graph> cache = CacheBuilder.newBuilder().build(loader);}</pre>
045 *
046 * @author Charles Fry
047 * @since 10.0
048 */
049@GwtCompatible(emulated = true)
050public abstract class CacheLoader<K, V> {
051  /**
052   * Constructor for use by subclasses.
053   */
054  protected CacheLoader() {}
055
056  /**
057   * Computes or retrieves the value corresponding to {@code key}.
058   *
059   * @param key the non-null key whose value should be loaded
060   * @return the value associated with {@code key}; <b>must not be null</b>
061   * @throws Exception if unable to load the result
062   * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
063   *     treated like any other {@code Exception} in all respects except that, when it is caught,
064   *     the thread's interrupt status is set
065   */
066  public abstract V load(K key) throws Exception;
067
068  /**
069   * Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This
070   * method is called when an existing cache entry is refreshed by
071   * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link LoadingCache#refresh}.
072   *
073   * <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
074   * overridden with an asynchronous implementation when using
075   * {@link CacheBuilder#refreshAfterWrite}.
076   *
077   * <p><b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>.
078   *
079   * @param key the non-null key whose value should be loaded
080   * @param oldValue the non-null old value corresponding to {@code key}
081   * @return the future new value associated with {@code key}; <b>must not be null, must not return
082   *     null</b>
083   * @throws Exception if unable to reload the result
084   * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
085   *     treated like any other {@code Exception} in all respects except that, when it is caught,
086   *     the thread's interrupt status is set
087   * @since 11.0
088   */
089  @GwtIncompatible // Futures
090  public ListenableFuture<V> reload(K key, V oldValue) throws Exception {
091    checkNotNull(key);
092    checkNotNull(oldValue);
093    return Futures.immediateFuture(load(key));
094  }
095
096  /**
097   * Computes or retrieves the values corresponding to {@code keys}. This method is called by
098   * {@link LoadingCache#getAll}.
099   *
100   * <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
101   * contain will be cached, but {@code getAll} will throw an exception. If the returned map
102   * contains extra keys not present in {@code keys} then all returned entries will be cached, but
103   * only the entries for {@code keys} will be returned from {@code getAll}.
104   *
105   * <p>This method should be overriden when bulk retrieval is significantly more efficient than
106   * many individual lookups. Note that {@link LoadingCache#getAll} will defer to individual calls
107   * to {@link LoadingCache#get} if this method is not overriden.
108   *
109   * @param keys the unique, non-null keys whose values should be loaded
110   * @return a map from each key in {@code keys} to the value associated with that key; <b>may not
111   *     contain null values</b>
112   * @throws Exception if unable to load the result
113   * @throws InterruptedException if this method is interrupted. {@code InterruptedException} is
114   *     treated like any other {@code Exception} in all respects except that, when it is caught,
115   *     the thread's interrupt status is set
116   * @since 11.0
117   */
118  public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
119    // This will be caught by getAll(), causing it to fall back to multiple calls to
120    // LoadingCache.get
121    throw new UnsupportedLoadingOperationException();
122  }
123
124  /**
125   * Returns a cache loader based on an <i>existing</i> function instance. Note that there's no need
126   * to create a <i>new</i> function just to pass it in here; just subclass {@code CacheLoader} and
127   * implement {@link #load load} instead.
128   *
129   * @param function the function to be used for loading values; must never return {@code null}
130   * @return a cache loader that loads values by passing each key to {@code function}
131   */
132  public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
133    return new FunctionToCacheLoader<K, V>(function);
134  }
135
136  private static final class FunctionToCacheLoader<K, V> extends CacheLoader<K, V>
137      implements Serializable {
138    private final Function<K, V> computingFunction;
139
140    public FunctionToCacheLoader(Function<K, V> computingFunction) {
141      this.computingFunction = checkNotNull(computingFunction);
142    }
143
144    @Override
145    public V load(K key) {
146      return computingFunction.apply(checkNotNull(key));
147    }
148
149    private static final long serialVersionUID = 0;
150  }
151
152  /**
153   * Returns a cache loader based on an <i>existing</i> supplier instance. Note that there's no need
154   * to create a <i>new</i> supplier just to pass it in here; just subclass {@code CacheLoader} and
155   * implement {@link #load load} instead.
156   *
157   * @param supplier the supplier to be used for loading values; must never return {@code null}
158   * @return a cache loader that loads values by calling {@link Supplier#get}, irrespective of the
159   *     key
160   */
161  public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
162    return new SupplierToCacheLoader<V>(supplier);
163  }
164
165  /**
166   * Returns a {@code CacheLoader} which wraps {@code loader}, executing calls to
167   * {@link CacheLoader#reload} using {@code executor}.
168   *
169   * <p>This method is useful only when {@code loader.reload} has a synchronous implementation, such
170   * as {@linkplain #reload the default implementation}.
171   *
172   * @since 17.0
173   */
174  @GwtIncompatible // Executor + Futures
175  public static <K, V> CacheLoader<K, V> asyncReloading(
176      final CacheLoader<K, V> loader, final Executor executor) {
177    checkNotNull(loader);
178    checkNotNull(executor);
179    return new CacheLoader<K, V>() {
180      @Override
181      public V load(K key) throws Exception {
182        return loader.load(key);
183      }
184
185      @Override
186      public ListenableFuture<V> reload(final K key, final V oldValue) throws Exception {
187        ListenableFutureTask<V> task =
188            ListenableFutureTask.create(
189                new Callable<V>() {
190                  @Override
191                  public V call() throws Exception {
192                    return loader.reload(key, oldValue).get();
193                  }
194                });
195        executor.execute(task);
196        return task;
197      }
198
199      @Override
200      public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
201        return loader.loadAll(keys);
202      }
203    };
204  }
205
206  private static final class SupplierToCacheLoader<V> extends CacheLoader<Object, V>
207      implements Serializable {
208    private final Supplier<V> computingSupplier;
209
210    public SupplierToCacheLoader(Supplier<V> computingSupplier) {
211      this.computingSupplier = checkNotNull(computingSupplier);
212    }
213
214    @Override
215    public V load(Object key) {
216      checkNotNull(key);
217      return computingSupplier.get();
218    }
219
220    private static final long serialVersionUID = 0;
221  }
222
223  /**
224   * Exception thrown by {@code loadAll()} to indicate that it is not supported.
225   *
226   * @since 19.0
227   */
228  public static final class UnsupportedLoadingOperationException
229      extends UnsupportedOperationException {
230    // Package-private because this should only be thrown by loadAll() when it is not overridden.
231    // Cache implementors may want to catch it but should not need to be able to throw it.
232    UnsupportedLoadingOperationException() {}
233  }
234
235  /**
236   * Thrown to indicate that an invalid response was returned from a call to {@link CacheLoader}.
237   *
238   * @since 11.0
239   */
240  public static final class InvalidCacheLoadException extends RuntimeException {
241    public InvalidCacheLoadException(String message) {
242      super(message);
243    }
244  }
245}