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

ben-manes / caffeine / #5173

29 Dec 2025 05:27AM UTC coverage: 0.0% (-100.0%) from 100.0%
#5173

push

github

ben-manes
speed up development ci build

0 of 3838 branches covered (0.0%)

0 of 7869 relevant lines covered (0.0%)

0.0 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/spi/CaffeineCachingProvider.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.spi;
17

18
import static javax.cache.configuration.OptionalFeature.STORE_BY_REFERENCE;
19

20
import java.io.IOException;
21
import java.net.URI;
22
import java.net.URL;
23
import java.util.ArrayList;
24
import java.util.Collections;
25
import java.util.Enumeration;
26
import java.util.HashMap;
27
import java.util.Map;
28
import java.util.Properties;
29
import java.util.WeakHashMap;
30

31
import javax.cache.CacheManager;
32
import javax.cache.Caching;
33
import javax.cache.configuration.OptionalFeature;
34
import javax.cache.spi.CachingProvider;
35

36
import org.jspecify.annotations.NullMarked;
37
import org.jspecify.annotations.Nullable;
38
import org.osgi.service.component.annotations.Activate;
39
import org.osgi.service.component.annotations.Component;
40

41
import com.github.benmanes.caffeine.jcache.CacheManagerImpl;
42
import com.google.errorprone.annotations.Var;
43
import com.google.errorprone.annotations.concurrent.GuardedBy;
44

45
/**
46
 * A provider that produces a JCache implementation backed by Caffeine. Typically, this provider is
47
 * instantiated using {@link Caching#getCachingProvider()} which discovers this implementation
48
 * through a {@link java.util.ServiceLoader}.
49
 * <p>
50
 * This provider is expected to be used for application life cycle events, like initialization. It
51
 * is not expected that all requests flow through the provider to obtain the cache manager and cache
52
 * instances for request operations. Internally, this implementation is synchronized to avoid using
53
 * excess memory due to its infrequent usage.
54
 *
55
 * @author ben.manes@gmail.com (Ben Manes)
56
 */
