• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.62
today-context/src/main/java/infra/cache/support/AbstractCacheManager.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17
package infra.cache.support;
18

19
import org.jspecify.annotations.Nullable;
20

21
import java.util.Collection;
22
import java.util.Collections;
23
import java.util.LinkedHashSet;
24
import java.util.Set;
25
import java.util.concurrent.ConcurrentHashMap;
26
import java.util.concurrent.ConcurrentMap;
27

28
import infra.beans.factory.InitializingBean;
29
import infra.cache.Cache;
30
import infra.cache.CacheManager;
31

32
/**
33
 * Abstract base class implementing the common {@link CacheManager} methods.
34
 * Useful for 'static' environments where the backing caches do not change.
35
 *
36
 * @author Costin Leau
37
 * @author Juergen Hoeller
38
 * @author Stephane Nicoll
39
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
40
 * @since 2020-08-15 19:18
41
 */
42
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
2✔
43

44
  private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
6✔
45

46
  private volatile Set<String> cacheNames = Collections.emptySet();
4✔
47

48
  // Early cache initialization on startup
49

50
  @Override
51
  public void afterPropertiesSet() {
52
    initializeCaches();
2✔
53
  }
1✔
54

55
  /**
56
   * Initialize the static configuration of caches.
57
   * <p>Triggered on startup through {@link #afterPropertiesSet()};
58
   * can also be called to re-initialize at runtime.
59
   *
60
   * @see #loadCaches()
61
   * @since 4.0
62
   */
63
  public void initializeCaches() {
64
    Collection<? extends Cache> caches = loadCaches();
3✔
65

66
    synchronized(this.cacheMap) {
5✔
67
      this.cacheNames = Collections.emptySet();
3✔
68
      this.cacheMap.clear();
3✔
69
      Set<String> cacheNames = new LinkedHashSet<>(caches.size());
6✔
70
      for (Cache cache : caches) {
10✔
71
        String name = cache.getName();
3✔
72
        this.cacheMap.put(name, decorateCache(cache));
8✔
73
        cacheNames.add(name);
4✔
74
      }
1✔
75
      this.cacheNames = Collections.unmodifiableSet(cacheNames);
4✔
76
    }
3✔
77
  }
1✔
78

79
  /**
80
   * Load the initial caches for this cache manager.
81
   * <p>Called by {@link #afterPropertiesSet()} on startup.
82
   * The returned collection may be empty but must not be {@code null}.
83
   */
84
  protected abstract Collection<? extends Cache> loadCaches();
85

86
  // Lazy cache initialization on access
87

88
  @Override
89
  @Nullable
90
  public Cache getCache(String name) {
91
    // Quick check for existing cache...
92
    Cache cache = this.cacheMap.get(name);
6✔
93
    if (cache != null) {
2✔
94
      return cache;
2✔
95
    }
96

97
    // The provider may support on-demand cache creation...
98
    Cache missingCache = getMissingCache(name);
4✔
99
    if (missingCache != null) {
2✔
100
      // Fully synchronize now for missing cache registration
101
      synchronized(this.cacheMap) {
5✔
102
        cache = this.cacheMap.get(name);
6✔
103
        if (cache == null) {
2!
104
          cache = decorateCache(missingCache);
4✔
105
          this.cacheMap.put(name, cache);
6✔
106
          updateCacheNames(name);
3✔
107
        }
108
      }
3✔
109
    }
110
    return cache;
2✔
111
  }
112

113
  @Override
114
  public Collection<String> getCacheNames() {
115
    return this.cacheNames;
3✔
116
  }
117

118
  // Common cache initialization delegates for subclasses
119

120
  /**
121
   * Check for a registered cache of the given name.
122
   * In contrast to {@link #getCache(String)}, this method does not trigger
123
   * the lazy creation of missing caches via {@link #getMissingCache(String)}.
124
   *
125
   * @param name the cache identifier (must not be {@code null})
126
   * @return the associated Cache instance, or {@code null} if none found
127
   * @see #getCache(String)
128
   * @see #getMissingCache(String)
129
   * @since 4.0
130
   */
131
  @Nullable
132
  protected final Cache lookupCache(String name) {
133
    return this.cacheMap.get(name);
×
134
  }
135

136
  /**
137
   * Update the exposed {@link #cacheNames} set with the given name.
138
   * <p>This will always be called within a full {@link #cacheMap} lock
139
   * and effectively behaves like a {@code CopyOnWriteArraySet} with
140
   * preserved order but exposed as an unmodifiable reference.
141
   *
142
   * @param name the name of the cache to be added
143
   */
144
  private void updateCacheNames(String name) {
145
    Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames);
6✔
146
    cacheNames.add(name);
4✔
147
    this.cacheNames = Collections.unmodifiableSet(cacheNames);
4✔
148
  }
1✔
149

150
  // Overridable template methods for cache initialization
151

152
  /**
153
   * Decorate the given Cache object if necessary.
154
   *
155
   * @param cache the Cache object to be added to this CacheManager
156
   * @return the decorated Cache object to be used instead,
157
   * or simply the passed-in Cache object by default
158
   */
159
  protected Cache decorateCache(Cache cache) {
160
    return cache;
2✔
161
  }
162

163
  /**
164
   * Return a missing cache with the specified {@code name}, or {@code null} if
165
   * such a cache does not exist or could not be created on demand.
166
   * <p>Caches may be lazily created at runtime if the native provider supports it.
167
   * If a lookup by name does not yield any result, an {@code AbstractCacheManager}
168
   * subclass gets a chance to register such a cache at runtime. The returned cache
169
   * will be automatically added to this cache manager.
170
   *
171
   * @param name the name of the cache to retrieve
172
   * @return the missing cache, or {@code null} if no such cache exists or could be
173
   * created on demand
174
   * @see #getCache(String)
175
   * @since 4.0
176
   */
177
  @Nullable
178
  protected Cache getMissingCache(String name) {
179
    return null;
×
180
  }
181

182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc