diff --git a/src/main/java/com/devcycle/sdk/server/common/api/IDevCycleApi.java b/src/main/java/com/devcycle/sdk/server/common/api/IDevCycleApi.java index 98ec779..9e6eb49 100755 --- a/src/main/java/com/devcycle/sdk/server/common/api/IDevCycleApi.java +++ b/src/main/java/com/devcycle/sdk/server/common/api/IDevCycleApi.java @@ -62,7 +62,7 @@ public interface IDevCycleApi { */ @Headers({"Content-Type:application/json"}) @GET("config/v1/server/{sdkToken}.json") - Call getConfig(@Path("sdkToken") String sdkToken, @Header("If-None-Match") String etag); + Call getConfig(@Path("sdkToken") String sdkToken, @Header("If-None-Match") String etag, @Header("If-Modified-Since") String lastModified); /** * Post events to DevCycle for user diff --git a/src/main/java/com/devcycle/sdk/server/local/managers/EnvironmentConfigManager.java b/src/main/java/com/devcycle/sdk/server/local/managers/EnvironmentConfigManager.java index e6059ea..e1edb2f 100644 --- a/src/main/java/com/devcycle/sdk/server/local/managers/EnvironmentConfigManager.java +++ b/src/main/java/com/devcycle/sdk/server/local/managers/EnvironmentConfigManager.java @@ -16,6 +16,8 @@ import retrofit2.Response; import java.io.IOException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -30,6 +32,7 @@ public final class EnvironmentConfigManager { private ProjectConfig config; private String configETag = ""; + private String configLastModified = ""; private final String sdkKey; private final int pollingIntervalMS; @@ -69,7 +72,7 @@ public boolean isConfigInitialized() { } private ProjectConfig getConfig() throws DevCycleException { - Call config = this.configApiClient.getConfig(this.sdkKey, this.configETag); + Call config = this.configApiClient.getConfig(this.sdkKey, this.configETag, this.configLastModified); this.config = getResponseWithRetries(config, 1); return this.config; } @@ -129,13 +132,31 @@ private ProjectConfig getConfigResponse(Call call) throws DevCycl if (response.isSuccessful()) { String currentETag = response.headers().get("ETag"); + String headerLastModified = response.headers().get("Last-Modified"); + + if (!this.configLastModified.isEmpty() && headerLastModified != null && !headerLastModified.isEmpty()) { + ZonedDateTime parsedLastModified = ZonedDateTime.parse( + headerLastModified, + DateTimeFormatter.RFC_1123_DATE_TIME + ); + ZonedDateTime configLastModified = ZonedDateTime.parse( + this.configLastModified, + DateTimeFormatter.RFC_1123_DATE_TIME + ); + + if (parsedLastModified.isBefore(configLastModified)) { + DevCycleLogger.warning("Received a config with last-modified header before the current stored timestamp. Not saving config."); + return this.config; + } + } + ProjectConfig config = response.body(); try { ObjectMapper mapper = new ObjectMapper(); localBucketing.storeConfig(sdkKey, mapper.writeValueAsString(config)); } catch (JsonProcessingException e) { if (this.config != null) { - DevCycleLogger.error("Unable to parse config with etag: " + currentETag + ". Using cache, etag " + this.configETag); + DevCycleLogger.error("Unable to parse config with etag: " + currentETag + ". Using cache, etag " + this.configETag + " last-modified: " + this.configLastModified); return this.config; } else { errorResponse.setMessage(e.getMessage()); @@ -143,9 +164,10 @@ private ProjectConfig getConfigResponse(Call call) throws DevCycl } } this.configETag = currentETag; + this.configLastModified = headerLastModified; return response.body(); } else if (httpResponseCode == HttpResponseCode.NOT_MODIFIED) { - DevCycleLogger.debug("Config not modified, using cache, etag: " + this.configETag); + DevCycleLogger.debug("Config not modified, using cache, etag: " + this.configETag + " last-modified: " + this.configLastModified); return this.config; } else { if (response.errorBody() != null) { diff --git a/src/test/java/com/devcycle/sdk/server/common/api/DVCApiMock.java b/src/test/java/com/devcycle/sdk/server/common/api/DVCApiMock.java index 2d7a126..d866c25 100644 --- a/src/test/java/com/devcycle/sdk/server/common/api/DVCApiMock.java +++ b/src/test/java/com/devcycle/sdk/server/common/api/DVCApiMock.java @@ -30,7 +30,7 @@ public Call track(DevCycleUserAndEvents userAndEvents, Boolean } @Override - public Call getConfig(String sdkToken, String etag) { + public Call getConfig(String sdkToken, String etag, String lastModified) { // TODO Auto-generated method stub return null; }