Skip to content

Commit ed1eb30

Browse files
authored
feat: add infinispan jdk17 module (#245)
1 parent 4a56844 commit ed1eb30

File tree

8 files changed

+261
-11
lines changed

8 files changed

+261
-11
lines changed

README.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,18 @@ example), so it is safer to code against this API for long-term flexibility*
3434

3535
The following backing cache implementations have bindings already provided by this library:
3636

37-
| Backend | Provider | Artifact |
38-
| :-----: | :------: | :------: |
39-
| [Caffeine](https://github.com/ben-manes/caffeine/wiki) | `CaffeineProvider` | `cache-provider-caffeine` |
40-
| [Caffeine3](https://github.com/ben-manes/caffeine/wiki) | `Caffeine3Provider` | `cache-provider-caffeine3` |
41-
| [Guava](https://github.com/google/guava/wiki/CachesExplained) | `GuavaProvider` | `cache-provider-guava` |
42-
| [Cache2k](https://cache2k.org) | `Cache2kProvider` | `cache-provider-cache2k` |
43-
| [AndroidX](https://developer.android.com/reference/androidx/collection/LruCache) | `AndroidLruProvider` | `cache-provider-androidx` |
44-
| [ExpiringMap](https://github.com/jhalterman/expiringmap#expiringmap) | `ExpiringMapProvider` | `cache-provider-expiringmap` |
45-
| [Ehcache v3 (heap)](https://www.ehcache.org/documentation/3.0/index.html) | `EhcacheProvider` | `cache-provider-ehcache` |
46-
| [Infinispan (heap)](https://infinispan.org/documentation/) | `InfinispanProvider` | `cache-provider-infinispan` |
47-
| [Infinispan v14 (heap)](https://infinispan.org/documentation/) | `InfinispanProvider` | `cache-provider-infinispan-java11` |
37+
| Backend | Provider | Artifact |
38+
|:--------------------------------------------------------------------------------:|:---------------------:|:----------------------------------:|
39+
| [Caffeine](https://github.com/ben-manes/caffeine/wiki) | `CaffeineProvider` | `cache-provider-caffeine` |
40+
| [Caffeine3](https://github.com/ben-manes/caffeine/wiki) | `Caffeine3Provider` | `cache-provider-caffeine3` |
41+
| [Guava](https://github.com/google/guava/wiki/CachesExplained) | `GuavaProvider` | `cache-provider-guava` |
42+
| [Cache2k](https://cache2k.org) | `Cache2kProvider` | `cache-provider-cache2k` |
43+
| [AndroidX](https://developer.android.com/reference/androidx/collection/LruCache) | `AndroidLruProvider` | `cache-provider-androidx` |
44+
| [ExpiringMap](https://github.com/jhalterman/expiringmap#expiringmap) | `ExpiringMapProvider` | `cache-provider-expiringmap` |
45+
| [Ehcache v3 (heap)](https://www.ehcache.org/documentation/3.0/index.html) | `EhcacheProvider` | `cache-provider-ehcache` |
46+
| [Infinispan (heap)](https://infinispan.org/documentation/) | `InfinispanProvider` | `cache-provider-infinispan` |
47+
| [Infinispan v14 (heap)](https://infinispan.org/documentation/) | `InfinispanProvider` | `cache-provider-infinispan-java11` |
48+
| [Infinispan v15 (heap)](https://infinispan.org/documentation/) | `InfinispanProvider` | `cache-provider-infinispan-java17` |
4849

4950
Don't see your preferred implementation listed above?
5051
Fear not, it is not difficult to create your own binding, and we'd be happy to accept it in a PR!

core/src/main/java/io/github/xanthic/cache/core/CacheApiSettings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ private static void populateProviders(CacheApiSettings cacheApiSettings) {
139139
loadImpl.accept("io.github.xanthic.cache.provider.caffeine3.Caffeine3Provider");
140140
loadImpl.accept("io.github.xanthic.cache.provider.caffeine.CaffeineProvider");
141141
loadImpl.accept("io.github.xanthic.cache.provider.cache2k.Cache2kProvider");
142+
loadImpl.accept("io.github.xanthic.cache.provider.infinispanjdk17.InfinispanProvider");
142143
loadImpl.accept("io.github.xanthic.cache.provider.infinispanjdk11.InfinispanProvider");
143144
loadImpl.accept("io.github.xanthic.cache.provider.infinispan.InfinispanProvider");
144145
loadImpl.accept("io.github.xanthic.cache.provider.expiringmap.ExpiringMapProvider");
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
dependencies {
2+
api(project(":cache-core"))
3+
4+
implementation(platform("org.infinispan:infinispan-bom:15.0.0.Final"))
5+
6+
compileOnly("org.infinispan:infinispan-component-annotations")
7+
implementation("org.infinispan:infinispan-core")
8+
9+
testImplementation(testFixtures(project(":cache-core")))
10+
}
11+
12+
java {
13+
sourceCompatibility = JavaVersion.VERSION_17
14+
targetCompatibility = JavaVersion.VERSION_17
15+
}
16+
17+
publishing.publications.withType<MavenPublication> {
18+
pom {
19+
name.set("Xanthic - Infinispan Provider Module for JDK 17")
20+
description.set("Xanthic Provider dependency for Infinispan on JDK 17+")
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package io.github.xanthic.cache.provider.infinispanjdk17;
2+
3+
import io.github.xanthic.cache.api.Cache;
4+
import lombok.Value;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
import java.util.Map;
9+
import java.util.function.BiConsumer;
10+
import java.util.function.BiFunction;
11+
import java.util.function.Function;
12+
13+
@Value
14+
class InfinispanDelegate<K, V> implements Cache<K, V> {
15+
org.infinispan.Cache<K, V> cache;
16+
17+
@Override
18+
public V get(@NotNull K key) {
19+
return cache.get(key);
20+
}
21+
22+
@Override
23+
public V put(@NotNull K key, @NotNull V value) {
24+
return cache.put(key, value);
25+
}
26+
27+
@Override
28+
public V remove(@NotNull K key) {
29+
return cache.remove(key);
30+
}
31+
32+
@Override
33+
public void clear() {
34+
cache.clear();
35+
}
36+
37+
@Override
38+
public long size() {
39+
return cache.size();
40+
}
41+
42+
@Nullable
43+
@Override
44+
public V compute(@NotNull K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
45+
return cache.compute(key, computeFunc);
46+
}
47+
48+
@Override
49+
public V computeIfAbsent(@NotNull K key, @NotNull Function<K, V> computeFunc) {
50+
return cache.computeIfAbsent(key, computeFunc);
51+
}
52+
53+
@Override
54+
public V computeIfPresent(@NotNull K key, @NotNull BiFunction<? super K, ? super V, ? extends V> computeFunc) {
55+
return cache.computeIfPresent(key, computeFunc);
56+
}
57+
58+
@Override
59+
public V putIfAbsent(@NotNull K key, @NotNull V value) {
60+
return cache.putIfAbsent(key, value);
61+
}
62+
63+
@Override
64+
public V merge(@NotNull K key, @NotNull V value, @NotNull BiFunction<V, V, V> mergeFunc) {
65+
return cache.merge(key, value, mergeFunc);
66+
}
67+
68+
@Override
69+
public boolean replace(@NotNull K key, @NotNull V value) {
70+
return cache.replace(key, value) != null;
71+
}
72+
73+
@Override
74+
public boolean replace(@NotNull K key, @NotNull V oldValue, @NotNull V newValue) {
75+
return cache.replace(key, oldValue, newValue);
76+
}
77+
78+
@Override
79+
public void putAll(@NotNull Map<? extends K, ? extends V> map) {
80+
cache.putAll(map);
81+
}
82+
83+
@Override
84+
public void forEach(@NotNull BiConsumer<? super K, ? super V> action) {
85+
cache.forEach(action);
86+
}
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package io.github.xanthic.cache.provider.infinispanjdk17;
2+
3+
import io.github.xanthic.cache.api.RemovalListener;
4+
import io.github.xanthic.cache.api.domain.RemovalCause;
5+
import lombok.Value;
6+
import org.infinispan.notifications.Listener;
7+
import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
8+
import org.infinispan.notifications.cachelistener.annotation.CacheEntryExpired;
9+
import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
10+
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
11+
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
12+
import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
13+
import org.infinispan.notifications.cachelistener.event.CacheEntryExpiredEvent;
14+
import org.infinispan.notifications.cachelistener.event.CacheEntryInvalidatedEvent;
15+
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
16+
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
17+
import org.infinispan.notifications.cachelistener.event.Event;
18+
19+
import java.lang.annotation.Annotation;
20+
import java.util.Collections;
21+
import java.util.EnumSet;
22+
import java.util.IdentityHashMap;
23+
import java.util.Set;
24+
25+
@Value
26+
@Listener
27+
class InfinispanListener<K, V> {
28+
static final Set<Event.Type> EVENTS;
29+
static final Set<Class<? extends Annotation>> ANNOTATIONS;
30+
31+
RemovalListener<K, V> removalListener;
32+
33+
@CacheEntriesEvicted
34+
public void onPostEvictions(CacheEntriesEvictedEvent<K, V> event) {
35+
if (!event.isPre())
36+
event.getEntries().forEach((k, v) -> removalListener.onRemoval(k, v, RemovalCause.SIZE));
37+
}
38+
39+
@CacheEntryExpired
40+
public void onExpiry(CacheEntryExpiredEvent<K, V> event) {
41+
removalListener.onRemoval(event.getKey(), event.getValue(), RemovalCause.TIME);
42+
}
43+
44+
@CacheEntryInvalidated
45+
public void onInvalidation(CacheEntryInvalidatedEvent<K, V> event) {
46+
removalListener.onRemoval(event.getKey(), event.getValue(), RemovalCause.OTHER);
47+
}
48+
49+
@CacheEntryModified
50+
public void onPostModifyExisting(CacheEntryModifiedEvent<K, V> event) {
51+
if (!event.isCreated() && !event.isPre())
52+
removalListener.onRemoval(event.getKey(), event.getOldValue(), RemovalCause.REPLACED);
53+
}
54+
55+
@CacheEntryRemoved
56+
public void onPostRemoval(CacheEntryRemovedEvent<K, V> event) {
57+
if (!event.isPre())
58+
removalListener.onRemoval(event.getKey(), event.getOldValue(), RemovalCause.MANUAL);
59+
}
60+
61+
static {
62+
EVENTS = EnumSet.noneOf(Event.Type.class);
63+
EVENTS.add(Event.Type.CACHE_ENTRY_EVICTED);
64+
EVENTS.add(Event.Type.CACHE_ENTRY_EXPIRED);
65+
EVENTS.add(Event.Type.CACHE_ENTRY_INVALIDATED);
66+
EVENTS.add(Event.Type.CACHE_ENTRY_MODIFIED);
67+
EVENTS.add(Event.Type.CACHE_ENTRY_REMOVED);
68+
69+
ANNOTATIONS = Collections.newSetFromMap(new IdentityHashMap<>());
70+
ANNOTATIONS.add(CacheEntriesEvicted.class);
71+
ANNOTATIONS.add(CacheEntryExpired.class);
72+
ANNOTATIONS.add(CacheEntryInvalidated.class);
73+
ANNOTATIONS.add(CacheEntryModified.class);
74+
ANNOTATIONS.add(CacheEntryRemoved.class);
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.github.xanthic.cache.provider.infinispanjdk17;
2+
3+
import io.github.xanthic.cache.api.Cache;
4+
import io.github.xanthic.cache.api.ICacheSpec;
5+
import io.github.xanthic.cache.api.domain.ExpiryType;
6+
import io.github.xanthic.cache.core.AbstractCacheProvider;
7+
import org.infinispan.commons.api.CacheContainerAdmin;
8+
import org.infinispan.configuration.cache.ConfigurationBuilder;
9+
import org.infinispan.manager.DefaultCacheManager;
10+
import org.infinispan.manager.EmbeddedCacheManager;
11+
12+
import java.util.UUID;
13+
import java.util.concurrent.TimeUnit;
14+
15+
/**
16+
* Provides {@link Cache} instances using Infinispan's {@link org.infinispan.Cache} in heap-mode.
17+
* <p>
18+
* Implements size and time-based expiry.
19+
*/
20+
public final class InfinispanProvider extends AbstractCacheProvider {
21+
private static final EmbeddedCacheManager MANAGER = new DefaultCacheManager();
22+
23+
@Override
24+
public <K, V> Cache<K, V> build(ICacheSpec<K, V> spec) {
25+
ConfigurationBuilder builder = new ConfigurationBuilder();
26+
builder.simpleCache(true);
27+
if (spec.maxSize() != null) builder.memory().maxCount(spec.maxSize());
28+
handleExpiration(spec.expiryTime(), spec.expiryType(), (time, type) -> {
29+
if (type == ExpiryType.POST_WRITE)
30+
builder.expiration().lifespan(time.toNanos(), TimeUnit.NANOSECONDS);
31+
else
32+
builder.expiration().maxIdle(time.toNanos(), TimeUnit.NANOSECONDS);
33+
});
34+
35+
org.infinispan.Cache<K, V> cache = MANAGER.administration()
36+
.withFlags(CacheContainerAdmin.AdminFlag.VOLATILE)
37+
.createCache(UUID.randomUUID().toString(), builder.build());
38+
39+
if (spec.removalListener() != null) {
40+
cache.addFilteredListener(
41+
new InfinispanListener<>(spec.removalListener()),
42+
(key, oldValue, oldMeta, newValue, newMeta, eventType) -> eventType != null && InfinispanListener.EVENTS.contains(eventType.getType()),
43+
null,
44+
InfinispanListener.ANNOTATIONS
45+
);
46+
}
47+
48+
return new InfinispanDelegate<>(cache);
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.github.xanthic.cache.provider.infinispanjdk17;
2+
3+
import io.github.xanthic.cache.core.provider.ProviderTestBase;
4+
5+
public class InfinispanJava17ProviderTest extends ProviderTestBase {
6+
7+
public InfinispanJava17ProviderTest() {
8+
super(new InfinispanProvider());
9+
}
10+
11+
}

settings.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ include(
1717
":provider-guava",
1818
":provider-infinispan",
1919
":provider-infinispan-java11",
20+
":provider-infinispan-java17",
2021
)
2122

2223
project(":bom").name = "cache-bom"
@@ -35,3 +36,4 @@ project(":provider-expiringmap").name = "cache-provider-expiringmap"
3536
project(":provider-guava").name = "cache-provider-guava"
3637
project(":provider-infinispan").name = "cache-provider-infinispan"
3738
project(":provider-infinispan-java11").name = "cache-provider-infinispan-java11"
39+
project(":provider-infinispan-java17").name = "cache-provider-infinispan-java17"

0 commit comments

Comments
 (0)