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

ben-manes / caffeine / #5651

18 Jul 2026 03:26AM UTC coverage: 66.303% (-33.7%) from 100.0%
#5651

push

github

ben-manes
dependency updates

2809 of 4164 branches covered (67.46%)

5584 of 8422 relevant lines covered (66.3%)

0.66 hits per line

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

0.0
/jcache/src/main/java/com/github/benmanes/caffeine/jcache/CacheManagerImpl.java
1
/*
2
 * Copyright 2015 Ben Manes. All Rights Reserved.
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
package com.github.benmanes.caffeine.jcache;
17

18
import static java.util.Objects.requireNonNull;
19

20
import java.lang.System.Logger;
21
import java.lang.System.Logger.Level;
22
import java.lang.ref.WeakReference;
23
import java.net.URI;
24
import java.util.Collection;
25
import java.util.List;
26
import java.util.Map;
27
import java.util.Properties;
28
import java.util.concurrent.ConcurrentHashMap;
29

30
import javax.cache.Cache;
31
import javax.cache.CacheException;
32
import javax.cache.CacheManager;
33
import javax.cache.configuration.CompleteConfiguration;
34
import javax.cache.configuration.Configuration;
35
import javax.cache.spi.CachingProvider;
36

37
import org.jspecify.annotations.Nullable;
38

39
/**
40
 * An implementation of JSR-107 {@link CacheManager} that manages Caffeine-based caches.
41
 *
42
 * @author ben.manes@gmail.com (Ben Manes)
43
 */
