diff --git a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderOptions.java b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderOptions.java
index c8d38fc30..552713038 100644
--- a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderOptions.java
+++ b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderOptions.java
@@ -1,6 +1,7 @@
package dev.openfeature.contrib.providers.gofeatureflag;
-import com.google.common.cache.CacheBuilder;
+import com.github.benmanes.caffeine.cache.Caffeine;
+
import dev.openfeature.sdk.ProviderEvaluation;
import lombok.Builder;
import lombok.Getter;
@@ -49,14 +50,26 @@ public class GoFeatureFlagProviderOptions {
/**
* (optional) If cache custom configuration is wanted, you should provide
- * a cache builder.
+ * a cache configuration caffeine object.
+ * Example:
+ *
+ * GoFeatureFlagProviderOptions.builder()
+ * .caffeineConfig(
+ * Caffeine.newBuilder()
+ * .initialCapacity(100)
+ * .maximumSize(100000)
+ * .expireAfterWrite(Duration.ofMillis(5L * 60L * 1000L))
+ * .build()
+ * )
+ * .build();
+ *
+ *
* Default:
* CACHE_TTL_MS: 5min
- * CACHE_CONCURRENCY_LEVEL: 1
* CACHE_INITIAL_CAPACITY: 100
* CACHE_MAXIMUM_SIZE: 100000
*/
- private CacheBuilder> cacheBuilder;
+ private Caffeine> cacheConfig;
/**
* (optional) enable cache value.
diff --git a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/CacheController.java b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/CacheController.java
index d3ca23f2f..450e69517 100644
--- a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/CacheController.java
+++ b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/CacheController.java
@@ -1,34 +1,33 @@
package dev.openfeature.contrib.providers.gofeatureflag.controller;
+import java.time.Duration;
+
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+
import dev.openfeature.contrib.providers.gofeatureflag.GoFeatureFlagProviderOptions;
import dev.openfeature.contrib.providers.gofeatureflag.bean.BeanUtils;
import dev.openfeature.sdk.EvaluationContext;
import dev.openfeature.sdk.ProviderEvaluation;
import lombok.Builder;
-import java.time.Duration;
-
/**
* CacheController is a controller to manage the cache of the provider.
*/
public class CacheController {
public static final long DEFAULT_CACHE_TTL_MS = 5L * 60L * 1000L;
- public static final int DEFAULT_CACHE_CONCURRENCY_LEVEL = 1;
public static final int DEFAULT_CACHE_INITIAL_CAPACITY = 100;
public static final int DEFAULT_CACHE_MAXIMUM_SIZE = 100000;
private final Cache> cache;
@Builder
public CacheController(GoFeatureFlagProviderOptions options) {
- this.cache = options.getCacheBuilder() != null ? options.getCacheBuilder().build() : buildDefaultCache();
+ this.cache = options.getCacheConfig() != null ? options.getCacheConfig().build() : buildDefaultCache();
}
private Cache> buildDefaultCache() {
- return CacheBuilder.newBuilder()
- .concurrencyLevel(DEFAULT_CACHE_CONCURRENCY_LEVEL)
+ return Caffeine.newBuilder()
.initialCapacity(DEFAULT_CACHE_INITIAL_CAPACITY)
.maximumSize(DEFAULT_CACHE_MAXIMUM_SIZE)
.expireAfterWrite(Duration.ofMillis(DEFAULT_CACHE_TTL_MS))
diff --git a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/GoFeatureFlagController.java b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/GoFeatureFlagController.java
index 5c98577be..648af2d69 100644
--- a/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/GoFeatureFlagController.java
+++ b/providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/GoFeatureFlagController.java
@@ -5,7 +5,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import com.google.common.net.HttpHeaders;
import dev.openfeature.contrib.providers.gofeatureflag.EvaluationResponse;
import dev.openfeature.contrib.providers.gofeatureflag.GoFeatureFlagProviderOptions;
import dev.openfeature.contrib.providers.gofeatureflag.bean.ConfigurationChange;
@@ -60,6 +59,11 @@ public class GoFeatureFlagController {
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
private static final String BEARER_TOKEN = "Bearer ";
+ private static final String HTTP_HEADER_CONTENT_TYPE = "Content-Type";
+ private static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
+ private static final String HTTP_HEADER_ETAG = "ETag";
+ private static final String HTTP_HEADER_IF_NONE_MATCH = "If-None-Match";
+
/**
* apiKey contains the token to use while calling GO Feature Flag relay proxy.
*/
@@ -137,13 +141,13 @@ public EvaluationResponse evaluateFlag(
Request.Builder reqBuilder = new Request.Builder()
.url(url)
- .addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON)
+ .addHeader(HTTP_HEADER_CONTENT_TYPE, APPLICATION_JSON)
.post(RequestBody.create(
requestMapper.writeValueAsBytes(goffRequest),
MediaType.get("application/json; charset=utf-8")));
if (this.apiKey != null && !this.apiKey.isEmpty()) {
- reqBuilder.addHeader(HttpHeaders.AUTHORIZATION, BEARER_TOKEN + this.apiKey);
+ reqBuilder.addHeader(HTTP_HEADER_AUTHORIZATION, BEARER_TOKEN + this.apiKey);
}
try (Response response = this.httpClient.newCall(reqBuilder.build()).execute()) {
@@ -216,13 +220,13 @@ public void sendEventToDataCollector(List eventsList) {
Request.Builder reqBuilder = new Request.Builder()
.url(url)
- .addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON)
+ .addHeader(HTTP_HEADER_CONTENT_TYPE, APPLICATION_JSON)
.post(RequestBody.create(
requestMapper.writeValueAsBytes(events),
MediaType.get("application/json; charset=utf-8")));
if (this.apiKey != null && !this.apiKey.isEmpty()) {
- reqBuilder.addHeader(HttpHeaders.AUTHORIZATION, BEARER_TOKEN + this.apiKey);
+ reqBuilder.addHeader(HTTP_HEADER_AUTHORIZATION, BEARER_TOKEN + this.apiKey);
}
try (Response response = this.httpClient.newCall(reqBuilder.build()).execute()) {
@@ -259,14 +263,14 @@ public ConfigurationChange configurationHasChanged() throws GoFeatureFlagExcepti
Request.Builder reqBuilder = new Request.Builder()
.url(url)
- .addHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON)
+ .addHeader(HTTP_HEADER_CONTENT_TYPE, APPLICATION_JSON)
.get();
if (this.etag != null && !this.etag.isEmpty()) {
- reqBuilder.addHeader(HttpHeaders.IF_NONE_MATCH, this.etag);
+ reqBuilder.addHeader(HTTP_HEADER_IF_NONE_MATCH, this.etag);
}
if (this.apiKey != null && !this.apiKey.isEmpty()) {
- reqBuilder.addHeader(HttpHeaders.AUTHORIZATION, BEARER_TOKEN + this.apiKey);
+ reqBuilder.addHeader(HTTP_HEADER_AUTHORIZATION, BEARER_TOKEN + this.apiKey);
}
try (Response response = this.httpClient.newCall(reqBuilder.build()).execute()) {
@@ -283,7 +287,7 @@ public ConfigurationChange configurationHasChanged() throws GoFeatureFlagExcepti
}
boolean isInitialConfiguration = this.etag == null;
- this.etag = response.header(HttpHeaders.ETAG);
+ this.etag = response.header(HTTP_HEADER_ETAG);
return isInitialConfiguration
? ConfigurationChange.FLAG_CONFIGURATION_INITIALIZED
: ConfigurationChange.FLAG_CONFIGURATION_UPDATED;
diff --git a/providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java b/providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java
index ed8c0df3f..64f2c7f07 100644
--- a/providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java
+++ b/providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java
@@ -1,5 +1,10 @@
package dev.openfeature.contrib.providers.gofeatureflag;
+import static dev.openfeature.contrib.providers.gofeatureflag.controller.GoFeatureFlagController.requestMapper;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@@ -10,42 +15,34 @@
import java.util.List;
import java.util.Map;
-import com.google.common.cache.CacheBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.net.HttpHeaders;
+
+import dev.openfeature.contrib.providers.gofeatureflag.exception.InvalidEndpoint;
+import dev.openfeature.contrib.providers.gofeatureflag.exception.InvalidOptions;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.ErrorCode;
-import dev.openfeature.sdk.EvaluationContext;
import dev.openfeature.sdk.FlagEvaluationDetails;
import dev.openfeature.sdk.ImmutableContext;
-import dev.openfeature.sdk.OpenFeatureAPI;
-import dev.openfeature.sdk.ProviderState;
-import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
-import lombok.extern.slf4j.Slf4j;
-import org.jetbrains.annotations.NotNull;
import dev.openfeature.sdk.ImmutableMetadata;
import dev.openfeature.sdk.MutableContext;
import dev.openfeature.sdk.MutableStructure;
+import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Reason;
import dev.openfeature.sdk.Value;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import dev.openfeature.contrib.providers.gofeatureflag.exception.InvalidEndpoint;
-import dev.openfeature.contrib.providers.gofeatureflag.exception.InvalidOptions;
import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.Dispatcher;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
-import org.junit.jupiter.api.TestInfo;
-
-import static dev.openfeature.contrib.providers.gofeatureflag.controller.GoFeatureFlagController.requestMapper;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
@Slf4j
class GoFeatureFlagProviderTest {
@@ -361,9 +358,9 @@ void should_resolve_from_cache() {
@SneakyThrows
@Test
void should_resolve_from_cache_max_size() {
- CacheBuilder cacheBuilder = CacheBuilder.newBuilder().maximumSize(1);
+ Caffeine caffeine = Caffeine.newBuilder().maximumSize(1);
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder()
- .endpoint(this.baseUrl.toString()).timeout(1000).cacheBuilder(cacheBuilder).build());
+ .endpoint(this.baseUrl.toString()).timeout(1000).cacheConfig(caffeine).build());
String providerName = this.testName;
OpenFeatureAPI.getInstance().setProviderAndWait(providerName, g);
Client client = OpenFeatureAPI.getInstance().getClient(providerName);
@@ -406,10 +403,6 @@ void should_resolve_from_cache_max_size() {
.flagMetadata(defaultMetadata)
.build();
assertEquals(wantStr2, gotStr);
-
- // verify that value previously fetch from cache now not fetched from cache since cache max size is 1, and cache is full.
- got = client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
- assertEquals(want, got);
}
@SneakyThrows