1/*
2 * Copyright (C) 2011 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.cache;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.annotations.Beta;
22import com.google.common.annotations.GwtCompatible;
23import com.google.common.annotations.GwtIncompatible;
24import com.google.common.base.Function;
25import com.google.common.base.Supplier;
26import com.google.common.util.concurrent.Futures;
27import com.google.common.util.concurrent.ListenableFuture;
28
29import java.io.Serializable;
30import java.util.Map;
31
32/**
33 * Computes or retrieves values, based on a key, for use in populating a {@code Cache}.
34 *
35 * <p>Most implementations will only need to implement {@link #load}. Other methods may be
36 * overridden as desired.
37 *
38 * @author Charles Fry
39 * @since 10.0
40 */
41@Beta
42@GwtCompatible(emulated = true)
43public abstract class CacheLoader<K, V> {
44  /**
45   * Constructor for use by subclasses.
46   */
47  protected CacheLoader() {}
48
49  /**
50   * Computes or retrieves the value corresponding to {@code key}.
51   *
52   * @param key the non-null key whose value should be loaded
53   * @return the value associated with {@code key}; <b>must not be null</b>
54   */
55  public abstract V load(K key) throws Exception;
56
57  /**
58   * Computes or retrieves a replacement value corresponding to an already-cached {@code key}. This
59   * method is called when an existing cache entry is refreshed by
60   * {@link CacheBuilder#refreshAfterWrite}, or through a call to {@link Cache#refresh}.
61   *
62   * <p>This implementation synchronously delegates to {@link #load}. It is recommended that it be
63   * overridden with an asynchronous implementation when using
64   * {@link CacheBuilder#refreshAfterWrite}.
65   *
66   * <p><b>Note:</b> <i>all exceptions thrown by this method will be logged and then swallowed</i>.
67   *
68   * @param key the non-null key whose value should be loaded
69   * @param oldValue the non-null old value corresponding to {@code key}
70   * @return the future new value associated with {@code key};
71   *     <b>must not be null, must not return null</b>
72   * @since 11.0
73   */
74  @GwtIncompatible("Futures")
75  public ListenableFuture<V> reload(K key, V oldValue) throws Exception {
76    return Futures.immediateFuture(load(key));
77  }
78
79  /**
80   * Computes or retrieves the values corresponding to {@code keys}. This method is called by
81   * {@link Cache#getAll}.
82   *
83   * <p>If the returned map doesn't contain all requested {@code keys} then the entries it does
84   * contain will be cached, but {@code getAll} will throw an exception. If the returned map
85   * contains extra keys not present in {@code keys} then all returned entries will be cached,
86   * but only the entries for {@code keys} will be returned from {@code getAll}.
87   *
88   * <p>This method should be overriden when bulk retrieval is significantly more efficient than
89   * many individual lookups. Note that {@link Cache#getAll} will defer to individual calls to
90   * {@link Cache#get} if this method is not overriden.
91   *
92   * @param keys the unique, non-null keys whose values should be loaded
93   * @return a map from each key in {@code keys} to the value associated with that key;
94   *     <b>may not contain null values</b>
95   * @since 11.0
96   */
97  public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
98    // This will be caught by getAll(), causing it to fall back to multiple calls to Cache.get
99    throw new UnsupportedLoadingOperationException();
100  }
101
102  /**
103   * Returns a {@code CacheLoader} which creates values by applying a {@code Function} to the key.
104   */
105  public static <K, V> CacheLoader<K, V> from(Function<K, V> function) {
106    return new FunctionToCacheLoader<K, V>(function);
107  }
108
109  private static final class FunctionToCacheLoader<K, V>
110      extends CacheLoader<K, V> implements Serializable {
111    private final Function<K, V> computingFunction;
112
113    public FunctionToCacheLoader(Function<K, V> computingFunction) {
114      this.computingFunction = checkNotNull(computingFunction);
115    }
116
117    @Override
118    public V load(K key) {
119      return computingFunction.apply(key);
120    }
121
122    private static final long serialVersionUID = 0;
123  }
124
125  /**
126   * Returns a {@code CacheLoader} which obtains values from a {@code Supplier} (independent of the
127   * key).
128   */
129  public static <V> CacheLoader<Object, V> from(Supplier<V> supplier) {
130    return new SupplierToCacheLoader<V>(supplier);
131  }
132
133  private static final class SupplierToCacheLoader<V>
134      extends CacheLoader<Object, V> implements Serializable {
135    private final Supplier<V> computingSupplier;
136
137    public SupplierToCacheLoader(Supplier<V> computingSupplier) {
138      this.computingSupplier = checkNotNull(computingSupplier);
139    }
140
141    @Override
142    public V load(Object key) {
143      return computingSupplier.get();
144    }
145
146    private static final long serialVersionUID = 0;
147  }
148
149  static final class UnsupportedLoadingOperationException extends UnsupportedOperationException {}
150
151  /**
152   * Thrown to indicate that an invalid response was returned from a call to {@link CacheLoader}.
153   *
154   * @since 11.0
155   */
156  public static final class InvalidCacheLoadException extends RuntimeException {
157    public InvalidCacheLoadException(String message) {
158      super(message);
159    }
160  }
161}
162