44
@SuppressWarnings("PMD.CloseResource")
45
public final class CacheManagerImpl implements CacheManager {
46
  private static final Logger logger = System.getLogger(CacheManagerImpl.class.getName());
×
47

48
  private final Object lock;
49

50
  final WeakReference<ClassLoader> classLoaderReference;
51
  final Map<String, CacheProxy<?, ?>> caches;
52
  final CachingProvider cacheProvider;
53
  final Properties properties;
54
  final URI uri;
55

56
  final boolean runsAsAnOsgiBundle;
57

58
  volatile boolean closed;
59

60
  public CacheManagerImpl(CachingProvider cacheProvider, boolean runsAsAnOsgiBundle,
61
      URI uri, ClassLoader classLoader, Properties properties) {
×
62
    this.classLoaderReference = new WeakReference<>(requireNonNull(classLoader));
×
63
    this.cacheProvider = requireNonNull(cacheProvider);
×
64
    this.runsAsAnOsgiBundle = runsAsAnOsgiBundle;
×
65
    this.properties = requireNonNull(properties);
×
66
    this.caches = new ConcurrentHashMap<>();
×
67
    this.uri = requireNonNull(uri);
×
68
    this.lock = new Object();
×
69
  }
×
70

71
  @Override
72
  public CachingProvider getCachingProvider() {
73
    return cacheProvider;
×
74
  }
75

76
  @Override
77
  public URI getURI() {
78
    return uri;
×
79
  }
80

81
  @Override
82
  public @Nullable ClassLoader getClassLoader() {
83
    return classLoaderReference.get();
×
84
  }
85

86
  @Override
87
  public Properties getProperties() {
88
    return properties;
×
89
  }
90

91
  @Override
92
  public <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(
93
      String cacheName, C configuration) {
94
    requireNonNull(configuration);
×
95
    var classLoader = Thread.currentThread().getContextClassLoader();
×
96
    try {
97
      if (runsAsAnOsgiBundle) {
×
98
        // override the context class loader with the CachingManager's classloader
99
        Thread.currentThread().setContextClassLoader(getClassLoader());
×
100
      }
101

102
      synchronized (lock) {
×
103
        requireNotClosed();
×
104
        CacheProxy<?, ?> cache = caches.compute(cacheName, (name, existing) -> {
×
105
          if (existing != null) {
×
106
            throw new CacheException("Cache " + cacheName + " already exists");
×
107
          } else if (CacheFactory.isDefinedExternally(this, cacheName)) {
×
108
            throw new CacheException("Cache " + cacheName + " is configured externally");
×
109
          }
110
          return CacheFactory.createCache(this, cacheName, configuration);
×
111
        });
112

113
        @SuppressWarnings("unchecked")
114
        var config = cache.getConfiguration(CompleteConfiguration.class);
×
115
        enableManagement(cache.getName(), config.isManagementEnabled());
×
116
        enableStatistics(cache.getName(), config.isStatisticsEnabled());
×
117

118
        @SuppressWarnings("unchecked")
119
        var castedCache = (Cache<K, V>) cache;
×
120
        return castedCache;
×
121
      }
122
    } finally {
123
      Thread.currentThread().setContextClassLoader(classLoader);
×
124
    }
125
  }
126

127
  @Override
128
  public <K, V> @Nullable Cache<K, V> getCache(
129
      String cacheName, Class<K> keyType, Class<V> valueType) {
130
    requireNonNull(keyType);
×
131
    requireNonNull(valueType);
×
132
    var classLoader = Thread.currentThread().getContextClassLoader();
×
133
    try {
134
      if (runsAsAnOsgiBundle) {
×
135
        // override the context class loader with the CachingManager's classloader
136
        Thread.currentThread().setContextClassLoader(getClassLoader());
×
137
      }
138
      CacheProxy<K, V> cache = getCache(cacheName);
×
139
      if (cache == null) {
×
140
        return null;
×
141
      }
142

143
      @SuppressWarnings("unchecked")
144
      var config = cache.getConfiguration(CompleteConfiguration.class);
×
145
      if (keyType != config.getKeyType()) {
×
146
        throw new ClassCastException("Incompatible cache key types specified, expected "
×
147
            + config.getKeyType() + " but " + keyType + " was specified");
×
148
      } else if (valueType != config.getValueType()) {
×
149
        throw new ClassCastException("Incompatible cache value types specified, expected "
×
150
            + config.getValueType() + " but " + valueType + " was specified");
×
151
      }
152
      return cache;
×
153
    } finally {
154
      Thread.currentThread().setContextClassLoader(classLoader);
×
155
    }
156
  }
157

158
  @Override
159
  public <K, V> @Nullable CacheProxy<K, V> getCache(String cacheName) {
160
    requireNonNull(cacheName);
×
161
    var classLoader = Thread.currentThread().getContextClassLoader();
×
162
    try {
163
      if (runsAsAnOsgiBundle) {
×
164
        // override the context class loader with the CachingManager's classloader
165
        Thread.currentThread().setContextClassLoader(getClassLoader());
×
166
      }
167

168
      synchronized (lock) {
×
169
        requireNotClosed();
×
170
        CacheProxy<?, ?> cache = caches.computeIfAbsent(cacheName, name -> {
×
171
          CacheProxy<?, ?> created = CacheFactory.tryToCreateFromExternalSettings(this, name);
×
172
          if (created != null) {
×
173
            @SuppressWarnings("unchecked")
174
            var config = created.getConfiguration(CompleteConfiguration.class);
×
175
            created.enableManagement(config.isManagementEnabled());
×
176
            created.enableStatistics(config.isStatisticsEnabled());
×
177
          }
178
          return created;
×
179
        });
180

181
        @SuppressWarnings("unchecked")
182
        var castedCache = (CacheProxy<K, V>) cache;
×
183
        return castedCache;
×
184
      }
185
    } finally {
186
      Thread.currentThread().setContextClassLoader(classLoader);
×
187
    }
188
  }
189

190
  @Override
191
  @SuppressWarnings("PreferredInterfaceType")
192
  public Collection<String> getCacheNames() {
193
    requireNotClosed();
×
194
    return List.copyOf(caches.keySet());
×
195
  }
196

197
  @Override
198
  public void destroyCache(String cacheName) {
199
    requireNotClosed();
×
200

201
    Cache<?, ?> cache = caches.remove(cacheName);
×
202
    if (cache != null) {
×
203
      cache.close();
×
204
    }
205
  }
×
206

207
  /** Removes the cache from the registry if it is still the registered instance. */
208
  void destroyCache(String cacheName, CacheProxy<?, ?> cache) {
209
    requireNotClosed();
×
210
    caches.remove(cacheName, cache);
×
211
  }
×
212

213
  @Override
214
  public void enableManagement(String cacheName, boolean enabled) {
215
    requireNotClosed();
×
216

217
    CacheProxy<?, ?> cache = caches.get(cacheName);
×
218
    if (cache == null) {
×
219
      return;
×
220
    }
221
    cache.enableManagement(enabled);
×
222
  }
×
223

224
  @Override
225
  public void enableStatistics(String cacheName, boolean enabled) {
226
    requireNotClosed();
×
227

228
    CacheProxy<?, ?> cache = caches.get(cacheName);
×
229
    if (cache == null) {
×
230
      return;
×
231
    }
232
    cache.enableStatistics(enabled);
×
233
  }
×
234

235
  @Override
236
  public void close() {
237
    if (isClosed()) {
×
238
      return;
×
239
    }
240
    synchronized (lock) {
×
241
      if (isClosed()) {
×
242
        return;
×
243
      }
244
      for (Cache<?, ?> cache : caches.values()) {
×
245
        try {
246
          cache.close();
×
247
        } catch (RuntimeException e) {
×
248
          logger.log(Level.WARNING, "Exception thrown when closing cache " + cache.getName(), e);
×
249
        }
×
250
      }
×
251
      closed = true;
×
252
    }
×
253
    ClassLoader classLoader = classLoaderReference.get();
×
254
    if (classLoader != null) {
×
255
      cacheProvider.close(uri, classLoader);
×
256
    }
257
  }
×
258

259
  @Override
260
  public boolean isClosed() {
261
    return closed;
×
262
  }
263

264
  @Override
265
  public <T> T unwrap(Class<T> clazz) {
266
    if (clazz.isInstance(this)) {
×
267
      return clazz.cast(this);
×
268
    }
269
    throw new IllegalArgumentException("Unwrapping to " + clazz
×
270
        + " is not supported by this implementation");
271
  }
272

273
  /** Checks that the cache manager is not closed. */
274
  private void requireNotClosed() {
275
    if (isClosed()) {
×
276
      throw new IllegalStateException();
×
277
    }
278
  }
×
279
}
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