Skip to content

Commit

Permalink
refactors cache resolver (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcGiffing authored Feb 25, 2024
1 parent 9abaa77 commit a5c79f2
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 109 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache;

import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.distributed.AsyncBucketProxy;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;

import java.util.concurrent.CompletableFuture;

public abstract class AbstractCacheResolverTemplate<T> {

public ProxyManagerWrapper resolve(String cacheName) {
AbstractProxyManager<T> proxyManager = getProxyManager(cacheName);
return ((key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
if(isAsync()) {
AsyncBucketProxy bucket = proxyManager.asAsync()
.builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(castStringToCacheKey(key), () -> CompletableFuture.completedFuture(bucketConfiguration))
.toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
} else {
Bucket bucket = proxyManager
.builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(castStringToCacheKey(key), () -> bucketConfiguration)
.toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
}
});
}

public abstract T castStringToCacheKey(String key);

public abstract boolean isAsync();

public abstract AbstractProxyManager<T> getProxyManager(String cacheName);



}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@

package com.giffing.bucket4j.spring.boot.starter.config.cache.hazelcast;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.map.IMap;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.distributed.AsyncBucketProxy;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.distributed.proxy.ProxyManager;
import io.github.bucket4j.grid.hazelcast.HazelcastProxyManager;

Expand All @@ -16,7 +14,7 @@
* It uses the {@link HazelcastInstance} to retrieve the needed cache.
*
*/
public class HazelcastCacheResolver implements AsyncCacheResolver {
public class HazelcastCacheResolver extends AbstractCacheResolverTemplate<String> implements AsyncCacheResolver {

private final HazelcastInstance hazelcastInstance;

Expand All @@ -26,23 +24,20 @@ public HazelcastCacheResolver(HazelcastInstance hazelcastInstance, boolean async
this.hazelcastInstance = hazelcastInstance;
this.async = async;
}


@Override
public String castStringToCacheKey(String key) {
return key;
}

@Override
public boolean isAsync() {
return async;
}

@Override
public ProxyManagerWrapper resolve(String cacheName) {
public AbstractProxyManager<String> getProxyManager(String cacheName) {
IMap<String, byte[]> map = hazelcastInstance.getMap(cacheName);
HazelcastProxyManager<String> hazelcastProxyManager = new HazelcastProxyManager<>(map);
return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
if(async) {
AsyncBucketProxy bucket = hazelcastProxyManager.asAsync().builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key, bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
} else {
Bucket bucket = hazelcastProxyManager.builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key, bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
}
};
return new HazelcastProxyManager<>(map);
}
}
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache.ignite;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;

import io.github.bucket4j.distributed.AsyncBucketProxy;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.grid.ignite.thick.IgniteProxyManager;
import org.apache.ignite.Ignite;

public class IgniteCacheResolver implements AsyncCacheResolver {
public class IgniteCacheResolver extends AbstractCacheResolverTemplate<String> implements AsyncCacheResolver {

private final Ignite ignite;

public IgniteCacheResolver(Ignite ignite) {
this.ignite = ignite;
}


@Override
public String castStringToCacheKey(String key) {
return key;
}

@Override
public boolean isAsync() {
return false;
}

@Override
public ProxyManagerWrapper resolve(String cacheName) {
public AbstractProxyManager<String> getProxyManager(String cacheName) {
org.apache.ignite.IgniteCache<String, byte[]> cache = ignite.cache(cacheName);
IgniteProxyManager<String> igniteProxyManager = new IgniteProxyManager<>(cache);
return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
AsyncBucketProxy bucket = igniteProxyManager.asAsync().builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key, bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
};
return new IgniteProxyManager<>(cache);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache.infinispan;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
import io.github.bucket4j.distributed.AsyncBucketProxy;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.grid.infinispan.InfinispanProxyManager;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
Expand All @@ -12,7 +11,7 @@
import org.infinispan.functional.impl.ReadWriteMapImpl;
import org.infinispan.manager.CacheContainer;

public class InfinispanCacheResolver implements AsyncCacheResolver {
public class InfinispanCacheResolver extends AbstractCacheResolverTemplate<String> implements AsyncCacheResolver {

private final CacheContainer cacheContainer;

Expand All @@ -21,16 +20,21 @@ public InfinispanCacheResolver(CacheContainer cacheContainer) {
}

@Override
public ProxyManagerWrapper resolve(String cacheName) {
public String castStringToCacheKey(String key) {
return key;
}

@Override
public boolean isAsync() {
return true;
}

@Override
public AbstractProxyManager<String> getProxyManager(String cacheName) {
Cache<String, byte[]> cache = cacheContainer.getCache(cacheName);
InfinispanProxyManager<String> infinispanProxyManager = new InfinispanProxyManager<>(toMap(cache));
return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
AsyncBucketProxy bucket = infinispanProxyManager.asAsync().builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key, bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
};
return new InfinispanProxyManager<>(toMap(cache));
}

private static FunctionalMap.ReadWriteMap<String, byte[]> toMap(Cache<String, byte[]> cache) {
AdvancedCache<String, byte[]> advancedCache = cache.getAdvancedCache();
FunctionalMapImpl<String, byte[]> functionalMap = FunctionalMapImpl.create(advancedCache);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache.jcache;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.config.cache.SyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
import com.giffing.bucket4j.spring.boot.starter.exception.JCacheNotFoundException;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.distributed.proxy.ProxyManager;
import io.github.bucket4j.grid.jcache.JCacheProxyManager;

Expand All @@ -17,26 +16,30 @@
* It uses Bucket4Js {@link JCacheProxyManager} to implement the {@link ProxyManager}.
*
*/
public class JCacheCacheResolver implements SyncCacheResolver {
public class JCacheCacheResolver extends AbstractCacheResolverTemplate<String> implements SyncCacheResolver {

private final CacheManager cacheManager;

public JCacheCacheResolver(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}

public ProxyManagerWrapper resolve(String cacheName) {

@Override
public String castStringToCacheKey(String key) {
return key;
}

@Override
public boolean isAsync() {
return false;
}

@Override
public AbstractProxyManager<String> getProxyManager(String cacheName) {
Cache<String, byte[]> springCache = cacheManager.getCache(cacheName);
if (springCache == null) {
throw new JCacheNotFoundException(cacheName);
}

JCacheProxyManager<String> jCacheProxyManager = new JCacheProxyManager<>(springCache);
return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
Bucket bucket = jCacheProxyManager.builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key, bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
};
return new JCacheProxyManager<>(springCache);
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache.redis.jedis;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.config.cache.SyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy;
import io.github.bucket4j.distributed.proxy.ProxyManager;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.redis.jedis.cas.JedisBasedProxyManager;
import static java.nio.charset.StandardCharsets.UTF_8;
import redis.clients.jedis.JedisPool;

import java.time.Duration;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
* This class is the Redis implementation of the {@link CacheResolver}.
*
*/
public class JedisCacheResolver implements SyncCacheResolver {
public class JedisCacheResolver extends AbstractCacheResolverTemplate<byte[]> implements SyncCacheResolver {

private final JedisPool pool;

public JedisCacheResolver(JedisPool pool) {
this.pool = pool;
}

@Override
public ProxyManagerWrapper resolve(String cacheName) {
final ProxyManager<byte[]> proxyManager = JedisBasedProxyManager.builderFor(pool)
@Override
public boolean isAsync() {
return false;
}

@Override
public byte[] castStringToCacheKey(String key) {
return key.getBytes(UTF_8);
}

@Override
public AbstractProxyManager<byte[]> getProxyManager(String cacheName) {
return JedisBasedProxyManager.builderFor(pool)
.withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10)))
.build();

return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
Bucket bucket = proxyManager.builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key.getBytes(UTF_8), bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
};

}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
package com.giffing.bucket4j.spring.boot.starter.config.cache.redis.lettuce;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.time.Duration;

import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate;
import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver;
import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper;
import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder;

import io.github.bucket4j.distributed.AsyncBucketProxy;
import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy;
import io.github.bucket4j.distributed.proxy.ProxyManager;
import io.github.bucket4j.distributed.proxy.AbstractProxyManager;
import io.github.bucket4j.redis.lettuce.cas.LettuceBasedProxyManager;
import io.lettuce.core.RedisClient;

import java.time.Duration;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
* This class is the Redis implementation of the {@link CacheResolver}.
*/
public class LettuceCacheResolver implements AsyncCacheResolver {
public class LettuceCacheResolver extends AbstractCacheResolverTemplate<byte[]> implements AsyncCacheResolver {

private final RedisClient redisClient;

Expand All @@ -27,16 +24,19 @@ public LettuceCacheResolver(RedisClient redisClient) {
}

@Override
public ProxyManagerWrapper resolve(String cacheName) {
final ProxyManager<byte[]> proxyManager = LettuceBasedProxyManager.builderFor(redisClient)
public boolean isAsync() {
return true;
}

@Override
public AbstractProxyManager<byte[]> getProxyManager(String cacheName) {
return LettuceBasedProxyManager.builderFor(redisClient)
.withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10)))
.build();
}

return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> {
AsyncBucketProxy bucket = proxyManager.asAsync().builder()
.withImplicitConfigurationReplacement(version, replaceStrategy)
.build(key.getBytes(UTF_8), bucketConfiguration).toListenable(metricsListener);
return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens));
};
@Override
public byte[] castStringToCacheKey(String key) {
return key.getBytes(UTF_8);
}
}
Loading

0 comments on commit a5c79f2

Please sign in to comment.