57
@Component
58
@NullMarked
59
public final class CaffeineCachingProvider implements CachingProvider {
60
  private static final ClassLoader DEFAULT_CLASS_LOADER =
×
61
      new JCacheClassLoader(Thread.currentThread().getContextClassLoader());
×
62

63
  @GuardedBy("itself")
64
  final Map<ClassLoader, Map<URI, CacheManager>> cacheManagers;
65

66
  boolean isOsgiComponent;
67

68
  public CaffeineCachingProvider() {
×
69
    this.cacheManagers = new WeakHashMap<>(1);
×
70
  }
×
71

72
  @Override
73
  public ClassLoader getDefaultClassLoader() {
74
    return DEFAULT_CLASS_LOADER;
×
75
  }
76

77
  @Override
78
  public URI getDefaultURI() {
79
    return URI.create(getClass().getName());
×
80
  }
81

82
  @Override
83
  public Properties getDefaultProperties() {
84
    return new Properties();
×
85
  }
86

87
  @Override
88
  public CacheManager getCacheManager() {
89
    return getCacheManager(getDefaultURI(), getDefaultClassLoader());
×
90
  }
91

92
  @Override
93
  public CacheManager getCacheManager(URI uri, ClassLoader classLoader) {
94
    return getCacheManager(uri, classLoader, getDefaultProperties());
×
95
  }
96

97
  @Override
98
  public CacheManager getCacheManager(URI uri,
99
      ClassLoader classLoader, @Nullable Properties properties) {
100
    URI managerUri = getManagerUri(uri);
×
101
    ClassLoader managerClassLoader = getManagerClassLoader(classLoader);
×
102

103
    synchronized (cacheManagers) {
×
104
      Map<URI, CacheManager> cacheManagersByUri = cacheManagers.computeIfAbsent(
×
105
          managerClassLoader, any -> new HashMap<>());
×
106
      return cacheManagersByUri.computeIfAbsent(managerUri, any -> {
×
107
        Properties managerProperties = (properties == null) ? getDefaultProperties() : properties;
×
108
        return new CacheManagerImpl(this, isOsgiComponent,
×
109
            managerUri, managerClassLoader, managerProperties);
110
      });
111
    }
112
  }
113

114
  @Override
115
  public void close() {
116
    synchronized (cacheManagers) {
×
117
      for (ClassLoader classLoader : new ArrayList<>(cacheManagers.keySet())) {
×
118
        close(classLoader);
×
119
      }
×
120
    }
×
121
  }
×
122

123
  @Override
124
  @SuppressWarnings("PMD.CloseResource")
125
  public void close(ClassLoader classLoader) {
126
    synchronized (cacheManagers) {
×
127
      ClassLoader managerClassLoader = getManagerClassLoader(classLoader);
×
128
      Map<URI, CacheManager> cacheManagersByUri = cacheManagers.remove(managerClassLoader);
×
129
      if (cacheManagersByUri != null) {
×
130
        for (CacheManager cacheManager : cacheManagersByUri.values()) {
×
131
          cacheManager.close();
×
132
        }
×
133
      }
134
    }
×
135
  }
×
136

137
  @Override
138
  @SuppressWarnings("PMD.CloseResource")
139
  public void close(URI uri, ClassLoader classLoader) {
140
    synchronized (cacheManagers) {
×
141
      ClassLoader managerClassLoader = getManagerClassLoader(classLoader);
×
142
      Map<URI, CacheManager> cacheManagersByUri = cacheManagers.get(managerClassLoader);
×
143

144
      if (cacheManagersByUri != null) {
×
145
        CacheManager cacheManager = cacheManagersByUri.remove(getManagerUri(uri));
×
146
        if (cacheManager != null) {
×
147
          cacheManager.close();
×
148
        }
149
        if (cacheManagersByUri.isEmpty()) {
×
150
          cacheManagers.remove(managerClassLoader);
×
151
        }
152
      }
153
    }
×
154
  }
×
155

156
  @Override
157
  public boolean isSupported(OptionalFeature optionalFeature) {
158
    return (optionalFeature == STORE_BY_REFERENCE);
×
159
  }
160

161
  private URI getManagerUri(@Nullable URI uri) {
162
    return (uri == null) ? getDefaultURI() : uri;
×
163
  }
164

165
  private ClassLoader getManagerClassLoader(@Nullable ClassLoader classLoader) {
166
    return (classLoader == null) ? getDefaultClassLoader() : classLoader;
×
167
  }
168

169
  /**
170
   * A {@link ClassLoader} that combines {@code Thread.currentThread().getContextClassLoader()}
171
   * and {@code getClass().getClassLoader()}.
172
   */
173
  static class JCacheClassLoader extends ClassLoader {
174

175
    public JCacheClassLoader(@Nullable ClassLoader parent) {
176
      super(parent);
×
177
    }
×
178

179
    @Override
180
    public Class<?> loadClass(String name) throws ClassNotFoundException {
181
      @Var ClassNotFoundException error = null;
×
182

183
      ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
×
184
      if ((contextClassLoader != null) && (contextClassLoader != DEFAULT_CLASS_LOADER)) {
×
185
        try {
186
          return contextClassLoader.loadClass(name);
×
187
        } catch (ClassNotFoundException e) {
×
188
          error = e;
×
189
        }
190
      }
191

192
      ClassLoader classClassLoader = getClassClassLoader();
×
193
      if ((classClassLoader != null) && (classClassLoader != contextClassLoader)) {
×
194
        try {
195
          return classClassLoader.loadClass(name);
×
196
        } catch (ClassNotFoundException e) {
×
197
          error = e;
×
198
        }
199
      }
200

201
      ClassLoader parentClassLoader = getParent();
×
202
      if ((parentClassLoader != null)
×
203
          && (parentClassLoader != classClassLoader)
204
          && (parentClassLoader != contextClassLoader)) {
205
        try {
206
          return parentClassLoader.loadClass(name);
×
207
        } catch (ClassNotFoundException e) {
×
208
          error = e;
×
209
        }
210
      }
211
      throw (error == null) ? new ClassNotFoundException(name) : error;
×
212
    }
213

214
    @Override
215
    public @Nullable URL getResource(String name) {
216
      ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
×
217
      if ((contextClassLoader != null) && (contextClassLoader != DEFAULT_CLASS_LOADER)) {
×
218
        URL resource = contextClassLoader.getResource(name);
×
219
        if (resource != null) {
×
220
          return resource;
×
221
        }
222
      }
223

224
      ClassLoader classClassLoader = getClassClassLoader();
×
225
      if ((classClassLoader != null) && (classClassLoader != contextClassLoader)) {
×
226
        URL resource = classClassLoader.getResource(name);
×
227
        if (resource != null) {
×
228
          return resource;
×
229
        }
230
      }
231

232
      ClassLoader parentClassLoader = getParent();
×
233
      if ((parentClassLoader != null)
×
234
          && (parentClassLoader != classClassLoader)
235
          && (parentClassLoader != contextClassLoader)) {
236
        return parentClassLoader.getResource(name);
×
237
      }
238

239
      return null;
×
240
    }
241

242
    @Override
243
    public Enumeration<URL> getResources(String name) throws IOException {
244
      var resources = new ArrayList<URL>();
×
245

246
      ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
×
247
      if ((contextClassLoader != null) && contextClassLoader != DEFAULT_CLASS_LOADER) {
×
248
        resources.addAll(Collections.list(contextClassLoader.getResources(name)));
×
249
      }
250

251
      ClassLoader classClassLoader = getClassClassLoader();
×
252
      if ((classClassLoader != null) && (classClassLoader != contextClassLoader)) {
×
253
        resources.addAll(Collections.list(classClassLoader.getResources(name)));
×
254
      }
255

256
      ClassLoader parentClassLoader = getParent();
×
257
      if ((parentClassLoader != null)
×
258
          && (parentClassLoader != classClassLoader)
259
          && (parentClassLoader != contextClassLoader)) {
260
        resources.addAll(Collections.list(parentClassLoader.getResources(name)));
×
261
      }
262

263
      return Collections.enumeration(resources);
×
264
    }
265

266
    @Nullable ClassLoader getClassClassLoader() {
267
      return getClass().getClassLoader();
×
268
    }
269
  }
270

271
  @Activate
272
  @SuppressWarnings("unused")
273
  private void activate() {
274
    isOsgiComponent = true;
×
275
  }
×
276
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc