Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 85 additions & 18 deletions src/main/java/cloud/eppo/api/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.io.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -62,6 +63,9 @@ public class Configuration {
private final Map<String, FlagConfig> flags;
private final Map<String, BanditParameters> bandits;
private final boolean isConfigObfuscated;
private final String environmentName;
private final Date configFetchedAt;
private final Date configPublishedAt;

@SuppressWarnings("unused")
private final byte[] flagConfigJson;
Expand All @@ -74,12 +78,18 @@ public class Configuration {
Map<String, BanditReference> banditReferences,
Map<String, BanditParameters> bandits,
boolean isConfigObfuscated,
String environmentName,
Date configFetchedAt,
Date configPublishedAt,
byte[] flagConfigJson,
byte[] banditParamsJson) {
this.flags = flags;
this.banditReferences = banditReferences;
this.bandits = bandits;
this.isConfigObfuscated = isConfigObfuscated;
this.environmentName = environmentName;
this.configFetchedAt = configFetchedAt;
this.configPublishedAt = configPublishedAt;

// Graft the `forServer` boolean into the flagConfigJson'
if (flagConfigJson != null && flagConfigJson.length != 0) {
Expand All @@ -105,37 +115,65 @@ public static Configuration emptyConfig() {
Collections.emptyMap(),
Collections.emptyMap(),
false,
null,
null,
null,
emptyFlagsBytes,
null);
}

@Override
public String toString() {
return "Configuration{" +
"banditReferences=" + banditReferences +
", flags=" + flags +
", bandits=" + bandits +
", isConfigObfuscated=" + isConfigObfuscated +
", flagConfigJson=" + Arrays.toString(flagConfigJson) +
", banditParamsJson=" + Arrays.toString(banditParamsJson) +
'}';
return "Configuration{"
+ "banditReferences="
+ banditReferences
+ ", flags="
+ flags
+ ", bandits="
+ bandits
+ ", isConfigObfuscated="
+ isConfigObfuscated
+ ", environmentName='"
+ environmentName
+ '\''
+ ", configFetchedAt="
+ configFetchedAt
+ ", configPublishedAt="
+ configPublishedAt
+ ", flagConfigJson="
+ Arrays.toString(flagConfigJson)
+ ", banditParamsJson="
+ Arrays.toString(banditParamsJson)
+ '}';
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Configuration that = (Configuration) o;
return isConfigObfuscated == that.isConfigObfuscated
&& Objects.equals(banditReferences, that.banditReferences)
&& Objects.equals(flags, that.flags)
&& Objects.equals(bandits, that.bandits)
&& Objects.deepEquals(flagConfigJson, that.flagConfigJson)
&& Objects.deepEquals(banditParamsJson, that.banditParamsJson);
&& Objects.equals(banditReferences, that.banditReferences)
&& Objects.equals(flags, that.flags)
&& Objects.equals(bandits, that.bandits)
&& Objects.equals(environmentName, that.environmentName)
&& Objects.equals(configFetchedAt, that.configFetchedAt)
&& Objects.equals(configPublishedAt, that.configPublishedAt)
&& Objects.deepEquals(flagConfigJson, that.flagConfigJson)
&& Objects.deepEquals(banditParamsJson, that.banditParamsJson);
}

@Override
public int hashCode() {
return Objects.hash(banditReferences, flags, bandits, isConfigObfuscated, Arrays.hashCode(flagConfigJson), Arrays.hashCode(banditParamsJson));
return Objects.hash(
banditReferences,
flags,
bandits,
isConfigObfuscated,
environmentName,
configFetchedAt,
configPublishedAt,
Arrays.hashCode(flagConfigJson),
Arrays.hashCode(banditParamsJson));
}

public FlagConfig getFlag(String flagKey) {
Expand Down Expand Up @@ -205,6 +243,18 @@ public Set<String> getFlagKeys() {
return flags == null ? Collections.emptySet() : flags.keySet();
}

public String getEnvironmentName() {
return environmentName;
}

public Date getConfigFetchedAt() {
return configFetchedAt;
}

public Date getConfigPublishedAt() {
return configPublishedAt;
}

public static Builder builder(byte[] flagJson) {
return new Builder(flagJson);
}
Expand All @@ -226,6 +276,8 @@ public static class Builder {
private Map<String, BanditParameters> bandits = Collections.emptyMap();
private final byte[] flagJson;
private byte[] banditParamsJson;
private final String environmentName;
private final Date configPublishedAt;

private static FlagConfigResponse parseFlagResponse(byte[] flagJson) {
if (flagJson == null || flagJson.length == 0) {
Expand Down Expand Up @@ -268,15 +320,20 @@ public Builder(
boolean isConfigObfuscated) {
this.isConfigObfuscated = isConfigObfuscated;
this.flagJson = flagJson;
if (flagConfigResponse == null
|| flagConfigResponse.getFlags() == null
|| flagConfigResponse.getFlags().isEmpty()) {
if (flagConfigResponse == null || flagConfigResponse.getFlags() == null) {
log.warn("'flags' map missing in flag definition JSON");
flags = Collections.emptyMap();
banditReferences = Collections.emptyMap();
environmentName = null;
configPublishedAt = null;
} else {
flags = Collections.unmodifiableMap(flagConfigResponse.getFlags());
banditReferences = Collections.unmodifiableMap(flagConfigResponse.getBanditReferences());

// Extract environment name and published at timestamp from the response
environmentName = flagConfigResponse.getEnvironmentName();
configPublishedAt = flagConfigResponse.getCreatedAt();

log.debug("Loaded {} flag definitions from flag definition JSON", flags.size());
}
}
Expand Down Expand Up @@ -337,8 +394,18 @@ public Builder banditParameters(byte[] banditParameterJson) {
}

public Configuration build() {
// Record the time when configuration is built/fetched
Date configFetchedAt = new Date();
return new Configuration(
flags, banditReferences, bandits, isConfigObfuscated, flagJson, banditParamsJson);
flags,
banditReferences,
bandits,
isConfigObfuscated,
environmentName,
configFetchedAt,
configPublishedAt,
flagJson,
banditParamsJson);
}
}
}
1 change: 0 additions & 1 deletion src/main/java/cloud/eppo/api/EvaluationDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public class EvaluationDetails {
private final List<AllocationDetails> unmatchedAllocations;
private final List<AllocationDetails> unevaluatedAllocations;


public EvaluationDetails(
String environmentName,
Date configFetchedAt,
Expand Down
56 changes: 44 additions & 12 deletions src/main/java/cloud/eppo/ufc/dto/FlagConfigResponse.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cloud.eppo.ufc.dto;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -8,46 +9,69 @@ public class FlagConfigResponse {
private final Map<String, FlagConfig> flags;
private final Map<String, BanditReference> banditReferences;
private final Format format;
private final String environmentName;
private final Date createdAt;

public FlagConfigResponse(
Map<String, FlagConfig> flags,
Map<String, BanditReference> banditReferences,
Format dataFormat) {
Format dataFormat,
String environmentName,
Date createdAt) {
this.flags = flags;
this.banditReferences = banditReferences;
format = dataFormat;
this.format = dataFormat;
this.environmentName = environmentName;
this.createdAt = createdAt;
}

public FlagConfigResponse(
Map<String, FlagConfig> flags,
Map<String, BanditReference> banditReferences,
Format dataFormat) {
this(flags, banditReferences, dataFormat, null, null);
}

public FlagConfigResponse(
Map<String, FlagConfig> flags, Map<String, BanditReference> banditReferences) {
this(flags, banditReferences, Format.SERVER);
this(flags, banditReferences, Format.SERVER, null, null);
}

public FlagConfigResponse() {
this(new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), Format.SERVER);
this(new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), Format.SERVER, null, null);
}

@Override
public String toString() {
return "FlagConfigResponse{" +
"flags=" + flags +
", banditReferences=" + banditReferences +
", format=" + format +
'}';
return "FlagConfigResponse{"
+ "flags="
+ flags
+ ", banditReferences="
+ banditReferences
+ ", format="
+ format
+ ", environmentName='"
+ environmentName
+ '\''
+ ", createdAt="
+ createdAt
+ '}';
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
FlagConfigResponse that = (FlagConfigResponse) o;
return Objects.equals(flags, that.flags)
&& Objects.equals(banditReferences, that.banditReferences)
&& format == that.format;
&& Objects.equals(banditReferences, that.banditReferences)
&& format == that.format
&& Objects.equals(environmentName, that.environmentName)
&& Objects.equals(createdAt, that.createdAt);
}

@Override
public int hashCode() {
return Objects.hash(flags, banditReferences, format);
return Objects.hash(flags, banditReferences, format, environmentName, createdAt);
}

public Map<String, FlagConfig> getFlags() {
Expand All @@ -62,6 +86,14 @@ public Format getFormat() {
return format;
}

public String getEnvironmentName() {
return environmentName;
}

public Date getCreatedAt() {
return createdAt;
}

public enum Format {
SERVER,
CLIENT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import cloud.eppo.api.EppoValue;
import cloud.eppo.model.ShardRange;
import cloud.eppo.ufc.dto.*;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -35,7 +34,7 @@ public FlagConfigResponseDeserializer() {

@Override
public FlagConfigResponse deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JacksonException {
throws IOException {
JsonNode rootNode = jp.getCodec().readTree(jp);

if (rootNode == null || !rootNode.isObject()) {
Expand All @@ -55,6 +54,19 @@ public FlagConfigResponse deserialize(JsonParser jp, DeserializationContext ctxt
? FlagConfigResponse.Format.SERVER
: FlagConfigResponse.Format.valueOf(formatNode.asText());

// Parse environment name from environment object
String environmentName = null;
JsonNode environmentNode = rootNode.get("environment");
if (environmentNode != null && environmentNode.isObject()) {
JsonNode nameNode = environmentNode.get("name");
if (nameNode != null) {
environmentName = nameNode.asText();
}
}

// Parse createdAt
Date createdAt = parseUtcISODateNode(rootNode.get("createdAt"));

Map<String, FlagConfig> flags = new ConcurrentHashMap<>();

flagsNode
Expand All @@ -81,7 +93,7 @@ public FlagConfigResponse deserialize(JsonParser jp, DeserializationContext ctxt
}
}

return new FlagConfigResponse(flags, banditReferences, dataFormat);
return new FlagConfigResponse(flags, banditReferences, dataFormat, environmentName, createdAt);
}

private FlagConfig deserializeFlag(JsonNode jsonNode) {
Expand Down
Loading