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
15package com.google.common.cache;
16
17import com.google.common.annotations.GwtCompatible;
18import com.google.common.annotations.GwtIncompatible;
19import com.google.common.collect.Maps;
20import com.google.common.util.concurrent.Futures;
21import com.google.common.util.concurrent.ListenableFuture;
22
23import java.util.Map;
24import java.util.concurrent.atomic.AtomicInteger;
25
26/**
27 * Utility {@link CacheLoader} implementations intended for use in testing.
28 *
29 * @author mike nonemacher
30 */
31@GwtCompatible(emulated = true)
32class TestingCacheLoaders {
33
34  /**
35   * Returns a {@link CacheLoader} that implements a naive {@link CacheLoader#loadAll}, delegating
36   * {@link CacheLoader#load} calls to {@code loader}.
37   */
38  static <K, V> CacheLoader<K, V> bulkLoader(final CacheLoader<K, V> loader) {
39    return new CacheLoader<K, V>() {
40      @Override
41      public V load(K key) throws Exception {
42        return loader.load(key);
43      }
44
45      @Override
46      public Map<K, V> loadAll(Iterable<? extends K> keys) throws Exception {
47        Map<K, V> result = Maps.newHashMap(); // allow nulls
48        for (K key : keys) {
49          result.put(key, load(key));
50        }
51        return result;
52      }
53    };
54  }
55
56  /**
57   * Returns a {@link CacheLoader} that returns the given {@code constant} for every request.
58   */
59  static <K, V> ConstantLoader<K, V> constantLoader(V constant) {
60    return new ConstantLoader<K, V>(constant);
61  }
62
63  /**
64   * Returns a {@link CacheLoader} that returns the given {@code constant} for every request.
65   */
66  static IncrementingLoader incrementingLoader() {
67    return new IncrementingLoader();
68  }
69
70  /**
71   * Returns a {@link CacheLoader} that throws the given error for every request.
72   */
73  static <K, V> CacheLoader<K, V> errorLoader(final Error e) {
74    return new CacheLoader<K, V>() {
75      @Override
76      public V load(K key) {
77        throw e;
78      }
79    };
80  }
81
82  /**
83   * Returns a {@link CacheLoader} that throws the given exception for every request.
84   */
85  static <K, V> CacheLoader<K, V> exceptionLoader(final Exception e) {
86    return new CacheLoader<K, V>() {
87      @Override
88      public V load(K key) throws Exception {
89        throw e;
90      }
91    };
92  }
93
94  /**
95   * Returns a {@link CacheLoader} that returns the key for every request.
96   */
97  static <T> IdentityLoader<T> identityLoader() {
98    return new IdentityLoader<T>();
99  }
100
101  /**
102   * Returns a {@code new Object()} for every request, and increments a counter for every request.
103   * The count is accessible via {@link #getCount}.
104   */
105  static class CountingLoader extends CacheLoader<Object, Object> {
106    private final AtomicInteger count = new AtomicInteger();
107
108    @Override
109    public Object load(Object from) {
110      count.incrementAndGet();
111      return new Object();
112    }
113
114    public int getCount() {
115      return count.get();
116    }
117  }
118
119  static final class ConstantLoader<K, V> extends CacheLoader<K, V> {
120    private final V constant;
121
122    ConstantLoader(V constant) {
123      this.constant = constant;
124    }
125
126    @Override
127    public V load(K key) {
128      return constant;
129    }
130  }
131
132  /**
133   * Returns a {@code new Object()} for every request, and increments a counter for every request.
134   * An {@code Integer} loader that returns the key for {@code load} requests, and increments the
135   * old value on {@code reload} requests. The load counts are accessible via {@link #getLoadCount}
136   * and {@link #getReloadCount}.
137   */
138  static class IncrementingLoader extends CacheLoader<Integer, Integer> {
139    private final AtomicInteger countLoad = new AtomicInteger();
140    private final AtomicInteger countReload = new AtomicInteger();
141
142    @Override
143    public Integer load(Integer key) {
144      countLoad.incrementAndGet();
145      return key;
146    }
147
148    @GwtIncompatible("reload")
149    @Override
150    public ListenableFuture<Integer> reload(Integer key, Integer oldValue) {
151      countReload.incrementAndGet();
152      return Futures.immediateFuture(oldValue + 1);
153    }
154
155    public int getLoadCount() {
156      return countLoad.get();
157    }
158
159    public int getReloadCount() {
160      return countReload.get();
161    }
162  }
163
164  static final class IdentityLoader<T> extends CacheLoader<T, T> {
165    @Override
166    public T load(T key) {
167      return key;
168    }
169  }
170}
171